trie: make commit use channel for insert + leaf callbacks

This commit is contained in:
Martin Holst Swende 2019-12-17 23:14:24 +01:00
parent 4a0a205589
commit 3c8ec1b569
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
3 changed files with 49 additions and 17 deletions

@ -1 +1 @@
Subproject commit b5eb9900ee2147b40d3e681fe86efa4fd693959a Subproject commit 25f480521dae1937841bbcb034e862c4dfd53256

View file

@ -25,10 +25,17 @@ import (
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
) )
type Leaf struct {
size int
hash common.Hash
node node
}
type hasher struct { type hasher struct {
tmp sliceBuffer tmp sliceBuffer
sha keccakState sha keccakState
onleaf LeafCallback onleaf LeafCallback
leafCh chan *Leaf
} }
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
@ -178,16 +185,37 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) {
if hash == nil { if hash == nil {
hash = h.makeHashNode(h.tmp) hash = h.makeHashNode(h.tmp)
} }
if db != nil { if db != nil {
h.leafCh <- &Leaf{
size: len(h.tmp),
hash: common.BytesToHash(hash),
node: n,
}
}
return hash, nil
}
func (h *hasher) makeHashNode(data []byte) hashNode {
n := make(hashNode, h.sha.Size())
h.sha.Reset()
h.sha.Write(data)
h.sha.Read(n)
return n
}
// commitLoop does the actual insert + leaf callback for nodes
func (h *hasher) commitLoop(db *Database, wg *sync.WaitGroup) {
defer wg.Done()
for item := range h.leafCh {
var (
hash = item.hash
size = item.size
n = item.node
)
// We are pooling the trie nodes into an intermediate memory cache // We are pooling the trie nodes into an intermediate memory cache
hash := common.BytesToHash(hash)
db.lock.Lock() db.lock.Lock()
db.insert(hash, len(h.tmp), n) db.insert(hash, size, n)
db.lock.Unlock() db.lock.Unlock()
// Track external references from account->storage trie
if h.onleaf != nil { if h.onleaf != nil {
switch n := n.(type) { switch n := n.(type) {
case *shortNode: case *shortNode:
@ -203,13 +231,4 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) {
} }
} }
} }
return hash, nil
}
func (h *hasher) makeHashNode(data []byte) hashNode {
n := make(hashNode, h.sha.Size())
h.sha.Reset()
h.sha.Write(data)
h.sha.Read(n)
return n
} }

View file

@ -20,6 +20,7 @@ package trie
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"sync"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -415,7 +416,18 @@ func (t *Trie) Commit(onleaf LeafCallback) (root common.Hash, err error) {
if t.db == nil { if t.db == nil {
panic("commit called on trie with nil database") panic("commit called on trie with nil database")
} }
hash, cached, err := t.hashRoot(t.db, onleaf) if t.root == nil {
return emptyRoot, nil
}
h := newHasher(onleaf)
h.leafCh = make(chan *Leaf, 200) // arbitrary number
defer returnHasherToPool(h)
var wg sync.WaitGroup
wg.Add(1)
go h.commitLoop(t.db, &wg)
hash, cached, err := h.hash(t.root, t.db, true)
close(h.leafCh)
wg.Wait()
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
@ -431,3 +443,4 @@ func (t *Trie) hashRoot(db *Database, onleaf LeafCallback) (node, node, error) {
defer returnHasherToPool(h) defer returnHasherToPool(h)
return h.hash(t.root, db, true) return h.hash(t.root, db, true)
} }