Release oasis storage prune and compact subcomands#6521
Release oasis storage prune and compact subcomands#6521martintomazic wants to merge 12 commits intomasterfrom
Conversation
✅ Deploy Preview for oasisprotocol-oasis-core canceled.
|
c39199f to
ddd1106
Compare
| // By calculating retain round from the runtime state DB latest round, | ||
| // we ensure light history is never pruned past the latest synced runtime | ||
| // round. | ||
| retainRound := latest - numKept |
There was a problem hiding this comment.
In practice we should probably also respect executor prune handler that should prevent pruning past last normal round.
// runtimeLastNormalRound returns the last normal round for the given runtime.
func runtimeLastNormalRound(ctx context.Context, ndb db.NodeDB, runtimeID common.Namespace) (uint64, error) {
latest, ok := ndb.GetLatestVersion()
if !ok {
return 0, fmt.Errorf("consensus node DB is empty")
}
roots, err := ndb.GetRootsForVersion(latest)
if err != nil {
return 0, fmt.Errorf("failed to get roots for consensus version %d: %w", latest, err)
}
if len(roots) == 0 {
return 0, fmt.Errorf("no roots found for consensus version %d", latest)
}
tree := mkvs.NewWithRoot(nil, ndb, roots[0], mkvs.WithoutWriteLog())
defer tree.Close()
s := roothashState.NewImmutableState(tree)
rtState, err := s.RuntimeState(ctx, runtimeID)
if err != nil {
return 0, fmt.Errorf("failed to get runtime state: %w", err)
}
return rtState.LastNormalRound, nil
}We have two options:
- Pass consensus node DB to
pruneRuntimeDBs.- Or just open and close it there (simplest and least changes).
- This feels weird as this function should probably accept
retainRound, likepruneConsensusDBsshould acceptretainHeightinstead ofruntimeIds(solution 2.).
- Add new
consensusRetainHeightandruntimeRetainRoundfunctions that precompute this limits, possibly write unit tests for those two functions. The annoying part is that those two functions consume runtime histories, nodedbs and consensus nodedbs, meaning we loose resource encapsulation and need to keep them open throughout the whole command. Feels like a better direction, but requires a thorough refactor + makes logging and orchestration incredibly messy.
In addition adding this handler requires consensus state to be always present. Without it you can prune runtime state without having a consensus state locally (e.g. when hacking state if imported using snapshots, don't think this is needed though).
| ndb, close, err := openConsensusNodeDB(dataDir) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to open NodeDB: %w", err) | ||
| } | ||
| defer close() | ||
|
|
||
| latest, ok := ndb.GetLatestVersion() | ||
| if !ok { | ||
| logger.Info("skipping consensus pruning as state db is empty") | ||
| return nil | ||
| } | ||
|
|
||
| if latest < numKept { | ||
| logger.Info("skipping consensus pruning as the latest version is smaller than the number of versions to keep") | ||
| return nil | ||
| } | ||
|
|
||
| // In case of configured runtimes, do not prune past the earliest reindexed | ||
| // consensus height, so that light history can be populated correctly. | ||
| minReindexed, err := minReindexedHeight(dataDir, runtimes) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to fetch earliest reindexed consensus height: %w", err) | ||
| } | ||
|
|
||
| retainHeight := min( | ||
| latest-numKept, // underflow not possible due to if above. | ||
| uint64(minReindexed), | ||
| ) |
There was a problem hiding this comment.
E.g. this could be func consensusRetainHeight(ndb db.NodeDB, histories []history.Histories)(uint64, bool, error) and this function takes retainHeight: uint64 instead of the last two params, which would also allow us to unit test the business logic. As stated above this complicates the orchestration a lot though :(
All logic and style was preserved, except for following the new (better) storage inspect style of command definition.
ddd1106 to
c768a9a
Compare
| logger.Info("Starting databases pruning. This may take a while...") | ||
|
|
||
| dataDir := cmdCommon.DataDir() | ||
| ctx := cmd.Context() |
There was a problem hiding this comment.
NIT: We should probably wire
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM) .As cobra context does not capture this signals by default, resulting in non-graceful shutdown (never had an issue so fat though). Still it is annoying that BadgerDB command does not expose cancelation api, so even with this fixed it won't be complete.
Best way to mitigate unlikely stale state scenario. Moreover, it enables introducing context cancelation.
Code was preserved as is, expect for using the new new*Cmd() pattern introduced in the inspect command.
Offline compaction now also works for the runtime history and state DB.
Make it symetric with the prune command helpers.
c768a9a to
32bbd4e
Compare
|
Ready for a review. Please check the PR context, the main question is how much do we want to complicate our life with prune handlers - comment. Since the PR is already rather big, I am open to push one PR infront that does:
Then this PR becomes much smaller and focused only one new runtime logic and releasing the commands. |
| @@ -386,7 +386,7 @@ enabling it for the first time, or later changing it to retain less data. This | |||
| way they guarantee the node is healthy when it starts. | |||
|
|
|||
| Following successful pruning, to release disk space, they are encouraged to run | |||
There was a problem hiding this comment.
So many words :)
| Following successful pruning, to release disk space, they are encouraged to run | |
| After the pruning operators should run [the compaction command](#compact) to release disk space. |
Closes #6519.
Relatively trivial to review. LOC is big because I extracted commands to separate files and added missing tests (separate commits).
Motivation
How to test locally
For testing I used latest Sapphire snapshot (cca 7 months of data,
keep_n = 100_000). It took 10min to prune and 6min to compact. For consensus I used snapshot-old (cca 3 months of data,keep_n = 100_000), due to limited disk space on my machine. Pruning took 2min and compaction 3min.Node started syncing normally after prune/compact commands.
Possible follow-up
For #6454, we may want to add additional flag to the pruning command, e.g.
retain_height, that ignores pruning config and calculates corresponding rounds at this height of every runtime, implementingkeep_fromproposal.