Skip to content

Commit 5d96aa2

Browse files
authored
Merge pull request #6521 from oasisprotocol/martin/feature/release-storage-prune-cmd
Release oasis storage prune and compact subcomands
2 parents c9ba2f9 + d3189ce commit 5d96aa2

13 files changed

Lines changed: 1157 additions & 326 deletions

File tree

.changelog/6519.feature.0.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
go/oasis-node/cmd/storage: Release offline pruning command
2+
3+
Command `storage prune-experimental` has been released as
4+
`storage prune` and now in addition to consensus databases
5+
also prunes runtime databases.

.changelog/6519.feature.1.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
go/oasis-node/cmd/storage: Release offline compaction command
2+
3+
Command `storage compact-experimental` has been released as
4+
`storage compact` and now in addition to consensus databases
5+
also compacts runtime databases.

docs/oasis-node/cli.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -334,15 +334,15 @@ oasis1qqncl383h8458mr9cytatygctzwsx02n4c5f8ed7
334334

335335
## storage
336336

337-
### compact-experimental
337+
### compact
338338

339339
Run (when the node is not running):
340340

341341
```sh
342-
oasis-node storage compact-experimental --config /path/to/config/file
342+
oasis-node storage compact --config /path/to/config/file
343343
```
344344

345-
to trigger manual compaction of consensus database instances:
345+
to trigger manual compaction of all configured database instances:
346346

347347
```sh
348348
{"caller":"storage.go:310","level":"info","module":"cmd/storage", \
@@ -365,28 +365,28 @@ may stay constant or not be reclaimed for a very long time.
365365
This command gives operators manual control to release disk space during
366366
maintenance periods.
367367

368-
### prune-experimental
368+
### prune
369369

370370
Run (when the node is not running):
371371

372372
```sh
373-
oasis-node storage prune-experimental --config /path/to/config/file
373+
oasis-node storage prune --config /path/to/config/file
374374
```
375375

376-
to trigger manual pruning of consensus database instances:
376+
to trigger manual pruning of all configured database instances:
377377

378378
```sh
379-
{"caller":"storage.go:433","level":"info","module":"cmd/storage", \
380-
"msg":"Starting consensus databases pruning. This may take a while...", \
379+
{"caller":"prune.go:47","level":"info","module":"cmd/storage", \
380+
"msg":"Starting databases pruning. This may take a while...", \
381381
"ts":"2025-10-23T11:02:11.129822974Z"}
382382
```
383383

384384
Operators should run this whenever they change pruning configuration, e.g. when
385385
enabling it for the first time, or later changing it to retain less data. This
386386
way they guarantee the node is healthy when it starts.
387387

388-
Following successful pruning, to release disk space, they are encouraged to run
389-
[the compaction command](#compact-experimental).
388+
After the pruning operators should run [the compaction command](#compact)
389+
to release disk space.
390390

391391
### inspect
392392

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
package storage
2+
3+
import (
4+
"fmt"
5+
"io/fs"
6+
"path/filepath"
7+
"strings"
8+
9+
"github.com/spf13/cobra"
10+
11+
"github.com/oasisprotocol/oasis-core/go/common"
12+
cmtDBProvider "github.com/oasisprotocol/oasis-core/go/consensus/cometbft/db/badger"
13+
cmdCommon "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common"
14+
"github.com/oasisprotocol/oasis-core/go/runtime/registry"
15+
)
16+
17+
func newCompactCmd() *cobra.Command {
18+
cmd := &cobra.Command{
19+
Use: "compact",
20+
Args: cobra.NoArgs,
21+
Short: "trigger compaction for all databases",
22+
Long: `Optimize the storage for all databases by manually compacting the underlying storage engines.
23+
24+
WARNING: Ensure you have at least as much of a free disk as your largest database.
25+
`,
26+
PreRunE: func(_ *cobra.Command, args []string) error {
27+
if err := cmdCommon.Init(); err != nil {
28+
cmdCommon.EarlyLogAndExit(err)
29+
}
30+
31+
running, err := cmdCommon.IsNodeRunning()
32+
if err != nil {
33+
return fmt.Errorf("failed to ensure the node is not running: %w", err)
34+
}
35+
36+
if running {
37+
return fmt.Errorf("compaction can only be done when the node is not running")
38+
}
39+
return nil
40+
},
41+
RunE: func(cmd *cobra.Command, args []string) error {
42+
dataDir := cmdCommon.DataDir()
43+
44+
logger.Info("Starting database compactions. This may take a while...")
45+
46+
if err := compactConsensusDBs(dataDir); err != nil {
47+
return fmt.Errorf("failed to compact consensus databases: %w", err)
48+
}
49+
50+
runtimes, err := registry.GetConfiguredRuntimeIDs()
51+
if err != nil {
52+
return fmt.Errorf("failed to get configured runtimes: %w", err)
53+
}
54+
for _, rt := range runtimes {
55+
if err := compactRuntimeDBs(dataDir, rt); err != nil {
56+
return fmt.Errorf("failed to compact runtime dbs (runtime ID: %s): %w", rt, err)
57+
}
58+
}
59+
60+
return nil
61+
},
62+
}
63+
64+
return cmd
65+
}
66+
67+
func compactConsensusDBs(dataDir string) error {
68+
// Compact CometBFT managed databases: block store, evidence and state (NOT application state).
69+
if err := compactCometDBs(dataDir); err != nil {
70+
return fmt.Errorf("failed to compact CometBFT managed databases: %w", err)
71+
}
72+
73+
// Compact consensus NodeDB (application state).
74+
ndb, close, err := openConsensusNodeDB(dataDir)
75+
if err != nil {
76+
return fmt.Errorf("failed to open consensus NodeDB: %w", err)
77+
}
78+
defer close()
79+
80+
if err := ndb.Compact(); err != nil {
81+
return fmt.Errorf("failed to compact consensus node DB: %w", err)
82+
}
83+
84+
return nil
85+
}
86+
87+
func compactCometDBs(dataDir string) error {
88+
dir := fmt.Sprintf("%s/consensus/data", dataDir)
89+
90+
var dbDirs []string
91+
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
92+
if err != nil {
93+
return err
94+
}
95+
if d.IsDir() && strings.HasSuffix(d.Name(), ".db") {
96+
dbDirs = append(dbDirs, path)
97+
}
98+
return nil
99+
})
100+
if err != nil {
101+
return fmt.Errorf("failed to walk dir %s: %w", dir, err)
102+
}
103+
104+
if len(dbDirs) == 0 {
105+
return fmt.Errorf("zero database instances found")
106+
}
107+
108+
for _, dbDir := range dbDirs {
109+
if err := compactCometDB(dbDir); err != nil {
110+
return fmt.Errorf("failed to compact %s: %w", dbDir, err)
111+
}
112+
}
113+
return nil
114+
}
115+
116+
func compactCometDB(path string) error {
117+
logger := logger.With("path", path)
118+
db, err := cmtDBProvider.OpenBadger(path, logger)
119+
if err != nil {
120+
return fmt.Errorf("failed to open BadgerDB: %w", err)
121+
}
122+
defer db.Close()
123+
124+
logger.Info("compacting")
125+
126+
if err := db.Flatten(1); err != nil {
127+
return fmt.Errorf("failed to flatten db: %w", err)
128+
}
129+
130+
logger.Info("compaction completed")
131+
132+
return nil
133+
}
134+
135+
func compactRuntimeDBs(dataDir string, rt common.Namespace) error {
136+
history, err := openRuntimeLightHistory(dataDir, rt)
137+
if err != nil {
138+
return fmt.Errorf("failed to open runtime history: %w", err)
139+
}
140+
defer history.Close()
141+
if err := history.Compact(); err != nil {
142+
return fmt.Errorf("failed to compact runtime history: %w", err)
143+
}
144+
ndb, err := openRuntimeStateDB(dataDir, rt)
145+
if err != nil {
146+
return fmt.Errorf("failed to open runtime state DB: %w", err)
147+
}
148+
defer ndb.Close()
149+
if err := ndb.Compact(); err != nil {
150+
return fmt.Errorf("failed to compact runtime state DB: %w", err)
151+
}
152+
return nil
153+
}

0 commit comments

Comments
 (0)