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 fsbi "github.com/sjmudd/pstop/p_s/file_summary_by_instance"
15 "github.com/sjmudd/pstop/p_s/ps_table"
16 "github.com/sjmudd/pstop/wait_info"
17 ewsgben "github.com/sjmudd/pstop/p_s/events_waits_summary_global_by_event_name"
18 tiwsbt "github.com/sjmudd/pstop/p_s/table_io_waits_summary_by_table"
19 tlwsbt "github.com/sjmudd/pstop/p_s/table_lock_waits_summary_by_table"
20 "github.com/sjmudd/pstop/screen"
21 "github.com/sjmudd/pstop/version"
24 // what information to show
42 fsbi ps_table.Tabler // ufsbi.File_summary_by_instance
43 tiwsbt tiwsbt.Table_io_waits_summary_by_table
44 tlwsbt ps_table.Tabler // tlwsbt.Table_lock_waits_summary_by_table
45 ewsgben ps_table.Tabler // ewsgben.Events_waits_summary_global_by_event_name
47 screen screen.TermboxScreen
50 want_relative_stats bool
51 wait_info.WaitInfo // embedded
54 func (state *State) Setup(dbh *sql.DB) {
56 state.finished = false
58 state.screen.Initialise()
60 _, variables := lib.SelectAllGlobalVariablesByVariableName(state.dbh)
61 // setup to their initial types/values
62 state.fsbi = fsbi.NewFileSummaryByInstance(variables)
63 state.tlwsbt = new(tlwsbt.Table_lock_waits_summary_by_table)
64 state.ewsgben = new(ewsgben.Table_events_waits_summary_global_by_event_name)
66 state.want_relative_stats = true // we show info from the point we start collecting data
67 state.fsbi.SetWantRelativeStats(state.want_relative_stats)
69 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
71 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
73 state.users.SetWantRelativeStats(state.want_relative_stats) // ignored
74 state.users.SetNow() // ignored
75 state.ewsgben.SetWantRelativeStats(state.want_relative_stats) // ignored
76 state.ewsgben.SetNow() // ignored
78 state.ResetDBStatistics()
81 state.show = showLatency
82 state.tiwsbt.SetWantsLatency(true)
84 // get short name (to save space)
85 _, hostname := lib.SelectGlobalVariableByVariableName(state.dbh, "HOSTNAME")
86 if index := strings.Index(hostname, "."); index >= 0 {
87 hostname = hostname[0:index]
89 _, mysql_version := lib.SelectGlobalVariableByVariableName(state.dbh, "VERSION")
90 _, datadir := lib.SelectGlobalVariableByVariableName(state.dbh, "DATADIR")
91 state.SetHostname(hostname)
92 state.SetMySQLVersion(mysql_version)
93 state.SetDatadir(datadir)
97 func (state State) Finished() bool {
101 // indicate we have finished
102 func (state *State) SetFinished() {
103 state.finished = true
106 // do a fresh collection of data and then update the initial values based on that.
107 func (state *State) ResetDBStatistics() {
109 state.SyncReferenceValues()
112 func (state *State) SyncReferenceValues() {
114 state.fsbi.SyncReferenceValues()
115 state.tlwsbt.SyncReferenceValues()
116 state.tiwsbt.SyncReferenceValues()
117 lib.Logger.Println("state.SyncReferenceValues() took", time.Duration(time.Since(start)).String())
120 // collect all initial values on startup / reset
121 func (state *State) CollectAll() {
122 state.fsbi.Collect(state.dbh)
123 state.tlwsbt.Collect(state.dbh)
124 state.tiwsbt.Collect(state.dbh)
127 // Only collect the data we are looking at.
128 func (state *State) Collect() {
132 case showLatency, showOps:
133 state.tiwsbt.Collect(state.dbh)
135 state.fsbi.Collect(state.dbh)
137 state.tlwsbt.Collect(state.dbh)
139 state.users.Collect(state.dbh)
141 state.ewsgben.Collect(state.dbh)
143 lib.Logger.Println("state.Collect() took", time.Duration(time.Since(start)).String())
146 func (state State) MySQLVersion() string {
147 return state.mysql_version
150 func (state State) Datadir() string {
154 func (state *State) SetHelp(newHelp bool) {
161 func (state *State) SetDatadir(datadir string) {
162 state.datadir = datadir
165 func (state *State) SetMySQLVersion(mysql_version string) {
166 state.mysql_version = mysql_version
169 func (state *State) SetHostname(hostname string) {
170 state.hostname = hostname
173 func (state State) Help() bool {
177 // states go: showLatency -> showOps -> showIO -> showLocks -> showUsers -> showMutex
179 // display the output according to the mode we are in
180 func (state *State) Display() {
182 state.screen.DisplayHelp()
184 state.displayHeading()
186 case showLatency, showOps:
187 state.displayOpsOrLatency()
200 // fix_latency_setting() ensures the SetWantsLatency() value is
201 // correct. This needs to be done more cleanly.
202 func (state *State) fix_latency_setting() {
203 if state.show == showLatency {
204 state.tiwsbt.SetWantsLatency(true)
206 if state.show == showOps {
207 state.tiwsbt.SetWantsLatency(false)
211 // change to the previous display mode
212 func (state *State) DisplayPrevious() {
213 if state.show == showLatency {
214 state.show = showMutex
218 state.fix_latency_setting()
223 // change to the next display mode
224 func (state *State) DisplayNext() {
225 if state.show == showMutex {
226 state.show = showLatency
230 state.fix_latency_setting()
235 func (state State) displayHeading() {
237 state.displayDescription()
240 func (state State) displayLine0() {
241 _, uptime := lib.SelectGlobalStatusByVariableName(state.dbh, "UPTIME")
242 top_line := lib.MyName() + " " + version.Version() + " - " + now_hhmmss() + " " + state.hostname + " / " + state.mysql_version + ", up " + fmt.Sprintf("%-16s", lib.Uptime(uptime))
243 if state.want_relative_stats {
246 var initial time.Time
249 case showLatency, showOps:
250 initial = state.tiwsbt.Last()
252 initial = state.fsbi.Last()
254 initial = state.tlwsbt.Last()
256 initial = state.users.Last()
258 initial = state.ewsgben.Last()
260 // should not get here !
263 d := now.Sub(initial)
265 top_line = top_line + " [REL] " + fmt.Sprintf("%.0f seconds", d.Seconds())
267 top_line = top_line + " [ABS] "
269 state.screen.PrintAt(0, 0, top_line)
272 func (state State) displayDescription() {
273 description := "UNKNOWN"
276 case showLatency, showOps:
277 description = state.tiwsbt.Description()
279 description = state.fsbi.Description()
281 description = state.tlwsbt.Description()
283 description = state.users.Description()
285 description = state.ewsgben.Description()
288 state.screen.PrintAt(0, 1, description)
291 func (state *State) displayOpsOrLatency() {
292 state.screen.BoldPrintAt(0, 2, state.tiwsbt.Headings())
294 max_rows := state.screen.Height() - 3
295 row_content := state.tiwsbt.RowContent(max_rows)
298 for k := range row_content {
300 state.screen.PrintAt(0, y, row_content[k])
302 // print out empty rows
303 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
305 if y < state.screen.Height()-1 {
306 state.screen.PrintAt(0, y, state.tiwsbt.EmptyRowContent())
310 // print out the totals at the bottom
311 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tiwsbt.TotalRowContent())
314 // show actual I/O latency values
315 func (state State) displayIO() {
316 state.screen.BoldPrintAt(0, 2, state.fsbi.Headings())
318 // print out the data
319 max_rows := state.screen.Height() - 3
320 row_content := state.fsbi.RowContent(max_rows)
323 for k := range row_content {
325 state.screen.PrintAt(0, y, row_content[k])
327 // print out empty rows
328 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
330 if y < state.screen.Height()-1 {
331 state.screen.PrintAt(0, y, state.fsbi.EmptyRowContent())
335 // print out the totals at the bottom
336 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.fsbi.TotalRowContent())
339 func (state *State) displayLocks() {
340 state.screen.BoldPrintAt(0, 2, state.tlwsbt.Headings())
342 // print out the data
343 max_rows := state.screen.Height() - 3
344 row_content := state.tlwsbt.RowContent(max_rows)
347 for k := range row_content {
349 state.screen.PrintAt(0, y, row_content[k])
351 // print out empty rows
352 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
354 if y < state.screen.Height()-1 {
355 state.screen.PrintAt(0, y, state.tlwsbt.EmptyRowContent())
359 // print out the totals at the bottom
360 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tlwsbt.TotalRowContent())
363 func (state *State) displayUsers() {
364 state.screen.BoldPrintAt(0, 2, state.users.Headings())
366 // print out the data
367 max_rows := state.screen.Height() - 3
368 row_content := state.users.RowContent(max_rows)
371 for k := range row_content {
373 state.screen.PrintAt(0, y, row_content[k])
375 // print out empty rows
376 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
378 if y < state.screen.Height()-1 {
379 state.screen.PrintAt(0, y, state.users.EmptyRowContent())
383 // print out the totals at the bottom
384 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.users.TotalRowContent())
387 func (state *State) displayMutex() {
388 state.screen.BoldPrintAt(0, 2, state.ewsgben.Headings())
390 // print out the data
391 max_rows := state.screen.Height() - 3
392 row_content := state.ewsgben.RowContent(max_rows)
395 for k := range row_content {
397 state.screen.PrintAt(0, y, row_content[k])
399 // print out empty rows
400 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
402 if y < state.screen.Height()-1 {
403 state.screen.PrintAt(0, y, state.ewsgben.EmptyRowContent())
407 // print out the totals at the bottom
408 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.ewsgben.TotalRowContent())
411 // do we want to show all p_s data?
412 func (state State) WantRelativeStats() bool {
413 return state.want_relative_stats
416 // set if we want data from when we started/reset stats.
417 func (state *State) SetWantRelativeStats(want_relative_stats bool) {
418 state.want_relative_stats = want_relative_stats
420 state.fsbi.SetWantRelativeStats(want_relative_stats)
421 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
422 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
423 state.ewsgben.SetWantRelativeStats(state.want_relative_stats)
426 // if there's a better way of doing this do it better ...
427 func now_hhmmss() string {
429 return fmt.Sprintf("%2d:%02d:%02d", t.Hour(), t.Minute(), t.Second())
432 // record the latest screen size
433 func (state *State) ScreenSetSize(width, height int) {
434 state.screen.SetSize(width, height)
437 // clean up screen and disconnect database
438 func (state *State) Cleanup() {
440 if state.dbh != nil {
441 _ = state.dbh.Close()