trie: make db insert use size instead of full data, update tests

This commit is contained in:
Martin Holst Swende 2019-12-17 22:57:37 +01:00
parent 2a9d1e7067
commit 7cc9b10ed6
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
3 changed files with 30 additions and 10 deletions

View file

@ -314,24 +314,24 @@ func (db *Database) InsertBlob(hash common.Hash, blob []byte) {
db.lock.Lock() db.lock.Lock()
defer db.lock.Unlock() defer db.lock.Unlock()
db.insert(hash, blob, rawNode(blob)) db.insert(hash, len(blob), rawNode(blob))
} }
// insert inserts a collapsed trie node into the memory database. This method is // insert inserts a collapsed trie node into the memory database. This method is
// a more generic version of InsertBlob, supporting both raw blob insertions as // a more generic version of InsertBlob, supporting both raw blob insertions as
// well ex trie node insertions. The blob must always be specified to allow proper // well ex trie node insertions. The blob size must be specified to allow proper
// size tracking. // size tracking.
func (db *Database) insert(hash common.Hash, blob []byte, node node) { func (db *Database) insert(hash common.Hash, size int, node node) {
// If the node's already cached, skip // If the node's already cached, skip
if _, ok := db.dirties[hash]; ok { if _, ok := db.dirties[hash]; ok {
return return
} }
memcacheDirtyWriteMeter.Mark(int64(len(blob))) memcacheDirtyWriteMeter.Mark(int64(size))
// Create the cached entry for this node // Create the cached entry for this node
entry := &cachedNode{ entry := &cachedNode{
node: simplifyNode(node), node: simplifyNode(node),
size: uint16(len(blob)), size: uint16(size),
flushPrev: db.newest, flushPrev: db.newest,
} }
for _, child := range entry.childs() { for _, child := range entry.childs() {

View file

@ -184,7 +184,7 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) {
hash := common.BytesToHash(hash) hash := common.BytesToHash(hash)
db.lock.Lock() db.lock.Lock()
db.insert(hash, h.tmp, n) db.insert(hash, len(h.tmp), n)
db.lock.Unlock() db.lock.Unlock()
// Track external references from account->storage trie // Track external references from account->storage trie

View file

@ -512,14 +512,34 @@ func BenchmarkHash(b *testing.B) {
trie.Hash() trie.Hash()
} }
type account struct {
Nonce uint64
Balance *big.Int
Root common.Hash
Code []byte
}
// Benchmarks the trie Commit following a Hash. Since the trie caches the result of any operation, // Benchmarks the trie Commit following a Hash. Since the trie caches the result of any operation,
// we cannot use b.N as the number of hashing rouns, since all rounds apart from // we cannot use b.N as the number of hashing rouns, since all rounds apart from
// the first one will be NOOP. As such, we'll use b.N as the number of account to // the first one will be NOOP. As such, we'll use b.N as the number of account to
// insert into the trie before measuring the hashing. // insert into the trie before measuring the hashing.
func BenchmarkCommitAfterHash(b *testing.B) { func BenchmarkCommitAfterHash(b *testing.B) {
b.Run("no-onleaf", func(b *testing.B) {
benchmarkCommitAfterHash(b, nil)
})
onleaf := func(leaf []byte, parent common.Hash) error {
var a account
rlp.DecodeBytes(leaf, &a)
return nil
}
b.Run("with-onleaf", func(b *testing.B) {
benchmarkCommitAfterHash(b, onleaf)
})
}
func benchmarkCommitAfterHash(b *testing.B, onleaf LeafCallback) {
// Make the random benchmark deterministic // Make the random benchmark deterministic
random := rand.New(rand.NewSource(0)) random := rand.New(rand.NewSource(0))
// Create a realistic account trie to hash // Create a realistic account trie to hash
addresses := make([][20]byte, b.N) addresses := make([][20]byte, b.N)
for i := 0; i < len(addresses); i++ { for i := 0; i < len(addresses); i++ {
@ -535,17 +555,17 @@ func BenchmarkCommitAfterHash(b *testing.B) {
root = emptyRoot root = emptyRoot
code = crypto.Keccak256(nil) code = crypto.Keccak256(nil)
) )
accounts[i], _ = rlp.EncodeToBytes([]interface{}{nonce, balance, root, code}) accounts[i], _ = rlp.EncodeToBytes(&account{nonce, balance, root, code})
} }
// Insert the accounts into the trie and hash it
trie := newEmpty() trie := newEmpty()
for i := 0; i < len(addresses); i++ { for i := 0; i < len(addresses); i++ {
trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i]) trie.Update(crypto.Keccak256(addresses[i][:]), accounts[i])
} }
// Insert the accounts into the trie and hash it
trie.Hash() trie.Hash()
b.ResetTimer() b.ResetTimer()
b.ReportAllocs() b.ReportAllocs()
trie.Commit(nil) trie.Commit(onleaf)
} }
func tempDB() (string, *Database) { func tempDB() (string, *Database) {