Skip to content

Commit

Permalink
core/state/snapshot: simplify snapshot rebuild (#30772)
Browse files Browse the repository at this point in the history
This PR is purely for improved readability; I was doing work involving
the file and think this may help others who are trying to understand
what's going on.

1. `snapshot.Tree.Rebuild()` now returns a function that blocks until
regeneration is complete, allowing `Tree.waitBuild()` to be removed
entirely as all it did was search for the `done` channel behind this new
function.
2. Its usage inside `New()` is also simplified by (a) only waiting if
`!AsyncBuild`; and (b) avoiding the double negative of `if !NoBuild`.

---------

Co-authored-by: Martin HS <[email protected]>
  • Loading branch information
ARR4N and holiman authored Nov 25, 2024
1 parent 3c754e2 commit 2380012
Showing 1 changed file with 14 additions and 34 deletions.
48 changes: 14 additions & 34 deletions core/state/snapshot/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,47 +206,24 @@ func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, roo
log.Warn("Snapshot maintenance disabled (syncing)")
return snap, nil
}
// Create the building waiter iff the background generation is allowed
if !config.NoBuild && !config.AsyncBuild {
defer snap.waitBuild()
}
if err != nil {
log.Warn("Failed to load snapshot", "err", err)
if !config.NoBuild {
snap.Rebuild(root)
return snap, nil
if config.NoBuild {
return nil, err
}
wait := snap.Rebuild(root)
if !config.AsyncBuild {
wait()
}
return nil, err // Bail out the error, don't rebuild automatically.
return snap, nil
}
// Existing snapshot loaded, seed all the layers
for head != nil {
for ; head != nil; head = head.Parent() {
snap.layers[head.Root()] = head
head = head.Parent()
}
return snap, nil
}

// waitBuild blocks until the snapshot finishes rebuilding. This method is meant
// to be used by tests to ensure we're testing what we believe we are.
func (t *Tree) waitBuild() {
// Find the rebuild termination channel
var done chan struct{}

t.lock.RLock()
for _, layer := range t.layers {
if layer, ok := layer.(*diskLayer); ok {
done = layer.genPending
break
}
}
t.lock.RUnlock()

// Wait until the snapshot is generated
if done != nil {
<-done
}
}

// Disable interrupts any pending snapshot generator, deletes all the snapshot
// layers in memory and marks snapshots disabled globally. In order to resume
// the snapshot functionality, the caller must invoke Rebuild.
Expand Down Expand Up @@ -688,8 +665,9 @@ func (t *Tree) Journal(root common.Hash) (common.Hash, error) {

// Rebuild wipes all available snapshot data from the persistent database and
// discard all caches and diff layers. Afterwards, it starts a new snapshot
// generator with the given root hash.
func (t *Tree) Rebuild(root common.Hash) {
// generator with the given root hash. The returned function blocks until
// regeneration is complete.
func (t *Tree) Rebuild(root common.Hash) (wait func()) {
t.lock.Lock()
defer t.lock.Unlock()

Expand Down Expand Up @@ -721,9 +699,11 @@ func (t *Tree) Rebuild(root common.Hash) {
// Start generating a new snapshot from scratch on a background thread. The
// generator will run a wiper first if there's not one running right now.
log.Info("Rebuilding state snapshot")
disk := generateSnapshot(t.diskdb, t.triedb, t.config.CacheSize, root)
t.layers = map[common.Hash]snapshot{
root: generateSnapshot(t.diskdb, t.triedb, t.config.CacheSize, root),
root: disk,
}
return func() { <-disk.genPending }
}

// AccountIterator creates a new account iterator for the specified root hash and
Expand Down

0 comments on commit 2380012

Please sign in to comment.