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 tiwsbt "github.com/sjmudd/pstop/p_s/table_io_waits_summary_by_table"
17 tlwsbt "github.com/sjmudd/pstop/p_s/table_lock_waits_summary_by_table"
18 "github.com/sjmudd/pstop/screen"
19 "github.com/sjmudd/pstop/version"
22 // what information to show
39 fsbi ps_table.Tabler // ufsbi.File_summary_by_instance
40 tiwsbt tiwsbt.Table_io_waits_summary_by_table
41 tlwsbt ps_table.Tabler // tlwsbt.Table_lock_waits_summary_by_table
43 screen screen.TermboxScreen
46 want_relative_stats bool
49 func (state *State) Setup(dbh *sql.DB) {
51 state.finished = false
53 state.screen.Initialise()
55 _, variables := lib.SelectAllGlobalVariablesByVariableName(state.dbh)
56 // setup to their initial types/values
57 state.fsbi = fsbi.NewFileSummaryByInstance(variables)
58 state.tlwsbt = new(tlwsbt.Table_lock_waits_summary_by_table)
60 state.want_relative_stats = true // we show info from the point we start collecting data
61 state.fsbi.SetWantRelativeStats(state.want_relative_stats)
63 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
65 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
67 state.users.SetWantRelativeStats(state.want_relative_stats) // ignored
68 state.users.SetNow() // ignored
70 state.ResetDBStatistics()
73 state.show = showLatency
74 state.tiwsbt.SetWantsLatency(true)
76 // get short name (to save space)
77 _, hostname := lib.SelectGlobalVariableByVariableName(state.dbh, "HOSTNAME")
78 if index := strings.Index(hostname, "."); index >= 0 {
79 hostname = hostname[0:index]
81 _, mysql_version := lib.SelectGlobalVariableByVariableName(state.dbh, "VERSION")
82 _, datadir := lib.SelectGlobalVariableByVariableName(state.dbh, "DATADIR")
83 state.SetHostname(hostname)
84 state.SetMySQLVersion(mysql_version)
85 state.SetDatadir(datadir)
89 func (state State) Finished() bool {
93 // indicate we have finished
94 func (state *State) SetFinished() {
98 // do a fresh collection of data and then update the initial values based on that.
99 func (state *State) ResetDBStatistics() {
101 state.SyncReferenceValues()
104 func (state *State) SyncReferenceValues() {
106 state.fsbi.SyncReferenceValues()
107 state.tlwsbt.SyncReferenceValues()
108 state.tiwsbt.SyncReferenceValues()
109 lib.Logger.Println("state.SyncReferenceValues() took", time.Duration(time.Since(start)).String())
112 // collect all initial values on startup / reset
113 func (state *State) CollectAll() {
114 state.fsbi.Collect(state.dbh)
115 state.tlwsbt.Collect(state.dbh)
116 state.tiwsbt.Collect(state.dbh)
119 // Only collect the data we are looking at.
120 func (state *State) Collect() {
124 case showLatency, showOps:
125 state.tiwsbt.Collect(state.dbh)
127 state.fsbi.Collect(state.dbh)
129 state.tlwsbt.Collect(state.dbh)
131 state.users.Collect(state.dbh)
133 lib.Logger.Println("state.Collect() took", time.Duration(time.Since(start)).String())
136 func (state State) MySQLVersion() string {
137 return state.mysql_version
140 func (state State) Datadir() string {
144 func (state *State) SetHelp(newHelp bool) {
151 func (state *State) SetDatadir(datadir string) {
152 state.datadir = datadir
155 func (state *State) SetMySQLVersion(mysql_version string) {
156 state.mysql_version = mysql_version
159 func (state *State) SetHostname(hostname string) {
160 state.hostname = hostname
163 func (state State) Help() bool {
167 // states go: showLatency -> showOps -> showIO -> showLocks -> showUsers
169 // display the output according to the mode we are in
170 func (state *State) Display() {
172 state.screen.DisplayHelp()
174 state.displayHeading()
176 case showLatency, showOps:
177 state.displayOpsOrLatency()
188 // fix_latency_setting() ensures the SetWantsLatency() value is
189 // correct. This needs to be done more cleanly.
190 func (state *State) fix_latency_setting() {
191 if state.show == showLatency {
192 state.tiwsbt.SetWantsLatency(true)
194 if state.show == showOps {
195 state.tiwsbt.SetWantsLatency(false)
199 // change to the previous display mode
200 func (state *State) DisplayPrevious() {
201 if state.show == showLatency {
202 state.show = showUsers
206 state.fix_latency_setting()
211 // change to the next display mode
212 func (state *State) DisplayNext() {
213 if state.show == showUsers {
214 state.show = showLatency
218 state.fix_latency_setting()
223 func (state State) displayHeading() {
225 state.displayDescription()
228 func (state State) displayLine0() {
229 _, uptime := lib.SelectGlobalStatusByVariableName(state.dbh, "UPTIME")
230 top_line := lib.MyName() + " " + version.Version() + " - " + now_hhmmss() + " " + state.hostname + " / " + state.mysql_version + ", up " + fmt.Sprintf("%-16s", lib.Uptime(uptime))
231 if state.want_relative_stats {
234 var initial time.Time
237 case showLatency, showOps:
238 initial = state.tiwsbt.Last()
240 initial = state.fsbi.Last()
242 initial = state.tlwsbt.Last()
244 initial = state.users.Last()
246 // should not get here !
249 d := now.Sub(initial)
251 top_line = top_line + " [REL] " + fmt.Sprintf("%.0f seconds", d.Seconds())
253 top_line = top_line + " [ABS] "
255 state.screen.PrintAt(0, 0, top_line)
258 func (state State) displayDescription() {
259 description := "UNKNOWN"
262 case showLatency, showOps:
263 description = state.tiwsbt.Description()
265 description = state.fsbi.Description()
267 description = state.tlwsbt.Description()
269 description = state.users.Description()
272 state.screen.PrintAt(0, 1, description)
275 func (state *State) displayOpsOrLatency() {
276 state.screen.BoldPrintAt(0, 2, state.tiwsbt.Headings())
278 max_rows := state.screen.Height() - 3
279 row_content := state.tiwsbt.RowContent(max_rows)
282 for k := range row_content {
284 state.screen.PrintAt(0, y, row_content[k])
286 // print out empty rows
287 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
289 if y < state.screen.Height()-1 {
290 state.screen.PrintAt(0, y, state.tiwsbt.EmptyRowContent())
294 // print out the totals at the bottom
295 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tiwsbt.TotalRowContent())
298 // show actual I/O latency values
299 func (state State) displayIO() {
300 state.screen.BoldPrintAt(0, 2, state.fsbi.Headings())
302 // print out the data
303 max_rows := state.screen.Height() - 3
304 row_content := state.fsbi.RowContent(max_rows)
307 for k := range row_content {
309 state.screen.PrintAt(0, y, row_content[k])
311 // print out empty rows
312 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
314 if y < state.screen.Height()-1 {
315 state.screen.PrintAt(0, y, state.fsbi.EmptyRowContent())
319 // print out the totals at the bottom
320 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.fsbi.TotalRowContent())
323 func (state *State) displayLocks() {
324 state.screen.BoldPrintAt(0, 2, state.tlwsbt.Headings())
326 // print out the data
327 max_rows := state.screen.Height() - 3
328 row_content := state.tlwsbt.RowContent(max_rows)
331 for k := range row_content {
333 state.screen.PrintAt(0, y, row_content[k])
335 // print out empty rows
336 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
338 if y < state.screen.Height()-1 {
339 state.screen.PrintAt(0, y, state.tlwsbt.EmptyRowContent())
343 // print out the totals at the bottom
344 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tlwsbt.TotalRowContent())
347 func (state *State) displayUsers() {
348 state.screen.BoldPrintAt(0, 2, state.users.Headings())
350 // print out the data
351 max_rows := state.screen.Height() - 3
352 row_content := state.users.RowContent(max_rows)
355 for k := range row_content {
357 state.screen.PrintAt(0, y, row_content[k])
359 // print out empty rows
360 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
362 if y < state.screen.Height()-1 {
363 state.screen.PrintAt(0, y, state.users.EmptyRowContent())
367 // print out the totals at the bottom
368 state.screen.BoldPrintAt(0, state.screen.Height()-1, state.users.TotalRowContent())
371 // do we want to show all p_s data?
372 func (state State) WantRelativeStats() bool {
373 return state.want_relative_stats
376 // set if we want data from when we started/reset stats.
377 func (state *State) SetWantRelativeStats(want_relative_stats bool) {
378 state.want_relative_stats = want_relative_stats
380 state.fsbi.SetWantRelativeStats(want_relative_stats)
381 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
382 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
385 // if there's a better way of doing this do it better ...
386 func now_hhmmss() string {
388 return fmt.Sprintf("%2d:%02d:%02d", t.Hour(), t.Minute(), t.Second())
391 // record the latest screen size
392 func (state *State) ScreenSetSize(width, height int) {
393 state.screen.SetSize(width, height)
396 // clean up screen and disconnect database
397 func (state *State) Cleanup() {
399 if state.dbh != nil {
400 _ = state.dbh.Close()