1 // i_s - library routines for pstop.
3 // This file contains the library routines for managing the
4 // table_io_waits_by_table table.
10 "github.com/sjmudd/pstop/lib"
11 "github.com/sjmudd/pstop/p_s"
17 type map_string_int map[string]int
20 type Processlist struct {
23 current processlist_rows // processlist
24 results pl_by_user_rows // results by user
25 totals pl_by_user_row // totals of results
28 // Collect() collects data from the db, updating initial
29 // values if needed, and then subtracting initial values if we want
30 // relative values, after which it stores totals.
31 func (t *Processlist) Collect(dbh *sql.DB) {
32 lib.Logger.Println("Processlist.Collect() - starting collection of data")
35 t.current = select_processlist(dbh)
36 lib.Logger.Println("t.current collected", len(t.current), "row(s) from SELECT")
38 t.processlist2by_user()
41 // lib.Logger.Println( "- collecting t.totals from t.results" )
42 t.totals = t.results.totals()
44 lib.Logger.Println("Processlist.Collect() END, took:", time.Duration(time.Since(start)).String())
47 func (t *Processlist) Headings() string {
48 return t.results.Headings()
51 func (t Processlist) EmptyRowContent() string {
52 return t.results.emptyRowContent()
55 func (t Processlist) TotalRowContent() string {
56 return t.totals.row_content(t.totals)
59 func (t Processlist) RowContent(max_rows int) []string {
60 rows := make([]string, 0, max_rows)
62 for i := range t.results {
64 rows = append(rows, t.results[i].row_content(t.totals))
71 func (t Processlist) Description() string {
72 count := t.count_rows()
73 return fmt.Sprintf("Activity by Username (processlist) %d rows", count)
76 func (t Processlist) count_rows() int {
78 for row := range t.results {
79 if t.results[row].username != "" {
86 // return the hostname without the port part
87 func get_hostname(h_p string) string {
88 i := strings.Index(h_p, ":")
92 return h_p // shouldn't happen !!!
96 // read in processlist and add the appropriate values into a new pl_by_user table
97 func (t *Processlist) processlist2by_user() {
98 lib.Logger.Println("Processlist.processlist2by_user() START")
100 var re_active_repl_master_thread *regexp.Regexp = regexp.MustCompile("Sending binlog event to slave")
101 var re_select *regexp.Regexp = regexp.MustCompile(`(?i)SELECT`) // make case insensitive
102 var re_insert *regexp.Regexp = regexp.MustCompile(`(?i)INSERT`) // make case insensitive
103 var re_update *regexp.Regexp = regexp.MustCompile(`(?i)UPDATE`) // make case insensitive
104 var re_delete *regexp.Regexp = regexp.MustCompile(`(?i)DELETE`) // make case insensitive
106 var row pl_by_user_row
107 var results pl_by_user_rows
108 var my_hosts map_string_int
109 var my_db map_string_int
112 row_by_user := make(map[string]pl_by_user_row)
113 hosts_by_user := make(map[string]map_string_int)
114 dbs_by_user := make(map[string]map_string_int)
116 for i := range t.current {
117 // munge the username for special purposes (event scheduler, replication threads etc)
118 id := t.current[i].ID
119 username := t.current[i].USER // limit size for display
120 host := get_hostname(t.current[i].HOST)
121 command := t.current[i].COMMAND
122 db := t.current[i].DB
123 info := t.current[i].INFO
124 state := t.current[i].STATE
126 lib.Logger.Println("- id/user/host:", id, username, host)
128 if old_row, ok := row_by_user[username]; ok {
129 lib.Logger.Println("- found old row in row_by_user")
130 row = old_row // get old row
132 lib.Logger.Println("- NOT found old row in row_by_user")
133 // create new row - RESET THE VALUES !!!!
134 rowp := new(pl_by_user_row)
136 row.username = t.current[i].USER
137 row_by_user[username] = row
140 // ignore system SQL threads (may be more to filter out)
141 if username != "system user" && host != "" && command != "Sleep" && command != "Binlog Dump" {
142 row.runtime += t.current[i].TIME
145 if command == "Binlog Dump" && re_active_repl_master_thread.MatchString(state) {
149 // add the host if not known already
151 if my_hosts, ok = hosts_by_user[username]; !ok {
152 my_hosts = make(map_string_int)
154 my_hosts[host] = 1 // whatever - value doesn't matter
155 hosts_by_user[username] = my_hosts
157 row.hosts = uint64(len(hosts_by_user[username]))
159 // add the db count if not known already
161 if my_db, ok = dbs_by_user[username]; !ok {
162 my_db = make(map_string_int)
164 my_db[db] = 1 // whatever - value doesn't matter
165 dbs_by_user[username] = my_db
167 row.dbs = uint64(len(dbs_by_user[username]))
169 if re_select.MatchString(info) == true {
172 if re_insert.MatchString(info) == true {
175 if re_update.MatchString(info) == true {
178 if re_delete.MatchString(info) == true {
182 row_by_user[username] = row
185 results = make(pl_by_user_rows, 0, len(row_by_user))
186 for _, v := range row_by_user {
187 results = append(results, v)
190 t.results.Sort() // sort output
192 t.totals = t.results.totals()
194 lib.Logger.Println("Processlist.processlist2by_user() END")