refactor: simplify select to exclude task handling

This commit is contained in:
Arran Schlosberg 2024-11-27 10:38:43 +00:00
parent ed463c1ba2
commit 86da86c4ac
No known key found for this signature in database
GPG key ID: 5DD5567C12C5F312

View file

@ -18,6 +18,7 @@ package state
import (
"errors"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
@ -367,29 +368,29 @@ func (sf *subfetcher) loop() {
return
}
var tasks []*subfetcherTask
// Adding a default case to the select statement would spin the for loop so
// we instead have a `work` channel signaller. A necessary invariant is that
// there is a buffered item i.f.f. there are tasks; therefore only
// addTasks() may append to the above slice and only the <-work branch may
// deplete it.
work := make(chan struct{}, 1)
defer close(work)
addTasks := func(ts []*subfetcherTask) {
tasks = append(tasks, ts...)
select {
case work <- struct{}{}:
default:
}
}
work := make(chan *subfetcherTask)
go func() {
var wg sync.WaitGroup
for {
select {
case ts := <-sf.tasks:
addTasks(ts)
case tasks := <-sf.tasks:
wg.Add(1)
go func() {
defer wg.Done()
for _, t := range tasks {
work <- t
}
}()
case <-work:
for _, task := range tasks {
case <-sf.stop:
wg.Wait() // guarantee of no more sends on `work`
close(work)
return
}
}
}()
for task := range work {
if task.addr != nil {
key := *task.addr
if task.read {
@ -452,21 +453,4 @@ func (sf *subfetcher) loop() {
}
}
}
tasks = tasks[:0] // avoid reallocation
case <-sf.stop:
// Termination is requested, abort if no more tasks are pending. If
// there are some, exhaust them first.
if len(tasks) > 0 {
// See earlier invariant that guarantees a receive on `work` to clear `tasks`.
continue
}
select {
case ts := <-sf.tasks:
addTasks(ts)
default:
return
}
}
}
}