Repository navigation
fix(net): keep an aborted track's finished groups, expire ended tracks - #4378
Conversation
An abort, or a producer dropped without finish(), cleared the whole cache, so a slower reader lost groups that had fully arrived and the track ended short of them. Keep the finished groups and drop only the open ones: readers drain what finished, then see the abort (or the clean end, when the declared end had settled). Nothing pinned by a stale consumer lingers: once no producer remains, the latest group loses its protection, and the pool sweep reaches ended tracks through the new kio::Weak::read, since their closed channel refuses an upgrade. Previously a sealed track's groups were never swept at all. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Warning Review limit reachedNext included review available in 12 minutes. View limit detailsLimit details: You’ve used all 4 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (4)
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. Comment |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
MERGEPositive improvement, worth the complexity, and the approach looks right for this lifetime/expiry corner of the cache. Positive improvementYes. Two real bugs, both with regressions that fail on
Worth the complexityYes. The surface area is small and local:
Idle expiry ( Different approach?Not really. Clearing on abort and only special-casing Nits (non-blocking)
This is an automated review, not the maintainer's decision |
Merge summaryMerging as-is at
Maintainer approved merging in-session. (Written by Opus 5.5) |
Problem
track::Producer::abortcleared the whole cache unless the declared end had already settled (#4351), and so did a producer dropped withoutfinish(). A reader slower than the network lost groups that had fully arrived before the abort: the publisher's session dies one group short of the end, and the relay's readers skip everything they had not pulled yet.The clearing existed so a stale consumer could not pin the cache forever. That guard was also incomplete elsewhere: an ended track's latest group was always exempt from the pool's idle expiry, and the pool sweep never reached an ended track at all. Its channel is closed, so the account's
kio::Weak::upgradereturnedNone. A stale consumer on a finished track whose producer was dropped kept every one of its groups.Approach
commit_abortand the producer-drop teardown keep the finished groups and drop only the open ones, which nobody will finish. A consumer that already pulled an open group keeps its own handle, as before. Datagrams stay too, bounded at 64.poll_next_in_range(the ordered and spliced cursor) returns cached in-range groups before the abort, matchingpoll_recv_group, which already did. Readers get what finished, then the abort, or a clean end when the end had settled. Thesettledspecial case collapses into this.closed: the latest group joins the eviction order, so idle expiry reclaims it like any other group.kio::Weak::read, andTrackState::expire_closedaborts idle groups in place, since the closed channel refuses a write. That releases their frames; the leftover slots are skipped by every read path.The pool's idle expiry (
DEFAULT_EXPIRY, 30s for every origin and relay) is the bound. A pool with expiry disabled keeps idle content, as it does today for finished tracks.Tests
abort_keeps_finished_groups_for_a_slow_reader: finished groups, then the abort, on both the arrival and ordered cursors; the open group is gone. It fails onmain.dropped_producer_keeps_finished_groups_for_a_slow_reader: the same for a dropped producer. It fails onmain.closed_track_expires_its_latest_group: two sweeps reclaim the latest group of an aborted track and of a sealed one held by stale consumers, while a live track keeps its latest. It fails onmainfor the sealed track, which the sweep never reached.kioweak_reads_a_closed_channel.abort_drops_open_groups(wasabort_clears_cached_groups),teardown_ignores_a_settling_group(now uses an open group, which the teardown still drops), and moq-json'sa_dropped_failed_edit_aborts_the_track(the subscriber now drains the finished snapshot beforeFrameTooLarge).cargo nextest run --workspace: 5073 passed.just checkpasses.Impact
kio::Weak::read, which reads the state while another handle keeps it allocated, closed or not, without counting as a producer or consumer. Nothing else.finish(), keeps its finished groups readable, and consumers see them before the error. Open groups are still dropped. An ended track's groups, its latest included, are reclaimed by the pool's idle expiry.@moq/nethas no equivalent yet and needs a separate look.Refs #4351, #4361.
🤖 Generated with Claude Code
(Written by Claude Opus 5.5)