diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index 92fe352f2f..b7dae1d5f5 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -231,32 +231,38 @@ func (dl *diffLayer) initBloom() { // bloom func (dl *diffLayer) Prepare(origin *diskLayer) { dl.lock.Lock() + defer dl.lock.Unlock() + // If we already have a cumulative bloom, we're done here + if dl.cumulative != nil { + return + } + // Traverse up the parent tree dl.cumulative, _ = dl.diffed.Copy() layer := dl for { - if parent, ok := layer.parent.(*diffLayer); ok { - parent.lock.RLock() - dl.cumulative.UnionInPlace(parent.diffed) - parent.lock.RUnlock() - layer = parent - } else { + parent, ok := layer.parent.(*diffLayer) + if !ok { + break // We hit the disk layer + } + parent.lock.Lock() + // If we're lucky, the parent has a cumulative we can use. + if parent.cumulative != nil { + // Copy, nuke and done. + dl.cumulative.UnionInPlace(parent.cumulative) + parent.cumulative = nil + parent.lock.Unlock() break } + dl.cumulative.UnionInPlace(parent.diffed) + parent.lock.Unlock() + layer = parent } dl.origin = origin - dl.lock.Unlock() // Calculate the current false positive rate and update the error rate meter. k := float64(dl.cumulative.K()) n := float64(dl.cumulative.N()) m := float64(dl.cumulative.M()) snapshotBloomErrorGauge.Update(math.Pow(1.0-math.Exp((-k)*(n+0.5)/(m-1)), k)) - -} - -func (dl *diffLayer) Release() { - dl.lock.Lock() - dl.cumulative = nil - dl.lock.Unlock() } // Root returns the root hash for which this snapshot was made. diff --git a/core/state/snapshot/disklayer.go b/core/state/snapshot/disklayer.go index fec9513bc7..b0ea754a26 100644 --- a/core/state/snapshot/disklayer.go +++ b/core/state/snapshot/disklayer.go @@ -166,4 +166,3 @@ func (dl *diskLayer) Update(blockHash common.Hash, destructs map[common.Hash]str } func (dl *diskLayer) Prepare(*diskLayer) {} -func (dl *diskLayer) Release() {} diff --git a/core/state/snapshot/snapshot.go b/core/state/snapshot/snapshot.go index 5456f219e4..e918916f0a 100644 --- a/core/state/snapshot/snapshot.go +++ b/core/state/snapshot/snapshot.go @@ -23,6 +23,7 @@ import ( "fmt" "sync" "sync/atomic" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/rawdb" @@ -65,8 +66,9 @@ var ( snapshotFlushStorageItemMeter = metrics.NewRegisteredMeter("state/snapshot/flush/storage/item", nil) snapshotFlushStorageSizeMeter = metrics.NewRegisteredMeter("state/snapshot/flush/storage/size", nil) - snapshotBloomIndexTimer = metrics.NewRegisteredResettingTimer("state/snapshot/bloom/index", nil) - snapshotBloomErrorGauge = metrics.NewRegisteredGaugeFloat64("state/snapshot/bloom/error", nil) + snapshotBloomPrepareTimer = metrics.NewRegisteredResettingTimer("state/snapshot/bloom/prepare", nil) + snapshotBloomIndexTimer = metrics.NewRegisteredResettingTimer("state/snapshot/bloom/index", nil) + snapshotBloomErrorGauge = metrics.NewRegisteredGaugeFloat64("state/snapshot/bloom/error", nil) snapshotBloomAccountTrueHitMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/account/truehit", nil) snapshotBloomAccountFalseHitMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/account/falsehit", nil) @@ -107,7 +109,6 @@ type Snapshot interface { // Storage directly retrieves the storage data associated with a particular hash, // within a particular account. Storage(accountHash, storageHash common.Hash) ([]byte, error) - Release() } // snapshot is the internal version of the snapshot data layer that supports some @@ -219,6 +220,9 @@ func (t *Tree) waitBuild() { } func (t *Tree) PrepareSnapshot(blockRoot common.Hash) Snapshot { + defer func(start time.Time) { + snapshotBloomPrepareTimer.Update(time.Since(start)) + }(time.Now()) t.lock.RLock() defer t.lock.RUnlock() if snap := t.layers[blockRoot]; snap != nil { @@ -324,9 +328,6 @@ func (t *Tree) Cap(root common.Hash, layers int) error { default: // Many layers requested to be retained, cap normally persisted = t.cap(diff, layers) - if persisted != nil { - t.diskLayer = persisted - } } // Remove any layer that is stale or links into a stale layer children := make(map[common.Hash][]common.Hash) @@ -349,7 +350,21 @@ func (t *Tree) Cap(root common.Hash, layers int) error { remove(root) } } - // If the disk layer was modified, regenerate all the cummulative blooms + // If the disk layer was modified, wipe all the cumulative blooms + if persisted != nil { + // Update ref + t.diskLayer = persisted + var wipeCumulative func(root common.Hash) + wipeCumulative = func(root common.Hash) { + if diff, ok := t.layers[root].(*diffLayer); ok { + diff.cumulative = nil + } + for _, child := range children[root] { + wipeCumulative(child) + } + } + wipeCumulative(persisted.root) + } return nil } diff --git a/core/state/statedb.go b/core/state/statedb.go index 0b58bd1aca..8c5f0aa54f 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -866,7 +866,6 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) { log.Warn("Failed to cap snapshot tree", "root", root, "layers", 127, "err", err) } } - s.snap.Release() s.snap, s.snapDestructs, s.snapAccounts, s.snapStorage = nil, nil, nil, nil } return root, err