core/state/snapshot: retain cumulative across states

This commit is contained in:
Martin Holst Swende 2019-12-06 08:50:13 +01:00
parent 59009896b9
commit 26876ee39a
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
4 changed files with 42 additions and 23 deletions

View file

@ -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.

View file

@ -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() {}

View file

@ -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
}

View file

@ -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