Repository navigation
feat(moq-net): serve each subscriber its own ranges, with time anchors #5929
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
56 commits
Select commit
Hold shift + click to select a range
739082c
quest(m1): claim subscribe-ranges/dynamic
kixelated 40d72f0
feat(moq-net): serve each subscriber its own ranges, with time anchors
kixelated d68f823
chore(moq-net): box the cursor's range filter, regenerate Dart bindings
kixelated 81f8a87
docs: link the MIGRATE entries to #5929
kixelated 8c8c02f
Merge remote-tracking branch 'origin/main' into merge-5929
kixelated 7bea69b
Merge remote-tracking branch 'origin/main' into pr-5929
kixelated feb8a72
feat(moq-c): give the time anchor its own timestamp_us field
kixelated 5d89b17
Merge branch 'main' of github.com:moq-dev/moq into pr-5929
kixelated 13a2b33
fix(moq-c): refuse a raw track update at the call
kixelated 9dd0ab4
fix(moq-net): resolve time anchors only from frame-0 starts, refuse d…
kixelated c015690
docs: name the time anchor in the Swift and Dart aliases and the C++ …
kixelated 01cec52
quest(m1): the time anchor moves to exact timestamps with the bindings
kixelated b6e48df
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 52d2c4f
fix(moq-net): a lowered floor re-offers the cached groups it newly co…
kixelated e4f31c2
docs(moq-net): state the real bound on a time end; quest the one-grou…
kixelated d79f671
style(moq-net): name the passed-floor check in has_unread_group
kixelated 4a46ebe
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 9b680ec
docs(moq-net): quest local frame bounds; fix the stale drift cap comment
kixelated b2cb366
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated bb03fca
fix(moq-net): a lowered floor re-offers only groups readers can see
kixelated dee0478
docs(drafts): log the lowered Group Start behavior in the lite-07 cha…
kixelated cee4bc0
fix(moq-net): a failover clamp never widens a range
kixelated 7697958
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated a24bff1
fix(moq-net): an unresolved start never widens to the failover floor
kixelated d788a30
style(moq-net): format the pending-copy regression test
kixelated 7060b26
fix(moq-net): a replacement copy never reads below where the reader g…
kixelated bf1105b
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated a4eea28
fix(moq-mux): read the floor through the optional subscription main i…
kixelated e212240
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 8036328
fix(moq-net): a cursor holds only its range, and widening re-scans th…
kixelated 5f53bdd
fix(moq-net): a copy updated while pending names the ranges it will r…
kixelated 6c77716
docs(moq-net): a finished track ends a capped subscriber
kixelated 6db1f34
test(moq-net): apply the pending copy's update as the reader does
kixelated 27f7080
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 23c4b3c
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 30cb4f1
fix(moq-net): a time end stays open across a group yet to start
kixelated 03611bc
fix(moq-net): a time end settles only once every sequence below it is…
kixelated d679eaf
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 330ae11
test(moq-c): set refresh in the time anchor test's track info
kixelated ac9daca
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 9f0ec25
fix(moq-net): measure drift only within the groups a subscriber's ran…
kixelated 07eb25e
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 472a40f
perf(moq-net): keep a single servable run as cheap as a cap
kixelated a4c9be0
refactor(moq-net)!: drop time anchors from subscription ranges
kixelated ae8eff0
fix(moq-mux): walk past gaps between a subscriber's ranges; keep the …
kixelated 557ac89
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 1a3cf34
fix(moq-net): name the next group in range for a resumed reader
kixelated 2756260
fix(moq-net): resolve replaced ranges on any copy; republish on Contr…
kixelated 57116be
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 08ae9f7
style(moq-mux): format the merged hole walk
kixelated 84d2256
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated 3f8bb34
fix(moq-net): retake a pending drift snapshot; publish window and cap…
kixelated 16ccdd7
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated ab1bce6
fix(moq-net): start a cursor's published window empty
kixelated b84e94b
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated f49ba80
Merge branch 'main' of github.com:moq-dev/moq into iterate-5929
kixelated File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
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
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
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| # [M] A local subscriber reads only its frame bounds | ||
|
|
||
| ## Goal | ||
|
|
||
| A `track::Subscriber` whose ranges start or end partway through a group reads only the | ||
| frames they cover: a start at group 4 frame 5 hands out group 4 from frame 5, and an | ||
| end mid-group stops there, whatever another subscriber widened the aggregate to. Today | ||
| the model filters whole groups and hands out every cached frame, so local readers | ||
| (moq-ffi, moq-mux, in-process apps) see frames they never asked for. | ||
|
|
||
| ## Plan | ||
|
|
||
| Found by Codex on #5929 and reproduced on `main` (824179a3a) as well as on that PR: a | ||
| subscription starting at frame 5 of group 0 is handed the group from frame 0. #5929's | ||
| `Window` collapses each range to group sequences, but the leak predates it: `main`'s | ||
| cursor never positioned a delivered group either. Only the datagram path checks the | ||
| start frame (`mid_group` in `Cursor::poll_recv_datagram`). | ||
|
|
||
| The wire is not affected: the lite publisher positions each served group per | ||
| subscription (`position_group` in `rs/moq-net/src/lite/publisher.rs`, and the same | ||
| shape in `js/net/src/lite/publisher.ts`). | ||
|
|
||
| - Keep each range's absolute frame bounds in the `Window` beside its group runs. | ||
| - Position every group the cursor hands out (`group::Consumer::start_at`/`end_at`), on | ||
| the arrival, ordered, and re-offer paths, using the bounds of the range that covers it. | ||
| A group whose head is gone and that was asked for from frame 0 stays a miss, as | ||
| `position_group` does today. | ||
| - Then let the lite publisher rely on the model's positioning instead of its own, if | ||
| that is simpler. | ||
| - Check `js/net`'s `track` subscriber for the same shape and mirror the fix. | ||
|
|
||
| Regression test: a start at frame 5 and an end at frame 3 of a cached group, each read | ||
| through `recv_group` and `ordered()`. | ||
|
|
||
| ## Related | ||
|
|
||
| - [Dynamic range requests](/quest/m1/subscribe-ranges/dynamic.md) - the per-subscriber ranges this extends to frames |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # [L] Time anchors | ||
|
|
||
| ## Goal | ||
|
|
||
| A range start or end may name a presentation time: `Time(pts)` in the track's | ||
| timescale. A start resolves to the group containing pts, an end to just after that | ||
| group, and an untimed track refuses either. It lands in its own PR, before | ||
| [lite-07 finalizes](/quest/m1/lite07-finalize.md). | ||
|
|
||
| ## Plan | ||
|
|
||
| Split out of #5929 (maintainer, 2026-10-19), which ships absolute and relative | ||
| anchors only. Start from the `quest/m1/subscribe-ranges/time-end` branch, which | ||
| holds that PR's time anchors through every binding: `Anchor::Time`, the | ||
| `Holdings` resolution in `Window`, the end settlement (`Holdings::after`, | ||
| `TrackState::accounted`), and the failover handling. Merge main into it and drop | ||
| what #5929 changed since. | ||
|
|
||
| Decide first whether time starts ship alone. A start resolves once from the | ||
| cache, but keeping it without time ends needs a start-only anchor type in every | ||
| binding, which is why #5929 dropped both. | ||
|
|
||
| Open findings from #5929's review, each needing a regression test: | ||
|
|
||
| - **Per-read rescan behind a peer-controlled gap** (Codex 4320985614). Settling an | ||
| unresolved end walks back from the live edge on every unsettled read. A peer that | ||
| leaves an early sequence missing and keeps sending later groups makes each read | ||
| revisit a growing prefix until the gap's grace runs out. Keep an incremental | ||
| settle boundary, so each read scans only what arrived since. | ||
| - **Failover replacing an unsettled end** (Codex 4320985627). A copy capped at a | ||
| route switch reports an unsettled time end as unresolved, so the cap replaces | ||
| the `Time` anchor for good, and a group starting before the time that arrives | ||
| later on the old copy is delivered. Keep the time filter on the reader, separate | ||
| from the copy cap. | ||
| - **One speculative group past an end.** An unresolved end covers every sequence | ||
| through `u64::MAX`, so each group handed out before its first frame can leak past | ||
| it at the live edge. Cap it at the newest held group known to start at or before | ||
| pts, plus the first unstarted group above it, and recompute as groups start. | ||
| Raising the cap must wake readers: register on the speculative group's start | ||
| (`group::Producer::poll_started`) from both `Cursor::poll_recv_group` and | ||
| `poll_next_group`. A held group that never shows a start (a copy joined | ||
| mid-group) must not pin the cap. Datagrams are not in `lookup`, so on a | ||
| datagram-only timed track an end never resolves: resolve datagram starts too, | ||
| or leave datagram reads uncapped. Reproduced on #5929: range | ||
| `time(3000)..time(3500)` with three groups opened before any frame delivers | ||
| all three. | ||
|
|
||
| Also pass a time anchor the cache can't resolve to the `track::Dynamic` handler | ||
| in its range request, once [dynamic range requests](/quest/m1/subscribe-ranges/dynamic.md) | ||
| land, and update `quest/m1/binding-timestamps.md` for the anchor's | ||
| `timestamp_us` fields. | ||
|
|
||
| ## Related | ||
|
|
||
| - [Dynamic range requests](/quest/m1/subscribe-ranges/dynamic.md) - range requests a `Dynamic` handler resolves | ||
| - [Archive line](/quest/m1/archive/README.md) - DVR seek, which needs time anchors |
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.