@@ -5,13 +5,17 @@ import (
55 "context"
66 "errors"
77 "fmt"
8+ "io/fs"
89 "os"
910 "path/filepath"
11+ "strings"
1012 "time"
1113
14+ badgerDB "github.com/dgraph-io/badger/v4"
1215 "github.com/spf13/cobra"
1316
1417 "github.com/oasisprotocol/oasis-core/go/common"
18+ cmnBadger "github.com/oasisprotocol/oasis-core/go/common/badger"
1519 "github.com/oasisprotocol/oasis-core/go/common/crypto/hash"
1620 "github.com/oasisprotocol/oasis-core/go/common/logging"
1721 "github.com/oasisprotocol/oasis-core/go/config"
5357 RunE : doRenameNs ,
5458 }
5559
60+ storageCompactCmd = & cobra.Command {
61+ Use : "compact" ,
62+ Args : cobra .NoArgs ,
63+ Short : "trigger compaction across all the databases" ,
64+ Long : `Optimize the storage for all the databases by doing the compaction.
65+
66+ It is recommended to call this before doing storage snapshots or copying the data to a remote node.` ,
67+ RunE : doDbCompactions ,
68+ }
69+
5670 logger = logging .GetLogger ("cmd/storage" )
5771
5872 pretty = cmdCommon .Isatty (1 )
@@ -283,12 +297,87 @@ func doRenameNs(_ *cobra.Command, args []string) error {
283297 return nil
284298}
285299
300+ func doDbCompactions (_ * cobra.Command , args []string ) error {
301+ dataDir := cmdCommon .DataDir ()
302+
303+ dbDirs , err := findDBInstances (dataDir )
304+ if err != nil {
305+ return fmt .Errorf ("failed to find database instances: %w" , err )
306+ }
307+
308+ if len (dbDirs ) == 0 {
309+ return fmt .Errorf ("no database instances found (dataDir: %s)" , dataDir )
310+ }
311+
312+ if pretty {
313+ fmt .Println ("Starting database compactions. This may take a while..." )
314+ }
315+
316+ for _ , path := range dbDirs {
317+ if err := compactDB (path ); err != nil {
318+ logger .Error ("failed to compact" , "path" , path , "err" , err )
319+ if pretty {
320+ fmt .Printf ("Failed to compact %s: %v\n " , path , err )
321+ }
322+ }
323+ }
324+
325+ return nil
326+ }
327+
328+ func findDBInstances (dataDir string ) ([]string , error ) {
329+ var dbDirs []string
330+ err := filepath .WalkDir (dataDir , func (path string , d fs.DirEntry , err error ) error {
331+ if err != nil {
332+ return err
333+ }
334+ if d .IsDir () && strings .HasSuffix (d .Name (), ".db" ) {
335+ dbDirs = append (dbDirs , path )
336+ }
337+ return nil
338+ })
339+ if err != nil {
340+ return nil , fmt .Errorf ("failed to walk dir %s: %w" , dataDir , err )
341+ }
342+
343+ return dbDirs , nil
344+ }
345+
346+ func compactDB (path string ) error {
347+ logger = logger .With ("path" , path )
348+
349+ logger .Info ("compacting" )
350+ if pretty {
351+ fmt .Printf ("Compacting %s\n " , path )
352+ }
353+
354+ opts := badgerDB .DefaultOptions (path ).WithLogger (cmnBadger .NewLogAdapter (logger ))
355+ db , err := badgerDB .Open (opts )
356+ if err != nil {
357+ return fmt .Errorf ("failed to open db: %w" , err )
358+ }
359+ defer db .Close ()
360+
361+ if err := db .Flatten (8 ); err != nil {
362+ return fmt .Errorf ("failed to flatten db: %w" , err )
363+
364+ }
365+
366+ logger .Info ("compaction completed" )
367+ if pretty {
368+ fmt .Printf ("Compaction completed: %s\n " , path )
369+ }
370+
371+ return nil
372+ }
373+
286374// Register registers the client sub-command and all of its children.
287375func Register (parentCmd * cobra.Command ) {
288376 storageMigrateCmd .Flags ().AddFlagSet (bundle .Flags )
289377 storageCheckCmd .Flags ().AddFlagSet (bundle .Flags )
290378 storageCmd .AddCommand (storageMigrateCmd )
291379 storageCmd .AddCommand (storageCheckCmd )
292380 storageCmd .AddCommand (storageRenameNsCmd )
381+ storageCmd .AddCommand (storageCompactCmd )
293382 parentCmd .AddCommand (storageCmd )
294383}
0 commit comments