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
1 change: 0 additions & 1 deletion quest/m2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ ranked just below deterministic TS legs, which it requires.
- [Ordered owed wait](/quest/m2/ordered-owed-wait.md) - an ordered reader waits within max_delay for a missing group only while the track still owes it
- [Unbounded groups](/quest/m2/unbounded-groups/README.md) - groups and frames lose their size caps; the cache sheds parts of a group under pressure and refills the holes in place
- [Rust-backed @moq/net](/quest/m2/rs2ts/README.md) - measure browser baselines, complete WASM bindings, and adopt Rust behind @moq/net before the later JS-only stage
- [Front deadlines](/quest/m2/front-deadline-index.md) - a front's per-event cost stops growing with its track count: an expiry index and per-track wakes, proven by a churn benchmark
- [Front parking](/quest/m2/origin-front-parks.md) - an unroutable request waits on a front instead of re-asking on every route-table move
- [Route wakes](/quest/m2/route-wakes.md) - a route change wakes only the fronts it can move, so pool churn stops scaling with served paths
- [Route health](/quest/m2/route-health/README.md) - epoch-only active/passive track recovery over metadata-only subscriptions
Expand Down
39 changes: 0 additions & 39 deletions quest/m2/front-deadline-index.md

This file was deleted.

1 change: 0 additions & 1 deletion quest/m2/route-wakes.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,4 @@ Public API: none. Wire: none.
## Related

- [Routes and announces](/quest/m1/cluster-routing/routes.md) - the identity and selection views the index serves
- [Front deadlines](/quest/m2/front-deadline-index.md) - each spurious wake also pays that per-track poll and deadline scan
- [Front parking](/quest/m2/origin-front-parks.md) - replaces the `routed_broadcast` watch loop this wakes
54 changes: 54 additions & 0 deletions rs/moq-net/src/model/front.rs
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,21 @@ mod tests {
assert_eq!(format!("{actual:?}"), format!("{expected:?}"));
}

/// The expiry index and next deadline agree with a full scan of the tracks.
#[track_caller]
fn assert_index_matches_scan(front: &Front) {
let scanned: BTreeSet<_> = front
.tracks
.iter()
.filter_map(|(name, track)| match track.state {
TrackState::Parked { since } => Some((since + front.linger, name.clone())),
_ => None,
})
.collect();
assert_eq!(front.parked, scanned);
assert_eq!(front.next_deadline(), scanned.first().map(|(at, _)| *at));
}

/// A front serving `source` through `candidate`, with `video` spliced and read.
fn serving(candidate: Candidate, source: u64) -> Front {
let mut front = Front::new(LINGER);
Expand Down Expand Up @@ -1543,6 +1558,42 @@ mod tests {
assert_actions(front.step(Event::Closed), &[Action::End { err: Error::Dropped }]);
}

#[test]
fn deadline_index_matches_scan_across_track_transitions() {
use rand::{RngExt, SeedableRng};

let mut rng = rand::rngs::StdRng::seed_from_u64(0x66726f6e74);
let mut front = serving(remote(1), 100);
let mut now = Instant::now();
for _ in 0..4096 {
let track = name(&format!("track-{}", rng.random_range(0..32)));
let event = if !front.tracks.contains_key(&track) {
Event::TrackAssigned { track, now }
} else {
match rng.random_range(0..4) {
0 => Event::Used { track },
1 => Event::Unused { track, now },
2 => {
now += LINGER / 4;
Event::Deadline { now }
}
_ => Event::TrackInfo {
track,
source: 100,
closing: false,
result: Ok(info()),
},
}
};
for action in front.step(event) {
if let Action::Forget { track } = action {
front.step(Event::Forgotten { track });
}
}
assert_index_matches_scan(&front);
}
}

/// Every sequence of events up to a small depth, over a small alphabet,
/// checked against the invariants the driver relies on.
#[test]
Expand Down Expand Up @@ -1625,6 +1676,9 @@ mod tests {
let actions = next.step(event.clone());
*sequences += 1;

// Route-wide events skip the index update, so they must leave parked tracks alone.
assert_index_matches_scan(&next);

// An event that changes nothing produces nothing, except letting
// go of a source the front never took.
if format!("{next:?}") == before {
Expand Down
Loading