forked from cerc-io/plugeth
trie: while fast syncing, don't keep trie nodes in memory (#3186)
This commit is contained in:
parent
437c1e40b2
commit
f8608a5228
32
trie/sync.go
32
trie/sync.go
@ -31,9 +31,9 @@ var ErrNotRequested = errors.New("not requested")
|
|||||||
|
|
||||||
// request represents a scheduled or already in-flight state retrieval request.
|
// request represents a scheduled or already in-flight state retrieval request.
|
||||||
type request struct {
|
type request struct {
|
||||||
hash common.Hash // Hash of the node data content to retrieve
|
hash common.Hash // Hash of the node data content to retrieve
|
||||||
data []byte // Data content of the node, cached until all subtrees complete
|
data []byte // Data content of the node, cached until all subtrees complete
|
||||||
object *node // Target node to populate with retrieved data (hashnode originally)
|
raw bool // Whether this is a raw entry (code) or a trie node
|
||||||
|
|
||||||
parents []*request // Parent state nodes referencing this entry (notify all upon completion)
|
parents []*request // Parent state nodes referencing this entry (notify all upon completion)
|
||||||
depth int // Depth level within the trie the node is located to prioritise DFS
|
depth int // Depth level within the trie the node is located to prioritise DFS
|
||||||
@ -86,9 +86,7 @@ func (s *TrieSync) AddSubTrie(root common.Hash, depth int, parent common.Hash, c
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Assemble the new sub-trie sync request
|
// Assemble the new sub-trie sync request
|
||||||
node := node(hashNode(root.Bytes()))
|
|
||||||
req := &request{
|
req := &request{
|
||||||
object: &node,
|
|
||||||
hash: root,
|
hash: root,
|
||||||
depth: depth,
|
depth: depth,
|
||||||
callback: callback,
|
callback: callback,
|
||||||
@ -120,6 +118,7 @@ func (s *TrieSync) AddRawEntry(hash common.Hash, depth int, parent common.Hash)
|
|||||||
// Assemble the new sub-trie sync request
|
// Assemble the new sub-trie sync request
|
||||||
req := &request{
|
req := &request{
|
||||||
hash: hash,
|
hash: hash,
|
||||||
|
raw: true,
|
||||||
depth: depth,
|
depth: depth,
|
||||||
}
|
}
|
||||||
// If this sub-trie has a designated parent, link them together
|
// If this sub-trie has a designated parent, link them together
|
||||||
@ -152,7 +151,7 @@ func (s *TrieSync) Process(results []SyncResult) (int, error) {
|
|||||||
return i, ErrNotRequested
|
return i, ErrNotRequested
|
||||||
}
|
}
|
||||||
// If the item is a raw entry request, commit directly
|
// If the item is a raw entry request, commit directly
|
||||||
if request.object == nil {
|
if request.raw {
|
||||||
request.data = item.Data
|
request.data = item.Data
|
||||||
s.commit(request, nil)
|
s.commit(request, nil)
|
||||||
continue
|
continue
|
||||||
@ -162,11 +161,10 @@ func (s *TrieSync) Process(results []SyncResult) (int, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
*request.object = node
|
|
||||||
request.data = item.Data
|
request.data = item.Data
|
||||||
|
|
||||||
// Create and schedule a request for all the children nodes
|
// Create and schedule a request for all the children nodes
|
||||||
requests, err := s.children(request)
|
requests, err := s.children(request, node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
@ -203,27 +201,25 @@ func (s *TrieSync) schedule(req *request) {
|
|||||||
|
|
||||||
// children retrieves all the missing children of a state trie entry for future
|
// children retrieves all the missing children of a state trie entry for future
|
||||||
// retrieval scheduling.
|
// retrieval scheduling.
|
||||||
func (s *TrieSync) children(req *request) ([]*request, error) {
|
func (s *TrieSync) children(req *request, object node) ([]*request, 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 child struct {
|
||||||
node *node
|
node node
|
||||||
depth int
|
depth int
|
||||||
}
|
}
|
||||||
children := []child{}
|
children := []child{}
|
||||||
|
|
||||||
switch node := (*req.object).(type) {
|
switch node := (object).(type) {
|
||||||
case *shortNode:
|
case *shortNode:
|
||||||
node = node.copy() // Prevents linking all downloaded nodes together.
|
|
||||||
children = []child{{
|
children = []child{{
|
||||||
node: &node.Val,
|
node: node.Val,
|
||||||
depth: req.depth + len(node.Key),
|
depth: req.depth + len(node.Key),
|
||||||
}}
|
}}
|
||||||
case *fullNode:
|
case *fullNode:
|
||||||
node = node.copy()
|
|
||||||
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, child{
|
||||||
node: &node.Children[i],
|
node: node.Children[i],
|
||||||
depth: req.depth + 1,
|
depth: req.depth + 1,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -236,23 +232,21 @@ func (s *TrieSync) children(req *request) ([]*request, error) {
|
|||||||
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 {
|
||||||
if node, ok := (*child.node).(valueNode); ok {
|
if node, ok := (child.node).(valueNode); ok {
|
||||||
if err := req.callback(node, req.hash); err != nil {
|
if err := req.callback(node, req.hash); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the child references another node, resolve or schedule
|
// If the child references another node, resolve or schedule
|
||||||
if node, ok := (*child.node).(hashNode); ok {
|
if node, ok := (child.node).(hashNode); ok {
|
||||||
// Try to resolve the node from the local database
|
// Try to resolve the node from the local database
|
||||||
blob, _ := s.database.Get(node)
|
blob, _ := s.database.Get(node)
|
||||||
if local, err := decodeNode(node[:], blob, 0); local != nil && err == nil {
|
if local, err := decodeNode(node[:], blob, 0); local != nil && err == nil {
|
||||||
*child.node = local
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Locally unknown node, schedule for retrieval
|
// Locally unknown node, schedule for retrieval
|
||||||
requests = append(requests, &request{
|
requests = append(requests, &request{
|
||||||
object: child.node,
|
|
||||||
hash: common.BytesToHash(node),
|
hash: common.BytesToHash(node),
|
||||||
parents: []*request{req},
|
parents: []*request{req},
|
||||||
depth: child.depth,
|
depth: child.depth,
|
||||||
|
Loading…
Reference in New Issue
Block a user