core: prefetch next block state concurrently
This commit is contained in:
@ -80,10 +80,13 @@ func (st *insertStats) report(chain []*types.Block, index int, dirty common.Stor
|
||||
|
||||
// insertIterator is a helper to assist during chain import.
|
||||
type insertIterator struct {
|
||||
chain types.Blocks
|
||||
results <-chan error
|
||||
index int
|
||||
validator Validator
|
||||
chain types.Blocks // Chain of blocks being iterated over
|
||||
|
||||
results <-chan error // Verification result sink from the consensus engine
|
||||
errors []error // Header verification errors for the blocks
|
||||
|
||||
index int // Current offset of the iterator
|
||||
validator Validator // Validator to run if verification succeeds
|
||||
}
|
||||
|
||||
// newInsertIterator creates a new iterator based on the given blocks, which are
|
||||
@ -92,6 +95,7 @@ func newInsertIterator(chain types.Blocks, results <-chan error, validator Valid
|
||||
return &insertIterator{
|
||||
chain: chain,
|
||||
results: results,
|
||||
errors: make([]error, 0, len(chain)),
|
||||
index: -1,
|
||||
validator: validator,
|
||||
}
|
||||
@ -100,17 +104,44 @@ func newInsertIterator(chain types.Blocks, results <-chan error, validator Valid
|
||||
// next returns the next block in the iterator, along with any potential validation
|
||||
// error for that block. When the end is reached, it will return (nil, nil).
|
||||
func (it *insertIterator) next() (*types.Block, error) {
|
||||
// If we reached the end of the chain, abort
|
||||
if it.index+1 >= len(it.chain) {
|
||||
it.index = len(it.chain)
|
||||
return nil, nil
|
||||
}
|
||||
// Advance the iterator and wait for verification result if not yet done
|
||||
it.index++
|
||||
if err := <-it.results; err != nil {
|
||||
return it.chain[it.index], err
|
||||
if len(it.errors) <= it.index {
|
||||
it.errors = append(it.errors, <-it.results)
|
||||
}
|
||||
if it.errors[it.index] != nil {
|
||||
return it.chain[it.index], it.errors[it.index]
|
||||
}
|
||||
// Block header valid, run body validation and return
|
||||
return it.chain[it.index], it.validator.ValidateBody(it.chain[it.index])
|
||||
}
|
||||
|
||||
// peek returns the next block in the iterator, along with any potential validation
|
||||
// error for that block, but does **not** advance the iterator.
|
||||
//
|
||||
// Both header and body validation errors (nil too) is cached into the iterator
|
||||
// to avoid duplicating work on the following next() call.
|
||||
func (it *insertIterator) peek() (*types.Block, error) {
|
||||
// If we reached the end of the chain, abort
|
||||
if it.index+1 >= len(it.chain) {
|
||||
return nil, nil
|
||||
}
|
||||
// Wait for verification result if not yet done
|
||||
if len(it.errors) <= it.index+1 {
|
||||
it.errors = append(it.errors, <-it.results)
|
||||
}
|
||||
if it.errors[it.index+1] != nil {
|
||||
return it.chain[it.index+1], it.errors[it.index+1]
|
||||
}
|
||||
// Block header valid, ignore body validation since we don't have a parent anyway
|
||||
return it.chain[it.index+1], nil
|
||||
}
|
||||
|
||||
// previous returns the previous header that was being processed, or nil.
|
||||
func (it *insertIterator) previous() *types.Header {
|
||||
if it.index < 1 {
|
||||
|
Reference in New Issue
Block a user