Skip to content

fix(net): a parked read watches its edge abort - #5159

Merged
kixelated merged 2 commits into
mainfrom
fix/parked-read-edge-abort
Oct 10, 2026
Merged

kixelated merged 2 commits into
mainfrom
fix/parked-read-edge-abort

Conversation

@kixelated

@kixelated kixelated commented Oct 10, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

A read parked on its drift budget wakes when its successor gets its first frame or aborts, when a group lands above it, and when a frame write crosses its deadline. It does not wake when the live edge aborts.

Under a timestamp rewind, that abort can change the verdict on its own. Take a head at 0s, its successor at 1s, then a group at 10s, then the edge at 2s, with a 5s budget. The head is within budget against the 2s edge, so the read parks. When the edge aborts, the edge falls back to the 10s group and the head is 9s behind. Nothing wakes the read, though: the abort only closes the group, never touching the track, and the 10s frame was written before the read parked, so no write crosses the deadline afterwards.

#4892 listed this as pre-existing. The review of its release backport (#5130) found a variant there that the narrowed scan made new, and fixing that one also fixes this.

Approach

TrackState::poll_drifted (which GroupExpiry::is_expired and the resume path both call) now also registers on the resolved edge's closure, and re-resolves if the edge aborted before registration. That is the same pattern the successor already uses. An aborted group is never the edge again (live_edge skips it), so each pass resolves a lower group and the loop ends.

Finishing a group does not close it, so a finished edge that is later aborted or evicted still wakes the read. The group.rs docs on poll_closed/closed said a finish closes the group; they now say it does not.

Impact

  • Public API: none. Code change is internal to rs/moq-net/src/model/track.rs; rs/moq-net/src/model/group.rs gets doc fixes only.
  • Wire: none.

Tests

  • New a_parked_read_watches_its_rewound_edge_abort (no wall clock). It fails on main ("the edge's abort lost its wakeup") and passes here.
  • just test -p moq-net: 1707 passed, 5 skipped.
  • just check against origin/main: exit 0 (5692 Rust tests passed, 15 skipped; lint, doc, and the JS and workflow checks clean).

Benchmark

track_parked_read, with --warm-up-time 1, criterion medians. The machine was heavily loaded (load average about 69), so these show the shape, not exact costs:

parked main this PR
8 875 ns 871 ns
64 843 ns 1.16 µs
512 2.05 µs 882 ns

The run-to-run noise is larger than any difference, and there is no slope over parked reads. The fix adds one closure registration per poll on the edge group.

Follow-up

On main, track_parked_read can panic at benches/track.rs:457 with the default warm-up. Each append advances timestamps by 2.5ms, so a warm-up call of more than about 1.44M iterations moves the edge past the bench's 3600s budget, and the parked reads expire. Whether it panics depends on machine speed. Unchanged code hits it too (it panicked twice before this change). It needs its own fix, for example sizing the budget to the iteration count.

(Written by Claude Opus 5.5)

🤖 Generated with Claude Code

A parked read wakes on its successor and on frame writes crossing its
deadline, but not on the edge's abort. Under a timestamp rewind that abort
hands the edge to a lower group that already presented past the deadline,
and nothing wakes the read. Register on the edge's closure, and re-resolve
if its abort already landed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-10T13:17:38.012191Z b1b2992 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

You'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 7 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 301603f1-69df-4173-8b37-d6a89e89dbef

📥 Commits

Reviewing files that changed from the base of the PR and between a5b17e3 and b1b2992.


📒 Files selected for processing (2)
  • rs/moq-net/src/model/group.rs
  • rs/moq-net/src/model/track.rs

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kixelated

Copy link
Copy Markdown
Collaborator Author

Grok review of cac3a0db

Tight fix: GroupExpiry::is_expired (rs/moq-net/src/model/track.rs ~L3586) now registers on the resolved edge's closure and re-resolves when the edge already aborted, mirroring the successor pattern. The loop terminates since an aborted group drops out of drift_edge, and the new test reproduces the rewound-edge scenario from the description without wall clock.

No blocking issues.

Non-blocking:

  • The test finishes the edge before aborting it, so it relies on poll_closed still registering the waker on a finished-but-not-aborted group (a finish then later abort). That's the case that matters here and it passes, but a short comment on that poll_closed contract near the loop would keep a future refactor of poll_closed from silently dropping the wakeup.
  • One extra closure registration per parked poll on the edge group; the bench numbers are noise-dominated on a loaded box, fine for now. The track_parked_read warm-up panic noted in Follow-up deserves its own issue.
  • CI still pending at time of review.

Verdict: MERGE (once CI is green)

This is an automated review, not the maintainer's decision
(Written by Grok)

Main moved the drift wait into TrackState::poll_drifted, so the edge-abort
watch now lives there and also covers the resume path. Renames the new test,
since main gained a same-named one from the release backport, and says in
group.rs that finishing a group does not close it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@kixelated

Copy link
Copy Markdown
Collaborator Author

@codex review

(Written by Claude Opus 5.5)

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Chef's kiss.

Reviewed commit: b1b299219a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@kixelated
kixelated enabled auto-merge (squash) October 10, 2026 13:18
@kixelated

Copy link
Copy Markdown
Collaborator Author

Merge summary for b1b29921:

  • Resolved the conflict with main: main moved the drift wait into TrackState::poll_drifted, so the edge-abort watch now lives there. That also covers the resume path, which calls the same function.
  • The loop is not busy. It only re-resolves when the edge's group already aborted, and live_edge never picks an aborted group again (the abort flag is monotone and the track lock is held), so each pass resolves a lower group.
  • poll_closed contract: finishing a group does not close it (only an abort, including eviction, or the last producer dropping does), so a finished edge that later aborts still wakes the parked read. The group.rs docs claimed a finish closes the group; they now say it does not.
  • Renamed the new test to a_parked_read_watches_its_rewound_edge_abort, since main gained a same-named test from the release backport. It fails with the watch disabled and passes with it.
  • Reviews: Codex thumbs-up on this head. Local just check: lint and all Rust tests pass; the only failure was the known ts_passthrough_crosses_a_relay_through_a_flagged_jump flake, which also fails on main.

Public API: none. Wire: none.

(Written by Claude Opus 5.5)

@kixelated
kixelated merged commit e5446b0 into main Oct 10, 2026
7 checks passed
@kixelated
kixelated deleted the fix/parked-read-edge-abort branch October 10, 2026 15:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant