Repository navigation
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every route a session announced was its own listing handler, so a relay's cursor read B copies of each broadcast and a new broadcast cost O(B) at every hop. Routes now share their session's lister. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Quest outcome: draft, not complete. The Rust half of SUBSCRIBE_ALL works end to end and is tested on mock time, directly and through a relay. Covered: tracks now and later, a broadcast appearing and ending, a new epoch at one path, dynamic-only tracks never created, two downstreams sharing one upstream request, and lite-06 listing nothing. Left open, each with a recommendation in the description:
The benchmark caught an O(broadcasts) cost per new broadcast (813 µs at 64 broadcasts), now fixed by one lister per session (93 µs). The JS half is split into (Written by Claude Opus 5.5) |
A track both listed by SUBSCRIBE_ALL and requested by name is one copy per session: requests and listings resolve a broadcast through the copy the session already holds for its epoch, and a requested track hands its SUBSCRIBE over to the listing's feed once the feed covers it. A reader asking below a listed track's start opens a bounded SUBSCRIBE for the gap, at every hop. A listed track's demand is its resolved start, so a relay sees a lower floor instead of folding it into "oldest". The start names past the groups the publisher gave up before resolving it, so a warm relay answers as a cold one. SUBSCRIBE_ALL_UPDATE carries the readers' aggregate preferences upstream. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # rs/moq-net/tests/integration/main.rs
|
Iterate pushed ( One copy. A session now keeps its copies by path and epoch. A request and a listing of the same broadcast instance share one
Tests: Floor through a relay. A reader below TRACK_OK's group opens a SUBSCRIBE bounded at that group, at every hop. Two root causes surfaced while getting the relay case to pass, and both are fixed in
Tests: Preferences. Listed tracks' demand is aggregated: highest priority, widest max delay, and ascending only if every track asks for it. SUBSCRIBE_ALL_UPDATE carries the aggregate ( The draft gained two sentences on the relay aggregate and on SUBSCRIBEing below TRACK_OK. The bench now announces with epochs, and Open decisions are in the description, each with the recommendation implemented: epochless broadcasts are not shared, ordinary readers count toward the aggregate, the TRACK_INFO race drops the feed, and overlapping prefixes are left for a follow-up. One follow-up is worth its own PR. An ordinary relay has the same hidden floor: an absolute floor below a copy that an "oldest" reader already resolved is never fetched upstream. I reproduced it with a throwaway test. (Written by Claude Opus 5.5) |
# Conflicts: # rs/moq-net/src/lite/publisher.rs
|
Closing unmerged per maintainer decision. Listing every track moves from a push model (SUBSCRIBE_ALL) to a pull model: a per-broadcast lite TRACKS listing, then a SUBSCRIBE per track. So relays never merge pushed feeds into pulled copies. Replanned in #5985. Pieces to port by hand from this branch:
(Written by Claude Opus 5.5) |
Problem
An archive, or anything else that wants every track, has to read a catalog and open a SUBSCRIBE per track. It also misses tracks the catalog does not name. Quest: SUBSCRIBE_ALL, which gates the lite-07 cut.
Approach
Model.
origin::Consumer::broadcasts(prefix)yields every broadcast under a prefix as it appears.broadcast::Consumer::tracks()yields every track its producer creates.Lister, for aListingof the prefix. Every route one handler announces shares thatLister.broadcast::Dynamic) is never created.Wire (lite-07-wip only).
{Subscribe ID, Prefix, Priority, Order, Max Age}, then SUBSCRIBE_ALL_UPDATE.{Subscribe ID, Track ID, Sequence, Frame Start}.Publisher.
kio::Taskschild, so a wake costs only the touched track.TrackRunas a SUBSCRIBE, behind aRespondtrait that maps its responses onto TRACK_*.Prioritylane.Subscriber / relay.
ListServeper (session, prefix) fills every listing of that prefix from a single upstream request.Settled decisions
Settled by the maintainer for this iterate:
broadcasts(prefix)andtracks(). They name what is yielded, and the SUBSCRIBE_TRACKS mapping reuses them.Open decisions
The recommended option is implemented for each.
Benchmark
benches/subscribe-all.rssweeps listers (1, 8, 32) against broadcasts (1, 16, 64) through a relay, each against a plain-SUBSCRIBE control. The broadcasts now carry epochs, so the shared-copy registry is on the measured path.Medians from one local run after merging main (the round benchmark is on par with its control, as before):
subscribe_all_new_broadcastThe control (
subscribe_new_broadcast) grows by a similar 13 to 15% from 1 to 64 broadcasts at 8 and 32 listers, so there is no per-route slope. Before this PR's second commit, 64 broadcasts cost 813 µs at 1 lister.subscribe_all_roundstays ahead ofsubscribe_roundat every point (for example, 143 ms against 190 ms at 32 listers and 64 broadcasts).Impact
origin::Consumer::broadcasts, withorigin::Broadcasts(poll_next/next);broadcast::Consumer::tracks, withbroadcast::Tracks(poll_next/next).draft-lcurley-moq-litewith a changelog bullet.Alternatives
Follow-ups
broadcast::Tracksskips a track that closed before the cursor reached it.Checks
just check,just drafts check, andjust test interop --allpass locally after merging main. Each new test was checked to fail with its fix reverted.🤖 Generated with Claude Code