Merge pull request #25694 from karalabe/concurrent-heal-check

trie: check childrens' existence concurrently for snap heal
This commit is contained in:
Péter Szilágyi 2022-09-06 15:49:13 +03:00 committed by GitHub
commit d408cb6fba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -19,6 +19,7 @@ package trie
import ( import (
"errors" "errors"
"fmt" "fmt"
"sync"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/prque" "github.com/ethereum/go-ethereum/common/prque"
@ -381,11 +382,11 @@ func (s *Sync) scheduleCodeRequest(req *codeRequest) {
// retrieval scheduling. // retrieval scheduling.
func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) { func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
// Gather all the children of the node, irrelevant whether known or not // Gather all the children of the node, irrelevant whether known or not
type child struct { type childNode struct {
path []byte path []byte
node node node node
} }
var children []child var children []childNode
switch node := (object).(type) { switch node := (object).(type) {
case *shortNode: case *shortNode:
@ -393,14 +394,14 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
if hasTerm(key) { if hasTerm(key) {
key = key[:len(key)-1] key = key[:len(key)-1]
} }
children = []child{{ children = []childNode{{
node: node.Val, node: node.Val,
path: append(append([]byte(nil), req.path...), key...), path: append(append([]byte(nil), req.path...), key...),
}} }}
case *fullNode: case *fullNode:
for i := 0; i < 17; i++ { for i := 0; i < 17; i++ {
if node.Children[i] != nil { if node.Children[i] != nil {
children = append(children, child{ children = append(children, childNode{
node: node.Children[i], node: node.Children[i],
path: append(append([]byte(nil), req.path...), byte(i)), path: append(append([]byte(nil), req.path...), byte(i)),
}) })
@ -410,7 +411,10 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
panic(fmt.Sprintf("unknown node: %+v", node)) panic(fmt.Sprintf("unknown node: %+v", node))
} }
// Iterate over the children, and request all unknown ones // Iterate over the children, and request all unknown ones
requests := make([]*nodeRequest, 0, len(children)) var (
missing = make(chan *nodeRequest, len(children))
pending sync.WaitGroup
)
for _, child := range children { for _, child := range children {
// Notify any external watcher of a new key/value node // Notify any external watcher of a new key/value node
if req.callback != nil { if req.callback != nil {
@ -433,19 +437,36 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
if s.membatch.hasNode(child.path) { if s.membatch.hasNode(child.path) {
continue continue
} }
// If database says duplicate, then at least the trie node is present // Check the presence of children concurrently
// and we hold the assumption that it's NOT legacy contract code. pending.Add(1)
chash := common.BytesToHash(node) go func(child childNode) {
if rawdb.HasTrieNode(s.database, chash) { defer pending.Done()
continue
} // If database says duplicate, then at least the trie node is present
// Locally unknown node, schedule for retrieval // and we hold the assumption that it's NOT legacy contract code.
requests = append(requests, &nodeRequest{ chash := common.BytesToHash(node)
path: child.path, if rawdb.HasTrieNode(s.database, chash) {
hash: chash, return
parent: req, }
callback: req.callback, // Locally unknown node, schedule for retrieval
}) missing <- &nodeRequest{
path: child.path,
hash: chash,
parent: req,
callback: req.callback,
}
}(child)
}
}
pending.Wait()
requests := make([]*nodeRequest, 0, len(children))
for done := false; !done; {
select {
case miss := <-missing:
requests = append(requests, miss)
default:
done = true
} }
} }
return requests, nil return requests, nil