@@ -22,6 +22,7 @@ import (
2222 "fmt"
2323 "maps"
2424 "slices"
25+ "sync"
2526 "time"
2627
2728 "github.com/ethereum/go-ethereum/common"
@@ -447,8 +448,9 @@ func (t *SizeTracker) build(root common.Hash, blockNumber uint64, done chan buil
447448 return nil
448449 })
449450
451+ // Storage table is huge, iterate in parallel
450452 group .Go (func () error {
451- count , bytes , err := t .iterateTable (t .abort , rawdb .SnapshotStoragePrefix , "storage" )
453+ count , bytes , err := t .iterateTableParallel (t .abort , rawdb .SnapshotStoragePrefix , "storage" )
452454 if err != nil {
453455 return err
454456 }
@@ -465,8 +467,9 @@ func (t *SizeTracker) build(root common.Hash, blockNumber uint64, done chan buil
465467 return nil
466468 })
467469
470+ // Storage trienode table is huge, iterate in parallel
468471 group .Go (func () error {
469- count , bytes , err := t .iterateTable (t .abort , rawdb .TrieNodeStoragePrefix , "storagenode" )
472+ count , bytes , err := t .iterateTableParallel (t .abort , rawdb .TrieNodeStoragePrefix , "storagenode" )
470473 if err != nil {
471474 return err
472475 }
@@ -531,6 +534,7 @@ func (t *SizeTracker) iterateTable(closed chan struct{}, prefix []byte, name str
531534 logged = time .Now ()
532535 count , bytes int64
533536 )
537+
534538 iter := t .db .NewIterator (prefix , nil )
535539 defer iter .Release ()
536540
@@ -560,6 +564,44 @@ func (t *SizeTracker) iterateTable(closed chan struct{}, prefix []byte, name str
560564 return count , bytes , nil
561565}
562566
567+ // iterateTableParallel performs parallel iteration over a table by splitting into hex ranges
568+ // For storage tables, it splits on the first byte of the account hash (after the prefix)
569+ func (t * SizeTracker ) iterateTableParallel (closed chan struct {}, prefix []byte , name string ) (int64 , int64 , error ) {
570+ var (
571+ start = time .Now ()
572+ workers = 16
573+ totalCount int64
574+ totalBytes int64
575+ group errgroup.Group
576+ mu sync.Mutex
577+ )
578+ group .SetLimit (workers )
579+
580+ log .Info ("Starting parallel state iteration" , "category" , name , "workers" , workers )
581+
582+ for i := 0 ; i < 256 ; i ++ {
583+ h := byte (i )
584+ group .Go (func () error {
585+ count , bytes , err := t .iterateTable (closed , slices .Concat (prefix , []byte {h }), fmt .Sprintf ("%s-%x" , name , h ))
586+ if err != nil {
587+ return err
588+ }
589+ mu .Lock ()
590+ totalCount += count
591+ totalBytes += bytes
592+ mu .Unlock ()
593+ return nil
594+ })
595+ }
596+
597+ if err := group .Wait (); err != nil {
598+ return 0 , 0 , err
599+ }
600+
601+ log .Info ("Finished parallel state iteration" , "category" , name , "count" , totalCount , "size" , common .StorageSize (totalBytes ), "elapsed" , common .PrettyDuration (time .Since (start )))
602+ return totalCount , totalBytes , nil
603+ }
604+
563605func (t * SizeTracker ) upload (stats SizeStats ) {
564606 log .Debug ("Uploading state size" , "number" , stats .BlockNumber , "root" , stats .StateRoot , "stat" , stats )
565607 blockInfoGauge .Update (metrics.GaugeInfoValue {
0 commit comments