eth/protocols/snap: skip healing if the storage trie is already complete

This commit is contained in:
Gary Rong 2023-10-19 16:47:04 +08:00
parent 7e41beed18
commit a155a06dff
3 changed files with 25 additions and 3 deletions

View file

@ -42,4 +42,12 @@ var (
// boundaryAccountNodesGauge is the metric to track how many boundary trie // boundaryAccountNodesGauge is the metric to track how many boundary trie
// nodes in storage tries are met. // nodes in storage tries are met.
boundaryStorageNodesGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/boundary/storage", nil) boundaryStorageNodesGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/boundary/storage", nil)
// smallStorageGauge is the metric to track how many storages are retrieved
// in a single request.
smallStorageGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/small", nil)
// largeStorageGauge is the metric to track how many storages are large enough
// to retrieved concurrently.
largeStorageGauge = metrics.NewRegisteredGauge("eth/protocols/snap/sync/storage/large", nil)
) )

View file

@ -2014,6 +2014,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
if res.subTask == nil && res.mainTask.needState[j] && (i < len(res.hashes)-1 || !res.cont) { if res.subTask == nil && res.mainTask.needState[j] && (i < len(res.hashes)-1 || !res.cont) {
res.mainTask.needState[j] = false res.mainTask.needState[j] = false
res.mainTask.pend-- res.mainTask.pend--
smallStorageGauge.Inc(1)
} }
// If the last contract was chunked, mark it as needing healing // If the last contract was chunked, mark it as needing healing
// to avoid writing it out to disk prematurely. // to avoid writing it out to disk prematurely.
@ -2049,7 +2050,11 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
log.Debug("Chunked large contract", "initiators", len(keys), "tail", lastKey, "chunks", chunks) log.Debug("Chunked large contract", "initiators", len(keys), "tail", lastKey, "chunks", chunks)
} }
r := newHashRange(lastKey, chunks) r := newHashRange(lastKey, chunks)
if chunks == 1 {
smallStorageGauge.Inc(1)
} else {
largeStorageGauge.Inc(1)
}
// Our first task is the one that was just filled by this response. // Our first task is the one that was just filled by this response.
batch := ethdb.HookedBatch{ batch := ethdb.HookedBatch{
Batch: s.db.NewBatch(), Batch: s.db.NewBatch(),
@ -2187,7 +2192,16 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
// Large contracts could have generated new trie nodes, flush them to disk // Large contracts could have generated new trie nodes, flush them to disk
if res.subTask != nil { if res.subTask != nil {
if res.subTask.done { if res.subTask.done {
res.subTask.genTrie.Commit() root := res.subTask.genTrie.Commit()
accountHash := res.accounts[len(res.accounts)-1]
if root == res.subTask.root && rawdb.HasStorageTrieNode(s.db, accountHash, nil, root) {
// If the chunk's root is an overflown but full delivery, clear the heal request
for i, account := range res.mainTask.res.hashes {
if account == accountHash {
res.mainTask.needHeal[i] = false
}
}
}
} }
if res.subTask.genBatch.ValueSize() > ethdb.IdealBatchSize || res.subTask.done { if res.subTask.genBatch.ValueSize() > ethdb.IdealBatchSize || res.subTask.done {
if err := res.subTask.genBatch.Write(); err != nil { if err := res.subTask.genBatch.Write(); err != nil {

View file

@ -1871,7 +1871,7 @@ func verifyTrie(scheme string, db ethdb.KeyValueStore, root common.Hash, t *test
// TestSyncAccountPerformance tests how efficient the snap algo is at minimizing // TestSyncAccountPerformance tests how efficient the snap algo is at minimizing
// state healing // state healing
func TestSyncAccountPerformance(t *testing.T) { func TestSyncAccountPerformance(t *testing.T) {
t.SkipNow() t.Parallel()
testSyncAccountPerformance(t, rawdb.HashScheme) testSyncAccountPerformance(t, rawdb.HashScheme)
testSyncAccountPerformance(t, rawdb.PathScheme) testSyncAccountPerformance(t, rawdb.PathScheme)