Bound peering AS-path map and swap it instead of copying #16

Merged
clawbot merged 1 commits from issue-10-bound-peering-map into next 2026-09-21 16:01:09 +02:00
Collaborator

Part of the memory work in #3;
implements #10.

The peering handler kept every distinct AS path of the last 30 minutes in
memory (measured over a million entries) and every 30 seconds copied the
whole map and re-recorded every peering in the window, driving a large heap
sawtooth and near-continuous database writes.

Changes, all in internal/routewatch/peeringhandler.go:

  • processPeerings swaps the path map for a fresh empty one under the lock
    instead of copying it, so each path is processed exactly once and the
    memory is released every run. Stored results are unchanged because
    RecordPeering upserts last_seen.
  • A new distinct path is dropped once the map holds maxTrackedPaths
    (500000) entries; the running drop count is logged with each run. There
    is no per-handler metrics sink, so the run log is where it surfaces.
  • The 30-minute time prune and its ticker are removed; the swap makes them
    dead code. The map mutex drops from RWMutex to Mutex since the read
    path is gone.

Tests (internal/routewatch/peeringhandler_test.go): a run empties the
map; the same path seen before and after a run is recorded in both runs;
the cap drops and counts new paths while refreshing an already-tracked
path.

Disclosure: host make check cannot complete here because the host
golangci-lint is built with Go 1.25 and the host Go toolchain is 1.26,
which makes it panic on any package in this module. The gate was run as the
repo's authoritative Docker build (script/cibuild), whose pinned lint
stage matches the toolchain; it is green.

Model: opus-4-8

Part of the memory work in https://git.eeqj.de/sneak/routewatch/issues/3; implements https://git.eeqj.de/sneak/routewatch/issues/10. The peering handler kept every distinct AS path of the last 30 minutes in memory (measured over a million entries) and every 30 seconds copied the whole map and re-recorded every peering in the window, driving a large heap sawtooth and near-continuous database writes. Changes, all in `internal/routewatch/peeringhandler.go`: - `processPeerings` swaps the path map for a fresh empty one under the lock instead of copying it, so each path is processed exactly once and the memory is released every run. Stored results are unchanged because `RecordPeering` upserts `last_seen`. - A new distinct path is dropped once the map holds `maxTrackedPaths` (500000) entries; the running drop count is logged with each run. There is no per-handler metrics sink, so the run log is where it surfaces. - The 30-minute time prune and its ticker are removed; the swap makes them dead code. The map mutex drops from `RWMutex` to `Mutex` since the read path is gone. Tests (`internal/routewatch/peeringhandler_test.go`): a run empties the map; the same path seen before and after a run is recorded in both runs; the cap drops and counts new paths while refreshing an already-tracked path. Disclosure: host `make check` cannot complete here because the host `golangci-lint` is built with Go 1.25 and the host Go toolchain is 1.26, which makes it panic on any package in this module. The gate was run as the repo's authoritative Docker build (`script/cibuild`), whose pinned lint stage matches the toolchain; it is green. Model: opus-4-8
clawbot added the needs-review label 2026-09-21 15:11:17 +02:00
clawbot self-assigned this 2026-09-21 15:11:17 +02:00
clawbot added 1 commit 2026-09-21 15:11:17 +02:00
processPeerings now takes the accumulated AS-path map under the lock and
replaces it with a fresh empty one, so each path is processed once and the
map never grows past a single 30-second interval's traffic. HandleMessage
stops adding new paths once maxTrackedPaths (500000) is reached and counts
the drops, which are logged with each run. The 30-minute prune and its
ticker are removed as dead code under the swap, and the map mutex drops
from RWMutex to Mutex since the read path is gone. RecordPeering already
upserts last_seen, so stored peerings are unchanged.

Model: opus-4-8
Author
Collaborator

PASS — the map swap (no copy) under the lock, the maxTrackedPaths (500000) cap that drops and counts new paths, and removal of the 30-minute prune and its ticker all satisfy #10 and its definition of done; the three tests genuinely fail when the swap or the cap is broken, and the branch rebased onto the current next head is green.

Disclosure: host make check cannot run here (host golangci-lint panics on the Go 1.26 toolchain), so gating used the repo's authoritative Docker build with the lint and test stages forced to re-execute.

Model: opus-4-8

PASS — the map swap (no copy) under the lock, the `maxTrackedPaths` (500000) cap that drops and counts new paths, and removal of the 30-minute prune and its ticker all satisfy https://git.eeqj.de/sneak/routewatch/issues/10 and its definition of done; the three tests genuinely fail when the swap or the cap is broken, and the branch rebased onto the current `next` head is green. Disclosure: host `make check` cannot run here (host `golangci-lint` panics on the Go 1.26 toolchain), so gating used the repo's authoritative Docker build with the lint and test stages forced to re-execute. Model: opus-4-8
clawbot removed the needs-review label 2026-09-21 15:55:05 +02:00
clawbot merged commit 211fdad9c0 into next 2026-09-21 16:01:09 +02:00
clawbot deleted branch issue-10-bound-peering-map 2026-09-21 16:01:09 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/routewatch#16