1 // lib - library routines for pstop.
3 // this file contains the library routines related to the stored state in pstop.
11 "github.com/sjmudd/pstop/lib"
12 fsbi "github.com/sjmudd/pstop/performance_schema/file_summary_by_instance"
13 "github.com/sjmudd/pstop/performance_schema/ps_table"
14 tiwsbt "github.com/sjmudd/pstop/performance_schema/table_io_waits_summary_by_table"
15 tlwsbt "github.com/sjmudd/pstop/performance_schema/table_lock_waits_summary_by_table"
16 "github.com/sjmudd/pstop/screen"
17 "github.com/sjmudd/pstop/version"
20 // what information to show
35 fsbi ps_table.Tabler // ufsbi.File_summary_by_instance
36 tiwsbt tiwsbt.Table_io_waits_summary_by_table
37 tlwsbt ps_table.Tabler // tlwsbt.Table_lock_waits_summary_by_table
38 screen screen.TermboxScreen
41 want_relative_stats bool
44 func (state *State) Setup(dbh *sql.DB) {
47 state.screen.Initialise()
49 _, variables := lib.SelectAllGlobalVariablesByVariableName(state.dbh)
50 // setup to their initial types/values
51 state.fsbi = fsbi.NewFileSummaryByInstance(variables)
52 state.tlwsbt = new(tlwsbt.Table_lock_waits_summary_by_table)
54 state.want_relative_stats = true // we show info from the point we start collecting data
55 state.fsbi.SetWantRelativeStats(state.want_relative_stats)
57 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
59 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
62 state.ResetDBStatistics()
65 state.show = showLatency
66 state.tiwsbt.SetWantsLatency(true)
68 _, hostname := lib.SelectGlobalVariableByVariableName(state.dbh, "HOSTNAME")
69 _, mysql_version := lib.SelectGlobalVariableByVariableName(state.dbh, "VERSION")
70 _, datadir := lib.SelectGlobalVariableByVariableName(state.dbh, "DATADIR")
71 state.SetHostname(hostname)
72 state.SetMySQLVersion(mysql_version)
73 state.SetDatadir(datadir)
76 // do a fresh collection of data and then update the initial values based on that.
77 func (state *State) ResetDBStatistics() {
79 state.UpdateInitialValues()
82 func (state *State) UpdateInitialValues() {
84 state.fsbi.UpdateInitialValues()
85 state.tlwsbt.UpdateInitialValues()
86 state.tiwsbt.UpdateInitialValues()
87 lib.Logger.Println("state.UpdateInitialValues() took", time.Duration(time.Since(start)).String())
90 // collect all initial values on startup / reset
91 func (state *State) CollectAll() {
92 state.fsbi.Collect(state.dbh)
93 state.tlwsbt.Collect(state.dbh)
94 state.tiwsbt.Collect(state.dbh)
97 // Only collect the data we are looking at.
98 func (state *State) Collect() {
102 case showLatency, showOps:
103 state.tiwsbt.Collect(state.dbh)
105 state.fsbi.Collect(state.dbh)
107 state.tlwsbt.Collect(state.dbh)
109 lib.Logger.Println("state.Collect() took", time.Duration(time.Since(start)).String())
112 func (state State) MySQLVersion() string {
113 return state.mysql_version
116 func (state State) Datadir() string {
120 func (state *State) SetHelp(newHelp bool) {
127 func (state *State) SetDatadir(datadir string) {
128 state.datadir = datadir
131 func (state *State) SetMySQLVersion(mysql_version string) {
132 state.mysql_version = mysql_version
135 func (state *State) SetHostname(hostname string) {
136 state.hostname = hostname
139 func (state State) Help() bool {
143 // display the output according to the mode we are in
144 func (state *State) Display() {
146 state.screen.DisplayHelp()
148 state.displayHeading()
150 case showLatency, showOps:
151 state.displayOpsOrLatency()
160 // change to the next display mode
161 func (state *State) DisplayNext() {
162 if state.show == showLocks {
163 state.show = showLatency
167 // this needs to be done more cleanly
168 if state.show == showLatency {
169 state.tiwsbt.SetWantsLatency(true)
171 if state.show == showOps {
172 state.tiwsbt.SetWantsLatency(false)
178 func (state State) displayHeading() {
183 func (state State) displayLine0() {
184 _, uptime := lib.SelectGlobalStatusByVariableName(state.dbh, "UPTIME")
185 top_line := lib.MyName() + " " + version.Version() + " - " + now_hhmmss() + " " + state.hostname + " / " + state.mysql_version + ", up " + fmt.Sprintf("%-16s", lib.Uptime(uptime))
186 if state.want_relative_stats {
189 var initial time.Time
192 case showLatency, showOps:
193 initial = state.tiwsbt.Last()
195 initial = state.fsbi.Last()
197 initial = state.tlwsbt.Last()
199 initial = time.Now() // THIS IS WRONG !!!
202 d := now.Sub(initial)
204 top_line = top_line + " [REL] " + fmt.Sprintf("%.0f seconds", d.Seconds())
206 top_line = top_line + " [ABS] "
208 state.screen.PrintAt(0, 0, top_line)
211 func (state State) displayLine1() {
213 case showLatency, showOps:
214 state.screen.PrintAt(0, 1, state.tiwsbt.Description())
216 state.screen.PrintAt(0, 1, state.fsbi.Description())
218 state.screen.PrintAt(0, 1, state.tlwsbt.Description())
220 state.screen.PrintAt(0, 1, "UNKNOWN")
224 func (state *State) displayOpsOrLatency() {
225 state.screen.PrintAt(0, 2, state.tiwsbt.Headings())
227 max_rows := state.screen.Height() - 3
228 row_content := state.tiwsbt.RowContent(max_rows)
231 for k := range row_content {
233 state.screen.PrintAt(0, y, row_content[k])
235 // print out empty rows
236 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
238 if y < state.screen.Height()-1 {
239 state.screen.PrintAt(0, y, state.tiwsbt.EmptyRowContent())
243 // print out the totals at the bottom
244 state.screen.PrintAt(0, state.screen.Height()-1, state.tiwsbt.TotalRowContent())
247 // show actual I/O latency values
248 func (state State) displayIO() {
249 state.screen.PrintAt(0, 2, state.fsbi.Headings())
251 // print out the data
252 max_rows := state.screen.Height() - 3
253 row_content := state.fsbi.RowContent(max_rows)
256 for k := range row_content {
258 state.screen.PrintAt(0, y, row_content[k])
260 // print out empty rows
261 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
263 if y < state.screen.Height()-1 {
264 state.screen.PrintAt(0, y, state.fsbi.EmptyRowContent())
268 // print out the totals at the bottom
269 state.screen.PrintAt(0, state.screen.Height()-1, state.fsbi.TotalRowContent())
272 func (state *State) displayLocks() {
273 state.screen.PrintAt(0, 2, state.tlwsbt.Headings())
275 // print out the data
276 max_rows := state.screen.Height() - 3
277 row_content := state.tlwsbt.RowContent(max_rows)
280 for k := range row_content {
282 state.screen.PrintAt(0, y, row_content[k])
284 // print out empty rows
285 for k := len(row_content); k < (state.screen.Height() - 3); k++ {
287 if y < state.screen.Height()-1 {
288 state.screen.PrintAt(0, y, state.tlwsbt.EmptyRowContent())
292 // print out the totals at the bottom
293 state.screen.PrintAt(0, state.screen.Height()-1, state.tlwsbt.TotalRowContent())
296 // do we want to show all p_s data?
297 func (state State) WantRelativeStats() bool {
298 return state.want_relative_stats
301 // set if we want data from when we started/reset stats.
302 func (state *State) SetWantRelativeStats(want_relative_stats bool) {
303 state.want_relative_stats = want_relative_stats
305 state.fsbi.SetWantRelativeStats(want_relative_stats)
306 state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
307 state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
312 // if there's a better way of doing this do it better ...
313 func now_hhmmss() string {
315 return fmt.Sprintf("%2d:%02d:%02d", t.Hour(), t.Minute(), t.Second())
318 // record the latest screen size
319 func (state *State) ScreenSetSize(width, height int) {
320 state.screen.SetSize(width, height)
323 // clean up screen and disconnect database
324 func (state *State) Cleanup() {
326 if state.dbh != nil {
327 _ = state.dbh.Close()