From ee1ce04d7c64961d1595993d8bdbf49a1de65c83 Mon Sep 17 00:00:00 2001 From: Simon J Mudd Date: Mon, 30 Mar 2026 21:58:21 +0200 Subject: [PATCH] renamed wrapper to presenter - naming of "wrapper" was not ideal so renamed to "presenter" - changed directory, struct names and adjusted comments and imports --- app/collector.go | 4 +- presenter/base.go | 105 ++++++++++++++++++ {wrapper => presenter}/common.go | 12 +- .../fileinfolatency/fileinfolatency.go | 24 ++-- .../memoryusage/memoryusage.go | 20 ++-- .../mutexlatency/mutexlatency.go | 18 +-- .../stageslatency/stageslatency.go | 18 +-- .../tableiolatency/tableiolatency.go | 22 ++-- .../tableiolatency/tableiolatency_test.go | 18 +-- .../tableioops/tableioops.go | 22 ++-- .../tableioops/tableioops_test.go | 8 +- .../tablelocklatency/tablelocklatency.go | 22 ++-- .../userlatency/userlatency.go | 18 +-- .../userlatency/userlatency_test.go | 0 pstable/pstable.go | 16 +-- wrapper/base.go | 105 ------------------ 16 files changed, 216 insertions(+), 216 deletions(-) create mode 100644 presenter/base.go rename {wrapper => presenter}/common.go (90%) rename wrapper/fileinfolatency/wrapper.go => presenter/fileinfolatency/fileinfolatency.go (71%) rename wrapper/memoryusage/wrapper.go => presenter/memoryusage/memoryusage.go (80%) rename wrapper/mutexlatency/wrapper.go => presenter/mutexlatency/mutexlatency.go (75%) rename wrapper/stageslatency/wrapper.go => presenter/stageslatency/stageslatency.go (75%) rename wrapper/tableiolatency/wrapper.go => presenter/tableiolatency/tableiolatency.go (72%) rename wrapper/tableiolatency/wrapper_test.go => presenter/tableiolatency/tableiolatency_test.go (87%) rename wrapper/tableioops/wrapper.go => presenter/tableioops/tableioops.go (74%) rename wrapper/tableioops/wrapper_test.go => presenter/tableioops/tableioops_test.go (92%) rename wrapper/tablelocklatency/wrapper.go => presenter/tablelocklatency/tablelocklatency.go (77%) rename wrapper/userlatency/wrapper.go => presenter/userlatency/userlatency.go (88%) rename wrapper/userlatency/wrapper_test.go => presenter/userlatency/userlatency_test.go (100%) delete mode 100644 wrapper/base.go diff --git a/app/collector.go b/app/collector.go index 0fb8daa..61d1d77 100644 --- a/app/collector.go +++ b/app/collector.go @@ -5,10 +5,10 @@ import ( "github.com/sjmudd/ps-top/config" "github.com/sjmudd/ps-top/model/tableio" + "github.com/sjmudd/ps-top/presenter/tableiolatency" + "github.com/sjmudd/ps-top/presenter/tableioops" "github.com/sjmudd/ps-top/pstable" "github.com/sjmudd/ps-top/view" - "github.com/sjmudd/ps-top/wrapper/tableiolatency" - "github.com/sjmudd/ps-top/wrapper/tableioops" ) // DBCollector owns all the Tabler instances and coordinates data collection. diff --git a/presenter/base.go b/presenter/base.go new file mode 100644 index 0000000..9619c8e --- /dev/null +++ b/presenter/base.go @@ -0,0 +1,105 @@ +package presenter + +import ( + "fmt" + "time" + + "github.com/sjmudd/ps-top/model" +) + +// BasePresenter[T, M] implements Tabler for any model M that satisfies +// model.Model[T]. It delegates to a content function provided at construction. +type BasePresenter[T any, M model.Model[T]] struct { + model M + name string + sortFn func([]T) // optional sorting function; nil = no sort + hasData func(T) bool // predicate for counting rows with data; nil = count all rows + contentFn func(T, T) string // formats a single row +} + +// NewBasePresenter creates a new BasePresenter with the given model and options. +func NewBasePresenter[T any, M model.Model[T]]( + model M, + name string, + sortFn func([]T), + hasData func(T) bool, + contentFn func(T, T) string, +) *BasePresenter[T, M] { + return &BasePresenter[T, M]{ + model: model, + name: name, + sortFn: sortFn, + hasData: hasData, + contentFn: contentFn, + } +} + +// Collect implements Tabler. +func (bp *BasePresenter[T, M]) Collect() { + bp.model.Collect() + if bp.sortFn != nil { + results := bp.model.GetResults() + bp.sortFn(results) + } +} + +// ResetStatistics implements Tabler. +func (bp *BasePresenter[T, M]) ResetStatistics() { + bp.model.ResetStatistics() +} + +// HaveRelativeStats implements Tabler. +func (bp *BasePresenter[T, M]) HaveRelativeStats() bool { + return bp.model.HaveRelativeStats() +} + +// FirstCollectTime implements Tabler. +func (bp *BasePresenter[T, M]) FirstCollectTime() time.Time { + return bp.model.GetFirstCollected() +} + +// LastCollectTime implements Tabler. +func (bp *BasePresenter[T, M]) LastCollectTime() time.Time { + return bp.model.GetLastCollected() +} + +// WantRelativeStats implements Tabler. +func (bp *BasePresenter[T, M]) WantRelativeStats() bool { + return bp.model.WantRelativeStats() +} + +// RowContent implements Tabler. +func (bp *BasePresenter[T, M]) RowContent() []string { + results := bp.model.GetResults() + n := len(results) + return RowsFromGetter(n, func(i int) string { + return bp.contentFn(results[i], bp.model.GetTotals()) + }) +} + +// TotalRowContent implements Tabler. +func (bp *BasePresenter[T, M]) TotalRowContent() string { + totals := bp.model.GetTotals() + return TotalRowContent(totals, bp.contentFn) +} + +// EmptyRowContent implements Tabler. +func (bp *BasePresenter[T, M]) EmptyRowContent() string { + return EmptyRowContent(bp.contentFn) +} + +// Description implements Tabler. +func (bp *BasePresenter[T, M]) Description() string { + results := bp.model.GetResults() + n := len(results) + count := n + if bp.hasData != nil { + count = CountIf(n, func(i int) bool { return bp.hasData(results[i]) }) + } + return fmt.Sprintf("%s %d rows", bp.name, count) +} + +// GetModel returns the embedded model. Used by special presenters like tableioops. +func (bp *BasePresenter[T, M]) GetModel() M { + return bp.model +} diff --git a/wrapper/common.go b/presenter/common.go similarity index 90% rename from wrapper/common.go rename to presenter/common.go index d89e6ba..a31e0de 100644 --- a/wrapper/common.go +++ b/presenter/common.go @@ -1,4 +1,4 @@ -package wrapper +package presenter import ( "fmt" @@ -7,7 +7,7 @@ import ( ) // RowsFromGetter builds a slice of strings by calling the provided getter -// for each index. This centralizes the common loop used by many wrapper +// for each index. This centralizes the common loop used by many presenter // packages to produce display rows. func RowsFromGetter(n int, get func(i int) string) []string { rows := make([]string, 0, n) @@ -18,7 +18,7 @@ func RowsFromGetter(n int, get func(i int) string) []string { } // CountIf counts how many indices in [0,n) satisfy the predicate. -// Used by wrappers to implement Description() which counts rows with data. +// Used by presenters to implement Description() which counts rows with data. func CountIf(n int, pred func(i int) bool) int { count := 0 for i := 0; i < n; i++ { @@ -31,7 +31,7 @@ func CountIf(n int, pred func(i int) bool) int { // TotalRowContent returns the formatted totals row by calling the provided // content function with the totals value for both row and totals. -// This removes the repeated pattern found in many wrapper packages. +// This removes the repeated pattern found in many presenter packages. func TotalRowContent[T any](totals T, content func(T, T) string) string { return content(totals, totals) } @@ -44,7 +44,7 @@ func EmptyRowContent[T any](content func(T, T) string) string { return content(empty, empty) } -// MakeTableIOHeadings constructs a heading string used by the tableio wrappers. +// MakeTableIOHeadings constructs a heading string used by the tableio presenters. // The `kind` parameter should be either "Latency" or "Ops" (or similar) and will // be interpolated into the common table IO heading format. func MakeTableIOHeadings(kind string) string { @@ -70,7 +70,7 @@ func TimePct(sum, totals uint64) (string, string) { // PctStrings returns a slice of formatted percentage strings for each value // relative to the provided total. This centralizes the common pattern of // calling utils.FormatPct(utils.Divide(value, total)). It helps reduce -// duplicated code across wrapper content formatters. +// duplicated code across presenter content formatters. func PctStrings(total uint64, values ...uint64) []string { out := make([]string, len(values)) for i, v := range values { diff --git a/wrapper/fileinfolatency/wrapper.go b/presenter/fileinfolatency/fileinfolatency.go similarity index 71% rename from wrapper/fileinfolatency/wrapper.go rename to presenter/fileinfolatency/fileinfolatency.go index de5e1be..e8ec179 100644 --- a/wrapper/fileinfolatency/wrapper.go +++ b/presenter/fileinfolatency/fileinfolatency.go @@ -8,8 +8,8 @@ import ( "github.com/sjmudd/ps-top/config" "github.com/sjmudd/ps-top/model/fileinfo" + "github.com/sjmudd/ps-top/presenter" "github.com/sjmudd/ps-top/utils" - "github.com/sjmudd/ps-top/wrapper" ) var ( @@ -33,9 +33,9 @@ var ( name = "" } - timeStr, pctStr := wrapper.TimePct(row.SumTimerWait, totals.SumTimerWait) - pct := wrapper.PctStrings(row.SumTimerWait, row.SumTimerRead, row.SumTimerWrite, row.SumTimerMisc) - opsPct := wrapper.PctStrings(row.CountStar, row.CountRead, row.CountWrite, row.CountMisc) + timeStr, pctStr := presenter.TimePct(row.SumTimerWait, totals.SumTimerWait) + pct := presenter.PctStrings(row.SumTimerWait, row.SumTimerRead, row.SumTimerWrite, row.SumTimerMisc) + opsPct := presenter.PctStrings(row.CountStar, row.CountRead, row.CountWrite, row.CountMisc) return fmt.Sprintf("%10s %6s|%6s %6s %6s|%8s %8s|%8s %6s %6s %6s|%s", timeStr, @@ -53,26 +53,26 @@ var ( } ) -// Wrapper wraps a FileIoLatency struct. -type Wrapper struct { - *wrapper.BaseWrapper[fileinfo.Row, *fileinfo.FileIoLatency] +// Presenter presents a FileIoLatency struct. +type Presenter struct { + *presenter.BasePresenter[fileinfo.Row, *fileinfo.FileIoLatency] } -// NewFileSummaryByInstance creates a wrapper around FileIoLatency. -func NewFileSummaryByInstance(cfg *config.Config, db *sql.DB) *Wrapper { +// NewFileSummaryByInstance creates a presenter for FileIoLatency. +func NewFileSummaryByInstance(cfg *config.Config, db *sql.DB) *Presenter { fiol := fileinfo.NewFileSummaryByInstance(cfg, db) - bw := wrapper.NewBaseWrapper( + bp := presenter.NewBasePresenter( fiol, "File I/O Latency (file_summary_by_instance)", defaultSort, defaultHasData, defaultContent, ) - return &Wrapper{BaseWrapper: bw} + return &Presenter{BasePresenter: bp} } // Headings returns the headings for a table. -func (w *Wrapper) Headings() string { +func (p *Presenter) Headings() string { return fmt.Sprintf("%10s %6s|%6s %6s %6s|%8s %8s|%8s %6s %6s %6s|%s", "Latency", "%", diff --git a/wrapper/memoryusage/wrapper.go b/presenter/memoryusage/memoryusage.go similarity index 80% rename from wrapper/memoryusage/wrapper.go rename to presenter/memoryusage/memoryusage.go index 1523183..af922d6 100644 --- a/wrapper/memoryusage/wrapper.go +++ b/presenter/memoryusage/memoryusage.go @@ -8,18 +8,18 @@ import ( "github.com/sjmudd/ps-top/config" "github.com/sjmudd/ps-top/model/memoryusage" + "github.com/sjmudd/ps-top/presenter" "github.com/sjmudd/ps-top/utils" - "github.com/sjmudd/ps-top/wrapper" ) -// Wrapper wraps a MemoryUsage struct and implements the Tabler interface -// via embedded BaseWrapper. -type Wrapper struct { - *wrapper.BaseWrapper[memoryusage.Row, *memoryusage.MemoryUsage] +// Presenter presents a MemoryUsage struct and implements the Tabler interface +// via embedded BasePresenter. +type Presenter struct { + *presenter.BasePresenter[memoryusage.Row, *memoryusage.MemoryUsage] } -// NewMemoryUsage creates a wrapper around MemoryUsage. -func NewMemoryUsage(cfg *config.Config, db *sql.DB) *Wrapper { +// NewMemoryUsage creates a presenter for MemoryUsage. +func NewMemoryUsage(cfg *config.Config, db *sql.DB) *Presenter { mu := memoryusage.NewMemoryUsage(cfg, db) // Sort by CurrentBytesUsed descending, then Name ascending. @@ -64,17 +64,17 @@ func NewMemoryUsage(cfg *config.Config, db *sql.DB) *Wrapper { name) } - bw := wrapper.NewBaseWrapper(mu, + bp := presenter.NewBasePresenter(mu, "Memory Usage (memory_summary_global_by_event_name)", sortFn, hasData, contentFn, ) - return &Wrapper{BaseWrapper: bw} + return &Presenter{BasePresenter: bp} } // Headings returns the headings for a table. -func (w *Wrapper) Headings() string { +func (p *Presenter) Headings() string { return "CurBytes % High Bytes|MemOps %|CurAlloc % HiAlloc|Memory Area" // 1234567890 100.0% 1234567890|123456789 100.0%|12345678 100.0% 12345678|Some memory name } diff --git a/wrapper/mutexlatency/wrapper.go b/presenter/mutexlatency/mutexlatency.go similarity index 75% rename from wrapper/mutexlatency/wrapper.go rename to presenter/mutexlatency/mutexlatency.go index 28fd78d..e90b0f0 100644 --- a/wrapper/mutexlatency/wrapper.go +++ b/presenter/mutexlatency/mutexlatency.go @@ -8,8 +8,8 @@ import ( "github.com/sjmudd/ps-top/config" "github.com/sjmudd/ps-top/model/mutexlatency" + "github.com/sjmudd/ps-top/presenter" "github.com/sjmudd/ps-top/utils" - "github.com/sjmudd/ps-top/wrapper" ) var ( @@ -37,25 +37,25 @@ var ( } ) -// Wrapper wraps a MutexLatency struct. -type Wrapper struct { - *wrapper.BaseWrapper[mutexlatency.Row, *mutexlatency.MutexLatency] +// Presenter presents a MutexLatency struct. +type Presenter struct { + *presenter.BasePresenter[mutexlatency.Row, *mutexlatency.MutexLatency] } -// NewMutexLatency creates a wrapper around mutexlatency. -func NewMutexLatency(cfg *config.Config, db *sql.DB) *Wrapper { +// NewMutexLatency creates a presenter for mutexlatency. +func NewMutexLatency(cfg *config.Config, db *sql.DB) *Presenter { ml := mutexlatency.NewMutexLatency(cfg, db) - bw := wrapper.NewBaseWrapper( + bp := presenter.NewBasePresenter( ml, "Mutex Latency (events_waits_summary_global_by_event_name)", defaultSort, defaultHasData, defaultContent, ) - return &Wrapper{BaseWrapper: bw} + return &Presenter{BasePresenter: bp} } // Headings returns the headings for a table. -func (w *Wrapper) Headings() string { +func (p *Presenter) Headings() string { return fmt.Sprintf("%10s %8s %8s|%s", "Latency", "MtxCnt", "%", "Mutex Name") } diff --git a/wrapper/stageslatency/wrapper.go b/presenter/stageslatency/stageslatency.go similarity index 75% rename from wrapper/stageslatency/wrapper.go rename to presenter/stageslatency/stageslatency.go index c578a47..85cbe42 100644 --- a/wrapper/stageslatency/wrapper.go +++ b/presenter/stageslatency/stageslatency.go @@ -8,8 +8,8 @@ import ( "github.com/sjmudd/ps-top/config" "github.com/sjmudd/ps-top/model/stageslatency" + "github.com/sjmudd/ps-top/presenter" "github.com/sjmudd/ps-top/utils" - "github.com/sjmudd/ps-top/wrapper" ) var ( @@ -37,25 +37,25 @@ var ( } ) -// Wrapper wraps a Stages struct. -type Wrapper struct { - *wrapper.BaseWrapper[stageslatency.Row, *stageslatency.StagesLatency] +// Presenter presents a StagesLatency struct. +type Presenter struct { + *presenter.BasePresenter[stageslatency.Row, *stageslatency.StagesLatency] } -// NewStagesLatency creates a wrapper around stageslatency. -func NewStagesLatency(cfg *config.Config, db *sql.DB) *Wrapper { +// NewStagesLatency creates a presenter for stageslatency. +func NewStagesLatency(cfg *config.Config, db *sql.DB) *Presenter { sl := stageslatency.NewStagesLatency(cfg, db) - bw := wrapper.NewBaseWrapper( + bp := presenter.NewBasePresenter( sl, "SQL Stage Latency (events_stages_summary_global_by_event_name)", defaultSort, defaultHasData, defaultContent, ) - return &Wrapper{BaseWrapper: bw} + return &Presenter{BasePresenter: bp} } // Headings returns the headings for a table. -func (w *Wrapper) Headings() string { +func (p *Presenter) Headings() string { return fmt.Sprintf("%10s %6s %8s|%s", "Latency", "%", "Counter", "Stage Name") } diff --git a/wrapper/tableiolatency/wrapper.go b/presenter/tableiolatency/tableiolatency.go similarity index 72% rename from wrapper/tableiolatency/wrapper.go rename to presenter/tableiolatency/tableiolatency.go index f54f489..2fb148c 100644 --- a/wrapper/tableiolatency/wrapper.go +++ b/presenter/tableiolatency/tableiolatency.go @@ -6,11 +6,11 @@ import ( "slices" "github.com/sjmudd/ps-top/model/tableio" + "github.com/sjmudd/ps-top/presenter" "github.com/sjmudd/ps-top/utils" - "github.com/sjmudd/ps-top/wrapper" ) -// Default functions for BaseWrapper, shared with tests. +// Default functions for BasePresenter, shared with tests. var ( defaultSort = func(rows []tableio.Row) { slices.SortFunc(rows, func(a, b tableio.Row) int { @@ -42,24 +42,24 @@ var ( } ) -// Wrapper wraps a TableIo struct and implements Tabler via BaseWrapper. -type Wrapper struct { - *wrapper.BaseWrapper[tableio.Row, *tableio.TableIo] +// Presenter presents a TableIo struct and implements Tabler via BasePresenter. +type Presenter struct { + *presenter.BasePresenter[tableio.Row, *tableio.TableIo] } -// NewTableIoLatency creates a wrapper around tableio statistics using the provided model. -func NewTableIoLatency(model *tableio.TableIo) *Wrapper { - bw := wrapper.NewBaseWrapper( +// NewTableIoLatency creates a presenter for tableio statistics using the provided model. +func NewTableIoLatency(model *tableio.TableIo) *Presenter { + bp := presenter.NewBasePresenter( model, "Table I/O Latency (table_io_waits_summary_by_table)", defaultSort, defaultHasData, defaultContent, ) - return &Wrapper{BaseWrapper: bw} + return &Presenter{BasePresenter: bp} } // Headings returns the latency headings as a string. -func (w *Wrapper) Headings() string { - return wrapper.MakeTableIOHeadings("Latency") +func (p *Presenter) Headings() string { + return presenter.MakeTableIOHeadings("Latency") } diff --git a/wrapper/tableiolatency/wrapper_test.go b/presenter/tableiolatency/tableiolatency_test.go similarity index 87% rename from wrapper/tableiolatency/wrapper_test.go rename to presenter/tableiolatency/tableiolatency_test.go index dc0174b..da68c62 100644 --- a/wrapper/tableiolatency/wrapper_test.go +++ b/presenter/tableiolatency/tableiolatency_test.go @@ -6,13 +6,13 @@ import ( "github.com/sjmudd/ps-top/model" "github.com/sjmudd/ps-top/model/tableio" - "github.com/sjmudd/ps-top/wrapper" + "github.com/sjmudd/ps-top/presenter" ) -// newTableIo creates a Wrapper for testing with the given rows and totals. -// This helper constructs a TableIo model with injected data and wraps it -// using BaseWrapper with the default functions defined in this package. -func newTableIo(rows []tableio.Row, totals tableio.Row) *Wrapper { +// newTableIo creates a Presenter for testing with the given rows and totals. +// This helper constructs a TableIo model with injected data and presents it +// using BasePresenter with the default functions defined in this package. +func newTableIo(rows []tableio.Row, totals tableio.Row) *Presenter { // Create a TableIo with a BaseCollector, manually set Results/Totals. process := func(last, _ tableio.Rows) (tableio.Rows, tableio.Row) { // Not used because we set Results manually. @@ -23,15 +23,15 @@ func newTableIo(rows []tableio.Row, totals tableio.Row) *Wrapper { bc.Results = rows bc.Totals = totals - // Wrap using BaseWrapper with the default functions from this package. - bw := wrapper.NewBaseWrapper( + // Present using BasePresenter with the default functions from this package. + bp := presenter.NewBasePresenter( tiol, "Table I/O Latency (table_io_waits_summary_by_table)", defaultSort, defaultHasData, defaultContent, ) - return &Wrapper{BaseWrapper: bw} + return &Presenter{BasePresenter: bp} } // TestRowContentUsesSumTimerWait verifies that RowContent includes the expected @@ -64,7 +64,7 @@ func TestRowContentUsesSumTimerWait(t *testing.T) { // TestHeadings checks that the Headings output contains "Latency". func TestHeadings(t *testing.T) { - w := &Wrapper{} + w := &Presenter{} h := w.Headings() if !strings.Contains(h, "Latency") { t.Errorf("Headings missing 'Latency': %q", h) diff --git a/wrapper/tableioops/wrapper.go b/presenter/tableioops/tableioops.go similarity index 74% rename from wrapper/tableioops/wrapper.go rename to presenter/tableioops/tableioops.go index 68801de..1d05040 100644 --- a/wrapper/tableioops/wrapper.go +++ b/presenter/tableioops/tableioops.go @@ -6,8 +6,8 @@ import ( "slices" "github.com/sjmudd/ps-top/model/tableio" + "github.com/sjmudd/ps-top/presenter" "github.com/sjmudd/ps-top/utils" - "github.com/sjmudd/ps-top/wrapper" ) var ( @@ -51,25 +51,25 @@ var ( } ) -// Wrapper represents a wrapper around table I/O ops. It uses a shared TableIo model -// but presents different formatting and sorting than the latency wrapper. -type Wrapper struct { - *wrapper.BaseWrapper[tableio.Row, *tableio.TableIo] +// Presenter presents table I/O ops. It uses a shared TableIo model +// but different formatting and sorting than the latency presenter. +type Presenter struct { + *presenter.BasePresenter[tableio.Row, *tableio.TableIo] } -// NewTableIoOps creates a new ops wrapper using the provided shared TableIo model. -func NewTableIoOps(model *tableio.TableIo) *Wrapper { - bw := wrapper.NewBaseWrapper( +// NewTableIoOps creates a new ops presenter using the provided shared TableIo model. +func NewTableIoOps(model *tableio.TableIo) *Presenter { + bp := presenter.NewBasePresenter( model, "Table I/O Ops (table_io_waits_summary_by_table)", defaultSort, defaultHasData, defaultContent, ) - return &Wrapper{BaseWrapper: bw} + return &Presenter{BasePresenter: bp} } // Headings returns the ops headings. -func (w *Wrapper) Headings() string { - return wrapper.MakeTableIOHeadings("Ops") +func (p *Presenter) Headings() string { + return presenter.MakeTableIOHeadings("Ops") } diff --git a/wrapper/tableioops/wrapper_test.go b/presenter/tableioops/tableioops_test.go similarity index 92% rename from wrapper/tableioops/wrapper_test.go rename to presenter/tableioops/tableioops_test.go index bb2d6f0..a6c00d0 100644 --- a/wrapper/tableioops/wrapper_test.go +++ b/presenter/tableioops/tableioops_test.go @@ -8,15 +8,15 @@ import ( "github.com/sjmudd/ps-top/model/tableio" ) -// newTableIo creates a Wrapper for testing with the given rows and totals. +// newTableIo creates a Presenter for testing with the given rows and totals. // It constructs a shared TableIo model, injects the test data, and creates -// both latency and ops wrappers from the same model. -func newTableIo(rows []tableio.Row, totals tableio.Row) *Wrapper { +// an ops presenter from the model. +func newTableIo(rows []tableio.Row, totals tableio.Row) *Presenter { // Create a shared TableIo model (no database needed for these tests). model := tableio.NewTableIo(&config.Config{}, nil) model.Results = rows model.Totals = totals - // Create ops wrapper directly from the model. + // Create ops presenter directly from the model. return NewTableIoOps(model) } diff --git a/wrapper/tablelocklatency/wrapper.go b/presenter/tablelocklatency/tablelocklatency.go similarity index 77% rename from wrapper/tablelocklatency/wrapper.go rename to presenter/tablelocklatency/tablelocklatency.go index 1291da4..38cb2c4 100644 --- a/wrapper/tablelocklatency/wrapper.go +++ b/presenter/tablelocklatency/tablelocklatency.go @@ -8,8 +8,8 @@ import ( "github.com/sjmudd/ps-top/config" "github.com/sjmudd/ps-top/model/tablelocks" + "github.com/sjmudd/ps-top/presenter" "github.com/sjmudd/ps-top/utils" - "github.com/sjmudd/ps-top/wrapper" ) var ( @@ -30,8 +30,8 @@ var ( if row.SumTimerWait == 0 && name != "Totals" { name = "" } - timeStr, pctStr := wrapper.TimePct(row.SumTimerWait, totals.SumTimerWait) - pct := wrapper.PctStrings(row.SumTimerWait, + timeStr, pctStr := presenter.TimePct(row.SumTimerWait, totals.SumTimerWait) + pct := presenter.PctStrings(row.SumTimerWait, row.SumTimerRead, row.SumTimerWrite, row.SumTimerReadWithSharedLocks, @@ -67,26 +67,26 @@ var ( } ) -// Wrapper wraps a TableLock struct. -type Wrapper struct { - *wrapper.BaseWrapper[tablelocks.Row, *tablelocks.TableLocks] +// Presenter presents a TableLocks struct. +type Presenter struct { + *presenter.BasePresenter[tablelocks.Row, *tablelocks.TableLocks] } -// NewTableLockLatency creates a wrapper around TableLockLatency. -func NewTableLockLatency(cfg *config.Config, db *sql.DB) *Wrapper { +// NewTableLockLatency creates a presenter for TableLockLatency. +func NewTableLockLatency(cfg *config.Config, db *sql.DB) *Presenter { tl := tablelocks.NewTableLocks(cfg, db) - bw := wrapper.NewBaseWrapper( + bp := presenter.NewBasePresenter( tl, "Locks by Table Name (table_lock_waits_summary_by_table)", defaultSort, nil, // hasData: count all rows defaultContent, ) - return &Wrapper{BaseWrapper: bw} + return &Presenter{BasePresenter: bp} } // Headings returns the headings for a table. -func (w *Wrapper) Headings() string { +func (p *Presenter) Headings() string { return fmt.Sprintf("%10s %6s|%6s %6s|%6s %6s %6s %6s %6s|%6s %6s %6s %6s %6s|%-30s", "Latency", "%", "Read", "Write", diff --git a/wrapper/userlatency/wrapper.go b/presenter/userlatency/userlatency.go similarity index 88% rename from wrapper/userlatency/wrapper.go rename to presenter/userlatency/userlatency.go index cfbd2e6..091adbd 100644 --- a/wrapper/userlatency/wrapper.go +++ b/presenter/userlatency/userlatency.go @@ -8,8 +8,8 @@ import ( "github.com/sjmudd/ps-top/config" "github.com/sjmudd/ps-top/model/userlatency" + "github.com/sjmudd/ps-top/presenter" "github.com/sjmudd/ps-top/utils" - "github.com/sjmudd/ps-top/wrapper" ) // formatSeconds formats the given seconds into xxh xxm xxs or xxd xxh xxm @@ -100,26 +100,26 @@ var ( } ) -// Wrapper wraps a UserLatency struct. -type Wrapper struct { - *wrapper.BaseWrapper[userlatency.Row, *userlatency.UserLatency] +// Presenter presents a UserLatency struct. +type Presenter struct { + *presenter.BasePresenter[userlatency.Row, *userlatency.UserLatency] } -// NewUserLatency creates a wrapper around UserLatency. -func NewUserLatency(cfg *config.Config, db *sql.DB) *Wrapper { +// NewUserLatency creates a presenter for UserLatency. +func NewUserLatency(cfg *config.Config, db *sql.DB) *Presenter { ul := userlatency.NewUserLatency(cfg, db) - bw := wrapper.NewBaseWrapper( + bp := presenter.NewBasePresenter( ul, "Activity by Username (processlist)", defaultSort, defaultHasData, defaultContent, ) - return &Wrapper{BaseWrapper: bw} + return &Presenter{BasePresenter: bp} } // Headings returns the headings for a table. -func (w *Wrapper) Headings() string { +func (p *Presenter) Headings() string { return fmt.Sprintf("%-10s %6s|%-10s %6s|%4s %4s|%5s %3s|%3s %3s %3s %3s %3s|%s", "Run Time", "%", "Sleeping", "%", "Conn", "Actv", "Hosts", "DBs", "Sel", "Ins", "Upd", "Del", "Oth", "User") } diff --git a/wrapper/userlatency/wrapper_test.go b/presenter/userlatency/userlatency_test.go similarity index 100% rename from wrapper/userlatency/wrapper_test.go rename to presenter/userlatency/userlatency_test.go diff --git a/pstable/pstable.go b/pstable/pstable.go index e76f772..c4ec98c 100644 --- a/pstable/pstable.go +++ b/pstable/pstable.go @@ -9,13 +9,13 @@ import ( "github.com/sjmudd/ps-top/config" "github.com/sjmudd/ps-top/log" "github.com/sjmudd/ps-top/model/tableio" - "github.com/sjmudd/ps-top/wrapper/fileinfolatency" - "github.com/sjmudd/ps-top/wrapper/memoryusage" - "github.com/sjmudd/ps-top/wrapper/mutexlatency" - "github.com/sjmudd/ps-top/wrapper/stageslatency" - "github.com/sjmudd/ps-top/wrapper/tableiolatency" - "github.com/sjmudd/ps-top/wrapper/tablelocklatency" - "github.com/sjmudd/ps-top/wrapper/userlatency" + "github.com/sjmudd/ps-top/presenter/fileinfolatency" + "github.com/sjmudd/ps-top/presenter/memoryusage" + "github.com/sjmudd/ps-top/presenter/mutexlatency" + "github.com/sjmudd/ps-top/presenter/stageslatency" + "github.com/sjmudd/ps-top/presenter/tableiolatency" + "github.com/sjmudd/ps-top/presenter/tablelocklatency" + "github.com/sjmudd/ps-top/presenter/userlatency" ) // TablerType defines the type of PS table data @@ -64,7 +64,7 @@ func NewTabler(tablerType TablerType, cfg *config.Config, db *sql.DB) Tabler { case StagesLatency: t = stageslatency.NewStagesLatency(cfg, db) case TableIoLatency: - // Create a dedicated TableIo model for this latency wrapper. + // Create a dedicated TableIo model for this latency presenter. // If both latency and ops views are needed, create a shared model and pass // to both tableiolatency.NewTableIoLatency and tableioops.NewTableIoOps directly. model := tableio.NewTableIo(cfg, db) diff --git a/wrapper/base.go b/wrapper/base.go deleted file mode 100644 index 08b04a9..0000000 --- a/wrapper/base.go +++ /dev/null @@ -1,105 +0,0 @@ -package wrapper - -import ( - "fmt" - "time" - - "github.com/sjmudd/ps-top/model" -) - -// BaseWrapper[T, M] implements Tabler for any model M that satisfies -// model.Model[T]. It delegates to a content function provided at construction. -type BaseWrapper[T any, M model.Model[T]] struct { - model M - name string - sortFn func([]T) // optional sorting function; nil = no sort - hasData func(T) bool // predicate for counting rows with data; nil = count all rows - contentFn func(T, T) string // formats a single row -} - -// NewBaseWrapper creates a new BaseWrapper with the given model and options. -func NewBaseWrapper[T any, M model.Model[T]]( - model M, - name string, - sortFn func([]T), - hasData func(T) bool, - contentFn func(T, T) string, -) *BaseWrapper[T, M] { - return &BaseWrapper[T, M]{ - model: model, - name: name, - sortFn: sortFn, - hasData: hasData, - contentFn: contentFn, - } -} - -// Collect implements Tabler. -func (bw *BaseWrapper[T, M]) Collect() { - bw.model.Collect() - if bw.sortFn != nil { - results := bw.model.GetResults() - bw.sortFn(results) - } -} - -// ResetStatistics implements Tabler. -func (bw *BaseWrapper[T, M]) ResetStatistics() { - bw.model.ResetStatistics() -} - -// HaveRelativeStats implements Tabler. -func (bw *BaseWrapper[T, M]) HaveRelativeStats() bool { - return bw.model.HaveRelativeStats() -} - -// FirstCollectTime implements Tabler. -func (bw *BaseWrapper[T, M]) FirstCollectTime() time.Time { - return bw.model.GetFirstCollected() -} - -// LastCollectTime implements Tabler. -func (bw *BaseWrapper[T, M]) LastCollectTime() time.Time { - return bw.model.GetLastCollected() -} - -// WantRelativeStats implements Tabler. -func (bw *BaseWrapper[T, M]) WantRelativeStats() bool { - return bw.model.WantRelativeStats() -} - -// RowContent implements Tabler. -func (bw *BaseWrapper[T, M]) RowContent() []string { - results := bw.model.GetResults() - n := len(results) - return RowsFromGetter(n, func(i int) string { - return bw.contentFn(results[i], bw.model.GetTotals()) - }) -} - -// TotalRowContent implements Tabler. -func (bw *BaseWrapper[T, M]) TotalRowContent() string { - totals := bw.model.GetTotals() - return TotalRowContent(totals, bw.contentFn) -} - -// EmptyRowContent implements Tabler. -func (bw *BaseWrapper[T, M]) EmptyRowContent() string { - return EmptyRowContent(bw.contentFn) -} - -// Description implements Tabler. -func (bw *BaseWrapper[T, M]) Description() string { - results := bw.model.GetResults() - n := len(results) - count := n - if bw.hasData != nil { - count = CountIf(n, func(i int) bool { return bw.hasData(results[i]) }) - } - return fmt.Sprintf("%s %d rows", bw.name, count) -} - -// GetModel returns the embedded model. Used by special wrappers like tableioops. -func (bw *BaseWrapper[T, M]) GetModel() M { - return bw.model -}