From 882d0ad8a2221ac28f46b132df5932a80ef60cb7 Mon Sep 17 00:00:00 2001 From: Alex Aizman Date: Thu, 19 Dec 2024 13:02:33 -0500 Subject: [PATCH] scrub: dynamic table (UI works) * part six, prev. commit: 0634d834b7e53 * remove static template * hide zeros * refactor a bunch Signed-off-by: Alex Aizman --- cmd/aisnode/main.go | 2 +- cmd/cli/cli/scrub.go | 84 ++++++++++++++------------ cmd/cli/teb/performance.go | 8 +-- cmd/cli/teb/scrub.go | 117 +++++++++++++++++++++++++++++++++++++ cmd/cli/teb/templates.go | 6 -- core/lcopy.go | 2 +- core/meta/jsp.go | 2 +- fs/err.go | 2 +- fs/utils.go | 2 +- fs/xattr_unix.go | 2 +- ios/diskstats_linux.go | 2 +- reb/gfn.go | 2 +- reb/packed_struct.go | 2 +- reb/stages.go | 2 +- sys/proc.go | 2 +- transport/api.go | 2 +- transport/header.go | 2 +- transport/pool.go | 2 +- transport/stats.go | 2 +- xact/xreg/nonbck.go | 2 +- xact/xs/brename.go | 2 +- xact/xs/election.go | 2 +- xact/xs/etl.go | 2 +- xact/xs/pool_lso.go | 2 +- 24 files changed, 187 insertions(+), 68 deletions(-) create mode 100644 cmd/cli/teb/scrub.go diff --git a/cmd/aisnode/main.go b/cmd/aisnode/main.go index 79293643930..fcd1af15ade 100644 --- a/cmd/aisnode/main.go +++ b/cmd/aisnode/main.go @@ -1,6 +1,6 @@ // Package main for the AIS node executable. /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package main diff --git a/cmd/cli/cli/scrub.go b/cmd/cli/cli/scrub.go index 6548c982e30..30c017b37d6 100644 --- a/cmd/cli/cli/scrub.go +++ b/cmd/cli/cli/scrub.go @@ -35,13 +35,25 @@ import ( // - async execution // - pretty print +type ( + _log struct { + fh *os.File + tag string + fn string + cnt int + mu sync.Mutex + } + // fields exported => teb/template + scrubOne teb.ScrubOne +) + type ( scrubCtx struct { c *cli.Context scrubs []*scrubOne qbck cmn.QueryBcks pref string - tmpl string + units string // sizing small int64 large int64 @@ -57,25 +69,6 @@ type ( } _many bool } - _log struct { - fh *os.File - tag string - fn string - cnt int - mu sync.Mutex - } - // fields exported => teb/template - scrubOne struct { - parent *scrubCtx - Bck cmn.Bck - Listed uint64 - Stats struct { - Misplaced uint64 - MissingCp uint64 - SmallSz uint64 - LargeSz uint64 - } - } ) func scrubHandler(c *cli.Context) (err error) { @@ -102,10 +95,6 @@ func scrubHandler(c *cli.Context) (err error) { } ctx.last.Store(mono.NanoTime()) // pace interim results - ctx.tmpl = teb.ScrubTmpl - if flagIsSet(ctx.c, noHeaderFlag) { - ctx.tmpl = teb.ScrubBody - } ctx.ival = listObjectsWaitTime if flagIsSet(c, refreshFlag) { @@ -140,6 +129,11 @@ func scrubHandler(c *cli.Context) (err error) { return err } + ctx.units, err = parseUnitsFlag(ctx.c, unitsFlag) + if err != nil { + return err + } + if ctx.qbck.IsBucket() { err = waitForFunc(ctx.one, ctx.ival) } else { @@ -218,7 +212,19 @@ func (ctx *scrubCtx) many() error { } wg.Wait() - return teb.Print(ctx.scrubs, ctx.tmpl) + return ctx.prnt() +} + +// print and be done +func (ctx *scrubCtx) prnt() error { + out := make([]*teb.ScrubOne, len(ctx.scrubs)) + for i, scr := range ctx.scrubs { + out[i] = (*teb.ScrubOne)(scr) + } + all := teb.ScrubHelper{All: out} + tab := all.MakeTab(ctx.units) + + return teb.Print(out, tab.Template(flagIsSet(ctx.c, noHeaderFlag))) } func (ctx *scrubCtx) gols(bck cmn.Bck, wg cos.WG, mu *sync.Mutex) { @@ -239,7 +245,9 @@ func (ctx *scrubCtx) one() error { if err != nil { return err } - return teb.Print([]*scrubOne{scr}, ctx.tmpl) + + ctx.scrubs = []*scrubOne{scr} + return ctx.prnt() } func (ctx *scrubCtx) ls(bck cmn.Bck) (*scrubOne, error) { @@ -250,7 +258,7 @@ func (ctx *scrubCtx) ls(bck cmn.Bck) (*scrubOne, error) { bck.Props = bprops var ( lsargs api.ListArgs - scr = &scrubOne{parent: ctx, Bck: bck} + scr = &scrubOne{Bck: bck, Prefix: ctx.pref} lsmsg = &apc.LsoMsg{Prefix: ctx.pref, Flags: apc.LsObjCached | apc.LsMissing} ) lsmsg.AddProps(apc.GetPropsName, apc.GetPropsSize) @@ -279,7 +287,7 @@ func (ctx *scrubCtx) ls(bck cmn.Bck) (*scrubOne, error) { continue } debug.Assert(en.IsPresent(), bck.Cname(en.Name), " must be present") // (LsObjCached) - scr.upd(en, bprops) + scr.upd(ctx, en, bprops) } if lsmsg.ContinuationToken == "" { @@ -337,33 +345,33 @@ func (ctx *scrubCtx) ls(bck cmn.Bck) (*scrubOne, error) { // scrubOne // ////////////// -func (scr *scrubOne) upd(en *cmn.LsoEnt, bprops *cmn.Bprops) { +func (scr *scrubOne) upd(parent *scrubCtx, en *cmn.LsoEnt, bprops *cmn.Bprops) { scr.Listed++ if !en.IsStatusOK() { scr.Stats.Misplaced++ - scr.log(&scr.parent.log.misplaced, scr.Bck.Cname(en.Name)) + scr.log(&parent.log.misplaced, scr.Bck.Cname(en.Name), parent._many) return } if bprops.Mirror.Enabled && en.Copies < int16(bprops.Mirror.Copies) { scr.Stats.MissingCp++ - scr.log(&scr.parent.log.missing, scr.Bck.Cname(en.Name)) + scr.log(&parent.log.missing, scr.Bck.Cname(en.Name), parent._many) } - if en.Size <= scr.parent.small { + if en.Size <= parent.small { scr.Stats.SmallSz++ - scr.log(&scr.parent.log.small, scr.Bck.Cname(en.Name)) - } else if en.Size >= scr.parent.large { + scr.log(&parent.log.small, scr.Bck.Cname(en.Name), parent._many) + } else if en.Size >= parent.large { scr.Stats.LargeSz++ - scr.log(&scr.parent.log.large, scr.Bck.Cname(en.Name)) + scr.log(&parent.log.large, scr.Bck.Cname(en.Name), parent._many) } } -func (scr *scrubOne) log(to *_log, s string) { - if scr.parent._many { +func (*scrubOne) log(to *_log, s string, lock bool) { + if lock { to.mu.Lock() } fmt.Fprintln(to.fh, s) to.cnt++ - if scr.parent._many { + if lock { to.mu.Unlock() } } diff --git a/cmd/cli/teb/performance.go b/cmd/cli/teb/performance.go index b566658dfe3..a6ae4cf3ec7 100644 --- a/cmd/cli/teb/performance.go +++ b/cmd/cli/teb/performance.go @@ -73,7 +73,7 @@ func (c *PerfTabCtx) MakeTab(st StstMap) (*Table, int, error) { // 2. exclude zero columns unless requested specific match or (--all) if c.Regex == nil { - cols = _zerout(cols, st) + cols = st._zerout(cols) } // 3. sort (remaining) columns and shift `err-*` columns to the right @@ -91,7 +91,7 @@ func (c *PerfTabCtx) MakeTab(st StstMap) (*Table, int, error) { }) // 4. add STATUS column unless all nodes are online (`NodeOnline`) - cols = _addStatus(cols, st) + cols = st._addStatus(cols) // 5. add regex-specified (ie, user-requested) metrics that are missing // ------ api.GetStatsAndStatus() does not return zero counters ------- @@ -214,7 +214,7 @@ func (c *PerfTabCtx) MakeTab(st StstMap) (*Table, int, error) { // // remove all-zeros columns -func _zerout(cols []*header, st StstMap) []*header { +func (st StstMap) _zerout(cols []*header) []*header { for i := 0; i < len(cols); i++ { var found bool h := cols[i] @@ -240,7 +240,7 @@ func _zerout(cols []*header, st StstMap) []*header { } // (aternatively, could always add, conditionally hide) -func _addStatus(cols []*header, st StstMap) []*header { +func (st StstMap) _addStatus(cols []*header) []*header { for _, ds := range st { if ds.Status != NodeOnline { cols = append(cols, &header{name: colStatus, hide: false}) diff --git a/cmd/cli/teb/scrub.go b/cmd/cli/teb/scrub.go new file mode 100644 index 00000000000..436aaee0369 --- /dev/null +++ b/cmd/cli/teb/scrub.go @@ -0,0 +1,117 @@ +// Package teb contains templates and (templated) tables to format CLI output. +/* + * Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved. + */ +package teb + +import ( + "strconv" + + "github.com/NVIDIA/aistore/cmn" +) + +const ( + colBucket = "BUCKET" // + [/PREFIX] + colObjects = "OBJECTS" + colMisplaced = "MISPLACED" + colMissing = "MISSING COPIES" + colSmall = "SMALL" + colLarge = "LARGE" +) + +type ( + ScrubOne struct { + Bck cmn.Bck + Prefix string + Listed uint64 + Stats struct { + Misplaced uint64 + MissingCp uint64 + SmallSz uint64 + LargeSz uint64 + } + } + ScrubHelper struct { + All []*ScrubOne + } +) + +func (h *ScrubHelper) colFirst() string { + var num int + for _, scr := range h.All { + if scr.Prefix != "" { + num++ + } + } + switch { + case num == len(h.All): + return colBucket + "/PREFIX" + case num > 0: + return colBucket + "[/PREFIX]" + default: + return colBucket + } +} + +func (h *ScrubHelper) MakeTab(units string) *Table { + var ( + cols = []*header{ + {name: h.colFirst()}, + {name: colObjects}, + {name: colMisplaced}, + {name: colMissing}, + {name: colSmall}, + {name: colLarge}, + } + table = newTable(cols...) + ) + + _ = units // TODO -- FIXME: add total size; use units + + h.hideMisplaced(cols, colMisplaced) + h.hideMissing(cols, colMissing) + + for _, scr := range h.All { + row := []string{ + scr.Bck.Cname(scr.Prefix), + strconv.FormatUint(scr.Listed, 10), + strconv.FormatUint(scr.Stats.Misplaced, 10), + strconv.FormatUint(scr.Stats.MissingCp, 10), + strconv.FormatUint(scr.Stats.SmallSz, 10), + strconv.FormatUint(scr.Stats.LargeSz, 10), + } + table.addRow(row) + } + + return table +} + +// +// remove/hide a few named all-zero columns +// + +func (h *ScrubHelper) hideMisplaced(cols []*header, col string) { + for _, scr := range h.All { + if scr.Stats.Misplaced != 0 { + return + } + } + h._hideCol(cols, col) +} + +func (h *ScrubHelper) hideMissing(cols []*header, col string) { + for _, scr := range h.All { + if scr.Stats.MissingCp != 0 { + return + } + } + h._hideCol(cols, col) +} + +func (*ScrubHelper) _hideCol(cols []*header, name string) { + for _, col := range cols { + if col.name == name { + col.hide = true + } + } +} diff --git a/cmd/cli/teb/templates.go b/cmd/cli/teb/templates.go index 5805adb29b9..a0220d4fcc1 100644 --- a/cmd/cli/teb/templates.go +++ b/cmd/cli/teb/templates.go @@ -224,12 +224,6 @@ const ( "{{FormatBytesUns $v.TotalSize.PresentObjs 2}} {{FormatBytesUns $v.TotalSize.RemoteObjs 2}}\t {{$v.UsedPct}}%\n" + "{{end}}" - scrubHdr = "BUCKET\t OBJECTS\t MISPLACED\t MISSING COPIES\t SMALL\t LARGE\n" - ScrubBody = "{{range $v := . }}" + - "{{FormatBckName $v.Bck}}\t {{$v.Listed}}\t {{$v.Stats.Misplaced}}\t {{$v.Stats.MissingCp}}\t {{$v.Stats.SmallSz}}\t {{$v.Stats.LargeSz}}\n" + - "{{end}}" - ScrubTmpl = scrubHdr + ScrubBody - // For `object put` mass uploader. A caller adds to the template // total count and size. That is why the template ends with \t MultiPutTmpl = "Files to upload:\nEXTENSION\t COUNT\t SIZE\n" + diff --git a/core/lcopy.go b/core/lcopy.go index 61eba16d1d6..49257e4c842 100644 --- a/core/lcopy.go +++ b/core/lcopy.go @@ -1,6 +1,6 @@ // Package core provides core metadata and in-cluster API /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package core diff --git a/core/meta/jsp.go b/core/meta/jsp.go index 39a542dac55..74e2bc78c5b 100644 --- a/core/meta/jsp.go +++ b/core/meta/jsp.go @@ -1,6 +1,6 @@ // Package meta: cluster-level metadata /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package meta diff --git a/fs/err.go b/fs/err.go index 8556d0f05ee..3155607775c 100644 --- a/fs/err.go +++ b/fs/err.go @@ -1,6 +1,6 @@ // Package fs provides mountpath and FQN abstractions and methods to resolve/map stored content /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package fs diff --git a/fs/utils.go b/fs/utils.go index 2e5fed9088c..6372ca7ff90 100644 --- a/fs/utils.go +++ b/fs/utils.go @@ -1,6 +1,6 @@ // Package fs provides mountpath and FQN abstractions and methods to resolve/map stored content /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package fs diff --git a/fs/xattr_unix.go b/fs/xattr_unix.go index 16294058861..c074bad289f 100644 --- a/fs/xattr_unix.go +++ b/fs/xattr_unix.go @@ -1,6 +1,6 @@ // Package fs provides mountpath and FQN abstractions and methods to resolve/map stored content /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package fs diff --git a/ios/diskstats_linux.go b/ios/diskstats_linux.go index 627059d1f40..e5c173d4319 100644 --- a/ios/diskstats_linux.go +++ b/ios/diskstats_linux.go @@ -1,7 +1,7 @@ // Package ios is a collection of interfaces to the local storage subsystem; // the package includes OS-dependent implementations for those interfaces. /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package ios diff --git a/reb/gfn.go b/reb/gfn.go index 016707d6718..654d4094f13 100644 --- a/reb/gfn.go +++ b/reb/gfn.go @@ -1,6 +1,6 @@ // Package ais provides core functionality for the AIStore object storage. /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package reb diff --git a/reb/packed_struct.go b/reb/packed_struct.go index 0ae856b05a8..42f3c043d9b 100644 --- a/reb/packed_struct.go +++ b/reb/packed_struct.go @@ -1,6 +1,6 @@ // Package reb provides global cluster-wide rebalance upon adding/removing storage nodes. /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package reb diff --git a/reb/stages.go b/reb/stages.go index de66bc676f0..ff6db08e30b 100644 --- a/reb/stages.go +++ b/reb/stages.go @@ -1,6 +1,6 @@ // Package reb provides global cluster-wide rebalance upon adding/removing storage nodes. /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package reb diff --git a/sys/proc.go b/sys/proc.go index 2df3664c03e..282c07a670e 100644 --- a/sys/proc.go +++ b/sys/proc.go @@ -1,6 +1,6 @@ // Package sys provides methods to read system information /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package sys diff --git a/transport/api.go b/transport/api.go index 934609e62a6..296be9d12f3 100644 --- a/transport/api.go +++ b/transport/api.go @@ -1,7 +1,7 @@ // Package transport provides long-lived http/tcp connections for // intra-cluster communications (see README for details and usage example). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package transport diff --git a/transport/header.go b/transport/header.go index f0b09cc8a1e..2eeac0dad31 100644 --- a/transport/header.go +++ b/transport/header.go @@ -1,7 +1,7 @@ // Package transport provides long-lived http/tcp connections for // intra-cluster communications (see README for details and usage example). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package transport diff --git a/transport/pool.go b/transport/pool.go index ee05557581d..bba255abbe8 100644 --- a/transport/pool.go +++ b/transport/pool.go @@ -1,7 +1,7 @@ // Package transport provides long-lived http/tcp connections for // intra-cluster communications (see README for details and usage example). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package transport diff --git a/transport/stats.go b/transport/stats.go index 494516c72dd..902263c568c 100644 --- a/transport/stats.go +++ b/transport/stats.go @@ -1,7 +1,7 @@ // Package transport provides long-lived http/tcp connections for // intra-cluster communications (see README for details and usage example). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package transport diff --git a/xact/xreg/nonbck.go b/xact/xreg/nonbck.go index 69772c88dcc..0597a91ec85 100644 --- a/xact/xreg/nonbck.go +++ b/xact/xreg/nonbck.go @@ -1,6 +1,6 @@ // Package xreg provides registry and (renew, find) functions for AIS eXtended Actions (xactions). /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package xreg diff --git a/xact/xs/brename.go b/xact/xs/brename.go index e27b6ea7ccc..034a0e7127e 100644 --- a/xact/xs/brename.go +++ b/xact/xs/brename.go @@ -1,7 +1,7 @@ // Package xs is a collection of eXtended actions (xactions), including multi-object // operations, list-objects, (cluster) rebalance and (target) resilver, ETL, and more. /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package xs diff --git a/xact/xs/election.go b/xact/xs/election.go index 25a3344fb9c..16e70a109e7 100644 --- a/xact/xs/election.go +++ b/xact/xs/election.go @@ -1,7 +1,7 @@ // Package xs is a collection of eXtended actions (xactions), including multi-object // operations, list-objects, (cluster) rebalance and (target) resilver, ETL, and more. /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package xs diff --git a/xact/xs/etl.go b/xact/xs/etl.go index 7f9ce7675dd..09d24c6f775 100644 --- a/xact/xs/etl.go +++ b/xact/xs/etl.go @@ -1,7 +1,7 @@ // Package xs is a collection of eXtended actions (xactions), including multi-object // operations, list-objects, (cluster) rebalance and (target) resilver, ETL, and more. /* - * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. */ package xs diff --git a/xact/xs/pool_lso.go b/xact/xs/pool_lso.go index 50cce00e486..6ef6f513181 100644 --- a/xact/xs/pool_lso.go +++ b/xact/xs/pool_lso.go @@ -1,7 +1,7 @@ // Package xs is a collection of eXtended actions (xactions), including multi-object // operations, list-objects, (cluster) rebalance and (target) resilver, ETL, and more. /* - * Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved. */ package xs