Add tracker interface and tests #3

Merged
roysc merged 7 commits from tracker-interface into main 2023-09-26 11:34:42 +00:00
2 changed files with 21 additions and 14 deletions
Showing only changes of commit eab44c9965 - Show all commits

View File

@ -23,16 +23,21 @@ import (
"github.com/ethereum/go-ethereum/trie"
)
// PrefixBoundIterator is a NodeIterator constrained by a lower & upper bound (as hex path prefixes)
type PrefixBoundIterator struct {
trie.NodeIterator
EndPath []byte
}
// IteratorConstructor is a constructor returning a NodeIterator, which is used to decouple this
// code from the trie implementation.
type IteratorConstructor = func(startKey []byte) trie.NodeIterator
// PrefixBoundIterator is a NodeIterator constrained by a lower & upper bound (as hex path prefixes)
type PrefixBoundIterator struct {
trie.NodeIterator
StartPath, EndPath []byte
}
// NewPrefixBoundIterator returns an iterator with an upper bound value (hex path prefix)
func NewPrefixBoundIterator(it trie.NodeIterator, to []byte) *PrefixBoundIterator {
return &PrefixBoundIterator{NodeIterator: it, StartPath: it.Path(), EndPath: to}
}
func (it *PrefixBoundIterator) Next(descend bool) bool {
if it.EndPath == nil {
return it.NodeIterator.Next(descend)
@ -49,9 +54,8 @@ func (it *PrefixBoundIterator) Next(descend bool) bool {
return bytes.Compare(it.Path(), it.EndPath) <= 0
}
// NewPrefixBoundIterator returns an iterator with an upper bound value (hex path prefix)
func NewPrefixBoundIterator(it trie.NodeIterator, to []byte) *PrefixBoundIterator {
return &PrefixBoundIterator{NodeIterator: it, EndPath: to}
func (it *PrefixBoundIterator) Bounds() ([]byte, []byte) {
return it.StartPath, it.EndPath
}
// generates nibble slice prefixes at uniform intervals

View File

@ -69,11 +69,7 @@ func (tr *Tracker) dump() error {
log.Debug("Dumping recovery state", "to", tr.recoveryFile)
var rows [][]string
for it := range tr.started {
var endPath []byte
if impl, ok := it.NodeIterator.(*iter.PrefixBoundIterator); ok {
endPath = impl.EndPath
}
_, endPath := it.Bounds()
rows = append(rows, []string{
fmt.Sprintf("%x", it.Path()),
fmt.Sprintf("%x", endPath),
@ -184,6 +180,13 @@ func (it *Iterator) Next(descend bool) bool {
return ret
}
func (it *Iterator) Bounds() ([]byte, []byte) {
roysc marked this conversation as resolved Outdated

Is it explicit anywhere that you must call CloseAndSave in order to close the channel, set running to false, etc?

What happens if you don't call that, but the iterator completes?

If we need to call it, I think the pattern:

      tr := tracker.New(recoveryFile, NumIters)
      defer tr.CloseAndSave()  // <--- You must do this!

Needs to be documented explicitly somewhere (unless I am just missing something).

Is it explicit anywhere that you *must* call CloseAndSave in order to close the channel, set running to false, etc? What happens if you don't call that, but the iterator completes? If we need to call it, I think the pattern: ``` tr := tracker.New(recoveryFile, NumIters) defer tr.CloseAndSave() // <--- You must do this! ``` Needs to be documented explicitly somewhere (unless I am just missing something).
Outdated
Review

If it's not called, it should just be sort of a leak. The channels won't be flushed or saved, but once all its iterators die, the tracker will still be gc'd. No critical consequences that I foresee, but I will document it.

If it's not called, it should just be sort of a leak. The channels won't be flushed or saved, but once all its iterators die, the tracker will still be gc'd. No critical consequences that I foresee, but I will document it.
if impl, ok := it.NodeIterator.(*iter.PrefixBoundIterator); ok {
return impl.Bounds()
}
return nil, nil
}
// Rewinds to the path of the previous (pre-order) node:
// If the last byte of the path is zero, pops it. Otherwise, decrements it
// and pads with 0xF to 64 bytes (e.g. [1] => [0 f f f ...]).