Skip to content

refactor(moq-net): unify stats counters on Gauge/Usage, drop the guard zoo#1876

Merged
kixelated merged 1 commit into
stats-in-modelfrom
stats-gauge
Jun 22, 2026
Merged

refactor(moq-net): unify stats counters on Gauge/Usage, drop the guard zoo#1876
kixelated merged 1 commit into
stats-in-modelfrom
stats-gauge

Conversation

@kixelated

Copy link
Copy Markdown
Collaborator

Stacked on #1873 (base stats-in-model; retarget to dev once that merges).

Follow-up cleanup to the stats aggregator, applying the "just counters" shape from #1873 to the half it didn't touch. No behaviour change — same counters, same emitted .stats wire format.

1. One Gauge primitive for every lifecycle counter

The lifecycle counters were six loose AtomicU64s, and every guard's Drop re-derived the subtle "load closed (Acquire) before open (Relaxed)" snapshot ordering by hand. Now there's one Gauge { open, closed } with open() (RAII) / snapshot(), and the ordering lives in exactly one place (Gauge::snapshot). Counters becomes three Arc<Gauge> (announced / subscriptions / broadcasts) plus the shared Arc<Usage> from #1873; SessionCounters is just a Gauge.

2. Collapse the guard zoo

One generic Guard RAII token does the close-on-drop. The publisher/subscriber guard pairs collapse into side-parameterized types:

  • PublisherStats + SubscriberStatsBroadcastGuard (announced)
  • PublisherTrack + SubscriberTrackTrackGuard (subscriptions + a Meter over the payload counters)

Each delegates its close to the embedded Guardsix hand-written Drop impls and four guard types become two. (SessionStats and the refcounting SessionBroadcasts/BroadcastSubscription keep their roles but now bump a Gauge.)

3. Finish the payload migration

TrackGuard no longer carries frame()/bytes()/group() — the only remaining caller was the lite-publisher fetch path, which now bumps the shared Usage through a Meter (fetch reads random-access frames the model doesn't auto-meter). So every payload count flows through Usage/Meter, and the guards are pure lifecycle.

Net

stats.rs is ~120 lines shorter; the tricky memory ordering is centralized and pinned by one source-level test (the two old ordering tests merge into one).

Testing

moq-net 390 lib + moq-native 62 e2e pass (lite 01–03 + IETF 14–18, fetch, compression); clippy clean on changed files. (moq-relay/workspace still blocked locally by the pre-existing iroh-relay requires rustc 1.91.)

🤖 Generated with Claude Code

…he guard zoo

The lifecycle counters were six loose atomics bumped by six near-identical RAII
guards, each re-deriving the subtle "load closed (Acquire) before open (Relaxed)"
snapshot ordering. Replace that with one `Gauge { open, closed }` primitive (the
single place that ordering now lives) and one generic `Guard` RAII token.
`Counters` is now three `Arc<Gauge>` (announced/subscriptions/broadcasts) plus the
shared `Arc<Usage>` payload counters; `SessionCounters` is just a `Gauge`.

Collapse the publisher/subscriber guard pairs into side-parameterized
`BroadcastGuard` (announced) and `TrackGuard` (subscriptions + a `Meter` over the
payload counters), each delegating its close to the embedded `Guard` instead of a
hand-written `Drop`. Six `Drop` impls and four guard types become two.

Finish the payload migration: the lite-publisher fetch path now bumps the shared
`Usage` through a `Meter` (fetch reads random-access frames the model doesn't
auto-meter), so `TrackGuard` carries no payload methods at all. Every payload
count now flows through `Usage`/`Meter`; the guards are pure lifecycle.

No behaviour change: same counters, same emitted wire format. The two
source-level ordering tests collapse into one that pins `Gauge::snapshot`.

moq-net 390 lib + moq-native 62 e2e pass; clippy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@kixelated kixelated merged commit cbb5bf1 into stats-in-model Jun 22, 2026
1 check failed
@kixelated kixelated deleted the stats-gauge branch June 22, 2026 19:38
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