Record origin changes and show them on the prefix page (closes #161)
check / check (push) Successful in 1m3s
check / check (push) Successful in 1m3s
The routing table records a row each time a prefix and origin AS gets its first peer (announced) or loses its last (withdrawn), with the time and how many peers carry the prefix just after. The prefix handler writes the rows to a new origin_changes table, apart from routes. Every hour the database maintainer keeps each prefix's rows from the last 72 hours or its newest 500, whichever keeps more. The prefix page lists them newest first, at most 5,000. At most 100,000 rows wait in memory to be written; past that the oldest are dropped and logged. A stop loses the rows past its last write. Model: deepseek-v4-pro (implementation); opus-5-5 (commit message)
This commit was merged in pull request #231.
This commit is contained in:
@@ -2,7 +2,9 @@
|
||||
// and origin AS, it keeps the peers whose current route to the prefix has that
|
||||
// origin AS. It also keeps the two newest of those routes in full. It applies
|
||||
// announcements, withdrawals and peers' sessions going down. It answers the
|
||||
// route reads that the pages and the API need.
|
||||
// route reads that the pages and the API need. It also records each prefix and
|
||||
// origin AS pair's origin changes: when it gains its first peer and when it
|
||||
// loses its last.
|
||||
package routetable
|
||||
|
||||
import (
|
||||
@@ -91,6 +93,9 @@ type Params struct {
|
||||
// peer not in it gets the next number above all of them the first time it
|
||||
// announces a route.
|
||||
PeerNumbers map[string]uint
|
||||
// Now returns the time RouteWatch applies a change at. It is time.Now
|
||||
// unless a test gives one.
|
||||
Now func() time.Time
|
||||
}
|
||||
|
||||
// Table is the routing table. Its methods are safe for concurrent use.
|
||||
@@ -126,11 +131,24 @@ type Table struct {
|
||||
// originsWithoutKeptRoute counts the origins that peers carry but that
|
||||
// keep no route.
|
||||
originsWithoutKeptRoute int
|
||||
|
||||
// now returns the time RouteWatch applies a change at.
|
||||
now func() time.Time
|
||||
// originChanges holds the origin changes that wait to be written, oldest
|
||||
// first. originChangesDropped counts those dropped since the last
|
||||
// TakeOriginChanges.
|
||||
originChanges []OriginChange
|
||||
originChangesDropped int
|
||||
}
|
||||
|
||||
// New returns an empty table that numbers new peers on from
|
||||
// params.PeerNumbers.
|
||||
func New(params Params) *Table {
|
||||
now := params.Now
|
||||
if now == nil {
|
||||
now = time.Now
|
||||
}
|
||||
|
||||
t := &Table{
|
||||
ipv4: newFamily(ipv4Bits, minLookupMaskLengthV4),
|
||||
ipv6: newFamily(ipv6Bits, minLookupMaskLengthV6),
|
||||
@@ -139,6 +157,7 @@ func New(params Params) *Table {
|
||||
peerAddresses: make(map[uint]string, len(params.PeerNumbers)),
|
||||
newPeers: make(map[string]uint),
|
||||
changed: make(map[pair]struct{}),
|
||||
now: now,
|
||||
keptTimes: btree.NewG(keptTimesDegree, func(a, b keptTime) bool {
|
||||
return a.time.Before(b.time)
|
||||
}),
|
||||
@@ -268,8 +287,9 @@ func (t *Table) PeersDown(peers []string) {
|
||||
// Load puts one prefix and origin AS pair that the database holds into the
|
||||
// table, as startup does with each row it reads. The change's peers join the
|
||||
// pair's peer set, and its routes are kept as an announcement's would be.
|
||||
// Unlike an update, Load records no change, so TakeChanges does not hand the
|
||||
// pair back to be written again. Loading a pair twice changes nothing.
|
||||
// Unlike an update, Load records no change and no origin change, so
|
||||
// TakeChanges does not hand the pair back to be written again. Loading a pair
|
||||
// twice changes nothing.
|
||||
//
|
||||
// The caller makes sure that every peer change names, in its peer set or in
|
||||
// its routes, has a number in Params.PeerNumbers.
|
||||
@@ -460,6 +480,7 @@ func (t *Table) removeOrigin(prefix netip.Prefix, o *origin) {
|
||||
// r in full when it is one of the two newest routes of o. The peer's earlier
|
||||
// route, if o keeps one, is replaced: it is no longer the peer's current route.
|
||||
// The pair is recorded as changed only when its peer set or kept routes change.
|
||||
// When r is the origin's first peer, an announced origin change is recorded.
|
||||
func (t *Table) join(prefix netip.Prefix, o *origin, r route) {
|
||||
if slices.ContainsFunc(o.routes, r.equal) {
|
||||
// The peer announced its kept route again.
|
||||
@@ -469,6 +490,8 @@ func (t *Table) join(prefix netip.Prefix, o *origin, r route) {
|
||||
wasWithoutKeptRoute := o.withoutKeptRoute()
|
||||
|
||||
joined := !o.peers.Test(r.peer)
|
||||
|
||||
firstPeer := joined && o.peers.None()
|
||||
if joined {
|
||||
o.peers.Set(r.peer)
|
||||
|
||||
@@ -482,6 +505,10 @@ func (t *Table) join(prefix netip.Prefix, o *origin, r route) {
|
||||
if joined || dropped || kept {
|
||||
t.recordChange(prefix, o, wasWithoutKeptRoute)
|
||||
}
|
||||
|
||||
if firstPeer {
|
||||
t.recordOriginChange(prefix, o.asn, true, t.prefixPeerCount(prefix))
|
||||
}
|
||||
}
|
||||
|
||||
// leave takes peer out of the peer set of o, an origin of prefix, and drops
|
||||
@@ -540,7 +567,8 @@ func (t *Table) dropKeptRoute(o *origin, peer uint) bool {
|
||||
// recordChange records that the pair of prefix and the AS of o changed, and
|
||||
// brings the count of origins without a kept route up to date.
|
||||
// wasWithoutKeptRoute says whether o was such an origin before the change. An
|
||||
// origin that no peer carries any more is removed.
|
||||
// origin that no peer carries any more is removed, and a withdrawn origin
|
||||
// change is recorded.
|
||||
func (t *Table) recordChange(
|
||||
prefix netip.Prefix, o *origin, wasWithoutKeptRoute bool,
|
||||
) {
|
||||
@@ -549,6 +577,7 @@ func (t *Table) recordChange(
|
||||
t.countOriginWithoutKeptRoute(o, wasWithoutKeptRoute)
|
||||
|
||||
if o.peers.None() {
|
||||
t.recordOriginChange(prefix, o.asn, false, t.prefixPeerCount(prefix))
|
||||
t.removeOrigin(prefix, o)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user