Skip to content

feat(net): move wall-clock LRU expiry to the cache pool - #3169

Merged
kixelated merged 9 commits into
devfrom
claude/lru-wall-clock-pool-expiration-ae670a
Aug 31, 2026
Merged

feat(net): move wall-clock LRU expiry to the cache pool#3169
kixelated merged 9 commits into
devfrom
claude/lru-wall-clock-pool-expiration-ae670a

Conversation

@kixelated

@kixelated kixelated commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Separate media-timestamp retention from wall-clock cache reclamation. track::Info::max_age stays on the media timeline, while cache::Pool owns idle expiry.
  • Configure pool capacity and expiry together through cache::Config when constructing a pool. Expiry is immutable after construction, while capacity remains resizable for the relay memory governor.
  • Bounded pools, standalone origins, and relays use a 30-second default. Pool::unbounded() keeps its never-evict contract.
  • Make relay cache-duration configure both the idle LRU window and the media-timestamp retention ceiling.
  • Run write-driven expiry independently of the 256 KiB byte-debt gate, including small whole-frame writes, streamed frame chunks, and both datagram write paths.
  • Keep no-op expiry scans read-only so periodic scans do not wake track consumers when nothing can be reclaimed.
  • Snapshot each prefetched consumer's refresh cadence from the immutable pool expiry and the track's media-retention window.

Public API

  • Adds cache::DEFAULT_EXPIRY.
  • Adds cache::Config, with Config::with_capacity(...) and Config::with_expiry(...).
  • Changes Pool::new(...) to accept cache::Config instead of a capacity value.
  • Adds Pool::expiry().
  • Removes runtime expiry mutation. The expiry is fixed when the pool is created; Pool::resize(...) remains for dynamic capacity changes.
  • This is a breaking public API change, so the PR targets dev.

Observable behavior

Non-latest groups idle past the configured window are reclaimed with Error::Old on a subsequent write. The latest group remains protected, and there is no background reaper. This is observable to network clients fetching or reading cached history, but the wire encoding and protocol framing are unchanged.

Test plan

  • just fix origin/dev
  • just check origin/dev
  • just test default origin/dev (3,467 Rust tests, 52 Python tests, and all JavaScript suites passed)
  • Post-review package tests: just rs test -p moq-net -p moq-relay -p moq-ffi (1,415 passed)
  • Regression coverage for config application, bounded and unbounded defaults, explicit relay duration, FFI policy inheritance, sub-threshold whole-frame writes, streamed chunks, appended and forwarded datagrams, no-op scan wakeups, track-retention refresh cadence, standalone origins, relay defaults, and fetched backfill expiry

Cross-package sync

  • Updated relay configuration and moq-lite concept docs.
  • No IETF draft change because the wire format is unchanged.
  • No js/net mirror because browser clients do not own the relay-side cache pool. The related JavaScript retention design remains tracked in Retention should reclaim idle open groups now that expiry is timestamp-only #3161.
  • No FFI surface was added. The existing capacity option now preserves the origin's configured expiry.

(written by GPT-5)

Track max_age used to drive two different clocks: the media-timestamp
staleness budget and the wall-clock idle scan in evict_expired. The
wall-clock half now lives on cache::Pool as an expiry window (default
30s, None to disable), so a track can promise a 5s media window while
the pool reclaims anything unaccessed for 30s of real time. Media
timestamps stand still during a congestion stall, so a short max_age can
no longer age content out of the cache mid-stall; the LRU window is
purely about not pinning RAM on content nobody reads.

The origin's cache_duration keeps only its media-time role: clamping
each track's advertised max_age. The relay's cache-duration knob now
also sets the pool expiry, which is what its docs already promised
(retained since last written or served from cache). Frame-write
settlement now runs the expiry scan too, so a track appending frames to
open groups without inserting new ones still ages idle siblings out.

Progress on #3161 (the Rust reclamation half). Still open there: idle
reclamation with zero writes needs a wakeup the model layer deliberately
does not own, and the JS retention prune still keys off maxAge and
retains open groups.

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

chatgpt-codex-connector Bot commented Aug 29, 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-08-30T23:21:48.712763Z 3a5796c New commits
ℹ️ 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3afea3d1b8

ℹ️ 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".

Comment thread rs/moq-net/src/model/cache.rs Outdated
Comment thread rs/moq-net/src/model/cache.rs Outdated
Preserve the no-eviction contract for bare unbounded pools while explicitly enabling the default idle window for bounded pools, standalone origins, and relays. Run time-based scans for small whole-frame and streamed writes, with regression coverage for both paths.

Co-Authored-By: GPT-5 <noreply@openai.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f219573736

ℹ️ 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".

Comment thread rs/moq-net/src/model/cache.rs Outdated
Route both origin and forwarded datagram writes through the cache's throttled settlement path after releasing the track lock. This keeps idle group expiry progressing for active datagram-only publishers.

Co-Authored-By: GPT-5 <noreply@openai.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: deacd2f5b6

ℹ️ 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".

Comment thread rs/moq-net/src/model/group.rs Outdated
Keep the shared cache pool on prefetched consumers and query its current refresh cadence. Existing readers now follow expiry changes made after their cursor was created.

Co-Authored-By: GPT-5 <noreply@openai.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c3c2135282

ℹ️ 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".

Comment thread rs/moq-net/src/model/group.rs Outdated
Keep prefetched consumers on the stricter of the current pool expiry cadence and the track retention cadence. Add a regression test for a short track max_age with a longer pool expiry.

Co-Authored-By: GPT-5 <noreply@openai.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ebb30b649

ℹ️ 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".

Comment thread rs/moq-net/src/model/cache.rs
kixelated and others added 3 commits August 29, 2026 20:32
Clamp pending write-driven scan deadlines against the pool current expiry cadence so existing tracks respond promptly when a shared pool is shortened. Add a regression for the default-to-subsecond transition.

Co-Authored-By: GPT-5 <noreply@openai.com>
Keep the rotating scan cursor outside observable track state and inspect each candidate window before taking a notifying write guard. Rename the new expiry configurator to a setter so its shared mutation is explicit.
Make idle expiry immutable pool configuration while preserving dynamic capacity resizing for the relay memory governor.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 482d6fa834

ℹ️ 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".

Comment thread rs/moq-net/src/model/cache.rs
Comment thread rs/moq-net/src/model/cache.rs
@kixelated
kixelated merged commit 44b84a6 into dev Aug 31, 2026
4 checks passed
@kixelated
kixelated deleted the claude/lru-wall-clock-pool-expiration-ae670a branch August 31, 2026 02:27
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