check / check (push) Canceled after 57s
The prune test gains a third prefix with more than 500 rows newer than 72 hours, and checks every newer row survives and every older one is deleted, in a helper shared by the three prefixes. The prefix page test uses an origin AS the routing table does not carry. README's limit list says the routing table drops the oldest waiting origin changes past 100,000, and the prefix page entry says the page shows at most the newest 5,000. The tests read 5,000 and 100,000 from named limits instead of bare numbers, so the routing table's waiting cap is now exported for them. Model: deepseek-v4-pro
104 lines
3.0 KiB
Go
104 lines
3.0 KiB
Go
package routetable
|
|
|
|
import (
|
|
"net/netip"
|
|
"slices"
|
|
"time"
|
|
)
|
|
|
|
// MaxWaitingOriginChanges is the most origin changes the table keeps waiting
|
|
// for the prefix handler to write. The oldest change past it is dropped and
|
|
// counted.
|
|
const MaxWaitingOriginChanges = 100000
|
|
|
|
// OriginChange is one change of a prefix and origin AS pair: the origin AS
|
|
// gained its first peer, or lost its last.
|
|
type OriginChange struct {
|
|
Prefix netip.Prefix
|
|
OriginASN int
|
|
// Announced says the origin AS gained its first peer. When false, it
|
|
// lost its last peer.
|
|
Announced bool
|
|
// PeerCount is how many peers carry the prefix just after the change,
|
|
// counting every origin AS.
|
|
PeerCount int
|
|
// Time is when RouteWatch applied the change.
|
|
Time time.Time
|
|
}
|
|
|
|
// recordOriginChange records that the pair of prefix and asn gained its first
|
|
// peer, when announced, or lost its last, when not. The caller holds the lock.
|
|
// peerCount is how many peers carry the prefix just after the change.
|
|
func (t *Table) recordOriginChange(
|
|
prefix netip.Prefix, asn int, announced bool, peerCount int,
|
|
) {
|
|
change := OriginChange{
|
|
Prefix: prefix,
|
|
OriginASN: asn,
|
|
Announced: announced,
|
|
PeerCount: peerCount,
|
|
Time: t.now(),
|
|
}
|
|
|
|
t.originChanges = append(t.originChanges, change)
|
|
t.trimOriginChanges()
|
|
}
|
|
|
|
// TakeOriginChanges returns at most limit of the origin changes that wait to
|
|
// be written, oldest first, and how many were dropped since the last call. It
|
|
// then forgets what it returned.
|
|
func (t *Table) TakeOriginChanges(limit int) ([]OriginChange, int) {
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
|
|
n := min(limit, len(t.originChanges))
|
|
changes := slices.Clone(t.originChanges[:n])
|
|
t.originChanges = t.originChanges[n:]
|
|
|
|
dropped := t.originChangesDropped
|
|
t.originChangesDropped = 0
|
|
|
|
return changes, dropped
|
|
}
|
|
|
|
// PutBackOriginChanges records again what one TakeOriginChanges call returned,
|
|
// for a caller that could not write it. The next TakeOriginChanges returns
|
|
// those changes first, before the ones that arrived since. The oldest changes
|
|
// past the cap are dropped and counted.
|
|
func (t *Table) PutBackOriginChanges(changes []OriginChange) {
|
|
t.mu.Lock()
|
|
defer t.mu.Unlock()
|
|
|
|
t.originChanges = append(changes, t.originChanges...)
|
|
t.trimOriginChanges()
|
|
}
|
|
|
|
// trimOriginChanges drops the oldest origin changes past the cap and counts
|
|
// them. The caller holds the lock.
|
|
func (t *Table) trimOriginChanges() {
|
|
if extra := len(t.originChanges) - MaxWaitingOriginChanges; extra > 0 {
|
|
t.originChangesDropped += extra
|
|
t.originChanges = t.originChanges[extra:]
|
|
}
|
|
}
|
|
|
|
// OriginChangeCount returns how many origin changes wait for TakeOriginChanges.
|
|
func (t *Table) OriginChangeCount() int {
|
|
t.mu.RLock()
|
|
defer t.mu.RUnlock()
|
|
|
|
return len(t.originChanges)
|
|
}
|
|
|
|
// prefixPeerCount returns how many peers carry prefix, counting every origin
|
|
// AS. The caller holds the lock.
|
|
func (t *Table) prefixPeerCount(prefix netip.Prefix) int {
|
|
count := 0
|
|
|
|
for _, o := range t.origins(prefix) {
|
|
count += int(o.peers.Count())
|
|
}
|
|
|
|
return count
|
|
}
|