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/processlist"
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
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
50 users processlist.Object
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 = setup_instruments.NewSetupInstruments(dbh)
66 state.setup_instruments.EnableMonitoring()
68 _, variables := lib.SelectAllGlobalVariablesByVariableName(state.dbh)
69 // setup to their initial types/values
70 state.fsbi = fsbi.NewFileSummaryByInstance(variables)
71 state.tlwsbt = new(tlwsbt.Object)
72 state.ewsgben = new(ewsgben.Object)
73 state.essgben = new(essgben.Object)
75 state.want_relative_stats = true // we show info from the point we start collecting data
76 state.fsbi.SetWantRelativeStats(state.want_relative_stats)
78 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
80 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
82 state.users.SetWantRelativeStats(state.want_relative_stats) // ignored
83 state.users.SetNow() // ignored
84 state.essgben.SetWantRelativeStats(state.want_relative_stats)
85 state.essgben.SetNow()
86 state.ewsgben.SetWantRelativeStats(state.want_relative_stats) // ignored
87 state.ewsgben.SetNow() // ignored
89 state.ResetDBStatistics()
92 state.show = showLatency
93 state.tiwsbt.SetWantsLatency(true)
95 // get short name (to save space)
96 _, hostname := lib.SelectGlobalVariableByVariableName(state.dbh, "HOSTNAME")
97 if index := strings.Index(hostname, "."); index >= 0 {
98 hostname = hostname[0:index]
100 _, mysql_version := lib.SelectGlobalVariableByVariableName(state.dbh, "VERSION")
101 _, datadir := lib.SelectGlobalVariableByVariableName(state.dbh, "DATADIR")
102 state.SetHostname(hostname)
103 state.SetMySQLVersion(mysql_version)
104 state.SetDatadir(datadir)
107 // have we finished ?
108 func (state State) Finished() bool {
109 return state.finished
112 // indicate we have finished
113 func (state *State) SetFinished() {
114 state.finished = true
117 // do a fresh collection of data and then update the initial values based on that.
118 func (state *State) ResetDBStatistics() {
120 state.SyncReferenceValues()
123 func (state *State) SyncReferenceValues() {
125 state.fsbi.SyncReferenceValues()
126 state.tlwsbt.SyncReferenceValues()
127 state.tiwsbt.SyncReferenceValues()
128 state.essgben.SyncReferenceValues()
129 lib.Logger.Println("state.SyncReferenceValues() took", time.Duration(time.Since(start)).String())
132 // collect all initial values on startup / reset
133 func (state *State) CollectAll() {
134 state.fsbi.Collect(state.dbh)
135 state.tlwsbt.Collect(state.dbh)
136 state.tiwsbt.Collect(state.dbh)
139 // Only collect the data we are looking at.
140 func (state *State) Collect() {
144 case showLatency, showOps:
145 state.tiwsbt.Collect(state.dbh)
147 state.fsbi.Collect(state.dbh)
149 state.tlwsbt.Collect(state.dbh)
151 state.users.Collect(state.dbh)
153 state.ewsgben.Collect(state.dbh)
155 state.essgben.Collect(state.dbh)
157 lib.Logger.Println("state.Collect() took", time.Duration(time.Since(start)).String())
160 func (state State) MySQLVersion() string {
161 return state.mysql_version
164 func (state State) Datadir() string {
168 func (state *State) SetHelp(newHelp bool) {
175 func (state *State) SetDatadir(datadir string) {
176 state.datadir = datadir
179 func (state *State) SetMySQLVersion(mysql_version string) {
180 state.mysql_version = mysql_version
183 func (state *State) SetHostname(hostname string) {
184 state.hostname = hostname
187 func (state State) Help() bool {
191 // states go: showLatency -> showOps -> showIO -> showLocks -> showUsers -> showMutex -> showStages
193 // display the output according to the mode we are in
194 func (state *State) Display() {
196 state.screen.DisplayHelp()
198 state.displayHeading()
200 case showLatency, showOps:
201 state.displayOpsOrLatency()
211 state.displayStages()
216 // fix_latency_setting() ensures the SetWantsLatency() value is
217 // correct. This needs to be done more cleanly.
218 func (state *State) fix_latency_setting() {
219 if state.show == showLatency {
220 state.tiwsbt.SetWantsLatency(true)
222 if state.show == showOps {
223 state.tiwsbt.SetWantsLatency(false)
227 // change to the previous display mode
228 func (state *State) DisplayPrevious() {
229 if state.show == showLatency {
230 state.show = showStages
234 state.fix_latency_setting()
239 // change to the next display mode
240 func (state *State) DisplayNext() {
241 if state.show == showStages {
242 state.show = showLatency
246 state.fix_latency_setting()
251 func (state State) displayHeading() {
253 state.displayDescription()
256 func (state State) displayLine0() {
257 _, uptime := lib.SelectGlobalStatusByVariableName(state.dbh, "UPTIME")
258 top_line := lib.MyName() + " " + version.Version() + " - " + now_hhmmss() + " " + state.hostname + " / " + state.mysql_version + ", up " + fmt.Sprintf("%-16s", lib.Uptime(uptime))
259 if state.want_relative_stats {
262 var initial time.Time
265 case showLatency, showOps:
266 initial = state.tiwsbt.Last()
268 initial = state.fsbi.Last()
270 initial = state.tlwsbt.Last()
272 initial = state.users.Last()
274 initial = state.essgben.Last()
276 initial = state.ewsgben.Last()
278 // should not get here !
281 d := now.Sub(initial)
283 top_line = top_line + " [REL] " + fmt.Sprintf("%.0f seconds", d.Seconds())
285 top_line = top_line + " [ABS] "
287 state.screen.PrintAt(0, 0, top_line)
290 func (state State) displayDescription() {
291 description := "UNKNOWN"
294 case showLatency, showOps:
295 description = state.tiwsbt.Description()
297 description = state.fsbi.Description()
299 description = state.tlwsbt.Description()
301 description = state.users.Description()
303 description = state.ewsgben.Description()
305 description = state.essgben.Description()
308 state.screen.PrintAt(0, 1, description)
311 func (state *State) displayOpsOrLatency() {
312 state.screen.BoldPrintAt(0, 2, state.tiwsbt.Headings())
314 max_rows := state.screen.Height() - 3
315 row_content := state.tiwsbt.RowContent(max_rows)
318 for k := range row_content {
320 state.screen.PrintAt(0, y, row_content[k])
322 // print out empty rows
323 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
325 if y < state.screen.Height()-1 {
326 state.screen.PrintAt(0, y, state.tiwsbt.EmptyRowContent())
330 // print out the totals at the bottom
331 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tiwsbt.TotalRowContent())
334 // show actual I/O latency values
335 func (state State) displayIO() {
336 state.screen.BoldPrintAt(0, 2, state.fsbi.Headings())
338 // print out the data
339 max_rows := state.screen.Height() - 3
340 row_content := state.fsbi.RowContent(max_rows)
343 for k := range row_content {
345 state.screen.PrintAt(0, y, row_content[k])
347 // print out empty rows
348 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
350 if y < state.screen.Height()-1 {
351 state.screen.PrintAt(0, y, state.fsbi.EmptyRowContent())
355 // print out the totals at the bottom
356 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.fsbi.TotalRowContent())
359 func (state *State) displayLocks() {
360 state.screen.BoldPrintAt(0, 2, state.tlwsbt.Headings())
362 // print out the data
363 max_rows := state.screen.Height() - 3
364 row_content := state.tlwsbt.RowContent(max_rows)
367 for k := range row_content {
369 state.screen.PrintAt(0, y, row_content[k])
371 // print out empty rows
372 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
374 if y < state.screen.Height()-1 {
375 state.screen.PrintAt(0, y, state.tlwsbt.EmptyRowContent())
379 // print out the totals at the bottom
380 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tlwsbt.TotalRowContent())
383 func (state *State) displayUsers() {
384 state.screen.BoldPrintAt(0, 2, state.users.Headings())
386 // print out the data
387 max_rows := state.screen.Height() - 3
388 row_content := state.users.RowContent(max_rows)
391 for k := range row_content {
393 state.screen.PrintAt(0, y, row_content[k])
395 // print out empty rows
396 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
398 if y < state.screen.Height()-1 {
399 state.screen.PrintAt(0, y, state.users.EmptyRowContent())
403 // print out the totals at the bottom
404 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.users.TotalRowContent())
407 func (state *State) displayMutex() {
408 state.screen.BoldPrintAt(0, 2, state.ewsgben.Headings())
410 // print out the data
411 max_rows := state.screen.Height() - 3
412 row_content := state.ewsgben.RowContent(max_rows)
415 for k := range row_content {
417 state.screen.PrintAt(0, y, row_content[k])
419 // print out empty rows
420 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
422 if y < state.screen.Height()-1 {
423 state.screen.PrintAt(0, y, state.ewsgben.EmptyRowContent())
427 // print out the totals at the bottom
428 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.ewsgben.TotalRowContent())
431 func (state *State) displayStages() {
432 state.screen.BoldPrintAt(0, 2, state.essgben.Headings())
434 // print out the data
435 max_rows := state.screen.Height() - 3
436 row_content := state.essgben.RowContent(max_rows)
439 for k := range row_content {
441 state.screen.PrintAt(0, y, row_content[k])
443 // print out empty rows
444 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
446 if y < state.screen.Height()-1 {
447 state.screen.PrintAt(0, y, state.essgben.EmptyRowContent())
451 // print out the totals at the bottom
452 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.essgben.TotalRowContent())
456 // do we want to show all p_s data?
457 func (state State) WantRelativeStats() bool {
458 return state.want_relative_stats
461 // set if we want data from when we started/reset stats.
462 func (state *State) SetWantRelativeStats(want_relative_stats bool) {
463 state.want_relative_stats = want_relative_stats
465 state.fsbi.SetWantRelativeStats(want_relative_stats)
466 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
467 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
468 state.ewsgben.SetWantRelativeStats(state.want_relative_stats)
469 state.essgben.SetWantRelativeStats(state.want_relative_stats)
472 // if there's a better way of doing this do it better ...
473 func now_hhmmss() string {
475 return fmt.Sprintf("%2d:%02d:%02d", t.Hour(), t.Minute(), t.Second())
478 // record the latest screen size
479 func (state *State) ScreenSetSize(width, height int) {
480 state.screen.SetSize(width, height)
483 // clean up screen and disconnect database
484 func (state *State) Cleanup() {
486 if state.dbh != nil {
487 state.setup_instruments.RestoreConfiguration()
488 _ = state.dbh.Close()