Sensibly format rows with table name on the right.
[pstop.git] / app / app.go
index ed36f0c..45490f8 100644 (file)
@@ -1,6 +1,6 @@
-// lib - library routines for pstop.
+// app - pstop application package
 //
-// this file contains the library routines related to the stored state in pstop.
+// This file contains the library routines related to running the app.
 package app
 
 import (
@@ -45,7 +45,7 @@ const (
 )
 
 var (
-        re_valid_version = regexp.MustCompile(`^(5\.[67]\.|10\.[01])`)
+       re_valid_version = regexp.MustCompile(`^(5\.[67]\.|10\.[01])`)
 )
 
 type App struct {
@@ -53,7 +53,6 @@ type App struct {
        sigChan             chan os.Signal
        wi                  wait_info.WaitInfo
        finished            bool
-       datadir             string
        dbh                 *sql.DB
        help                bool
        hostname            string
@@ -75,8 +74,8 @@ func (app *App) Setup(dbh *sql.DB) {
        app.dbh = dbh
 
        if err := app.validate_mysql_version(); err != nil {
-                log.Fatal(err)
-        }
+               log.Fatal(err)
+       }
 
        app.finished = false
        app.screen.Initialise()
@@ -98,11 +97,11 @@ func (app *App) Setup(dbh *sql.DB) {
        app.tiwsbt.SetWantRelativeStats(app.want_relative_stats)
        app.tiwsbt.SetNow()
        app.users.SetWantRelativeStats(app.want_relative_stats) // ignored
-       app.users.SetNow()                                        // ignored
+       app.users.SetNow()                                      // ignored
        app.essgben.SetWantRelativeStats(app.want_relative_stats)
        app.essgben.SetNow()
        app.ewsgben.SetWantRelativeStats(app.want_relative_stats) // ignored
-       app.ewsgben.SetNow()                                        // ignored
+       app.ewsgben.SetNow()                                      // ignored
 
        app.ResetDBStatistics()
 
@@ -116,10 +115,8 @@ func (app *App) Setup(dbh *sql.DB) {
                hostname = hostname[0:index]
        }
        _, mysql_version := lib.SelectGlobalVariableByVariableName(app.dbh, "VERSION")
-       _, datadir := lib.SelectGlobalVariableByVariableName(app.dbh, "DATADIR")
        app.SetHostname(hostname)
        app.SetMySQLVersion(mysql_version)
-       app.SetDatadir(datadir)
 }
 
 // have we finished ?
@@ -180,10 +177,6 @@ func (app App) MySQLVersion() string {
        return app.mysql_version
 }
 
-func (app App) Datadir() string {
-       return app.datadir
-}
-
 func (app *App) SetHelp(newHelp bool) {
        app.help = newHelp
 
@@ -191,10 +184,6 @@ func (app *App) SetHelp(newHelp bool) {
        app.screen.Flush()
 }
 
-func (app *App) SetDatadir(datadir string) {
-       app.datadir = datadir
-}
-
 func (app *App) SetMySQLVersion(mysql_version string) {
        app.mysql_version = mysql_version
 }
@@ -331,23 +320,27 @@ func (app *App) displayOpsOrLatency() {
        app.screen.BoldPrintAt(0, 2, app.tiwsbt.Headings())
 
        max_rows := app.screen.Height() - 3
+       last_row := app.screen.Height() - 1
        row_content := app.tiwsbt.RowContent(max_rows)
 
        // print out rows
        for k := range row_content {
                y := 3 + k
                app.screen.PrintAt(0, y, row_content[k])
+               app.screen.ClearLine(len(row_content[k]), y)
        }
        // print out empty rows
-       for k := len(row_content); k < (app.screen.Height() - 3); k++ {
+       for k := len(row_content); k < max_rows; k++ {
                y := 3 + k
-               if y < app.screen.Height()-1 {
+               if y < max_rows - 1 {
                        app.screen.PrintAt(0, y, app.tiwsbt.EmptyRowContent())
                }
        }
 
        // print out the totals at the bottom
-       app.screen.BoldPrintAt(0, app.screen.Height()-1, app.tiwsbt.TotalRowContent())
+       total := app.tiwsbt.TotalRowContent()
+       app.screen.BoldPrintAt(0, last_row, total)
+       app.screen.ClearLine(len(total), last_row)
 }
 
 // show actual I/O latency values
@@ -355,120 +348,140 @@ func (app App) displayIO() {
        app.screen.BoldPrintAt(0, 2, app.fsbi.Headings())
 
        // print out the data
-       max_rows := app.screen.Height() - 3
+       max_rows := app.screen.Height() - 4
+       last_row := app.screen.Height() - 1
        row_content := app.fsbi.RowContent(max_rows)
 
        // print out rows
        for k := range row_content {
                y := 3 + k
                app.screen.PrintAt(0, y, row_content[k])
+               app.screen.ClearLine(len(row_content[k]), y)
        }
        // print out empty rows
-       for k := len(row_content); k < (app.screen.Height() - 3); k++ {
+       for k := len(row_content); k < max_rows; k++ {
                y := 3 + k
-               if y < app.screen.Height()-1 {
+               if y < last_row {
                        app.screen.PrintAt(0, y, app.fsbi.EmptyRowContent())
                }
        }
 
        // print out the totals at the bottom
-       app.screen.BoldPrintAt(0, app.screen.Height()-1, app.fsbi.TotalRowContent())
+       total := app.fsbi.TotalRowContent()
+       app.screen.BoldPrintAt(0, last_row, total)
+       app.screen.ClearLine(len(total), last_row)
 }
 
 func (app *App) displayLocks() {
        app.screen.BoldPrintAt(0, 2, app.tlwsbt.Headings())
 
        // print out the data
-       max_rows := app.screen.Height() - 3
+       max_rows := app.screen.Height() - 4
+       last_row := app.screen.Height() - 1
        row_content := app.tlwsbt.RowContent(max_rows)
 
        // print out rows
        for k := range row_content {
                y := 3 + k
                app.screen.PrintAt(0, y, row_content[k])
+               app.screen.ClearLine(len(row_content[k]), y)
        }
        // print out empty rows
        for k := len(row_content); k < (app.screen.Height() - 3); k++ {
                y := 3 + k
-               if y < app.screen.Height()-1 {
+               if y < last_row {
                        app.screen.PrintAt(0, y, app.tlwsbt.EmptyRowContent())
                }
        }
 
        // print out the totals at the bottom
-       app.screen.BoldPrintAt(0, app.screen.Height()-1, app.tlwsbt.TotalRowContent())
+       total := app.tlwsbt.TotalRowContent()
+       app.screen.BoldPrintAt(0, last_row, total)
+       app.screen.ClearLine(len(total), last_row)
 }
 
 func (app *App) displayUsers() {
        app.screen.BoldPrintAt(0, 2, app.users.Headings())
 
        // print out the data
-       max_rows := app.screen.Height() - 3
+       max_rows := app.screen.Height() - 4
+       last_row := app.screen.Height() - 1
        row_content := app.users.RowContent(max_rows)
 
        // print out rows
        for k := range row_content {
                y := 3 + k
                app.screen.PrintAt(0, y, row_content[k])
+               app.screen.ClearLine(len(row_content[k]), y)
        }
        // print out empty rows
-       for k := len(row_content); k < (app.screen.Height() - 3); k++ {
+       for k := len(row_content); k < max_rows; k++ {
                y := 3 + k
-               if y < app.screen.Height()-1 {
+               if y < last_row {
                        app.screen.PrintAt(0, y, app.users.EmptyRowContent())
                }
        }
 
        // print out the totals at the bottom
-       app.screen.BoldPrintAt(0, app.screen.Height()-1, app.users.TotalRowContent())
+       total := app.users.TotalRowContent()
+       app.screen.BoldPrintAt(0, last_row, total)
+       app.screen.ClearLine(len(total), last_row)
 }
 
 func (app *App) displayMutex() {
        app.screen.BoldPrintAt(0, 2, app.ewsgben.Headings())
 
        // print out the data
-       max_rows := app.screen.Height() - 3
+       max_rows := app.screen.Height() - 4
+       last_row := app.screen.Height() - 1
        row_content := app.ewsgben.RowContent(max_rows)
 
        // print out rows
        for k := range row_content {
                y := 3 + k
                app.screen.PrintAt(0, y, row_content[k])
+               app.screen.ClearLine(len(row_content[k]), y)
        }
        // print out empty rows
-       for k := len(row_content); k < (app.screen.Height() - 3); k++ {
+       for k := len(row_content); k < max_rows; k++ {
                y := 3 + k
-               if y < app.screen.Height()-1 {
+               if y < last_row {
                        app.screen.PrintAt(0, y, app.ewsgben.EmptyRowContent())
                }
        }
 
        // print out the totals at the bottom
-       app.screen.BoldPrintAt(0, app.screen.Height()-1, app.ewsgben.TotalRowContent())
+       total := app.ewsgben.TotalRowContent()
+       app.screen.BoldPrintAt(0, last_row, total)
+       app.screen.ClearLine(len(total), last_row)
 }
 
 func (app *App) displayStages() {
        app.screen.BoldPrintAt(0, 2, app.essgben.Headings())
 
        // print out the data
-       max_rows := app.screen.Height() - 3
+       max_rows := app.screen.Height() - 4
+       last_row := app.screen.Height() - 1
        row_content := app.essgben.RowContent(max_rows)
 
        // print out rows
        for k := range row_content {
                y := 3 + k
                app.screen.PrintAt(0, y, row_content[k])
+               app.screen.ClearLine(len(row_content[k]), y)
        }
        // print out empty rows
-       for k := len(row_content); k < (app.screen.Height() - 3); k++ {
+       for k := len(row_content); k < max_rows; k++ {
                y := 3 + k
-               if y < app.screen.Height()-1 {
+               if y < last_row {
                        app.screen.PrintAt(0, y, app.essgben.EmptyRowContent())
                }
        }
 
        // print out the totals at the bottom
-       app.screen.BoldPrintAt(0, app.screen.Height()-1, app.essgben.TotalRowContent())
+       total := app.essgben.TotalRowContent()
+       app.screen.BoldPrintAt(0, last_row, total)
+       app.screen.ClearLine(len(total), last_row)
 }
 
 // do we want to show all p_s data?
@@ -507,18 +520,6 @@ func (app *App) Cleanup() {
        }
 }
 
-// make chan for termbox events and run a poller to send events to the channel
-// - return the channel
-func new_tb_chan() chan termbox.Event {
-       termboxChan := make(chan termbox.Event)
-       go func() {
-               for {
-                       termboxChan <- termbox.PollEvent()
-               }
-       }()
-       return termboxChan
-}
-
 // get into a run loop
 func (app *App) Run() {
        app.done = make(chan struct{})
@@ -529,7 +530,7 @@ func (app *App) Run() {
 
        app.wi.SetWaitInterval(time.Second)
 
-       termboxChan := new_tb_chan()
+       termboxChan := app.screen.TermBoxChan()
 
        for !app.Finished() {
                select {
@@ -588,36 +589,37 @@ func (app *App) Run() {
 // rather than giving an error message if the requires P_S tables can't
 // be found.
 func (app *App) validate_mysql_version() error {
-        var tables = [...]string{
-                "performance_schema.events_waits_summary_global_by_event_name",
-                "performance_schema.file_summary_by_instance",
-                "performance_schema.table_io_waits_summary_by_table",
-                "performance_schema.table_lock_waits_summary_by_table",
-        }
-
-        lib.Logger.Println("validate_mysql_version()")
-
-        lib.Logger.Println("- Getting MySQL version")
-        err, mysql_version := lib.SelectGlobalVariableByVariableName(app.dbh, "VERSION")
-        if err != nil {
-                return err
-        }
-        lib.Logger.Println("- mysql_version: '" + mysql_version + "'")
-
-        if !re_valid_version.MatchString(mysql_version) {
-                return errors.New(lib.MyName() + " does not work with MySQL version " + mysql_version)
-        }
-        lib.Logger.Println("OK: MySQL version is valid, continuing")
-
-        lib.Logger.Println("Checking access to required tables:")
-        for i := range tables {
-                if err := lib.CheckTableAccess(app.dbh, tables[i]); err == nil {
-                        lib.Logger.Println("OK: " + tables[i] + " found")
-                } else {
-                        return err
-                }
-        }
-        lib.Logger.Println("OK: all table checks passed")
-
-        return nil
+       var tables = [...]string{
+               "performance_schema.events_stages_summary_global_by_event_name",
+               "performance_schema.events_waits_summary_global_by_event_name",
+               "performance_schema.file_summary_by_instance",
+               "performance_schema.table_io_waits_summary_by_table",
+               "performance_schema.table_lock_waits_summary_by_table",
+       }
+
+       lib.Logger.Println("validate_mysql_version()")
+
+       lib.Logger.Println("- Getting MySQL version")
+       err, mysql_version := lib.SelectGlobalVariableByVariableName(app.dbh, "VERSION")
+       if err != nil {
+               return err
+       }
+       lib.Logger.Println("- mysql_version: '" + mysql_version + "'")
+
+       if !re_valid_version.MatchString(mysql_version) {
+               return errors.New(lib.MyName() + " does not work with MySQL version " + mysql_version)
+       }
+       lib.Logger.Println("OK: MySQL version is valid, continuing")
+
+       lib.Logger.Println("Checking access to required tables:")
+       for i := range tables {
+               if err := lib.CheckTableAccess(app.dbh, tables[i]); err == nil {
+                       lib.Logger.Println("OK: " + tables[i] + " found")
+               } else {
+                       return err
+               }
+       }
+       lib.Logger.Println("OK: all table checks passed")
+
+       return nil
 }