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
38 fsbi ps_table.Tabler // ufsbi.File_summary_by_instance
39 tiwsbt tiwsbt.Table_io_waits_summary_by_table
40 tlwsbt ps_table.Tabler // tlwsbt.Table_lock_waits_summary_by_table
42 screen screen.TermboxScreen
45 want_relative_stats bool
48 func (state *State) Setup(dbh *sql.DB) {
51 state.screen.Initialise()
53 _, variables := lib.SelectAllGlobalVariablesByVariableName(state.dbh)
54 // setup to their initial types/values
55 state.fsbi = fsbi.NewFileSummaryByInstance(variables)
56 state.tlwsbt = new(tlwsbt.Table_lock_waits_summary_by_table)
58 state.want_relative_stats = true // we show info from the point we start collecting data
59 state.fsbi.SetWantRelativeStats(state.want_relative_stats)
61 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
63 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
65 state.users.SetWantRelativeStats(state.want_relative_stats) // ignored
66 state.users.SetNow() // ignored
68 state.ResetDBStatistics()
71 state.show = showLatency
72 state.tiwsbt.SetWantsLatency(true)
74 // get short name (to save space)
75 _, hostname := lib.SelectGlobalVariableByVariableName(state.dbh, "HOSTNAME")
76 if index := strings.Index(hostname, "."); index >= 0 {
77 hostname = hostname[0:index]
79 _, mysql_version := lib.SelectGlobalVariableByVariableName(state.dbh, "VERSION")
80 _, datadir := lib.SelectGlobalVariableByVariableName(state.dbh, "DATADIR")
81 state.SetHostname(hostname)
82 state.SetMySQLVersion(mysql_version)
83 state.SetDatadir(datadir)
86 // do a fresh collection of data and then update the initial values based on that.
87 func (state *State) ResetDBStatistics() {
89 state.SyncReferenceValues()
92 func (state *State) SyncReferenceValues() {
94 state.fsbi.SyncReferenceValues()
95 state.tlwsbt.SyncReferenceValues()
96 state.tiwsbt.SyncReferenceValues()
97 lib.Logger.Println("state.SyncReferenceValues() took", time.Duration(time.Since(start)).String())
100 // collect all initial values on startup / reset
101 func (state *State) CollectAll() {
102 state.fsbi.Collect(state.dbh)
103 state.tlwsbt.Collect(state.dbh)
104 state.tiwsbt.Collect(state.dbh)
107 // Only collect the data we are looking at.
108 func (state *State) Collect() {
112 case showLatency, showOps:
113 state.tiwsbt.Collect(state.dbh)
115 state.fsbi.Collect(state.dbh)
117 state.tlwsbt.Collect(state.dbh)
119 state.users.Collect(state.dbh)
121 lib.Logger.Println("state.Collect() took", time.Duration(time.Since(start)).String())
124 func (state State) MySQLVersion() string {
125 return state.mysql_version
128 func (state State) Datadir() string {
132 func (state *State) SetHelp(newHelp bool) {
139 func (state *State) SetDatadir(datadir string) {
140 state.datadir = datadir
143 func (state *State) SetMySQLVersion(mysql_version string) {
144 state.mysql_version = mysql_version
147 func (state *State) SetHostname(hostname string) {
148 state.hostname = hostname
151 func (state State) Help() bool {
155 // states go: showLatency -> showOps -> showIO -> showLocks -> showUsers
157 // display the output according to the mode we are in
158 func (state *State) Display() {
160 state.screen.DisplayHelp()
162 state.displayHeading()
164 case showLatency, showOps:
165 state.displayOpsOrLatency()
176 // fix_latency_setting() ensures the SetWantsLatency() value is
177 // correct. This needs to be done more cleanly.
178 func (state *State) fix_latency_setting() {
179 if state.show == showLatency {
180 state.tiwsbt.SetWantsLatency(true)
182 if state.show == showOps {
183 state.tiwsbt.SetWantsLatency(false)
187 // change to the previous display mode
188 func (state *State) DisplayPrevious() {
189 if state.show == showLatency {
190 state.show = showUsers
194 state.fix_latency_setting()
199 // change to the next display mode
200 func (state *State) DisplayNext() {
201 if state.show == showUsers {
202 state.show = showLatency
206 state.fix_latency_setting()
211 func (state State) displayHeading() {
213 state.displayDescription()
216 func (state State) displayLine0() {
217 _, uptime := lib.SelectGlobalStatusByVariableName(state.dbh, "UPTIME")
218 top_line := lib.MyName() + " " + version.Version() + " - " + now_hhmmss() + " " + state.hostname + " / " + state.mysql_version + ", up " + fmt.Sprintf("%-16s", lib.Uptime(uptime))
219 if state.want_relative_stats {
222 var initial time.Time
225 case showLatency, showOps:
226 initial = state.tiwsbt.Last()
228 initial = state.fsbi.Last()
230 initial = state.tlwsbt.Last()
232 initial = state.users.Last()
234 // should not get here !
237 d := now.Sub(initial)
239 top_line = top_line + " [REL] " + fmt.Sprintf("%.0f seconds", d.Seconds())
241 top_line = top_line + " [ABS] "
243 state.screen.PrintAt(0, 0, top_line)
246 func (state State) displayDescription() {
247 description := "UNKNOWN"
250 case showLatency, showOps:
251 description = state.tiwsbt.Description()
253 description = state.fsbi.Description()
255 description = state.tlwsbt.Description()
257 description = state.users.Description()
260 state.screen.PrintAt(0, 1, description)
263 func (state *State) displayOpsOrLatency() {
264 state.screen.PrintAt(0, 2, state.tiwsbt.Headings())
266 max_rows := state.screen.Height() - 3
267 row_content := state.tiwsbt.RowContent(max_rows)
270 for k := range row_content {
272 state.screen.PrintAt(0, y, row_content[k])
274 // print out empty rows
275 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
277 if y < state.screen.Height()-1 {
278 state.screen.PrintAt(0, y, state.tiwsbt.EmptyRowContent())
282 // print out the totals at the bottom
283 state.screen.PrintAt(0, state.screen.Height()-1, state.tiwsbt.TotalRowContent())
286 // show actual I/O latency values
287 func (state State) displayIO() {
288 state.screen.PrintAt(0, 2, state.fsbi.Headings())
290 // print out the data
291 max_rows := state.screen.Height() - 3
292 row_content := state.fsbi.RowContent(max_rows)
295 for k := range row_content {
297 state.screen.PrintAt(0, y, row_content[k])
299 // print out empty rows
300 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
302 if y < state.screen.Height()-1 {
303 state.screen.PrintAt(0, y, state.fsbi.EmptyRowContent())
307 // print out the totals at the bottom
308 state.screen.PrintAt(0, state.screen.Height()-1, state.fsbi.TotalRowContent())
311 func (state *State) displayLocks() {
312 state.screen.PrintAt(0, 2, state.tlwsbt.Headings())
314 // print out the data
315 max_rows := state.screen.Height() - 3
316 row_content := state.tlwsbt.RowContent(max_rows)
319 for k := range row_content {
321 state.screen.PrintAt(0, y, row_content[k])
323 // print out empty rows
324 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
326 if y < state.screen.Height()-1 {
327 state.screen.PrintAt(0, y, state.tlwsbt.EmptyRowContent())
331 // print out the totals at the bottom
332 state.screen.PrintAt(0, state.screen.Height()-1, state.tlwsbt.TotalRowContent())
335 func (state *State) displayUsers() {
336 state.screen.PrintAt(0, 2, state.users.Headings())
338 // print out the data
339 max_rows := state.screen.Height() - 3
340 row_content := state.users.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.users.EmptyRowContent())
355 // print out the totals at the bottom
356 state.screen.PrintAt(0, state.screen.Height()-1, state.users.TotalRowContent())
359 // do we want to show all p_s data?
360 func (state State) WantRelativeStats() bool {
361 return state.want_relative_stats
364 // set if we want data from when we started/reset stats.
365 func (state *State) SetWantRelativeStats(want_relative_stats bool) {
366 state.want_relative_stats = want_relative_stats
368 state.fsbi.SetWantRelativeStats(want_relative_stats)
369 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
370 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
373 // if there's a better way of doing this do it better ...
374 func now_hhmmss() string {
376 return fmt.Sprintf("%2d:%02d:%02d", t.Hour(), t.Minute(), t.Second())
379 // record the latest screen size
380 func (state *State) ScreenSetSize(width, height int) {
381 state.screen.SetSize(width, height)
384 // clean up screen and disconnect database
385 func (state *State) Cleanup() {
387 if state.dbh != nil {
388 _ = state.dbh.Close()