soft truncate

This commit is contained in:
jsvisa 2025-09-12 01:57:53 +08:00
parent 1c431f6f95
commit 96963e75ad
4 changed files with 22 additions and 59 deletions

View file

@ -1003,13 +1003,6 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
newHeadBlock, rootNumber = bc.rewindHead(header, root)
rawdb.WriteHeadBlockHash(db, newHeadBlock.Hash())
// Use soft truncate for fast rewind - actual truncation happens at the end
if bc.triedb.Scheme() == rawdb.PathScheme {
if err := bc.triedb.SoftTruncateHead(); err != nil {
log.Warn("Failed to soft truncate trie database", "err", err)
}
}
// Degrade the chain markers if they are explicitly reverted.
// In theory we should update all in-memory markers in the
// last step, however the direction of SetHead is from high
@ -1103,11 +1096,9 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
bc.blockCache.Purge()
bc.txLookupCache.Purge()
// Commit all soft truncations to align the state histories with the current state.
if bc.triedb.Scheme() == rawdb.PathScheme {
if err := bc.triedb.CommitTruncation(); err != nil {
log.Crit("Failed to commit trie database truncation", "err", err)
}
// Commit all recovery operations to finalize state freezer truncation.
if err := bc.triedb.RecoverDone(); err != nil {
log.Crit("Failed to finalize trie database recovery", "err", err)
}
// Clear safe block, finalized block if needed

View file

@ -280,35 +280,15 @@ func (db *Database) Recover(target common.Hash) error {
return pdb.Recover(target)
}
// TruncateHead truncates all state histories in the freezer above the bottom state layer.
// This operation is only supported by path-based database. It's typically used during
// state recovery to align the state histories with the current state.
func (db *Database) TruncateHead() error {
// RecoverDone commits all pending soft truncations after a series of recovery operations.
// This should be called after all recover operations are complete to finalize the state
// freezer truncation in one efficient batch operation.
func (db *Database) RecoverDone() error {
pdb, ok := db.backend.(*pathdb.Database)
if !ok {
return errors.New("not supported")
}
return pdb.TruncateHead()
}
// SoftTruncateHead marks state histories above the bottom state layer as logically deleted
// without physical truncation. This is much faster than TruncateHead.
func (db *Database) SoftTruncateHead() error {
pdb, ok := db.backend.(*pathdb.Database)
if !ok {
return errors.New("not supported")
}
return pdb.SoftTruncateHead()
}
// CommitTruncation performs the actual file truncation to match any soft truncations.
// This should be called after all soft truncations are complete.
func (db *Database) CommitTruncation() error {
pdb, ok := db.backend.(*pathdb.Database)
if !ok {
return errors.New("not supported")
}
return pdb.CommitTruncation()
return pdb.RecoverDone()
}
// Recoverable returns the indicator if the specified state is enabled to be

View file

@ -502,26 +502,20 @@ func (db *Database) Recover(root common.Hash) error {
if err := db.diskdb.SyncKeyValue(); err != nil {
return err
}
// Soft truncate the state freezer to the recovered state
if _, err := db.stateFreezer.SoftTruncateHead(dl.stateID()); err != nil {
return err
}
log.Debug("Recovered state", "root", root, "elapsed", common.PrettyDuration(time.Since(start)))
return nil
}
// TruncateHead truncates all state histories in the freezer above the bottom state layer.
func (db *Database) TruncateHead() error {
_, err := truncateFromHead(db.stateFreezer, db.tree.bottom().stateID())
return err
}
// SoftTruncateHead marks state histories above the bottom state layer as logically deleted
// without physical truncation. This is much faster than TruncateHead.
func (db *Database) SoftTruncateHead() error {
_, err := db.stateFreezer.SoftTruncateHead(db.tree.bottom().stateID())
return err
}
// CommitTruncation performs the actual file truncation to match any soft truncations.
// This should be called after all soft truncations are complete.
func (db *Database) CommitTruncation() error {
// RecoverDone commits all pending soft truncations after a series of recovery operations.
// This should be called after all recover operations are complete to finalize the state
// freezer truncation in one efficient batch operation.
func (db *Database) RecoverDone() error {
return db.stateFreezer.CommitTruncation()
}

View file

@ -600,18 +600,16 @@ func TestDatabaseRollback(t *testing.T) {
if err := tester.db.Recover(parent); err != nil {
t.Fatalf("Failed to revert db, err: %v", err)
}
if err := tester.db.SoftTruncateHead(); err != nil {
t.Fatalf("Failed to soft truncate head, err: %v", err)
}
if err := tester.db.CommitTruncation(); err != nil {
t.Fatalf("Failed to commit truncation, err: %v", err)
}
if i > 0 {
if err := tester.verifyState(parent); err != nil {
t.Fatalf("Failed to verify state, err: %v", err)
}
}
}
// Finalize all recovery operations
if err := tester.db.RecoverDone(); err != nil {
t.Fatalf("Failed to finalize recovery, err: %v", err)
}
if tester.db.tree.len() != 1 {
t.Fatal("Only disk layer is expected")
}