|
@@ -243,7 +243,7 @@ func (it *nodeIterator) seek(prefix []byte) error {
|
|
|
key = key[:len(key)-1]
|
|
key = key[:len(key)-1]
|
|
|
// Move forward until we're just before the closest match to key.
|
|
// Move forward until we're just before the closest match to key.
|
|
|
for {
|
|
for {
|
|
|
- state, parentIndex, path, err := it.peek(bytes.HasPrefix(key, it.path))
|
|
|
|
|
|
|
+ state, parentIndex, path, err := it.peekSeek(key)
|
|
|
if err == errIteratorEnd {
|
|
if err == errIteratorEnd {
|
|
|
return errIteratorEnd
|
|
return errIteratorEnd
|
|
|
} else if err != nil {
|
|
} else if err != nil {
|
|
@@ -255,16 +255,21 @@ func (it *nodeIterator) seek(prefix []byte) error {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// init initializes the the iterator.
|
|
|
|
|
+func (it *nodeIterator) init() (*nodeIteratorState, error) {
|
|
|
|
|
+ root := it.trie.Hash()
|
|
|
|
|
+ state := &nodeIteratorState{node: it.trie.root, index: -1}
|
|
|
|
|
+ if root != emptyRoot {
|
|
|
|
|
+ state.hash = root
|
|
|
|
|
+ }
|
|
|
|
|
+ return state, state.resolve(it.trie, nil)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// peek creates the next state of the iterator.
|
|
// peek creates the next state of the iterator.
|
|
|
func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, error) {
|
|
func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, error) {
|
|
|
|
|
+ // Initialize the iterator if we've just started.
|
|
|
if len(it.stack) == 0 {
|
|
if len(it.stack) == 0 {
|
|
|
- // Initialize the iterator if we've just started.
|
|
|
|
|
- root := it.trie.Hash()
|
|
|
|
|
- state := &nodeIteratorState{node: it.trie.root, index: -1}
|
|
|
|
|
- if root != emptyRoot {
|
|
|
|
|
- state.hash = root
|
|
|
|
|
- }
|
|
|
|
|
- err := state.resolve(it.trie, nil)
|
|
|
|
|
|
|
+ state, err := it.init()
|
|
|
return state, nil, nil, err
|
|
return state, nil, nil, err
|
|
|
}
|
|
}
|
|
|
if !descend {
|
|
if !descend {
|
|
@@ -292,6 +297,39 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
|
|
|
return nil, nil, nil, errIteratorEnd
|
|
return nil, nil, nil, errIteratorEnd
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// peekSeek is like peek, but it also tries to skip resolving hashes by skipping
|
|
|
|
|
+// over the siblings that do not lead towards the desired seek position.
|
|
|
|
|
+func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []byte, error) {
|
|
|
|
|
+ // Initialize the iterator if we've just started.
|
|
|
|
|
+ if len(it.stack) == 0 {
|
|
|
|
|
+ state, err := it.init()
|
|
|
|
|
+ return state, nil, nil, err
|
|
|
|
|
+ }
|
|
|
|
|
+ if !bytes.HasPrefix(seekKey, it.path) {
|
|
|
|
|
+ // If we're skipping children, pop the current node first
|
|
|
|
|
+ it.pop()
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Continue iteration to the next child
|
|
|
|
|
+ for len(it.stack) > 0 {
|
|
|
|
|
+ parent := it.stack[len(it.stack)-1]
|
|
|
|
|
+ ancestor := parent.hash
|
|
|
|
|
+ if (ancestor == common.Hash{}) {
|
|
|
|
|
+ ancestor = parent.parent
|
|
|
|
|
+ }
|
|
|
|
|
+ state, path, ok := it.nextChildAt(parent, ancestor, seekKey)
|
|
|
|
|
+ if ok {
|
|
|
|
|
+ if err := state.resolve(it.trie, path); err != nil {
|
|
|
|
|
+ return parent, &parent.index, path, err
|
|
|
|
|
+ }
|
|
|
|
|
+ return state, &parent.index, path, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ // No more child nodes, move back up.
|
|
|
|
|
+ it.pop()
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil, nil, nil, errIteratorEnd
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error {
|
|
func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error {
|
|
|
if hash, ok := st.node.(hashNode); ok {
|
|
if hash, ok := st.node.(hashNode); ok {
|
|
|
resolved, err := tr.resolveHash(hash, path)
|
|
resolved, err := tr.resolveHash(hash, path)
|
|
@@ -304,25 +342,38 @@ func (st *nodeIteratorState) resolve(tr *Trie, path []byte) error {
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func findChild(n *fullNode, index int, path []byte, ancestor common.Hash) (node, *nodeIteratorState, []byte, int) {
|
|
|
|
|
+ var (
|
|
|
|
|
+ child node
|
|
|
|
|
+ state *nodeIteratorState
|
|
|
|
|
+ childPath []byte
|
|
|
|
|
+ )
|
|
|
|
|
+ for ; index < len(n.Children); index++ {
|
|
|
|
|
+ if n.Children[index] != nil {
|
|
|
|
|
+ child = n.Children[index]
|
|
|
|
|
+ hash, _ := child.cache()
|
|
|
|
|
+ state = &nodeIteratorState{
|
|
|
|
|
+ hash: common.BytesToHash(hash),
|
|
|
|
|
+ node: child,
|
|
|
|
|
+ parent: ancestor,
|
|
|
|
|
+ index: -1,
|
|
|
|
|
+ pathlen: len(path),
|
|
|
|
|
+ }
|
|
|
|
|
+ childPath = append(childPath, path...)
|
|
|
|
|
+ childPath = append(childPath, byte(index))
|
|
|
|
|
+ return child, state, childPath, index
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return nil, nil, nil, 0
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Hash) (*nodeIteratorState, []byte, bool) {
|
|
func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Hash) (*nodeIteratorState, []byte, bool) {
|
|
|
switch node := parent.node.(type) {
|
|
switch node := parent.node.(type) {
|
|
|
case *fullNode:
|
|
case *fullNode:
|
|
|
- // Full node, move to the first non-nil child.
|
|
|
|
|
- for i := parent.index + 1; i < len(node.Children); i++ {
|
|
|
|
|
- child := node.Children[i]
|
|
|
|
|
- if child != nil {
|
|
|
|
|
- hash, _ := child.cache()
|
|
|
|
|
- state := &nodeIteratorState{
|
|
|
|
|
- hash: common.BytesToHash(hash),
|
|
|
|
|
- node: child,
|
|
|
|
|
- parent: ancestor,
|
|
|
|
|
- index: -1,
|
|
|
|
|
- pathlen: len(it.path),
|
|
|
|
|
- }
|
|
|
|
|
- path := append(it.path, byte(i))
|
|
|
|
|
- parent.index = i - 1
|
|
|
|
|
- return state, path, true
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ //Full node, move to the first non-nil child.
|
|
|
|
|
+ if child, state, path, index := findChild(node, parent.index+1, it.path, ancestor); child != nil {
|
|
|
|
|
+ parent.index = index - 1
|
|
|
|
|
+ return state, path, true
|
|
|
}
|
|
}
|
|
|
case *shortNode:
|
|
case *shortNode:
|
|
|
// Short node, return the pointer singleton child
|
|
// Short node, return the pointer singleton child
|
|
@@ -342,6 +393,52 @@ func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Has
|
|
|
return parent, it.path, false
|
|
return parent, it.path, false
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// nextChildAt is similar to nextChild, except that it targets a child as close to the
|
|
|
|
|
+// target key as possible, thus skipping siblings.
|
|
|
|
|
+func (it *nodeIterator) nextChildAt(parent *nodeIteratorState, ancestor common.Hash, key []byte) (*nodeIteratorState, []byte, bool) {
|
|
|
|
|
+ switch n := parent.node.(type) {
|
|
|
|
|
+ case *fullNode:
|
|
|
|
|
+ // Full node, move to the first non-nil child before the desired key position
|
|
|
|
|
+ child, state, path, index := findChild(n, parent.index+1, it.path, ancestor)
|
|
|
|
|
+ if child == nil {
|
|
|
|
|
+ // No more children in this fullnode
|
|
|
|
|
+ return parent, it.path, false
|
|
|
|
|
+ }
|
|
|
|
|
+ // If the child we found is already past the seek position, just return it.
|
|
|
|
|
+ if bytes.Compare(path, key) >= 0 {
|
|
|
|
|
+ parent.index = index - 1
|
|
|
|
|
+ return state, path, true
|
|
|
|
|
+ }
|
|
|
|
|
+ // The child is before the seek position. Try advancing
|
|
|
|
|
+ for {
|
|
|
|
|
+ nextChild, nextState, nextPath, nextIndex := findChild(n, index+1, it.path, ancestor)
|
|
|
|
|
+ // If we run out of children, or skipped past the target, return the
|
|
|
|
|
+ // previous one
|
|
|
|
|
+ if nextChild == nil || bytes.Compare(nextPath, key) >= 0 {
|
|
|
|
|
+ parent.index = index - 1
|
|
|
|
|
+ return state, path, true
|
|
|
|
|
+ }
|
|
|
|
|
+ // We found a better child closer to the target
|
|
|
|
|
+ state, path, index = nextState, nextPath, nextIndex
|
|
|
|
|
+ }
|
|
|
|
|
+ case *shortNode:
|
|
|
|
|
+ // Short node, return the pointer singleton child
|
|
|
|
|
+ if parent.index < 0 {
|
|
|
|
|
+ hash, _ := n.Val.cache()
|
|
|
|
|
+ state := &nodeIteratorState{
|
|
|
|
|
+ hash: common.BytesToHash(hash),
|
|
|
|
|
+ node: n.Val,
|
|
|
|
|
+ parent: ancestor,
|
|
|
|
|
+ index: -1,
|
|
|
|
|
+ pathlen: len(it.path),
|
|
|
|
|
+ }
|
|
|
|
|
+ path := append(it.path, n.Key...)
|
|
|
|
|
+ return state, path, true
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return parent, it.path, false
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path []byte) {
|
|
func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path []byte) {
|
|
|
it.path = path
|
|
it.path = path
|
|
|
it.stack = append(it.stack, state)
|
|
it.stack = append(it.stack, state)
|