import (
"database/sql"
"fmt"
+ "strings"
"time"
+ "github.com/sjmudd/pstop/i_s"
"github.com/sjmudd/pstop/lib"
- fsbi "github.com/sjmudd/pstop/performance_schema/file_summary_by_instance"
- "github.com/sjmudd/pstop/performance_schema/ps_table"
- tiwsbt "github.com/sjmudd/pstop/performance_schema/table_io_waits_summary_by_table"
- tlwsbt "github.com/sjmudd/pstop/performance_schema/table_lock_waits_summary_by_table"
+ ewsgben "github.com/sjmudd/pstop/p_s/events_waits_summary_global_by_event_name"
+ essgben "github.com/sjmudd/pstop/p_s/events_stages_summary_global_by_event_name"
+ fsbi "github.com/sjmudd/pstop/p_s/file_summary_by_instance"
+ "github.com/sjmudd/pstop/p_s/ps_table"
+ "github.com/sjmudd/pstop/p_s/setup_instruments"
+ tiwsbt "github.com/sjmudd/pstop/p_s/table_io_waits_summary_by_table"
+ tlwsbt "github.com/sjmudd/pstop/p_s/table_lock_waits_summary_by_table"
"github.com/sjmudd/pstop/screen"
"github.com/sjmudd/pstop/version"
+ "github.com/sjmudd/pstop/wait_info"
)
// what information to show
showOps = iota
showIO = iota
showLocks = iota
+ showUsers = iota
+ showMutex = iota
+ showStages = iota
)
type State struct {
+ finished bool
datadir string
dbh *sql.DB
help bool
hostname string
fsbi ps_table.Tabler // ufsbi.File_summary_by_instance
- tiwsbt tiwsbt.Table_io_waits_summary_by_table
+ tiwsbt tiwsbt.Object
tlwsbt ps_table.Tabler // tlwsbt.Table_lock_waits_summary_by_table
+ ewsgben ps_table.Tabler // ewsgben.Events_waits_summary_global_by_event_name
+ essgben ps_table.Tabler // essgben.Events_stages_summary_global_by_event_name
+ users i_s.Processlist
screen screen.TermboxScreen
show Show
mysql_version string
want_relative_stats bool
+ wait_info.WaitInfo // embedded
+ setup_instruments setup_instruments.SetupInstruments
}
func (state *State) Setup(dbh *sql.DB) {
state.dbh = dbh
+ state.finished = false
state.screen.Initialise()
+ state.setup_instruments.EnableMutexMonitoring(dbh)
+ state.setup_instruments.EnableStageMonitoring(dbh)
+
_, variables := lib.SelectAllGlobalVariablesByVariableName(state.dbh)
// setup to their initial types/values
state.fsbi = fsbi.NewFileSummaryByInstance(variables)
state.tlwsbt = new(tlwsbt.Table_lock_waits_summary_by_table)
+ state.ewsgben = new(ewsgben.Object)
+ state.essgben = new(essgben.Object)
state.want_relative_stats = true // we show info from the point we start collecting data
state.fsbi.SetWantRelativeStats(state.want_relative_stats)
state.tlwsbt.SetNow()
state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
state.tiwsbt.SetNow()
+ state.users.SetWantRelativeStats(state.want_relative_stats) // ignored
+ state.users.SetNow() // ignored
+ state.essgben.SetWantRelativeStats(state.want_relative_stats)
+ state.essgben.SetNow()
+ state.ewsgben.SetWantRelativeStats(state.want_relative_stats) // ignored
+ state.ewsgben.SetNow() // ignored
state.ResetDBStatistics()
state.show = showLatency
state.tiwsbt.SetWantsLatency(true)
+ // get short name (to save space)
_, hostname := lib.SelectGlobalVariableByVariableName(state.dbh, "HOSTNAME")
+ if index := strings.Index(hostname, "."); index >= 0 {
+ hostname = hostname[0:index]
+ }
_, mysql_version := lib.SelectGlobalVariableByVariableName(state.dbh, "VERSION")
_, datadir := lib.SelectGlobalVariableByVariableName(state.dbh, "DATADIR")
state.SetHostname(hostname)
state.SetDatadir(datadir)
}
+// have we finished ?
+func (state State) Finished() bool {
+ return state.finished
+}
+
+// indicate we have finished
+func (state *State) SetFinished() {
+ state.finished = true
+}
+
// do a fresh collection of data and then update the initial values based on that.
func (state *State) ResetDBStatistics() {
- // collect all initial values on startup / reset
- state.fsbi.Collect(state.dbh)
- state.tlwsbt.Collect(state.dbh)
- state.tiwsbt.Collect(state.dbh)
-
- state.UpdateInitialValues()
+ state.CollectAll()
+ state.SyncReferenceValues()
}
-func (state *State) UpdateInitialValues() {
+func (state *State) SyncReferenceValues() {
start := time.Now()
- state.fsbi.UpdateInitialValues()
- state.tlwsbt.UpdateInitialValues()
- state.tiwsbt.UpdateInitialValues()
- lib.Logger.Println("state.UpdateInitialValues() took", time.Duration(time.Since(start)).String())
+ state.fsbi.SyncReferenceValues()
+ state.tlwsbt.SyncReferenceValues()
+ state.tiwsbt.SyncReferenceValues()
+ state.essgben.SyncReferenceValues()
+ lib.Logger.Println("state.SyncReferenceValues() took", time.Duration(time.Since(start)).String())
+}
+
+// collect all initial values on startup / reset
+func (state *State) CollectAll() {
+ state.fsbi.Collect(state.dbh)
+ state.tlwsbt.Collect(state.dbh)
+ state.tiwsbt.Collect(state.dbh)
}
// Only collect the data we are looking at.
state.fsbi.Collect(state.dbh)
case showLocks:
state.tlwsbt.Collect(state.dbh)
+ case showUsers:
+ state.users.Collect(state.dbh)
+ case showMutex:
+ state.ewsgben.Collect(state.dbh)
+ case showStages:
+ state.essgben.Collect(state.dbh)
}
lib.Logger.Println("state.Collect() took", time.Duration(time.Since(start)).String())
}
return state.help
}
+// states go: showLatency -> showOps -> showIO -> showLocks -> showUsers -> showMutex -> showStages
+
// display the output according to the mode we are in
func (state *State) Display() {
if state.help {
state.displayIO()
case showLocks:
state.displayLocks()
+ case showUsers:
+ state.displayUsers()
+ case showMutex:
+ state.displayMutex()
+ case showStages:
+ state.displayStages()
}
}
}
-// change to the next display mode
-func (state *State) DisplayNext() {
- if state.show == showLocks {
- state.show = showLatency
- } else {
- state.show++
- }
- // this needs to be done more cleanly
+// fix_latency_setting() ensures the SetWantsLatency() value is
+// correct. This needs to be done more cleanly.
+func (state *State) fix_latency_setting() {
if state.show == showLatency {
state.tiwsbt.SetWantsLatency(true)
}
if state.show == showOps {
state.tiwsbt.SetWantsLatency(false)
}
+}
+
+// change to the previous display mode
+func (state *State) DisplayPrevious() {
+ if state.show == showLatency {
+ state.show = showStages
+ } else {
+ state.show--
+ }
+ state.fix_latency_setting()
+ state.screen.Clear()
+ state.screen.Flush()
+}
+
+// change to the next display mode
+func (state *State) DisplayNext() {
+ if state.show == showStages {
+ state.show = showLatency
+ } else {
+ state.show++
+ }
+ state.fix_latency_setting()
state.screen.Clear()
state.screen.Flush()
}
func (state State) displayHeading() {
state.displayLine0()
- state.displayLine1()
+ state.displayDescription()
}
func (state State) displayLine0() {
initial = state.fsbi.Last()
case showLocks:
initial = state.tlwsbt.Last()
+ case showUsers:
+ initial = state.users.Last()
+ case showStages:
+ initial = state.essgben.Last()
+ case showMutex:
+ initial = state.ewsgben.Last()
default:
- initial = time.Now() // THIS IS WRONG !!!
+ // should not get here !
}
d := now.Sub(initial)
state.screen.PrintAt(0, 0, top_line)
}
-func (state State) displayLine1() {
+func (state State) displayDescription() {
+ description := "UNKNOWN"
+
switch state.show {
case showLatency, showOps:
- state.screen.PrintAt(0, 1, state.tiwsbt.Description())
+ description = state.tiwsbt.Description()
case showIO:
- state.screen.PrintAt(0, 1, state.fsbi.Description())
+ description = state.fsbi.Description()
case showLocks:
- state.screen.PrintAt(0, 1, state.tlwsbt.Description())
- default:
- state.screen.PrintAt(0, 1, "UNKNOWN")
+ description = state.tlwsbt.Description()
+ case showUsers:
+ description = state.users.Description()
+ case showMutex:
+ description = state.ewsgben.Description()
+ case showStages:
+ description = state.essgben.Description()
}
+
+ state.screen.PrintAt(0, 1, description)
}
func (state *State) displayOpsOrLatency() {
- state.screen.PrintAt(0, 2, state.tiwsbt.Headings())
+ state.screen.BoldPrintAt(0, 2, state.tiwsbt.Headings())
max_rows := state.screen.Height() - 3
row_content := state.tiwsbt.RowContent(max_rows)
}
// print out the totals at the bottom
- state.screen.PrintAt(0, state.screen.Height()-1, state.tiwsbt.TotalRowContent())
+ state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tiwsbt.TotalRowContent())
}
// show actual I/O latency values
func (state State) displayIO() {
- state.screen.PrintAt(0, 2, state.fsbi.Headings())
+ state.screen.BoldPrintAt(0, 2, state.fsbi.Headings())
// print out the data
max_rows := state.screen.Height() - 3
}
// print out the totals at the bottom
- state.screen.PrintAt(0, state.screen.Height()-1, state.fsbi.TotalRowContent())
+ state.screen.BoldPrintAt(0, state.screen.Height()-1, state.fsbi.TotalRowContent())
}
func (state *State) displayLocks() {
- state.screen.PrintAt(0, 2, state.tlwsbt.Headings())
+ state.screen.BoldPrintAt(0, 2, state.tlwsbt.Headings())
// print out the data
max_rows := state.screen.Height() - 3
}
// print out the totals at the bottom
- state.screen.PrintAt(0, state.screen.Height()-1, state.tlwsbt.TotalRowContent())
+ state.screen.BoldPrintAt(0, state.screen.Height()-1, state.tlwsbt.TotalRowContent())
+}
+
+func (state *State) displayUsers() {
+ state.screen.BoldPrintAt(0, 2, state.users.Headings())
+
+ // print out the data
+ max_rows := state.screen.Height() - 3
+ row_content := state.users.RowContent(max_rows)
+
+ // print out rows
+ for k := range row_content {
+ y := 3 + k
+ state.screen.PrintAt(0, y, row_content[k])
+ }
+ // print out empty rows
+ for k := len(row_content); k < (state.screen.Height() - 3); k++ {
+ y := 3 + k
+ if y < state.screen.Height()-1 {
+ state.screen.PrintAt(0, y, state.users.EmptyRowContent())
+ }
+ }
+
+ // print out the totals at the bottom
+ state.screen.BoldPrintAt(0, state.screen.Height()-1, state.users.TotalRowContent())
}
+func (state *State) displayMutex() {
+ state.screen.BoldPrintAt(0, 2, state.ewsgben.Headings())
+
+ // print out the data
+ max_rows := state.screen.Height() - 3
+ row_content := state.ewsgben.RowContent(max_rows)
+
+ // print out rows
+ for k := range row_content {
+ y := 3 + k
+ state.screen.PrintAt(0, y, row_content[k])
+ }
+ // print out empty rows
+ for k := len(row_content); k < (state.screen.Height() - 3); k++ {
+ y := 3 + k
+ if y < state.screen.Height()-1 {
+ state.screen.PrintAt(0, y, state.ewsgben.EmptyRowContent())
+ }
+ }
+
+ // print out the totals at the bottom
+ state.screen.BoldPrintAt(0, state.screen.Height()-1, state.ewsgben.TotalRowContent())
+}
+
+func (state *State) displayStages() {
+ state.screen.BoldPrintAt(0, 2, state.essgben.Headings())
+
+ // print out the data
+ max_rows := state.screen.Height() - 3
+ row_content := state.essgben.RowContent(max_rows)
+
+ // print out rows
+ for k := range row_content {
+ y := 3 + k
+ state.screen.PrintAt(0, y, row_content[k])
+ }
+ // print out empty rows
+ for k := len(row_content); k < (state.screen.Height() - 3); k++ {
+ y := 3 + k
+ if y < state.screen.Height()-1 {
+ state.screen.PrintAt(0, y, state.essgben.EmptyRowContent())
+ }
+ }
+
+ // print out the totals at the bottom
+ state.screen.BoldPrintAt(0, state.screen.Height()-1, state.essgben.TotalRowContent())
+}
+
+
// do we want to show all p_s data?
func (state State) WantRelativeStats() bool {
return state.want_relative_stats
state.fsbi.SetWantRelativeStats(want_relative_stats)
state.tlwsbt.SetWantRelativeStats(state.want_relative_stats)
state.tiwsbt.SetWantRelativeStats(state.want_relative_stats)
-
- state.Display()
+ state.ewsgben.SetWantRelativeStats(state.want_relative_stats)
}
// if there's a better way of doing this do it better ...
func (state *State) Cleanup() {
state.screen.Close()
if state.dbh != nil {
+ state.setup_instruments.RestoreConfiguration(state.dbh)
_ = state.dbh.Close()
}
}