p2p/discover: remove hot-spin in table refresh trigger (#32912)
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run

This fixes a regression introduced in #32518. In that PR, we removed the
slowdown logic that would throttle lookups when the table runs empty.
Said logic was originally added in #20389.

Usually it's fine, but there exist pathological cases, such as hive
tests, where the node can only discover one other node, so it can only
ever query that node and won't get any results. In cases like these, we
need to throttle the creation of lookups to avoid crazy CPU usage.
This commit is contained in:
Felix Lange 2025-10-15 11:51:33 +02:00 committed by GitHub
parent 40505a9bc0
commit 7c107c2691
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -153,6 +153,7 @@ type lookupIterator struct {
cancel func()
lookup *lookup
tabRefreshing <-chan struct{}
lastLookup time.Time
}
type lookupFunc func(ctx context.Context) *lookup
@ -185,6 +186,9 @@ func (it *lookupIterator) Next() bool {
return false
}
if it.lookup == nil {
// Ensure enough time has passed between lookup creations.
it.slowdown()
it.lookup = it.nextLookup(it.ctx)
if it.lookup.empty() {
// If the lookup is empty right after creation, it means the local table
@ -235,6 +239,25 @@ func (it *lookupIterator) lookupFailed(tab *Table, timeout time.Duration) {
tab.waitForNodes(tout, 1)
}
// slowdown applies a delay between creating lookups. This exists to prevent hot-spinning
// in some test environments where lookups don't yield any results.
func (it *lookupIterator) slowdown() {
const minInterval = 1 * time.Second
now := time.Now()
diff := now.Sub(it.lastLookup)
it.lastLookup = now
if diff > minInterval {
return
}
wait := time.NewTimer(diff)
defer wait.Stop()
select {
case <-wait.C:
case <-it.ctx.Done():
}
}
// Close ends the iterator.
func (it *lookupIterator) Close() {
it.cancel()