Skip to content

Commit 1f05c3e

Browse files
gzliudanholimankaralabe
authored
trie: reuse dirty data instead of hitting disk when generating ethereum#22667 (#1065)
* core/state/snapshot: reuse memory data instead of hitting disk when generating * trie: minor nitpicks wrt the resolver optimization * core/state/snapshot, trie: use key/value store for resolver * trie: fix linter Co-authored-by: Martin Holst Swende <martin@swende.se> Co-authored-by: Péter Szilágyi <peterke@gmail.com>
1 parent 45d89bd commit 1f05c3e

File tree

1 file changed

+46
-6
lines changed

1 file changed

+46
-6
lines changed

trie/iterator.go

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323

2424
"github.com/XinFinOrg/XDPoSChain/common"
2525
"github.com/XinFinOrg/XDPoSChain/core/types"
26+
"github.com/XinFinOrg/XDPoSChain/ethdb"
2627
)
2728

2829
// Iterator is a key-value trie iterator that traverses a Trie.
@@ -102,6 +103,19 @@ type NodeIterator interface {
102103
// iterator is not positioned at a leaf. Callers must not retain references
103104
// to the value after calling Next.
104105
LeafProof() [][]byte
106+
107+
// AddResolver sets an intermediate database to use for looking up trie nodes
108+
// before reaching into the real persistent layer.
109+
//
110+
// This is not required for normal operation, rather is an optimization for
111+
// cases where trie nodes can be recovered from some external mechanism without
112+
// reading from disk. In those cases, this resolver allows short circuiting
113+
// accesses and returning them from memory.
114+
//
115+
// Before adding a similar mechanism to any other place in Geth, consider
116+
// making trie.Database an interface and wrapping at that level. It's a huge
117+
// refactor, but it could be worth it if another occurrence arises.
118+
AddResolver(ethdb.KeyValueStore)
105119
}
106120

107121
// nodeIteratorState represents the iteration state at one particular Node of the
@@ -119,6 +133,8 @@ type nodeIterator struct {
119133
stack []*nodeIteratorState // Hierarchy of trie nodes persisting the iteration state
120134
path []byte // Path to the current Node
121135
err error // Failure set in case of an internal error in the iterator
136+
137+
resolver ethdb.KeyValueStore // Optional intermediate resolver above the disk layer
122138
}
123139

124140
// errIteratorEnd is stored in nodeIterator.err when iteration is done.
@@ -143,6 +159,10 @@ func newNodeIterator(trie *Trie, start []byte) NodeIterator {
143159
return it
144160
}
145161

162+
func (it *nodeIterator) AddResolver(resolver ethdb.KeyValueStore) {
163+
it.resolver = resolver
164+
}
165+
146166
func (it *nodeIterator) Hash() common.Hash {
147167
if len(it.stack) == 0 {
148168
return common.Hash{}
@@ -261,7 +281,7 @@ func (it *nodeIterator) init() (*nodeIteratorState, error) {
261281
if root != types.EmptyRootHash {
262282
state.hash = root
263283
}
264-
return state, state.resolve(it.trie, nil)
284+
return state, state.resolve(it, nil)
265285
}
266286

267287
// peek creates the next state of the iterator.
@@ -285,7 +305,7 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
285305
}
286306
state, path, ok := it.nextChild(parent, ancestor)
287307
if ok {
288-
if err := state.resolve(it.trie, path); err != nil {
308+
if err := state.resolve(it, path); err != nil {
289309
return parent, &parent.index, path, err
290310
}
291311
return state, &parent.index, path, nil
@@ -318,7 +338,7 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by
318338
}
319339
state, path, ok := it.nextChildAt(parent, ancestor, seekKey)
320340
if ok {
321-
if err := state.resolve(it.trie, path); err != nil {
341+
if err := state.resolve(it, path); err != nil {
322342
return parent, &parent.index, path, err
323343
}
324344
return state, &parent.index, path, nil
@@ -329,9 +349,21 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by
329349
return nil, nil, nil, errIteratorEnd
330350
}
331351

332-
func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error {
352+
func (it *nodeIterator) resolveHash(hash hashNode, path []byte) (node, error) {
353+
if it.resolver != nil {
354+
if blob, err := it.resolver.Get(hash); err == nil && len(blob) > 0 {
355+
if resolved, err := decodeNode(hash, blob); err == nil {
356+
return resolved, nil
357+
}
358+
}
359+
}
360+
resolved, err := it.trie.resolveHash(hash, path)
361+
return resolved, err
362+
}
363+
364+
func (st *nodeIteratorState) resolve(it *nodeIterator, path []byte) error {
333365
if hash, ok := st.node.(hashNode); ok {
334-
resolved, err := tr.resolveHash(hash, path)
366+
resolved, err := it.resolveHash(hash, path)
335367
if err != nil {
336368
return err
337369
}
@@ -516,6 +548,10 @@ func (it *differenceIterator) Path() []byte {
516548
return it.b.Path()
517549
}
518550

551+
func (it *differenceIterator) AddResolver(resolver ethdb.KeyValueStore) {
552+
panic("not implemented")
553+
}
554+
519555
func (it *differenceIterator) Next(bool) bool {
520556
// Invariants:
521557
// - We always advance at least one element in b.
@@ -623,7 +659,11 @@ func (it *unionIterator) Path() []byte {
623659
return (*it.items)[0].Path()
624660
}
625661

626-
// Next returns the next Node in the union of tries being iterated over.
662+
func (it *unionIterator) AddResolver(resolver ethdb.KeyValueStore) {
663+
panic("not implemented")
664+
}
665+
666+
// Next returns the next node in the union of tries being iterated over.
627667
//
628668
// It does this by maintaining a heap of iterators, sorted by the iteration
629669
// order of their next elements, with one entry for each source trie. Each

0 commit comments

Comments
 (0)