Commit 9b09c0fc authored by Martin Holst Swende's avatar Martin Holst Swende Committed by Péter Szilágyi

* trie: utilize callbacks instead of amassing lists in ref/unref (#20529)

* trie/tests: add benchmarks and update trie tests

* trie: update benchmark tests

* trie: utilize callbacks instead of amassing lists of hashes in database ref/unref

* trie: replace remaining non-callback based accesses
parent 770316dc
...@@ -180,35 +180,31 @@ func (n *cachedNode) obj(hash common.Hash) node { ...@@ -180,35 +180,31 @@ func (n *cachedNode) obj(hash common.Hash) node {
return expandNode(hash[:], n.node) return expandNode(hash[:], n.node)
} }
// childs returns all the tracked children of this node, both the implicit ones // forChilds invokes the callback for all the tracked children of this node,
// from inside the node as well as the explicit ones from outside the node. // both the implicit ones from inside the node as well as the explicit ones
func (n *cachedNode) childs() []common.Hash { //from outside the node.
children := make([]common.Hash, 0, 16) func (n *cachedNode) forChilds(onChild func(hash common.Hash)) {
for child := range n.children { for child := range n.children {
children = append(children, child) onChild(child)
} }
if _, ok := n.node.(rawNode); !ok { if _, ok := n.node.(rawNode); !ok {
gatherChildren(n.node, &children) forGatherChildren(n.node, onChild)
} }
return children
} }
// gatherChildren traverses the node hierarchy of a collapsed storage node and // forGatherChildren traverses the node hierarchy of a collapsed storage node and
// retrieves all the hashnode children. // invokes the callback for all the hashnode children.
func gatherChildren(n node, children *[]common.Hash) { func forGatherChildren(n node, onChild func(hash common.Hash)) {
switch n := n.(type) { switch n := n.(type) {
case *rawShortNode: case *rawShortNode:
gatherChildren(n.Val, children) forGatherChildren(n.Val, onChild)
case rawFullNode: case rawFullNode:
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
gatherChildren(n[i], children) forGatherChildren(n[i], onChild)
} }
case hashNode: case hashNode:
*children = append(*children, common.BytesToHash(n)) onChild(common.BytesToHash(n))
case valueNode, nil: case valueNode, nil:
default: default:
panic(fmt.Sprintf("unknown node type: %T", n)) panic(fmt.Sprintf("unknown node type: %T", n))
} }
...@@ -334,11 +330,11 @@ func (db *Database) insert(hash common.Hash, blob []byte, node node) { ...@@ -334,11 +330,11 @@ func (db *Database) insert(hash common.Hash, blob []byte, node node) {
size: uint16(len(blob)), size: uint16(len(blob)),
flushPrev: db.newest, flushPrev: db.newest,
} }
for _, child := range entry.childs() { entry.forChilds(func(child common.Hash) {
if c := db.dirties[child]; c != nil { if c := db.dirties[child]; c != nil {
c.parents++ c.parents++
} }
} })
db.dirties[hash] = entry db.dirties[hash] = entry
// Update the flush-list endpoints // Update the flush-list endpoints
...@@ -570,9 +566,9 @@ func (db *Database) dereference(child common.Hash, parent common.Hash) { ...@@ -570,9 +566,9 @@ func (db *Database) dereference(child common.Hash, parent common.Hash) {
db.dirties[node.flushNext].flushPrev = node.flushPrev db.dirties[node.flushNext].flushPrev = node.flushPrev
} }
// Dereference all children and delete the node // Dereference all children and delete the node
for _, hash := range node.childs() { node.forChilds(func(hash common.Hash) {
db.dereference(hash, child) db.dereference(hash, child)
} })
delete(db.dirties, child) delete(db.dirties, child)
db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size)) db.dirtiesSize -= common.StorageSize(common.HashLength + int(node.size))
if node.children != nil { if node.children != nil {
...@@ -766,10 +762,14 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane ...@@ -766,10 +762,14 @@ func (db *Database) commit(hash common.Hash, batch ethdb.Batch, uncacher *cleane
if !ok { if !ok {
return nil return nil
} }
for _, child := range node.childs() { var err error
if err := db.commit(child, batch, uncacher); err != nil { node.forChilds(func(child common.Hash) {
return err if err == nil {
err = db.commit(child, batch, uncacher)
} }
})
if err != nil {
return err
} }
if err := batch.Put(hash[:], node.rlp()); err != nil { if err := batch.Put(hash[:], node.rlp()); err != nil {
return err return err
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment