1 // lib - library routines for pstop.
3 // this file contains the library routines related to the stored state in pstop.
12 "github.com/sjmudd/pstop/i_s"
13 "github.com/sjmudd/pstop/lib"
14 ewsgben "github.com/sjmudd/pstop/p_s/events_waits_summary_global_by_event_name"
15 essgben "github.com/sjmudd/pstop/p_s/events_stages_summary_global_by_event_name"
16 fsbi "github.com/sjmudd/pstop/p_s/file_summary_by_instance"
17 "github.com/sjmudd/pstop/p_s/ps_table"
18 "github.com/sjmudd/pstop/p_s/setup_instruments"
19 tiwsbt "github.com/sjmudd/pstop/p_s/table_io_waits_summary_by_table"
20 tlwsbt "github.com/sjmudd/pstop/p_s/table_lock_waits_summary_by_table"
21 "github.com/sjmudd/pstop/screen"
22 "github.com/sjmudd/pstop/version"
23 "github.com/sjmudd/pstop/wait_info"
26 // what information to show
45 fsbi ps_table.Tabler // ufsbi.File_summary_by_instance
46 tiwsbt tiwsbt.Table_io_waits_summary_by_table
47 tlwsbt ps_table.Tabler // tlwsbt.Table_lock_waits_summary_by_table
48 ewsgben ps_table.Tabler // ewsgben.Events_waits_summary_global_by_event_name
49 essgben ps_table.Tabler // essgben.Events_stages_summary_global_by_event_name
51 screen screen.TermboxScreen
54 want_relative_stats bool
55 wait_info.WaitInfo // embedded
56 setup_instruments setup_instruments.SetupInstruments
59 func (state *State) Setup(dbh *sql.DB) {
61 state.finished = false
63 state.screen.Initialise()
65 state.setup_instruments.EnableMutexMonitoring(dbh)
66 _, variables := lib.SelectAllGlobalVariablesByVariableName(state.dbh)
67 // setup to their initial types/values
68 state.fsbi = fsbi.NewFileSummaryByInstance(variables)
69 state.tlwsbt = new(tlwsbt.Table_lock_waits_summary_by_table)
70 state.ewsgben = new(ewsgben.Table_events_waits_summary_global_by_event_name)
71 state.essgben = new(essgben.Object)
73 state.want_relative_stats = true // we show info from the point we start collecting data
74 state.fsbi.SetWantRelativeStats(state.want_relative_stats)
76 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
78 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
80 state.users.SetWantRelativeStats(state.want_relative_stats) // ignored
81 state.users.SetNow() // ignored
82 state.essgben.SetWantRelativeStats(state.want_relative_stats)
83 state.essgben.SetNow()
84 state.ewsgben.SetWantRelativeStats(state.want_relative_stats) // ignored
85 state.ewsgben.SetNow() // ignored
87 state.ResetDBStatistics()
90 state.show = showLatency
91 state.tiwsbt.SetWantsLatency(true)
93 // get short name (to save space)
94 _, hostname := lib.SelectGlobalVariableByVariableName(state.dbh, "HOSTNAME")
95 if index := strings.Index(hostname, "."); index >= 0 {
96 hostname = hostname[0:index]
98 _, mysql_version := lib.SelectGlobalVariableByVariableName(state.dbh, "VERSION")
99 _, datadir := lib.SelectGlobalVariableByVariableName(state.dbh, "DATADIR")
100 state.SetHostname(hostname)
101 state.SetMySQLVersion(mysql_version)
102 state.SetDatadir(datadir)
105 // have we finished ?
106 func (state State) Finished() bool {
107 return state.finished
110 // indicate we have finished
111 func (state *State) SetFinished() {
112 state.finished = true
115 // do a fresh collection of data and then update the initial values based on that.
116 func (state *State) ResetDBStatistics() {
118 state.SyncReferenceValues()
121 func (state *State) SyncReferenceValues() {
123 state.fsbi.SyncReferenceValues()
124 state.tlwsbt.SyncReferenceValues()
125 state.tiwsbt.SyncReferenceValues()
126 state.essgben.SyncReferenceValues()
127 lib.Logger.Println("state.SyncReferenceValues() took", time.Duration(time.Since(start)).String())
130 // collect all initial values on startup / reset
131 func (state *State) CollectAll() {
132 state.fsbi.Collect(state.dbh)
133 state.tlwsbt.Collect(state.dbh)
134 state.tiwsbt.Collect(state.dbh)
137 // Only collect the data we are looking at.
138 func (state *State) Collect() {
142 case showLatency, showOps:
143 state.tiwsbt.Collect(state.dbh)
145 state.fsbi.Collect(state.dbh)
147 state.tlwsbt.Collect(state.dbh)
149 state.users.Collect(state.dbh)
151 state.ewsgben.Collect(state.dbh)
153 state.essgben.Collect(state.dbh)
155 lib.Logger.Println("state.Collect() took", time.Duration(time.Since(start)).String())
158 func (state State) MySQLVersion() string {
159 return state.mysql_version
162 func (state State) Datadir() string {
166 func (state *State) SetHelp(newHelp bool) {
173 func (state *State) SetDatadir(datadir string) {
174 state.datadir = datadir
177 func (state *State) SetMySQLVersion(mysql_version string) {
178 state.mysql_version = mysql_version
181 func (state *State) SetHostname(hostname string) {
182 state.hostname = hostname
185 func (state State) Help() bool {
189 // states go: showLatency -> showOps -> showIO -> showLocks -> showUsers -> showMutex -> showStages
191 // display the output according to the mode we are in
192 func (state *State) Display() {
194 state.screen.DisplayHelp()
196 state.displayHeading()
198 case showLatency, showOps:
199 state.displayOpsOrLatency()
209 state.displayStages()
214 // fix_latency_setting() ensures the SetWantsLatency() value is
215 // correct. This needs to be done more cleanly.
216 func (state *State) fix_latency_setting() {
217 if state.show == showLatency {
218 state.tiwsbt.SetWantsLatency(true)
220 if state.show == showOps {
221 state.tiwsbt.SetWantsLatency(false)
225 // change to the previous display mode
226 func (state *State) DisplayPrevious() {
227 if state.show == showLatency {
228 state.show = showStages
232 state.fix_latency_setting()
237 // change to the next display mode
238 func (state *State) DisplayNext() {
239 if state.show == showStages {
240 state.show = showLatency
244 state.fix_latency_setting()
249 func (state State) displayHeading() {
251 state.displayDescription()
254 func (state State) displayLine0() {
255 _, uptime := lib.SelectGlobalStatusByVariableName(state.dbh, "UPTIME")
256 top_line := lib.MyName() + " " + version.Version() + " - " + now_hhmmss() + " " + state.hostname + " / " + state.mysql_version + ", up " + fmt.Sprintf("%-16s", lib.Uptime(uptime))
257 if state.want_relative_stats {
260 var initial time.Time
263 case showLatency, showOps:
264 initial = state.tiwsbt.Last()
266 initial = state.fsbi.Last()
268 initial = state.tlwsbt.Last()
270 initial = state.users.Last()
272 initial = state.essgben.Last()
274 initial = state.ewsgben.Last()
276 // should not get here !
279 d := now.Sub(initial)
281 top_line = top_line + " [REL] " + fmt.Sprintf("%.0f seconds", d.Seconds())
283 top_line = top_line + " [ABS] "
285 state.screen.PrintAt(0, 0, top_line)
288 func (state State) displayDescription() {
289 description := "UNKNOWN"
292 case showLatency, showOps:
293 description = state.tiwsbt.Description()
295 description = state.fsbi.Description()
297 description = state.tlwsbt.Description()
299 description = state.users.Description()
301 description = state.ewsgben.Description()
303 description = state.essgben.Description()
306 state.screen.PrintAt(0, 1, description)
309 func (state *State) displayOpsOrLatency() {
310 state.screen.BoldPrintAt(0, 2, state.tiwsbt.Headings())
312 max_rows := state.screen.Height() - 3
313 row_content := state.tiwsbt.RowContent(max_rows)
316 for k := range row_content {
318 state.screen.PrintAt(0, y, row_content[k])
320 // print out empty rows
321 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
323 if y < state.screen.Height()-1 {
324 state.screen.PrintAt(0, y, state.tiwsbt.EmptyRowContent())
328 // print out the totals at the bottom
329 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tiwsbt.TotalRowContent())
332 // show actual I/O latency values
333 func (state State) displayIO() {
334 state.screen.BoldPrintAt(0, 2, state.fsbi.Headings())
336 // print out the data
337 max_rows := state.screen.Height() - 3
338 row_content := state.fsbi.RowContent(max_rows)
341 for k := range row_content {
343 state.screen.PrintAt(0, y, row_content[k])
345 // print out empty rows
346 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
348 if y < state.screen.Height()-1 {
349 state.screen.PrintAt(0, y, state.fsbi.EmptyRowContent())
353 // print out the totals at the bottom
354 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.fsbi.TotalRowContent())
357 func (state *State) displayLocks() {
358 state.screen.BoldPrintAt(0, 2, state.tlwsbt.Headings())
360 // print out the data
361 max_rows := state.screen.Height() - 3
362 row_content := state.tlwsbt.RowContent(max_rows)
365 for k := range row_content {
367 state.screen.PrintAt(0, y, row_content[k])
369 // print out empty rows
370 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
372 if y < state.screen.Height()-1 {
373 state.screen.PrintAt(0, y, state.tlwsbt.EmptyRowContent())
377 // print out the totals at the bottom
378 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tlwsbt.TotalRowContent())
381 func (state *State) displayUsers() {
382 state.screen.BoldPrintAt(0, 2, state.users.Headings())
384 // print out the data
385 max_rows := state.screen.Height() - 3
386 row_content := state.users.RowContent(max_rows)
389 for k := range row_content {
391 state.screen.PrintAt(0, y, row_content[k])
393 // print out empty rows
394 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
396 if y < state.screen.Height()-1 {
397 state.screen.PrintAt(0, y, state.users.EmptyRowContent())
401 // print out the totals at the bottom
402 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.users.TotalRowContent())
405 func (state *State) displayMutex() {
406 state.screen.BoldPrintAt(0, 2, state.ewsgben.Headings())
408 // print out the data
409 max_rows := state.screen.Height() - 3
410 row_content := state.ewsgben.RowContent(max_rows)
413 for k := range row_content {
415 state.screen.PrintAt(0, y, row_content[k])
417 // print out empty rows
418 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
420 if y < state.screen.Height()-1 {
421 state.screen.PrintAt(0, y, state.ewsgben.EmptyRowContent())
425 // print out the totals at the bottom
426 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.ewsgben.TotalRowContent())
429 func (state *State) displayStages() {
430 state.screen.BoldPrintAt(0, 2, state.essgben.Headings())
432 // print out the data
433 max_rows := state.screen.Height() - 3
434 row_content := state.essgben.RowContent(max_rows)
437 for k := range row_content {
439 state.screen.PrintAt(0, y, row_content[k])
441 // print out empty rows
442 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
444 if y < state.screen.Height()-1 {
445 state.screen.PrintAt(0, y, state.essgben.EmptyRowContent())
449 // print out the totals at the bottom
450 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.essgben.TotalRowContent())
454 // do we want to show all p_s data?
455 func (state State) WantRelativeStats() bool {
456 return state.want_relative_stats
459 // set if we want data from when we started/reset stats.
460 func (state *State) SetWantRelativeStats(want_relative_stats bool) {
461 state.want_relative_stats = want_relative_stats
463 state.fsbi.SetWantRelativeStats(want_relative_stats)
464 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
465 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
466 state.ewsgben.SetWantRelativeStats(state.want_relative_stats)
469 // if there's a better way of doing this do it better ...
470 func now_hhmmss() string {
472 return fmt.Sprintf("%2d:%02d:%02d", t.Hour(), t.Minute(), t.Second())
475 // record the latest screen size
476 func (state *State) ScreenSetSize(width, height int) {
477 state.screen.SetSize(width, height)
480 // clean up screen and disconnect database
481 func (state *State) Cleanup() {
483 if state.dbh != nil {
484 state.setup_instruments.Restore(state.dbh)
485 _ = state.dbh.Close()