mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 09:51:36 +00:00
BinaryTrie.Commit unconditionally walked every resolved in-memory node
and flushed it into the NodeSet, producing one Pebble write per resolved
internal + stem node on every block — even when the node's on-disk blob
was bitwise identical to the previous commit. On a warm 400M-state
workload this meant tens of thousands of redundant 65-byte writes per
block, compounding Pebble compaction pressure on every commit.
The existing mustRecompute flag tracks hash staleness, not disk-blob
staleness: after Hash() completes, mustRecompute is cleared even though
the fresh blob has not been persisted. It is therefore insufficient for
a skip-flush optimization.
This change mirrors MPT's committer pattern (trie/committer.go:51-56)
by adding a dirty flag on InternalNode and StemNode with the semantics
"the on-disk blob is stale". The flag is:
- set to true wherever the node is created or structurally modified
(the same call sites that already set mustRecompute = true),
- set to false only after the node has been passed to the flushfn
inside CollectNodes,
- left false on nodes produced by DeserializeNodeWithHash, matching
the "loaded from disk, already persisted" semantics.
CollectNodes short-circuits on !dirty subtrees; the propagation
invariant (an ancestor of any dirty node is itself dirty) is already
maintained by the existing InsertValuesAtStem / Insert paths, which now
mirror every mustRecompute = true setter with a dirty = true setter.
Serialization format, hash computation, state root, and the pathdb
write path are untouched. Empty NodeSets are already tolerated by
triedb/pathdb.writeNodes.
BenchmarkCollectNodes_SparseWrite (10,000-stem trie, one-leaf
modification + Commit per iteration, Apple M4 Pro):
before 12,653,000 ns/op 107,224,740 B/op 80,953 allocs/op
after 7,336 ns/op 37,774 B/op 134 allocs/op
speedup: ~1,725x memory: ~2,839x less allocs: ~604x fewer
End-to-end impact on a benchmarked geth build depends on workload;
the new TestBinaryTrieCommitIncremental provides a structural
regression guard.
|
||
|---|---|---|
| .. | ||
| bintrie | ||
| transitiontrie | ||
| trienode | ||
| bytepool.go | ||
| committer.go | ||
| database_test.go | ||
| encoding.go | ||
| encoding_test.go | ||
| errors.go | ||
| hasher.go | ||
| inspect.go | ||
| inspect_test.go | ||
| iterator.go | ||
| iterator_test.go | ||
| levelstats.go | ||
| levelstats_test.go | ||
| list_hasher.go | ||
| node.go | ||
| node_enc.go | ||
| node_test.go | ||
| proof.go | ||
| proof_test.go | ||
| secure_trie.go | ||
| secure_trie_test.go | ||
| stacktrie.go | ||
| stacktrie_fuzzer_test.go | ||
| stacktrie_test.go | ||
| sync.go | ||
| sync_test.go | ||
| tracer.go | ||
| tracer_test.go | ||
| trie.go | ||
| trie_id.go | ||
| trie_reader.go | ||
| trie_test.go | ||