Store a new prefix's earliest timestamp as first_seen (closes #112)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
A batch's prefix times were taken from each peer's last update for the prefix, and the latest of those was kept. The prefix tables hold only first_seen, written when the prefix is new, so a prefix announced by two peers seconds apart in one batch was stored first seen at the later time, and the IP lookup could answer with a first_seen after the route's last_seen. The flush now keeps, for each prefix, the earliest timestamp among all of the batch's updates for it. Model: opus-5-5
This commit is contained in:
@@ -347,8 +347,19 @@ func (h *PrefixHandler) flushBatch() {
|
||||
|
||||
lastUpdates := make(map[prefixAndPeer]prefixUpdate)
|
||||
|
||||
// Each prefix the batch names, announced or withdrawn, with the earliest
|
||||
// timestamp among all of its updates, not only each peer's last one: the
|
||||
// prefix tables store only first_seen, written when the prefix is new and
|
||||
// never changed after.
|
||||
prefixesToUpdate := make(map[string]time.Time)
|
||||
|
||||
for _, update := range batch {
|
||||
lastUpdates[prefixAndPeer{update.prefix, update.peer}] = update
|
||||
|
||||
seen, exists := prefixesToUpdate[update.prefix]
|
||||
if !exists || update.timestamp.Before(seen) {
|
||||
prefixesToUpdate[update.prefix] = update.timestamp
|
||||
}
|
||||
}
|
||||
|
||||
// Collect routes to upsert and delete
|
||||
@@ -357,16 +368,7 @@ func (h *PrefixHandler) flushBatch() {
|
||||
routesToDelete []database.LiveRouteDeletion
|
||||
)
|
||||
|
||||
// Collect unique prefixes to update
|
||||
prefixesToUpdate := make(map[string]time.Time)
|
||||
|
||||
for _, update := range lastUpdates {
|
||||
// Track prefix for both announcements and withdrawals
|
||||
seen, exists := prefixesToUpdate[update.prefix]
|
||||
if !exists || update.timestamp.After(seen) {
|
||||
prefixesToUpdate[update.prefix] = update.timestamp
|
||||
}
|
||||
|
||||
// An announcement is stored when its path gives an origin, or when it
|
||||
// ends in an AS set of several members: that route is stored with
|
||||
// origin 0 (none). An announcement with an empty path is not stored.
|
||||
|
||||
@@ -83,6 +83,52 @@ func TestPrefixHandlerStoresPrefixesTheIPLookupFinds(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPrefixHandlerStoresANewPrefixFirstSeenAtItsEarliestUpdate announces a
|
||||
// prefix the database does not hold yet twice in one batch, the second time 5
|
||||
// seconds after the first, through the prefix handler into a real database. The
|
||||
// prefix is stored first seen at the time of the first announcement, whether
|
||||
// the two come from two peers or from one, and the IP lookup answers with that
|
||||
// time.
|
||||
func TestPrefixHandlerStoresANewPrefixFirstSeenAtItsEarliestUpdate(
|
||||
t *testing.T,
|
||||
) {
|
||||
t.Parallel()
|
||||
|
||||
const (
|
||||
otherPeerIP = "2001:db8:ffff::2"
|
||||
secondAfter = 5 * time.Second
|
||||
)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
firstPeer, secondPeer string
|
||||
}{
|
||||
{name: "two peers", firstPeer: testPeerIP, secondPeer: otherPeerIP},
|
||||
{name: "one peer", firstPeer: testPeerIP, secondPeer: testPeerIP},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
first := peerAnnouncement(tt.firstPeer, testV4Prefix)
|
||||
second := peerAnnouncement(tt.secondPeer, testV4Prefix)
|
||||
second.ParsedTimestamp = first.ParsedTimestamp.Add(secondAfter)
|
||||
db := handleBatches(t, [][]*ristypes.RISMessage{{first, second}})
|
||||
|
||||
info, err := db.GetIPInfo("192.0.2.1")
|
||||
if err != nil {
|
||||
t.Fatalf("GetIPInfo(192.0.2.1): %v", err)
|
||||
}
|
||||
|
||||
if !info.FirstSeen.Equal(first.ParsedTimestamp) {
|
||||
t.Errorf("first_seen of %s = %s, want %s", testV4Prefix,
|
||||
info.FirstSeen, first.ParsedTimestamp)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestPrefixHandlerAppliesEachPeersLastUpdateInABatch runs updates for one
|
||||
// prefix through the prefix handler into a real database. All updates carry the
|
||||
// same timestamp, as updates within one second of the feed do. Within a batch,
|
||||
|
||||
Reference in New Issue
Block a user