@@ -135,7 +135,7 @@ type nodeIteratorState struct {
135
135
node node // Trie node being iterated
136
136
parent common.Hash // Hash of the first full ancestor node (nil if current is the root)
137
137
index int // Child to be processed next
138
- pathlen int // Length of the path to this node
138
+ pathlen int // Length of the path to the parent node
139
139
}
140
140
141
141
type nodeIterator struct {
@@ -145,7 +145,7 @@ type nodeIterator struct {
145
145
err error // Failure set in case of an internal error in the iterator
146
146
147
147
resolver NodeResolver // optional node resolver for avoiding disk hits
148
- pool []* nodeIteratorState // local pool for iteratorstates
148
+ pool []* nodeIteratorState // local pool for iterator states
149
149
}
150
150
151
151
// errIteratorEnd is stored in nodeIterator.err when iteration is done.
@@ -304,14 +304,15 @@ func (it *nodeIterator) seek(prefix []byte) error {
304
304
// The path we're looking for is the hex encoded key without terminator.
305
305
key := keybytesToHex (prefix )
306
306
key = key [:len (key )- 1 ]
307
+
307
308
// Move forward until we're just before the closest match to key.
308
309
for {
309
310
state , parentIndex , path , err := it .peekSeek (key )
310
311
if err == errIteratorEnd {
311
312
return errIteratorEnd
312
313
} else if err != nil {
313
314
return seekError {prefix , err }
314
- } else if bytes . Compare (path , key ) >= 0 {
315
+ } else if reachedPath (path , key ) {
315
316
return nil
316
317
}
317
318
it .push (state , parentIndex , path )
@@ -339,7 +340,6 @@ func (it *nodeIterator) peek(descend bool) (*nodeIteratorState, *int, []byte, er
339
340
// If we're skipping children, pop the current node first
340
341
it .pop ()
341
342
}
342
-
343
343
// Continue iteration to the next child
344
344
for len (it .stack ) > 0 {
345
345
parent := it .stack [len (it .stack )- 1 ]
@@ -372,7 +372,6 @@ func (it *nodeIterator) peekSeek(seekKey []byte) (*nodeIteratorState, *int, []by
372
372
// If we're skipping children, pop the current node first
373
373
it .pop ()
374
374
}
375
-
376
375
// Continue iteration to the next child
377
376
for len (it .stack ) > 0 {
378
377
parent := it .stack [len (it .stack )- 1 ]
@@ -449,16 +448,18 @@ func (it *nodeIterator) findChild(n *fullNode, index int, ancestor common.Hash)
449
448
state * nodeIteratorState
450
449
childPath []byte
451
450
)
452
- for ; index < len (n .Children ); index ++ {
451
+ for ; index < len (n .Children ); index = nextChildIndex ( index ) {
453
452
if n .Children [index ] != nil {
454
453
child = n .Children [index ]
455
454
hash , _ := child .cache ()
455
+
456
456
state = it .getFromPool ()
457
457
state .hash = common .BytesToHash (hash )
458
458
state .node = child
459
459
state .parent = ancestor
460
460
state .index = - 1
461
461
state .pathlen = len (path )
462
+
462
463
childPath = append (childPath , path ... )
463
464
childPath = append (childPath , byte (index ))
464
465
return child , state , childPath , index
@@ -471,8 +472,8 @@ func (it *nodeIterator) nextChild(parent *nodeIteratorState, ancestor common.Has
471
472
switch node := parent .node .(type ) {
472
473
case * fullNode :
473
474
// Full node, move to the first non-nil child.
474
- if child , state , path , index := it .findChild (node , parent .index + 1 , ancestor ); child != nil {
475
- parent .index = index - 1
475
+ if child , state , path , index := it .findChild (node , nextChildIndex ( parent .index ) , ancestor ); child != nil {
476
+ parent .index = prevChildIndex ( index )
476
477
return state , path , true
477
478
}
478
479
case * shortNode :
@@ -498,23 +499,23 @@ func (it *nodeIterator) nextChildAt(parent *nodeIteratorState, ancestor common.H
498
499
switch n := parent .node .(type ) {
499
500
case * fullNode :
500
501
// Full node, move to the first non-nil child before the desired key position
501
- child , state , path , index := it .findChild (n , parent .index + 1 , ancestor )
502
+ child , state , path , index := it .findChild (n , nextChildIndex ( parent .index ) , ancestor )
502
503
if child == nil {
503
504
// No more children in this fullnode
504
505
return parent , it .path , false
505
506
}
506
507
// If the child we found is already past the seek position, just return it.
507
- if bytes . Compare (path , key ) >= 0 {
508
- parent .index = index - 1
508
+ if reachedPath (path , key ) {
509
+ parent .index = prevChildIndex ( index )
509
510
return state , path , true
510
511
}
511
512
// The child is before the seek position. Try advancing
512
513
for {
513
- nextChild , nextState , nextPath , nextIndex := it .findChild (n , index + 1 , ancestor )
514
+ nextChild , nextState , nextPath , nextIndex := it .findChild (n , nextChildIndex ( index ) , ancestor )
514
515
// If we run out of children, or skipped past the target, return the
515
516
// previous one
516
- if nextChild == nil || bytes . Compare (nextPath , key ) >= 0 {
517
- parent .index = index - 1
517
+ if nextChild == nil || reachedPath (nextPath , key ) {
518
+ parent .index = prevChildIndex ( index )
518
519
return state , path , true
519
520
}
520
521
// We found a better child closer to the target
@@ -541,7 +542,7 @@ func (it *nodeIterator) push(state *nodeIteratorState, parentIndex *int, path []
541
542
it .path = path
542
543
it .stack = append (it .stack , state )
543
544
if parentIndex != nil {
544
- * parentIndex ++
545
+ * parentIndex = nextChildIndex ( * parentIndex )
545
546
}
546
547
}
547
548
@@ -550,8 +551,54 @@ func (it *nodeIterator) pop() {
550
551
it .path = it .path [:last .pathlen ]
551
552
it .stack [len (it .stack )- 1 ] = nil
552
553
it .stack = it .stack [:len (it .stack )- 1 ]
553
- // last is now unused
554
- it .putInPool (last )
554
+
555
+ it .putInPool (last ) // last is now unused
556
+ }
557
+
558
+ // reachedPath normalizes a path by truncating a terminator if present, and
559
+ // returns true if it is greater than or equal to the target. Using this,
560
+ // the path of a value node embedded a full node will compare less than the
561
+ // full node's children.
562
+ func reachedPath (path , target []byte ) bool {
563
+ if hasTerm (path ) {
564
+ path = path [:len (path )- 1 ]
565
+ }
566
+ return bytes .Compare (path , target ) >= 0
567
+ }
568
+
569
+ // A value embedded in a full node occupies the last slot (16) of the array of
570
+ // children. In order to produce a pre-order traversal when iterating children,
571
+ // we jump to this last slot first, then go back iterate the child nodes (and
572
+ // skip the last slot at the end):
573
+
574
+ // prevChildIndex returns the index of a child in a full node which precedes
575
+ // the given index when performing a pre-order traversal.
576
+ func prevChildIndex (index int ) int {
577
+ switch index {
578
+ case 0 : // We jumped back to iterate the children, from the value slot
579
+ return 16
580
+ case 16 : // We jumped to the embedded value slot at the end, from the placeholder index
581
+ return - 1
582
+ case 17 : // We skipped the value slot after iterating all the children
583
+ return 15
584
+ default : // We are iterating the children in sequence
585
+ return index - 1
586
+ }
587
+ }
588
+
589
+ // nextChildIndex returns the index of a child in a full node which follows
590
+ // the given index when performing a pre-order traversal.
591
+ func nextChildIndex (index int ) int {
592
+ switch index {
593
+ case - 1 : // Jump from the placeholder index to the embedded value slot
594
+ return 16
595
+ case 15 : // Skip the value slot after iterating the children
596
+ return 17
597
+ case 16 : // From the embedded value slot, jump back to iterate the children
598
+ return 0
599
+ default : // Iterate children in sequence
600
+ return index + 1
601
+ }
555
602
}
556
603
557
604
func compareNodes (a , b NodeIterator ) int {
0 commit comments