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
23 current table_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 *Object) Collect(dbh *sql.DB) {
32 lib.Logger.Println("Object.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("Object.Collect() END, took:", time.Duration(time.Since(start)).String())
47 func (t *Object) Headings() string {
48 return t.results.Headings()
51 func (t Object) EmptyRowContent() string {
52 return t.results.emptyRowContent()
55 func (t Object) TotalRowContent() string {
56 return t.totals.row_content(t.totals)
59 func (t Object) 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 Object) Description() string {
72 count := t.count_rows()
73 return fmt.Sprintf("Activity by Username (processlist) %d rows", count)
76 func (t Object) 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 *Object) processlist2by_user() {
98 lib.Logger.Println("Object.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 != "Binlog Dump" {
142 if command == "Sleep" {
143 row.sleeptime += t.current[i].TIME
145 row.runtime += t.current[i].TIME
149 if command == "Binlog Dump" && re_active_repl_master_thread.MatchString(state) {
153 // add the host if not known already
155 if my_hosts, ok = hosts_by_user[username]; !ok {
156 my_hosts = make(map_string_int)
158 my_hosts[host] = 1 // whatever - value doesn't matter
159 hosts_by_user[username] = my_hosts
161 row.hosts = uint64(len(hosts_by_user[username]))
163 // add the db count if not known already
165 if my_db, ok = dbs_by_user[username]; !ok {
166 my_db = make(map_string_int)
168 my_db[db] = 1 // whatever - value doesn't matter
169 dbs_by_user[username] = my_db
171 row.dbs = uint64(len(dbs_by_user[username]))
173 if re_select.MatchString(info) == true {
176 if re_insert.MatchString(info) == true {
179 if re_update.MatchString(info) == true {
182 if re_delete.MatchString(info) == true {
186 row_by_user[username] = row
189 results = make(pl_by_user_rows, 0, len(row_by_user))
190 for _, v := range row_by_user {
191 results = append(results, v)
194 t.results.Sort() // sort output
196 t.totals = t.results.totals()
198 lib.Logger.Println("Object.processlist2by_user() END")