trie: polish the changes

This commit is contained in:
Gary Rong 2024-09-19 11:24:15 +08:00
parent b4db8bacdf
commit ed692c19b6
3 changed files with 13 additions and 92 deletions

View file

@ -18,7 +18,6 @@ package trie
import ( import (
"fmt" "fmt"
"runtime"
"sync" "sync"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -115,36 +114,13 @@ func (c *committer) commit(path []byte, n node, topmost bool) (node, []*wrapNode
} }
} }
type task struct {
node node
index int
path []byte
}
// commitChildren commits the children of the given fullnode // commitChildren commits the children of the given fullnode
func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) ([17]node, []*wrapNode) { func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) ([17]node, []*wrapNode) {
var ( var (
wg sync.WaitGroup wg sync.WaitGroup
children [17]node children [17]node
results [16][]*wrapNode results [16][]*wrapNode
tasks = make(chan task)
) )
if parallel {
worker := func() {
defer wg.Done()
for t := range tasks {
children[t.index], results[t.index] = c.commit(t.path, t.node, false)
}
}
threads := runtime.NumCPU()
if threads > 16 {
threads = 16
}
for i := 0; i < threads; i++ {
wg.Add(1)
go worker()
}
}
for i := 0; i < 16; i++ { for i := 0; i < 16; i++ {
child := n.Children[i] child := n.Children[i]
if child == nil { if child == nil {
@ -163,15 +139,14 @@ func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) ([17
if !parallel { if !parallel {
children[i], results[i] = c.commit(append(path, byte(i)), child, false) children[i], results[i] = c.commit(append(path, byte(i)), child, false)
} else { } else {
tasks <- task{ wg.Add(1)
index: i, go func(index int) {
node: child, defer wg.Done()
path: append(path, byte(i)), children[index], results[index] = c.commit(append(path, byte(index)), child, false)
} }(i)
} }
} }
if parallel { if parallel {
close(tasks)
wg.Wait() wg.Wait()
} }
// For the 17th child, it's possible the type is valuenode. // For the 17th child, it's possible the type is valuenode.
@ -215,7 +190,6 @@ func (c *committer) store(path []byte, n node) (node, *wrapNode) {
path: string(path), path: string(path),
node: trienode.New(nhash, nodeToBytes(n)), node: trienode.New(nhash, nodeToBytes(n)),
} }
// Collect the corresponding leaf node if it's required. We don't check // Collect the corresponding leaf node if it's required. We don't check
// full node since it's impossible to store value in fullNode. The key // full node since it's impossible to store value in fullNode. The key
// length of leaves should be exactly same.. // length of leaves should be exactly same..
@ -227,7 +201,6 @@ func (c *committer) store(path []byte, n node) (node, *wrapNode) {
} }
} }
} }
return hash, wNode return hash, wNode
} }

View file

@ -37,24 +37,13 @@ import (
// //
// Trie is not safe for concurrent use. // Trie is not safe for concurrent use.
type Trie struct { type Trie struct {
root node root node
owner common.Hash owner common.Hash
committed bool // The Flag whether the commit operation is already performed
// Flag whether the commit operation is already performed. If so the reader *trieReader // The handler trie can retrieve nodes from
// trie is not usable(latest states is invisible). tracer *tracer // The tool to track the trie changes
committed bool mutate int // The number of trie mutations that have been performed
hashed int // The number of mutations that have been hashed
// reader is the handler trie can retrieve nodes from.
reader *trieReader
// tracer is the tool to track the trie changes.
tracer *tracer
// The number of trie mutations that have been performed
mutate int
// The number of mutations that have been hashed
hashed int
} }
// newFlag returns the cache flag value for a newly created node. // newFlag returns the cache flag value for a newly created node.
@ -311,7 +300,6 @@ func (t *Trie) Update(key, value []byte) error {
} }
func (t *Trie) update(key, value []byte) error { func (t *Trie) update(key, value []byte) error {
t.mutate++
k := keybytesToHex(key) k := keybytesToHex(key)
if len(value) != 0 { if len(value) != 0 {
_, n, err := t.insert(t.root, nil, k, valueNode(value)) _, n, err := t.insert(t.root, nil, k, valueNode(value))
@ -645,6 +633,7 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) {
for _, path := range t.tracer.deletedNodes() { for _, path := range t.tracer.deletedNodes() {
nodes.AddNode(path, trienode.NewDeleted()) nodes.AddNode(path, trienode.NewDeleted())
} }
// If the number of changes is below 100, we let one thread handle it
t.root = newCommitter(nodes, t.tracer, collectLeaf, t.mutate > 100).Commit(t.root) t.root = newCommitter(nodes, t.tracer, collectLeaf, t.mutate > 100).Commit(t.root)
t.mutate = 0 t.mutate = 0
return rootHash, nodes return rootHash, nodes

View file

@ -35,7 +35,6 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/internal/testrand"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/trienode"
"github.com/holiman/uint256" "github.com/holiman/uint256"
@ -1207,43 +1206,3 @@ func FuzzTrie(f *testing.F) {
} }
}) })
} }
func BenchmarkCommit(b *testing.B) {
benchmarkCommit(b, 500)
benchmarkCommit(b, 1000)
benchmarkCommit(b, 2000)
benchmarkCommit(b, 5000)
}
func benchmarkCommit(b *testing.B, n int) {
b.Run(fmt.Sprintf("commit-%vnodes-single", n), func(b *testing.B) {
testCommit(b, n, false)
})
b.Run(fmt.Sprintf("commit-%vnodes-parallel", n), func(b *testing.B) {
testCommit(b, n, true)
})
}
func testCommit(b *testing.B, n int, parallel bool) {
// test 10 times to get a better average
N := 10
tries := make([]*Trie, N)
for i := 0; i < N; i++ {
tries[i] = NewEmpty(nil)
for j := 0; j < n; j++ {
key := testrand.Bytes(32)
val := testrand.Bytes(32)
tries[i].Update(key, val)
}
tries[i].Hash()
if !parallel {
tries[i].mutate = 0
}
}
b.ResetTimer()
for i := 0; i < 10; i++ {
tries[i].Commit(true)
}
}