Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions doc/concept/standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,18 @@ to model priority 127, where higher values are served first. A track that
never sets a priority is 127 as well, so it goes out as 128 on IETF and 127
on moq-lite.

On drafts 14–19, the Rust publisher serves relative joining `FETCH` requests
with offset zero for `NextObject` subscriptions. The fetch delivers the saved
current-group prefix, and the subscription delivers later objects. Standalone,
absolute joining, and nonzero-offset fetches are refused. Draft-20 uses
subscription fills instead. JavaScript publishing does not yet serve `FETCH`;
The Rust publisher answers a standalone `FETCH` by walking its range one group
at a time, in ascending order, from the cache. A relay fetches each missing
group upstream with a `FETCH` of that one whole group, and an upstream refusal
is the refusal the fetcher sees. A descending range of several groups is
refused. A standalone `FETCH` carries no timestamps, since no `SUBSCRIBE_OK`
declared a timescale for it.

On drafts 14–19, the Rust publisher also serves relative and absolute joining
`FETCH` requests for `NextObject` subscriptions: the whole groups before the
subscription's group, then that group's saved prefix, while the subscription
delivers later objects. Draft-20 uses subscription fills instead. JavaScript
publishing does not yet serve `FETCH`;
Rust and JavaScript subscribers request unfiltered delivery on older drafts
because they do not issue joining fetches. Other publishers may replay a cached
backlog for that filter; selecting the next group instead would leave static
Expand Down
2 changes: 2 additions & 0 deletions quest/m1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ transport, benchmark tooling); worktrees isolate commits, not semantics.

- [Publish delay](/quest/m1/publish-delay.md) - js/publish encoders advertise `delay` behind the earliest rendition, like moq-mux
- [Data jitter](/quest/m1/data-jitter.md) - JSON and binary tracks with a capture time advertise a detected `delay` and `jitter`
- [Subgroup refusal](/quest/m1/ietf-subgroup-refusal.md) - a non-zero subgroup stream from a moq-transport peer ends that stream, never the session
- [Moxygen compatibility](/quest/m1/moxygen/README.md) - one subgroup per group, whole-group FETCH, and one datagram per group, never a full moxygen pass
- [Fetch without SUBSCRIBE](/quest/m1/ietf-fetch-only.md) - a relay fetches from an IETF upstream without subscribing, finished tracks included, with End of Track always reported
- [JavaScript FETCH](/quest/m1/js-fetch.md) - generic on-demand group serving and IETF FETCH for browser publishers
- [Archive](/quest/m1/archive/README.md) - record selected tracks to any object_store and replay them over FETCH or derived HLS, on the catalog and store the release ships
- [Wildcard](/quest/m1/wildcard/README.md) - a relay resolves subscriptions against advertised prefixes, a service claims the prefix it could serve and refuses the rest instead of enumerating broadcasts, and the browser player treats a covering claim as availability
Expand Down
30 changes: 30 additions & 0 deletions quest/m1/ietf-fetch-only.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# [M] Fetch without SUBSCRIBE

## Goal

A relay serves a FETCH-only demand for an IETF upstream track without
SUBSCRIBE upstream. A finished upstream track can still be fetched, and a
FETCH_OK that reaches the end of the track says so every time.

## Plan

The origin splices a route only once the track's info is known. moq-lite gets
it from TRACK_INFO, so its fetch-only demand never subscribes. IETF has no
TRACK_INFO, so today fetch-only demand still makes the relay SUBSCRIBE upstream.
Two symptoms follow:

- A finished upstream track refuses the SUBSCRIBE, so its groups cannot be
fetched either.
- The live subscription races the group FETCHes. End of Track is known only
once an upstream FETCH_OK reports it, so a downstream FETCH that runs to the
end can answer before that and leave End of Track unset. moxygen's "FETCH
with large objects" case flakes on this.

TRACK_STATUS is the likely source of the info. The publisher refuses it today,
so both sides are in scope. Keep the SUBSCRIBE path for real subscription
demand.

## Related

- [Moxygen compatibility](/quest/m1/moxygen/README.md) - the line whose FETCH cases this steadies
- [JavaScript FETCH](/quest/m1/js-fetch.md) - the browser publisher answers these fetches
22 changes: 22 additions & 0 deletions quest/m1/ietf-subgroup-refusal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# [S] Subgroup refusal stays on the stream

## Goal

A peer that sends a non-zero subgroup on moq-transport loses that one stream,
never the session. Every other track on the session keeps flowing.

## Plan

Against moxygen's `moqtest_server`, a track with two subgroups per group ended
the relay's upstream session, and the server reconnected. Our side refuses the
stream today. Whether the session ends because of how we refuse it (the reset
code, STOP_SENDING, or the alias state it leaves behind) or because the peer
reacts badly to a correct refusal is not known yet. Reproduce it first. If the
peer is at fault, say so on its tracker and keep a regression test for our side.

A test with an IETF peer that sends a subgroup 1 stream next to a healthy track
is the check.

## Related

- [Moxygen compatibility](/quest/m1/moxygen/README.md) - subgroups stay out of scope; only the blast radius is in
2 changes: 1 addition & 1 deletion quest/m1/moxygen/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Docs stay inline in the change that makes them stale. No new guide.

## Quests

- [Group FETCH](/quest/m1/moxygen/fetch.md) - an IETF FETCH of whole groups is served from cache or fetched upstream, one group at a time
- [Sparse FETCH ranges](/quest/m1/moxygen/fetch-span.md) - a FETCH costs the groups it returns, not the span of its range
- [Datagram groups](/quest/m1/moxygen/datagram.md) - an IETF datagram that is one object in a group arrives as a moq-lite datagram group

## Related
Expand Down
27 changes: 27 additions & 0 deletions quest/m1/moxygen/fetch-span.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# [M] Sparse FETCH ranges

## Goal

A FETCH's cost follows the groups it can return, not the span of its range.
A track whose sequences are sparse, or whose history is long gone, answers a
wide range without spinning a worker or probing upstream once per missing
sequence.

## Plan

The standalone FETCH walk asks `track::Consumer::fetch_group` for every
sequence from start to the newest group, stepping over each miss. With no
fetch handler, every miss resolves at once, so a range over millions of
missing sequences runs without yielding. With a handler, a relay sends one
upstream FETCH per missing sequence. Either way a single request from a peer
buys work proportional to the newest sequence number.

Seek the next group the track can serve instead of stepping by one. Where a
relay cannot know which groups its upstream still holds, decide what bound
or refusal is honest rather than probing blindly. Benchmark range span and
present-group count as separate axes.

## Related

- [Moxygen compatibility](/quest/m1/moxygen/README.md) - the line whose FETCH walk this bounds
- [Fetch without SUBSCRIBE](/quest/m1/ietf-fetch-only.md) - also changes how a relay reaches upstream for fetches
26 changes: 0 additions & 26 deletions quest/m1/moxygen/fetch.md

This file was deleted.

3 changes: 2 additions & 1 deletion rs/moq-net/src/ietf/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,8 @@ impl Message for Fetch<'_> {
);

let subscriber_priority = subscriber_priority.unwrap_or(128);
let group_order = group_order.unwrap_or(GroupOrder::Descending);
// No preference: the publisher picks the order.
let group_order = group_order.unwrap_or(GroupOrder::Any);

Ok(Self {
request_id,
Expand Down
Loading
Loading