mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-18 21:01:38 +00:00
triedb/pathdb: thread flatStateCodec through internals
Route the flatStateCodec from Database through every flat-state call
site so that the trie-specific aspects of persistence and key derivation
live behind a single abstraction. Pure refactor: merkle behavior and
on-disk layout are unchanged because the only codec wired up is
merkleFlatCodec, whose methods are thin wrappers over the existing
rawdb accessors.
Threaded sites:
disklayer.account/storage use codec.{Read,AccountCacheKey,
StorageCacheKey} instead of direct
rawdb calls and bare hash slicing.
flush.writeStates takes a codec parameter; persistence
goes through codec.{Write,Delete}
{Account,Storage}.
buffer.flush carries the codec down into writeStates.
states.write/dbsize takes the codec for prefix-size
accounting.
generate.go (g.codec) the generator owns a codec, used by
generateAccounts/generateStorages
callbacks; the unused top-level
splitMarker helper is removed in favor
of codec.SplitMarker.
context.go the generator context owns the codec
and uses codec.{AccountPrefix,
StoragePrefix,Account/StorageKeyLength}
to construct iterators.
reader.go (HistoricalState) uses codec.{Account,Storage}Key for
caller-side key derivation.
The marker comparisons in writeStates remain merkle-shaped (two-tier
account+storage marker) because the bintrie path will use a separate
writer over single-tier stem markers in a later commit.
All existing pathdb tests pass.
This commit is contained in:
parent
eaf5523a5a
commit
f1d7143afa
9 changed files with 78 additions and 63 deletions
|
|
@ -132,7 +132,10 @@ func (b *buffer) size() uint64 {
|
||||||
|
|
||||||
// flush persists the in-memory dirty trie node into the disk if the configured
|
// flush persists the in-memory dirty trie node into the disk if the configured
|
||||||
// memory threshold is reached. Note, all data must be written atomically.
|
// memory threshold is reached. Note, all data must be written atomically.
|
||||||
func (b *buffer) flush(root common.Hash, db ethdb.KeyValueStore, freezers []ethdb.AncientWriter, progress []byte, nodesCache, statesCache *fastcache.Cache, id uint64, postFlush func()) {
|
//
|
||||||
|
// codec is the flat-state codec used for state persistence and cache key
|
||||||
|
// derivation. It is supplied by the disk layer's owning Database.
|
||||||
|
func (b *buffer) flush(root common.Hash, db ethdb.KeyValueStore, codec flatStateCodec, freezers []ethdb.AncientWriter, progress []byte, nodesCache, statesCache *fastcache.Cache, id uint64, postFlush func()) {
|
||||||
if b.done != nil {
|
if b.done != nil {
|
||||||
panic("duplicated flush operation")
|
panic("duplicated flush operation")
|
||||||
}
|
}
|
||||||
|
|
@ -158,7 +161,7 @@ func (b *buffer) flush(root common.Hash, db ethdb.KeyValueStore, freezers []ethd
|
||||||
// Terminate the state snapshot generation if it's active
|
// Terminate the state snapshot generation if it's active
|
||||||
var (
|
var (
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
batch = db.NewBatchWithSize((b.nodes.dbsize() + b.states.dbsize()) * 11 / 10) // extra 10% for potential pebble internal stuff
|
batch = db.NewBatchWithSize((b.nodes.dbsize() + b.states.dbsize(codec)) * 11 / 10) // extra 10% for potential pebble internal stuff
|
||||||
)
|
)
|
||||||
// Explicitly sync the state freezer to ensure all written data is persisted to disk
|
// Explicitly sync the state freezer to ensure all written data is persisted to disk
|
||||||
// before updating the key-value store.
|
// before updating the key-value store.
|
||||||
|
|
@ -170,7 +173,7 @@ func (b *buffer) flush(root common.Hash, db ethdb.KeyValueStore, freezers []ethd
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
nodes := b.nodes.write(batch, nodesCache)
|
nodes := b.nodes.write(batch, nodesCache)
|
||||||
accounts, slots := b.states.write(batch, progress, statesCache)
|
accounts, slots := b.states.write(batch, codec, progress, statesCache)
|
||||||
rawdb.WritePersistentStateID(batch, id)
|
rawdb.WritePersistentStateID(batch, id)
|
||||||
rawdb.WriteSnapshotRoot(batch, root)
|
rawdb.WriteSnapshotRoot(batch, root)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -95,19 +95,21 @@ type generatorContext struct {
|
||||||
account *holdableIterator // Iterator of account snapshot data
|
account *holdableIterator // Iterator of account snapshot data
|
||||||
storage *holdableIterator // Iterator of storage snapshot data
|
storage *holdableIterator // Iterator of storage snapshot data
|
||||||
db ethdb.KeyValueStore // Key-value store containing the snapshot data
|
db ethdb.KeyValueStore // Key-value store containing the snapshot data
|
||||||
|
codec flatStateCodec // Flat-state codec for prefix/key-length selection
|
||||||
batch ethdb.Batch // Database batch for writing data atomically
|
batch ethdb.Batch // Database batch for writing data atomically
|
||||||
logged time.Time // The timestamp when last generation progress was displayed
|
logged time.Time // The timestamp when last generation progress was displayed
|
||||||
}
|
}
|
||||||
|
|
||||||
// newGeneratorContext initializes the context for generation.
|
// newGeneratorContext initializes the context for generation.
|
||||||
func newGeneratorContext(root common.Hash, marker []byte, db ethdb.KeyValueStore) *generatorContext {
|
func newGeneratorContext(root common.Hash, marker []byte, db ethdb.KeyValueStore, codec flatStateCodec) *generatorContext {
|
||||||
ctx := &generatorContext{
|
ctx := &generatorContext{
|
||||||
root: root,
|
root: root,
|
||||||
db: db,
|
db: db,
|
||||||
|
codec: codec,
|
||||||
batch: db.NewBatch(),
|
batch: db.NewBatch(),
|
||||||
logged: time.Now(),
|
logged: time.Now(),
|
||||||
}
|
}
|
||||||
accMarker, storageMarker := splitMarker(marker)
|
accMarker, storageMarker := codec.SplitMarker(marker)
|
||||||
ctx.openIterator(snapAccount, accMarker)
|
ctx.openIterator(snapAccount, accMarker)
|
||||||
ctx.openIterator(snapStorage, storageMarker)
|
ctx.openIterator(snapStorage, storageMarker)
|
||||||
return ctx
|
return ctx
|
||||||
|
|
@ -118,12 +120,12 @@ func newGeneratorContext(root common.Hash, marker []byte, db ethdb.KeyValueStore
|
||||||
// to time to avoid blocking leveldb compaction for a long time.
|
// to time to avoid blocking leveldb compaction for a long time.
|
||||||
func (ctx *generatorContext) openIterator(kind string, start []byte) {
|
func (ctx *generatorContext) openIterator(kind string, start []byte) {
|
||||||
if kind == snapAccount {
|
if kind == snapAccount {
|
||||||
iter := ctx.db.NewIterator(rawdb.SnapshotAccountPrefix, start)
|
iter := ctx.db.NewIterator(ctx.codec.AccountPrefix(), start)
|
||||||
ctx.account = newHoldableIterator(rawdb.NewKeyLengthIterator(iter, 1+common.HashLength))
|
ctx.account = newHoldableIterator(rawdb.NewKeyLengthIterator(iter, ctx.codec.AccountKeyLength()))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
iter := ctx.db.NewIterator(rawdb.SnapshotStoragePrefix, start)
|
iter := ctx.db.NewIterator(ctx.codec.StoragePrefix(), start)
|
||||||
ctx.storage = newHoldableIterator(rawdb.NewKeyLengthIterator(iter, 1+2*common.HashLength))
|
ctx.storage = newHoldableIterator(rawdb.NewKeyLengthIterator(iter, ctx.codec.StorageKeyLength()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// reopenIterator releases the specified snapshot iterator and re-open it
|
// reopenIterator releases the specified snapshot iterator and re-open it
|
||||||
|
|
|
||||||
|
|
@ -276,7 +276,7 @@ func (db *Database) setStateGenerator() error {
|
||||||
// Construct the generator and link it to the disk layer, ensuring that the
|
// Construct the generator and link it to the disk layer, ensuring that the
|
||||||
// generation progress is resolved to prevent accessing uncovered states
|
// generation progress is resolved to prevent accessing uncovered states
|
||||||
// regardless of whether background state snapshot generation is allowed.
|
// regardless of whether background state snapshot generation is allowed.
|
||||||
dl.setGenerator(newGenerator(db.diskdb, noBuild, generator.Marker, stats))
|
dl.setGenerator(newGenerator(db.diskdb, db.flatCodec, noBuild, generator.Marker, stats))
|
||||||
|
|
||||||
// Short circuit if the background generation is not permitted
|
// Short circuit if the background generation is not permitted
|
||||||
if noBuild || db.waitSync {
|
if noBuild || db.waitSync {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package pathdb
|
package pathdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -199,13 +198,15 @@ func (dl *diskLayer) account(hash common.Hash, depth int) ([]byte, error) {
|
||||||
|
|
||||||
// If the layer is being generated, ensure the requested account has
|
// If the layer is being generated, ensure the requested account has
|
||||||
// already been covered by the generator.
|
// already been covered by the generator.
|
||||||
|
codec := dl.db.flatCodec
|
||||||
marker := dl.genMarker()
|
marker := dl.genMarker()
|
||||||
if marker != nil && bytes.Compare(hash.Bytes(), marker) > 0 {
|
if marker != nil && codec.MarkerCompare(hash.Bytes(), marker) > 0 {
|
||||||
return nil, errNotCoveredYet
|
return nil, errNotCoveredYet
|
||||||
}
|
}
|
||||||
// Try to retrieve the account from the memory cache
|
// Try to retrieve the account from the memory cache
|
||||||
|
cacheKey := codec.AccountCacheKey(hash)
|
||||||
if dl.states != nil {
|
if dl.states != nil {
|
||||||
if blob, found := dl.states.HasGet(nil, hash[:]); found {
|
if blob, found := dl.states.HasGet(nil, cacheKey); found {
|
||||||
cleanStateHitMeter.Mark(1)
|
cleanStateHitMeter.Mark(1)
|
||||||
cleanStateReadMeter.Mark(int64(len(blob)))
|
cleanStateReadMeter.Mark(int64(len(blob)))
|
||||||
|
|
||||||
|
|
@ -219,7 +220,7 @@ func (dl *diskLayer) account(hash common.Hash, depth int) ([]byte, error) {
|
||||||
cleanStateMissMeter.Mark(1)
|
cleanStateMissMeter.Mark(1)
|
||||||
}
|
}
|
||||||
// Try to retrieve the account from the disk.
|
// Try to retrieve the account from the disk.
|
||||||
blob := rawdb.ReadAccountSnapshot(dl.db.diskdb, hash)
|
blob := codec.ReadAccount(dl.db.diskdb, hash)
|
||||||
|
|
||||||
// Store the resolved data in the clean cache. The background buffer flusher
|
// Store the resolved data in the clean cache. The background buffer flusher
|
||||||
// may also write to the clean cache concurrently, but two writers cannot
|
// may also write to the clean cache concurrently, but two writers cannot
|
||||||
|
|
@ -227,7 +228,7 @@ func (dl *diskLayer) account(hash common.Hash, depth int) ([]byte, error) {
|
||||||
// it will be found in the frozen buffer, eliminating the need to check the
|
// it will be found in the frozen buffer, eliminating the need to check the
|
||||||
// database.
|
// database.
|
||||||
if dl.states != nil {
|
if dl.states != nil {
|
||||||
dl.states.Set(hash[:], blob)
|
dl.states.Set(cacheKey, blob)
|
||||||
cleanStateWriteMeter.Mark(int64(len(blob)))
|
cleanStateWriteMeter.Mark(int64(len(blob)))
|
||||||
}
|
}
|
||||||
if len(blob) == 0 {
|
if len(blob) == 0 {
|
||||||
|
|
@ -276,14 +277,19 @@ func (dl *diskLayer) storage(accountHash, storageHash common.Hash, depth int) ([
|
||||||
|
|
||||||
// If the layer is being generated, ensure the requested storage slot
|
// If the layer is being generated, ensure the requested storage slot
|
||||||
// has already been covered by the generator.
|
// has already been covered by the generator.
|
||||||
key := storageKeySlice(accountHash, storageHash)
|
codec := dl.db.flatCodec
|
||||||
|
combinedKey := storageKeySlice(accountHash, storageHash) // marker comparison key (merkle layout)
|
||||||
marker := dl.genMarker()
|
marker := dl.genMarker()
|
||||||
if marker != nil && bytes.Compare(key, marker) > 0 {
|
if marker != nil && codec.MarkerCompare(combinedKey, marker) > 0 {
|
||||||
return nil, errNotCoveredYet
|
return nil, errNotCoveredYet
|
||||||
}
|
}
|
||||||
// Try to retrieve the storage slot from the memory cache
|
// Try to retrieve the storage slot from the memory cache. The codec
|
||||||
|
// decides the cache key shape so it can avoid colliding with account
|
||||||
|
// keys (relevant once the bintrie codec lands; for merkle this remains
|
||||||
|
// the historical 64-byte combined key).
|
||||||
|
cacheKey := codec.StorageCacheKey(accountHash, storageHash)
|
||||||
if dl.states != nil {
|
if dl.states != nil {
|
||||||
if blob, found := dl.states.HasGet(nil, key); found {
|
if blob, found := dl.states.HasGet(nil, cacheKey); found {
|
||||||
cleanStateHitMeter.Mark(1)
|
cleanStateHitMeter.Mark(1)
|
||||||
cleanStateReadMeter.Mark(int64(len(blob)))
|
cleanStateReadMeter.Mark(int64(len(blob)))
|
||||||
|
|
||||||
|
|
@ -296,8 +302,8 @@ func (dl *diskLayer) storage(accountHash, storageHash common.Hash, depth int) ([
|
||||||
}
|
}
|
||||||
cleanStateMissMeter.Mark(1)
|
cleanStateMissMeter.Mark(1)
|
||||||
}
|
}
|
||||||
// Try to retrieve the account from the disk
|
// Try to retrieve the storage slot from the disk
|
||||||
blob := rawdb.ReadStorageSnapshot(dl.db.diskdb, accountHash, storageHash)
|
blob := codec.ReadStorage(dl.db.diskdb, accountHash, storageHash)
|
||||||
|
|
||||||
// Store the resolved data in the clean cache. The background buffer flusher
|
// Store the resolved data in the clean cache. The background buffer flusher
|
||||||
// may also write to the clean cache concurrently, but two writers cannot
|
// may also write to the clean cache concurrently, but two writers cannot
|
||||||
|
|
@ -305,7 +311,7 @@ func (dl *diskLayer) storage(accountHash, storageHash common.Hash, depth int) ([
|
||||||
// it will be found in the frozen buffer, eliminating the need to check the
|
// it will be found in the frozen buffer, eliminating the need to check the
|
||||||
// database.
|
// database.
|
||||||
if dl.states != nil {
|
if dl.states != nil {
|
||||||
dl.states.Set(key, blob)
|
dl.states.Set(cacheKey, blob)
|
||||||
cleanStateWriteMeter.Mark(int64(len(blob)))
|
cleanStateWriteMeter.Mark(int64(len(blob)))
|
||||||
}
|
}
|
||||||
if len(blob) == 0 {
|
if len(blob) == 0 {
|
||||||
|
|
@ -491,7 +497,7 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
|
||||||
|
|
||||||
// Freeze the live buffer and schedule background flushing
|
// Freeze the live buffer and schedule background flushing
|
||||||
dl.frozen = combined
|
dl.frozen = combined
|
||||||
dl.frozen.flush(bottom.root, dl.db.diskdb, []ethdb.AncientWriter{dl.db.stateFreezer, dl.db.trienodeFreezer}, progress, dl.nodes, dl.states, bottom.stateID(), func() {
|
dl.frozen.flush(bottom.root, dl.db.diskdb, dl.db.flatCodec, []ethdb.AncientWriter{dl.db.stateFreezer, dl.db.trienodeFreezer}, progress, dl.nodes, dl.states, bottom.stateID(), func() {
|
||||||
// Resume the background generation if it's not completed yet.
|
// Resume the background generation if it's not completed yet.
|
||||||
// The generator is assumed to be available if the progress is
|
// The generator is assumed to be available if the progress is
|
||||||
// not nil.
|
// not nil.
|
||||||
|
|
@ -599,7 +605,7 @@ func (dl *diskLayer) revert(h *stateHistory) (*diskLayer, error) {
|
||||||
writeNodes(batch, nodes, dl.nodes)
|
writeNodes(batch, nodes, dl.nodes)
|
||||||
|
|
||||||
// Provide the original values of modified accounts and storages for revert
|
// Provide the original values of modified accounts and storages for revert
|
||||||
writeStates(batch, progress, accounts, storages, dl.states)
|
writeStates(batch, dl.db.flatCodec, progress, accounts, storages, dl.states)
|
||||||
rawdb.WritePersistentStateID(batch, dl.id-1)
|
rawdb.WritePersistentStateID(batch, dl.id-1)
|
||||||
rawdb.WriteSnapshotRoot(batch, h.meta.parent)
|
rawdb.WriteSnapshotRoot(batch, h.meta.parent)
|
||||||
if err := batch.Write(); err != nil {
|
if err := batch.Write(); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -71,10 +71,16 @@ func writeNodes(batch ethdb.Batch, nodes map[common.Hash]map[string]*trienode.No
|
||||||
// This function assumes the background generator is already terminated and states
|
// This function assumes the background generator is already terminated and states
|
||||||
// before the supplied marker has been correctly generated.
|
// before the supplied marker has been correctly generated.
|
||||||
//
|
//
|
||||||
|
// The codec parameter abstracts the trie-specific persistence and cache key
|
||||||
|
// derivation. The marker comparisons retain merkle-specific shape (two-tier
|
||||||
|
// account+storage marker) because the bintrie path uses a separate writer
|
||||||
|
// (writeStems, added in a later commit) that operates on a single-tier
|
||||||
|
// marker over stems rather than (account, storage) pairs.
|
||||||
|
//
|
||||||
// TODO(rjl493456442) do we really need this generation marker? The state updates
|
// TODO(rjl493456442) do we really need this generation marker? The state updates
|
||||||
// after the marker can also be written and will be fixed by generator later if
|
// after the marker can also be written and will be fixed by generator later if
|
||||||
// it's outdated.
|
// it's outdated.
|
||||||
func writeStates(batch ethdb.Batch, genMarker []byte, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte, clean *fastcache.Cache) (int, int) {
|
func writeStates(batch ethdb.Batch, codec flatStateCodec, genMarker []byte, accountData map[common.Hash][]byte, storageData map[common.Hash]map[common.Hash][]byte, clean *fastcache.Cache) (int, int) {
|
||||||
var (
|
var (
|
||||||
accounts int
|
accounts int
|
||||||
slots int
|
slots int
|
||||||
|
|
@ -88,15 +94,16 @@ func writeStates(batch ethdb.Batch, genMarker []byte, accountData map[common.Has
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
accounts += 1
|
accounts += 1
|
||||||
|
cacheKey := codec.AccountCacheKey(addrHash)
|
||||||
if len(blob) == 0 {
|
if len(blob) == 0 {
|
||||||
rawdb.DeleteAccountSnapshot(batch, addrHash)
|
codec.DeleteAccount(batch, addrHash)
|
||||||
if clean != nil {
|
if clean != nil {
|
||||||
clean.Set(addrHash[:], nil)
|
clean.Set(cacheKey, nil)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rawdb.WriteAccountSnapshot(batch, addrHash, blob)
|
codec.WriteAccount(batch, addrHash, blob)
|
||||||
if clean != nil {
|
if clean != nil {
|
||||||
clean.Set(addrHash[:], blob)
|
clean.Set(cacheKey, blob)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -116,16 +123,16 @@ func writeStates(batch ethdb.Batch, genMarker []byte, accountData map[common.Has
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
slots += 1
|
slots += 1
|
||||||
key := storageKeySlice(addrHash, storageHash)
|
cacheKey := codec.StorageCacheKey(addrHash, storageHash)
|
||||||
if len(blob) == 0 {
|
if len(blob) == 0 {
|
||||||
rawdb.DeleteStorageSnapshot(batch, addrHash, storageHash)
|
codec.DeleteStorage(batch, addrHash, storageHash)
|
||||||
if clean != nil {
|
if clean != nil {
|
||||||
clean.Set(key, nil)
|
clean.Set(cacheKey, nil)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rawdb.WriteStorageSnapshot(batch, addrHash, storageHash, blob)
|
codec.WriteStorage(batch, addrHash, storageHash, blob)
|
||||||
if clean != nil {
|
if clean != nil {
|
||||||
clean.Set(key, blob)
|
clean.Set(cacheKey, blob)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ type generator struct {
|
||||||
running bool // Flag indicating whether the background generation is running
|
running bool // Flag indicating whether the background generation is running
|
||||||
|
|
||||||
db ethdb.KeyValueStore // Key-value store containing the snapshot data
|
db ethdb.KeyValueStore // Key-value store containing the snapshot data
|
||||||
|
codec flatStateCodec // Flat-state codec for key derivation, persistence, iterators
|
||||||
stats *generatorStats // Generation statistics used throughout the entire life cycle
|
stats *generatorStats // Generation statistics used throughout the entire life cycle
|
||||||
abort chan chan struct{} // Notification channel to abort generating the snapshot in this layer
|
abort chan chan struct{} // Notification channel to abort generating the snapshot in this layer
|
||||||
done chan struct{} // Notification channel when generation is done
|
done chan struct{} // Notification channel when generation is done
|
||||||
|
|
@ -109,7 +110,11 @@ type generator struct {
|
||||||
// progress indicates the starting position for resuming snapshot generation.
|
// progress indicates the starting position for resuming snapshot generation.
|
||||||
// It must be provided even if generation is not allowed; otherwise, uncovered
|
// It must be provided even if generation is not allowed; otherwise, uncovered
|
||||||
// states may be exposed for serving.
|
// states may be exposed for serving.
|
||||||
func newGenerator(db ethdb.KeyValueStore, noBuild bool, progress []byte, stats *generatorStats) *generator {
|
//
|
||||||
|
// codec is the flat-state codec used for marker handling, prefix selection,
|
||||||
|
// persistence, and iterator construction. It must match the codec configured
|
||||||
|
// on the owning Database.
|
||||||
|
func newGenerator(db ethdb.KeyValueStore, codec flatStateCodec, noBuild bool, progress []byte, stats *generatorStats) *generator {
|
||||||
if stats == nil {
|
if stats == nil {
|
||||||
stats = &generatorStats{start: time.Now()}
|
stats = &generatorStats{start: time.Now()}
|
||||||
}
|
}
|
||||||
|
|
@ -117,6 +122,7 @@ func newGenerator(db ethdb.KeyValueStore, noBuild bool, progress []byte, stats *
|
||||||
noBuild: noBuild,
|
noBuild: noBuild,
|
||||||
progress: progress,
|
progress: progress,
|
||||||
db: db,
|
db: db,
|
||||||
|
codec: codec,
|
||||||
stats: stats,
|
stats: stats,
|
||||||
abort: make(chan chan struct{}),
|
abort: make(chan chan struct{}),
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
|
|
@ -134,7 +140,7 @@ func (g *generator) run(root common.Hash) {
|
||||||
log.Warn("Paused the leftover generation cycle")
|
log.Warn("Paused the leftover generation cycle")
|
||||||
}
|
}
|
||||||
g.running = true
|
g.running = true
|
||||||
go g.generate(newGeneratorContext(root, g.progress, g.db))
|
go g.generate(newGeneratorContext(root, g.progress, g.db, g.codec))
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop terminates the background generation if it's actively running.
|
// stop terminates the background generation if it's actively running.
|
||||||
|
|
@ -168,15 +174,6 @@ func (g *generator) progressMarker() []byte {
|
||||||
return g.progress
|
return g.progress
|
||||||
}
|
}
|
||||||
|
|
||||||
// splitMarker is an internal helper which splits the generation progress marker
|
|
||||||
// into two parts.
|
|
||||||
func splitMarker(marker []byte) ([]byte, []byte) {
|
|
||||||
var accMarker []byte
|
|
||||||
if len(marker) > 0 {
|
|
||||||
accMarker = marker[:common.HashLength]
|
|
||||||
}
|
|
||||||
return accMarker, marker
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateSnapshot regenerates a brand-new snapshot based on an existing state
|
// generateSnapshot regenerates a brand-new snapshot based on an existing state
|
||||||
// database and head block asynchronously. The snapshot is returned immediately
|
// database and head block asynchronously. The snapshot is returned immediately
|
||||||
|
|
@ -188,7 +185,7 @@ func generateSnapshot(triedb *Database, root common.Hash, noBuild bool) *diskLay
|
||||||
genMarker = []byte{} // Initialized but empty!
|
genMarker = []byte{} // Initialized but empty!
|
||||||
)
|
)
|
||||||
dl := newDiskLayer(root, 0, triedb, nil, nil, newBuffer(triedb.config.WriteBufferSize, nil, nil, 0), nil)
|
dl := newDiskLayer(root, 0, triedb, nil, nil, newBuffer(triedb.config.WriteBufferSize, nil, nil, 0), nil)
|
||||||
dl.setGenerator(newGenerator(triedb.diskdb, noBuild, genMarker, stats))
|
dl.setGenerator(newGenerator(triedb.diskdb, triedb.flatCodec, noBuild, genMarker, stats))
|
||||||
|
|
||||||
if !noBuild {
|
if !noBuild {
|
||||||
dl.generator.run(root)
|
dl.generator.run(root)
|
||||||
|
|
@ -633,12 +630,12 @@ func (g *generator) generateStorages(ctx *generatorContext, account common.Hash,
|
||||||
}(time.Now())
|
}(time.Now())
|
||||||
|
|
||||||
if delete {
|
if delete {
|
||||||
rawdb.DeleteStorageSnapshot(ctx.batch, account, common.BytesToHash(key))
|
g.codec.DeleteStorage(ctx.batch, account, common.BytesToHash(key))
|
||||||
wipedStorageMeter.Mark(1)
|
wipedStorageMeter.Mark(1)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if write {
|
if write {
|
||||||
rawdb.WriteStorageSnapshot(ctx.batch, account, common.BytesToHash(key), val)
|
g.codec.WriteStorage(ctx.batch, account, common.BytesToHash(key), val)
|
||||||
generatedStorageMeter.Mark(1)
|
generatedStorageMeter.Mark(1)
|
||||||
} else {
|
} else {
|
||||||
recoveredStorageMeter.Mark(1)
|
recoveredStorageMeter.Mark(1)
|
||||||
|
|
@ -682,7 +679,7 @@ func (g *generator) generateAccounts(ctx *generatorContext, accMarker []byte) er
|
||||||
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if delete {
|
if delete {
|
||||||
rawdb.DeleteAccountSnapshot(ctx.batch, account)
|
g.codec.DeleteAccount(ctx.batch, account)
|
||||||
wipedAccountMeter.Mark(1)
|
wipedAccountMeter.Mark(1)
|
||||||
accountWriteCounter.Inc(time.Since(start).Nanoseconds())
|
accountWriteCounter.Inc(time.Since(start).Nanoseconds())
|
||||||
|
|
||||||
|
|
@ -708,7 +705,7 @@ func (g *generator) generateAccounts(ctx *generatorContext, accMarker []byte) er
|
||||||
} else {
|
} else {
|
||||||
data := types.SlimAccountRLP(acc)
|
data := types.SlimAccountRLP(acc)
|
||||||
dataLen = len(data)
|
dataLen = len(data)
|
||||||
rawdb.WriteAccountSnapshot(ctx.batch, account, data)
|
g.codec.WriteAccount(ctx.batch, account, data)
|
||||||
generatedAccountMeter.Mark(1)
|
generatedAccountMeter.Mark(1)
|
||||||
}
|
}
|
||||||
g.stats.storage += common.StorageSize(1 + common.HashLength + dataLen)
|
g.stats.storage += common.StorageSize(1 + common.HashLength + dataLen)
|
||||||
|
|
@ -788,7 +785,7 @@ func (g *generator) generate(ctx *generatorContext) {
|
||||||
// processed twice by the generator(they are already processed in the
|
// processed twice by the generator(they are already processed in the
|
||||||
// last run) but it's fine.
|
// last run) but it's fine.
|
||||||
var (
|
var (
|
||||||
accMarker, _ = splitMarker(g.progress)
|
accMarker, _ = g.codec.SplitMarker(g.progress)
|
||||||
abort chan struct{}
|
abort chan struct{}
|
||||||
)
|
)
|
||||||
if err := g.generateAccounts(ctx, accMarker); err != nil {
|
if err := g.generateAccounts(ctx, accMarker); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ func TestAccountIteratorBasics(t *testing.T) {
|
||||||
|
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
batch := db.NewBatch()
|
batch := db.NewBatch()
|
||||||
states.write(batch, nil, nil)
|
states.write(batch, &merkleFlatCodec{}, nil, nil)
|
||||||
batch.Write()
|
batch.Write()
|
||||||
it = newDiskAccountIterator(db, common.Hash{})
|
it = newDiskAccountIterator(db, common.Hash{})
|
||||||
verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator
|
verifyIterator(t, 100, it, verifyNothing) // Nil is allowed for single layer iterator
|
||||||
|
|
@ -176,7 +176,7 @@ func TestStorageIteratorBasics(t *testing.T) {
|
||||||
|
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
batch := db.NewBatch()
|
batch := db.NewBatch()
|
||||||
states.write(batch, nil, nil)
|
states.write(batch, &merkleFlatCodec{}, nil, nil)
|
||||||
batch.Write()
|
batch.Write()
|
||||||
for account := range accounts {
|
for account := range accounts {
|
||||||
it := newDiskStorageIterator(db, account, common.Hash{})
|
it := newDiskStorageIterator(db, account, common.Hash{})
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,7 @@ func (r *HistoricalStateReader) AccountRLP(address common.Address) ([]byte, erro
|
||||||
// and try to define a low granularity lock if the current approach doesn't
|
// and try to define a low granularity lock if the current approach doesn't
|
||||||
// work later.
|
// work later.
|
||||||
dl := r.db.tree.bottom()
|
dl := r.db.tree.bottom()
|
||||||
hash := crypto.Keccak256Hash(address.Bytes())
|
hash := r.db.flatCodec.AccountKey(address)
|
||||||
latest, err := dl.account(hash, 0)
|
latest, err := dl.account(hash, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -310,8 +310,7 @@ func (r *HistoricalStateReader) Storage(address common.Address, key common.Hash)
|
||||||
// and try to define a low granularity lock if the current approach doesn't
|
// and try to define a low granularity lock if the current approach doesn't
|
||||||
// work later.
|
// work later.
|
||||||
dl := r.db.tree.bottom()
|
dl := r.db.tree.bottom()
|
||||||
addrHash := crypto.Keccak256Hash(address.Bytes())
|
addrHash, keyHash := r.db.flatCodec.StorageKey(address, key)
|
||||||
keyHash := crypto.Keccak256Hash(key.Bytes())
|
|
||||||
latest, err := dl.storage(addrHash, keyHash, 0)
|
latest, err := dl.storage(addrHash, keyHash, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,6 @@ import (
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
"github.com/VictoriaMetrics/fastcache"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
|
@ -424,8 +423,8 @@ func (s *stateSet) decode(r *rlp.Stream) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// write flushes state mutations into the provided database batch as a whole.
|
// write flushes state mutations into the provided database batch as a whole.
|
||||||
func (s *stateSet) write(batch ethdb.Batch, genMarker []byte, clean *fastcache.Cache) (int, int) {
|
func (s *stateSet) write(batch ethdb.Batch, codec flatStateCodec, genMarker []byte, clean *fastcache.Cache) (int, int) {
|
||||||
return writeStates(batch, genMarker, s.accountData, s.storageData, clean)
|
return writeStates(batch, codec, genMarker, s.accountData, s.storageData, clean)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset clears all cached state data, including any optional sorted lists that
|
// reset clears all cached state data, including any optional sorted lists that
|
||||||
|
|
@ -438,11 +437,13 @@ func (s *stateSet) reset() {
|
||||||
s.storageListSorted = make(map[common.Hash][]common.Hash)
|
s.storageListSorted = make(map[common.Hash][]common.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dbsize returns the approximate size for db write.
|
// dbsize returns the approximate size for db write. The codec supplies
|
||||||
func (s *stateSet) dbsize() int {
|
// the per-entry on-disk overhead so this calculation tracks the actual
|
||||||
m := len(s.accountData) * len(rawdb.SnapshotAccountPrefix)
|
// schema in use (merkle vs. bintrie).
|
||||||
|
func (s *stateSet) dbsize(codec flatStateCodec) int {
|
||||||
|
m := len(s.accountData) * codec.AccountPrefixSize()
|
||||||
for _, slots := range s.storageData {
|
for _, slots := range s.storageData {
|
||||||
m += len(slots) * len(rawdb.SnapshotStoragePrefix)
|
m += len(slots) * codec.StoragePrefixSize()
|
||||||
}
|
}
|
||||||
return m + int(s.size)
|
return m + int(s.size)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue