bump version to v0.3.2
[pstop.git] / state / state.go
index 824d9fb..de0d4ff 100644 (file)
@@ -6,15 +6,21 @@ package state
 import (
        "database/sql"
        "fmt"
+       "strings"
        "time"
 
+       "github.com/sjmudd/pstop/i_s/processlist"
        "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
@@ -25,31 +31,46 @@ const (
        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               processlist.Object
        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 = setup_instruments.NewSetupInstruments(dbh)
+       state.setup_instruments.EnableMonitoring()
+
        _, 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.tlwsbt = new(tlwsbt.Object)
+       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)
@@ -58,6 +79,12 @@ func (state *State) Setup(dbh *sql.DB) {
        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()
 
@@ -65,7 +92,11 @@ func (state *State) Setup(dbh *sql.DB) {
        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)
@@ -73,24 +104,59 @@ func (state *State) Setup(dbh *sql.DB) {
        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() {
-       state.Collect()
-       state.UpdateInitialValues()
+       state.CollectAll()
+       state.SyncReferenceValues()
 }
 
-func (state *State) UpdateInitialValues() {
-       state.fsbi.UpdateInitialValues()
-       state.tlwsbt.UpdateInitialValues()
-       state.tiwsbt.UpdateInitialValues()
+func (state *State) SyncReferenceValues() {
+       start := time.Now()
+       state.fsbi.SyncReferenceValues()
+       state.tlwsbt.SyncReferenceValues()
+       state.tiwsbt.SyncReferenceValues()
+       state.essgben.SyncReferenceValues()
+       lib.Logger.Println("state.SyncReferenceValues() took", time.Duration(time.Since(start)).String())
 }
 
-func (state *State) Collect() {
+// 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.
+func (state *State) Collect() {
+       start := time.Now()
+
+       switch state.show {
+       case showLatency, showOps:
+               state.tiwsbt.Collect(state.dbh)
+       case showIO:
+               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())
+}
+
 func (state State) MySQLVersion() string {
        return state.mysql_version
 }
@@ -122,6 +188,8 @@ func (state State) Help() bool {
        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 {
@@ -135,31 +203,54 @@ func (state *State) Display() {
                        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() {
@@ -177,8 +268,14 @@ 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)
@@ -190,21 +287,29 @@ func (state State) displayLine0() {
        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)
@@ -223,12 +328,12 @@ func (state *State) displayOpsOrLatency() {
        }
 
        // 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
@@ -248,11 +353,11 @@ func (state State) displayIO() {
        }
 
        // 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
@@ -272,9 +377,82 @@ func (state *State) displayLocks() {
        }
 
        // 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
@@ -287,8 +465,8 @@ func (state *State) SetWantRelativeStats(want_relative_stats bool) {
        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)
+       state.essgben.SetWantRelativeStats(state.want_relative_stats)
 }
 
 // if there's a better way of doing this do it better ...
@@ -306,6 +484,7 @@ func (state *State) ScreenSetSize(width, height int) {
 func (state *State) Cleanup() {
        state.screen.Close()
        if state.dbh != nil {
+               state.setup_instruments.RestoreConfiguration()
                _ = state.dbh.Close()
        }
 }