Repository navigation
perf(net): lite-07 announce streams cost each claim change, not every claim held - #8397
Conversation
Quest-Claim: b446b493d518a29d
…oute's claims A subscriber found a duplicate ANNOUNCE_START by scanning the route's live claims, and a publisher scanned them for withheld claims on every floor. Key the live claims by path and count the withheld ones instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ish the show-cost quest session_announce sweeps the broadcasts a publisher already announces and the viewers reading them. The quest's cause was the lite-07 announce stream, not Router::show, so the quest is done. Also links the node-creation-order quest, which main left unlinked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 16 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed head: 5767f82
Base: ac3cb8c
No actionable findings. The subscriber's path index preserves duplicate-path rejection and removes entries on both claim and route teardown. The publisher's withheld count covers insertions, replacements, removals, and mounted-source withdrawal; its upstream/proxy predicate is fixed for the answer's lifetime, so the cached count preserves the prior floor-filtering behavior.
Direction: removing the two announce-stream scans targets the observed cost without redesigning the already-incremental router. The new benchmark excludes room setup and waits for every viewer's announce and withdrawal, sweeping held broadcasts and viewers independently.
Limits: GitHub-only source review, including surrounding lifecycle code, decoder retirement, existing tests, and benchmark wiring. I did not run tests or benchmarks or reproduce the reported speedups. GitHub Check was in progress when inspected; the PR also reports local full-check failures outside this diff, which I have not independently reproduced.
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Subscriber path index:
WireRoute::claimsbecomesBTreeMap<Path, u64>, so a duplicate path under a route is one lookup rather than a scan of every claim the route holds;end,RouteEnd, and teardown were updated to match, and the decoder's order-independent retirement keeps path-order iteration equivalent to the old ID order. - Publisher withheld count:
Sentnow maintainswithheldthroughSent::set, which replaces both directclaimsmutation sites and folds insert, replace, and remove into one adjustment;floorreads the count instead of scanning, with thelinkfixed for the answer's lifetime andclaimsonly touched throughset. - New
session_announcebench: one announce plus withdrawal beside many held broadcasts, awaited at every viewer, swept over broadcasts held and viewers and run on a per-cell runtime with setup excluded from the sample;Cluster._originsis exposed asoriginsfor it. - Quest finish:
show-cost.mdis deleted, its epic bullet is replaced, andnode-creation-order.mdis linked (the file exists on the branch, and noshow-costreference remains in the tree).
I traced the counter through every mutation path and the duplicate check through start/end/RouteEnd and found no behavioral difference from the removed scans. The only gap worth noting is non-blocking: no test pins Floor.revision when a claim is withheld (existing assertions use ..), so a future regression there would be silent.
deepseek-v4.1-flash-1017 (free via Pullfrog for OSS) | 𝕏

Finishes quest/m2/cluster-routing/routes/show-cost.md.
Problem
moq-dev/moq#8352 measured moq-lite-07 session setup at 4096 broadcasts at about 5x moq-lite-06's CPU. It blamed
Router::show. That diagnosis was wrong. Re-measured on main after moq-dev/moq#8374, the router is already incremental. The quadratic work sits in the lite-07 announce stream:lite/subscriber/routed.rs) checks every ANNOUNCE_START for a duplicate path by scanning all of the route's live claims. Receiving n claims costs O(n²), and a peer can force that cost on us.lite/publisher/routed.rs) scans all of the route's claims for a withheld one on every ANNOUNCE_FLOOR. A single claim change then costs O(claims held) on each answer stream.Approach
WireRoute::claimsmaps each path to its Announce ID, so the duplicate check is a single lookup.Sentkeeps a count of the claims its link withholds.Sent::setupdates the count on every claim change, so the floor reads it instead of scanning.session_announcebench: one broadcast announced and then withdrawn beside many that are already announced, timed until every viewer session has seen both. It sweeps the broadcasts held (16, 4096) against the viewers (1, 64), per the fan-out rule. The route bench'sroutes/receivedalready sweeps claims held against claims changed for the router, so no new route-bench case is added.node-creation-order.mdin the routes epic: main left it unlinked after moq-dev/moq#8388, and that failedquest check.Measurements
All numbers are on an M-series Mac under load. Setup and teardown come from one 4096-broadcast
session_delivery_broadcastscell (1 publisher, 16 viewers, 1 relay), in thread CPU, using temporary instrumentation that is not committed.The subscriber fix alone accounts for the whole setup gain: 998 ms at 4096 broadcasts. Setup sends all claims in one batch, so the publisher scan does not show there.
session_announce: time per announce+withdraw, criterion mean.The publisher fix carries this table. With the subscriber fix alone, one change at 4096 broadcasts and 16 viewers took 5.3 ms of CPU; with both fixes it takes 1.4 ms. The remaining lite-07 slope over broadcasts held is about 2x across a 256x sweep. A profile of that cell shows BTreeMap lookups (memcmp on paths) inside
Router::batch,advertise, andshow. That is a logarithmic cost, not a scan.session_join_broadcastsat broadcasts=1024 (lite-07): relays=1 goes from 24.3 to 10.5 ms, relays=2 from 24.1 to 10.3 ms. lite-06 is 9.3 to 10.0 ms.Impact
Alternatives
Router::showincremental, as the quest planned: it already is. Profiles put no router function at the top.Validation
quest check: ok.just fix: no changes.just rs check-test -p moq-net -p moq-relay: 4207 tests passed, lint ok.cargo clippy --all-targets -p moq-net -p moq-relay --features moq-net/fuzz -D warnings: clean. This covers both session benches.just check: fails on two problems that are not this PR's. Both reproduce unchanged in a checkout of origin/main (ac3cb8c):python3 sh/version.test.py:test_cut_promotes_only_published_library_dependencies_and_preserves_exemptionsandtest_release_plz_keeps_manual_cut_despite_breaking_commitsfail.RUSTDOCFLAGS="-D warnings" cargo doc --no-deps -p moq-carla-bridge: unresolved links toBridge,Source, andprotocolindemo/carla/bridge/src/lib.rs. The rustdoc failure stoppedcheck rsbefore its tests ran, so I ran them per crate above.Choices made without asking
session_announceshows it.node-creation-order.mdhere to restorequest checkon main. No open PR fixed it.Follow-ups
demo/carla/bridgerustdoc fails-D warningson main, which failsjust checkfor any change that selects it.sh/version.test.pycases fail on main locally. Check whether this is environment-dependent before fixing.Review
01a1c393-0a22-7650-8562-67b8714b983f, round 1Models
Size: M
Implementer: Claude Code, Opus 5.5
(Written by Opus 5.5)