check / check (push) Canceled after 0s
The prefix handler ran one PeerDown per peer, one after another. When the sessions of several peers went down together, their walks queued up. A returning full-table peer's messages stayed held back while the walks ahead of its own ran, and could reach the limit of 20,000. The table's PeersDown now takes several peers out of every prefix in one walk. One walk runs at a time. The next one takes every peer whose session went down since the previous one began. The doc of maxHeldBackMessages says how long a peer's messages are held back. The limit is now 150,000 messages, about 150 MiB. The status page shows how many messages each handler holds back. Model: opus-5-5
70 lines
1.4 KiB
Go
70 lines
1.4 KiB
Go
package routetable
|
|
|
|
import (
|
|
"net/netip"
|
|
"runtime"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestPeersDownLetsReadsIn reads the table's counts again and again while a
|
|
// peer that carries more than two batches of prefixes goes down. PeersDown lets
|
|
// the lock go after every walkBatch prefixes, so a read must get in while the
|
|
// peer still carries some of its prefixes but no longer all.
|
|
func TestPeersDownLetsReadsIn(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const (
|
|
asn = 1000
|
|
peer = "192.0.2.1"
|
|
// prefixCount is more prefixes than two of walkBatch.
|
|
prefixCount = 2*walkBatch + 1
|
|
)
|
|
|
|
routeTime := time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC)
|
|
table := New(Params{})
|
|
addr := netip.MustParseAddr("1.0.0.0")
|
|
|
|
for range prefixCount {
|
|
prefix := netip.PrefixFrom(addr, addr.BitLen())
|
|
table.Announce(prefix, asn, Route{Peer: peer, Time: routeTime})
|
|
|
|
addr = addr.Next()
|
|
}
|
|
|
|
// Hold a read lock until PeersDown waits for the lock, so that the first
|
|
// read below starts once PeersDown holds it. TryRLock fails once a writer
|
|
// waits.
|
|
table.mu.RLock()
|
|
|
|
peerDownDone := make(chan struct{})
|
|
|
|
go func() {
|
|
defer close(peerDownDone)
|
|
|
|
table.PeersDown([]string{peer})
|
|
}()
|
|
|
|
for table.mu.TryRLock() {
|
|
table.mu.RUnlock()
|
|
runtime.Gosched()
|
|
}
|
|
|
|
table.mu.RUnlock()
|
|
|
|
for {
|
|
routes := table.Counts().IPv4Routes
|
|
if routes > 0 && routes < prefixCount {
|
|
break
|
|
}
|
|
|
|
select {
|
|
case <-peerDownDone:
|
|
t.Fatal("no read got in while PeersDown ran")
|
|
default:
|
|
}
|
|
}
|
|
|
|
<-peerDownDone
|
|
}
|