trie: cache collapsed tries node, not rlp blobs (#16876)
The current trie memory database/cache that we do pruning on stores trie nodes as binary rlp encoded blobs, and also stores the node relationships/references for GC purposes. However, most of the trie nodes (everything apart from a value node) is in essence just a collection of references. This PR switches out the RLP encoded trie blobs with the collapsed-but-not-serialized trie nodes. This permits most of the references to be recovered from within the node data structure, avoiding the need to track them a second time (expensive memory wise).
This commit is contained in:
committed by
Felix Lange
parent
8db8d074e2
commit
d926bf2c7e
@@ -137,9 +137,6 @@ func (h *hasher) hashChildren(original node, db *Database) (node, node, error) {
|
||||
return original, original, err
|
||||
}
|
||||
}
|
||||
if collapsed.Val == nil {
|
||||
collapsed.Val = valueNode(nil) // Ensure that nil children are encoded as empty strings.
|
||||
}
|
||||
return collapsed, cached, nil
|
||||
|
||||
case *fullNode:
|
||||
@@ -152,14 +149,9 @@ func (h *hasher) hashChildren(original node, db *Database) (node, node, error) {
|
||||
if err != nil {
|
||||
return original, original, err
|
||||
}
|
||||
} else {
|
||||
collapsed.Children[i] = valueNode(nil) // Ensure that nil children are encoded as empty strings.
|
||||
}
|
||||
}
|
||||
cached.Children[16] = n.Children[16]
|
||||
if collapsed.Children[16] == nil {
|
||||
collapsed.Children[16] = valueNode(nil)
|
||||
}
|
||||
return collapsed, cached, nil
|
||||
|
||||
default:
|
||||
@@ -192,34 +184,22 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) {
|
||||
|
||||
if db != nil {
|
||||
// We are pooling the trie nodes into an intermediate memory cache
|
||||
db.lock.Lock()
|
||||
hash := common.BytesToHash(hash)
|
||||
db.insert(hash, h.tmp)
|
||||
// Track all direct parent->child node references
|
||||
switch n := n.(type) {
|
||||
case *shortNode:
|
||||
if child, ok := n.Val.(hashNode); ok {
|
||||
db.reference(common.BytesToHash(child), hash)
|
||||
}
|
||||
case *fullNode:
|
||||
for i := 0; i < 16; i++ {
|
||||
if child, ok := n.Children[i].(hashNode); ok {
|
||||
db.reference(common.BytesToHash(child), hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
db.lock.Lock()
|
||||
db.insert(hash, h.tmp, n)
|
||||
db.lock.Unlock()
|
||||
|
||||
// Track external references from account->storage trie
|
||||
if h.onleaf != nil {
|
||||
switch n := n.(type) {
|
||||
case *shortNode:
|
||||
if child, ok := n.Val.(valueNode); ok && child != nil {
|
||||
if child, ok := n.Val.(valueNode); ok {
|
||||
h.onleaf(child, hash)
|
||||
}
|
||||
case *fullNode:
|
||||
for i := 0; i < 16; i++ {
|
||||
if child, ok := n.Children[i].(valueNode); ok && child != nil {
|
||||
if child, ok := n.Children[i].(valueNode); ok {
|
||||
h.onleaf(child, hash)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user