check / check (push) Canceled after 0s
The prefix handler ran one PeerDown per peer, one after another, and stopped taking messages at 20,000 held-back messages. Sessions going down together queued up their walks, so a returning full-table peer could reach that limit. 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 meanwhile, so a message is held back for two walks at most. Each walk takes about 2.6 seconds for each full-table peer it takes out. The limit is now 150,000 messages, about 150 MiB: enough when four full-table peers go down together. 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
|
|
}
|