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 ( import (
"errors" "errors"
"sync"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -367,29 +368,29 @@ func (sf *subfetcher) loop() {
return return
} }
var tasks []*subfetcherTask work := make(chan *subfetcherTask)
// Adding a default case to the select statement would spin the for loop so go func() {
// we instead have a `work` channel signaller. A necessary invariant is that var wg sync.WaitGroup
// 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:
}
}
for { for {
select { select {
case ts := <-sf.tasks: case tasks := <-sf.tasks:
addTasks(ts) wg.Add(1)
go func() {
defer wg.Done()
for _, t := range tasks {
work <- t
}
}()
case <-work: case <-sf.stop:
for _, task := range tasks { wg.Wait() // guarantee of no more sends on `work`
close(work)
return
}
}
}()
for task := range work {
if task.addr != nil { if task.addr != nil {
key := *task.addr key := *task.addr
if task.read { 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
}
}
}
} }