@@ -20,6 +20,7 @@ import (
2020 "sync"
2121
2222 "github.com/ava-labs/libevm/common"
23+ "github.com/ava-labs/libevm/libevm/options"
2324 "github.com/ava-labs/libevm/log"
2425 "github.com/ava-labs/libevm/metrics"
2526)
@@ -49,9 +50,11 @@ type triePrefetcher struct {
4950 storageDupMeter metrics.Meter
5051 storageSkipMeter metrics.Meter
5152 storageWasteMeter metrics.Meter
53+
54+ options []PrefetcherOption
5255}
5356
54- func newTriePrefetcher (db Database , root common.Hash , namespace string ) * triePrefetcher {
57+ func newTriePrefetcher (db Database , root common.Hash , namespace string , opts ... PrefetcherOption ) * triePrefetcher {
5558 prefix := triePrefetchMetricsPrefix + namespace
5659 p := & triePrefetcher {
5760 db : db ,
@@ -67,6 +70,8 @@ func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePre
6770 storageDupMeter : metrics .GetOrRegisterMeter (prefix + "/storage/dup" , nil ),
6871 storageSkipMeter : metrics .GetOrRegisterMeter (prefix + "/storage/skip" , nil ),
6972 storageWasteMeter : metrics .GetOrRegisterMeter (prefix + "/storage/waste" , nil ),
73+
74+ options : opts ,
7075 }
7176 return p
7277}
@@ -99,6 +104,7 @@ func (p *triePrefetcher) close() {
99104 }
100105 }
101106 }
107+ p .releaseWorkerPools ()
102108 // Clear out all fetchers (will crash on a second call, deliberate)
103109 p .fetchers = nil
104110}
@@ -122,6 +128,8 @@ func (p *triePrefetcher) copy() *triePrefetcher {
122128 storageDupMeter : p .storageDupMeter ,
123129 storageSkipMeter : p .storageSkipMeter ,
124130 storageWasteMeter : p .storageWasteMeter ,
131+
132+ options : p .options ,
125133 }
126134 // If the prefetcher is already a copy, duplicate the data
127135 if p .fetches != nil {
@@ -150,7 +158,7 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm
150158 id := p .trieID (owner , root )
151159 fetcher := p .fetchers [id ]
152160 if fetcher == nil {
153- fetcher = newSubfetcher (p .db , p .root , owner , root , addr )
161+ fetcher = newSubfetcher (p .db , p .root , owner , root , addr , p . options ... )
154162 p .fetchers [id ] = fetcher
155163 }
156164 fetcher .schedule (keys )
@@ -226,11 +234,13 @@ type subfetcher struct {
226234 seen map [string ]struct {} // Tracks the entries already loaded
227235 dups int // Number of duplicate preload tasks
228236 used [][]byte // Tracks the entries used in the end
237+
238+ pool * subfetcherPool
229239}
230240
231241// newSubfetcher creates a goroutine to prefetch state items belonging to a
232242// particular root hash.
233- func newSubfetcher (db Database , state common.Hash , owner common.Hash , root common.Hash , addr common.Address ) * subfetcher {
243+ func newSubfetcher (db Database , state common.Hash , owner common.Hash , root common.Hash , addr common.Address , opts ... PrefetcherOption ) * subfetcher {
234244 sf := & subfetcher {
235245 db : db ,
236246 state : state ,
@@ -243,6 +253,7 @@ func newSubfetcher(db Database, state common.Hash, owner common.Hash, root commo
243253 copy : make (chan chan Trie ),
244254 seen : make (map [string ]struct {}),
245255 }
256+ options .As [prefetcherConfig ](opts ... ).applyTo (sf )
246257 go sf .loop ()
247258 return sf
248259}
@@ -294,7 +305,10 @@ func (sf *subfetcher) abort() {
294305// out of tasks or its underlying trie is retrieved for committing.
295306func (sf * subfetcher ) loop () {
296307 // No matter how the loop stops, signal anyone waiting that it's terminated
297- defer close (sf .term )
308+ defer func () {
309+ sf .pool .wait ()
310+ close (sf .term )
311+ }()
298312
299313 // Start by opening the trie and stop processing if it fails
300314 if sf .owner == (common.Hash {}) {
@@ -325,14 +339,14 @@ func (sf *subfetcher) loop() {
325339 sf .lock .Unlock ()
326340
327341 // Prefetch any tasks until the loop is interrupted
328- for i , task := range tasks {
342+ for _ , task := range tasks {
329343 select {
330- case <- sf . stop :
331- // If termination is requested, add any leftover back and return
332- sf .lock . Lock ()
333- sf . tasks = append ( sf . tasks , tasks [ i :] ... )
334- sf . lock . Unlock ()
335- return
344+ //libevm:start
345+ //
346+ // The <- sf.stop case has been removed, in keeping with the equivalent change below. Future geth
347+ // versions also remove it so our modification here can be undone when merging upstream.
348+ //
349+ //libevm:end
336350
337351 case ch := <- sf .copy :
338352 // Somebody wants a copy of the current trie, grant them
@@ -344,9 +358,9 @@ func (sf *subfetcher) loop() {
344358 sf .dups ++
345359 } else {
346360 if len (task ) == common .AddressLength {
347- sf .trie .GetAccount (common .BytesToAddress (task ))
361+ sf .pool .GetAccount (common .BytesToAddress (task ))
348362 } else {
349- sf .trie .GetStorage (sf .addr , task )
363+ sf .pool .GetStorage (sf .addr , task )
350364 }
351365 sf .seen [string (task )] = struct {}{}
352366 }
@@ -358,8 +372,26 @@ func (sf *subfetcher) loop() {
358372 ch <- sf .db .CopyTrie (sf .trie )
359373
360374 case <- sf .stop :
361- // Termination is requested, abort and leave remaining tasks
362- return
375+ //libevm:start
376+ //
377+ // This is copied, with alteration, from ethereum/go-ethereum#29519
378+ // and can be deleted once we update to include that change.
379+
380+ // Termination is requested, abort if no more tasks are pending. If
381+ // there are some, exhaust them first.
382+ sf .lock .Lock ()
383+ done := len (sf .tasks ) == 0
384+ sf .lock .Unlock ()
385+
386+ if done {
387+ return
388+ }
389+
390+ select {
391+ case sf .wake <- struct {}{}:
392+ default :
393+ }
394+ //libevm:end
363395 }
364396 }
365397}
0 commit comments