Merge pull request #25694 from karalabe/concurrent-heal-check
trie: check childrens' existence concurrently for snap heal
This commit is contained in:
commit
d408cb6fba
57
trie/sync.go
57
trie/sync.go
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user