perf: known_routes retention, digest identity, and a working batched reconfirm - #98
Merged
MrAlders0n merged 8 commits intoAug 12, 2026
Merged
Conversation
Member
Author
446564
approved these changes
Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What this PR does
known_routeshas no retention — nothing ever deletes from it. The MeshMapper deployment hit 32M rows / 28 GB in 24 days and the hourlyReconfirmRoutesseq-scans the whole table, which had grown to 31 minutes per run — a core pinned for half of every hour, getting worse every day.Three changes:
Retention. Routes age out
routes.retention(default 14d) afterlast_seen; routes seen fewer thanmin_observationstimes only getroutes.grace(7d) — that noise floor matters because a single flood packet mints a dozen one-off rows that are never observed again. New observations bumplast_seen, so routes the mesh still uses never expire. All configurable, documented in config.yaml.example.Route identity is a 16-byte digest now. The unique key was the whole ordered
UUID[], so a 10-hop route cost ~380 bytes of index per entry. Migration 024 rebuilds the table keyed on(iata, path_key)wherepath_keyis an md5 ofnode_ids(Go and SQL compute it identically; there's a test pinning both to the same vector).idstays for the API, just unindexed.Reconfirm is batched, and the ambiguity check actually works. The old check compared 1–3 byte hop prefixes against the 4-byte
prefix_4column — bytea equality needs equal length, so it has never matched a row. It's now length-aware against a pre-aggregated ambiguous-prefix set, and each tick checks the 750K least-recently-confirmed rows instead of everything, so the cost stays flat as the table grows. The retention delete runs in the same task right before it, so the table's two writers never overlap.Numbers from my prod after deploying:
Notes for upgrading
The migration copies every row — it bakes in no retention policy, so your configured (or default) values apply on the first tick after startup. The copy is the startup cost: ~38 minutes at 34M rows on my box, proportionally less on smaller tables. Once it commits there's no going back to the old binary (the old unique index is gone), so take a backup first.
Expect route counts to drop after the first few ticks: expired and genuinely-ambiguous routes get removed for the first time (about 5% of surviving rows here were stale entries the broken check should have been evicting all along).