Skip to content

relay: decode DYNAMIC_GROUPS once at ingestion, not per request#21

Merged
floatdrop merged 3 commits into
draft-18from
dynamic-groups-parse-once
Jun 26, 2026
Merged

relay: decode DYNAMIC_GROUPS once at ingestion, not per request#21
floatdrop merged 3 commits into
draft-18from
dynamic-groups-parse-once

Conversation

@floatdrop

Copy link
Copy Markdown
Owner

Summary

The §10.2.13 NEW_GROUP_REQUEST path called trackSupportsDynamicGroups on every request, which parsed the entire Track Properties block, pulled out the one DYNAMIC_GROUPS field, and discarded the rest. Track Properties are immutable for a track entry's lifetime (§9.6, first-setter-wins), so that decode only needs to happen once.

This decodes DYNAMIC_GROUPS when Properties is set and caches the result on the TrackEntry.

What changed

  • TrackEntry gains a cached dynamicGroups bool / dynamicGroupsErr error, populated by a new setPropertiesLocked helper that both stores the raw bytes and decodes the field in one step (so the cache can't drift). AddUpstream's WithProperties path and SetProperties both route through it.
  • New TrackEntry.DynamicGroups() (bool, error) accessor; propagateNewGroupUpstream reads it instead of re-parsing.
  • The raw Properties bytes are still stored verbatim for the §9.6 opaque downstream passthrough — only the one field the relay semantically acts on is decoded eagerly.
  • The §12.6 PROTOCOL_VIOLATION (DYNAMIC_GROUPS value > 1) is cached alongside, so the caller's "log and decline" behavior is unchanged.
  • trackSupportsDynamicGroups moves into registry as parseDynamicGroups. That emptied newgroup.go (newGroupRequestValue was already inlined in a prior commit), so newgroup.go and newgroup_internal_test.go are deleted; their tests move to registry/dynamic_groups_test.go, with the dynamic-groups test rewritten to exercise the public SetProperties / DynamicGroups path.

Testing

  • go test ./... — pass
  • go test -race ./pkg/relay/... — pass
  • go vet ./pkg/relay/... — clean
  • gofmt -l — clean

🤖 Generated with Claude Code

floatdrop and others added 3 commits June 26, 2026 23:57
The §10.2.13 NEW_GROUP_REQUEST path called trackSupportsDynamicGroups on
every request, which parsed the entire Track Properties block, pulled out
the one DYNAMIC_GROUPS field, and discarded the rest. Track Properties are
immutable for the entry's lifetime (§9.6, first-setter-wins), so the decode
only needs to happen once.

Decode DYNAMIC_GROUPS when Properties is set (centralized through a new
setPropertiesLocked) and cache the (bool, error) on the TrackEntry, exposed
via DynamicGroups(). The raw bytes are still stored verbatim for the §9.6
opaque downstream passthrough; only the one field the relay semantically
acts on is now decoded eagerly. The §12.6 PROTOCOL_VIOLATION (DYNAMIC_GROUPS
value > 1) is cached alongside so the caller's decline behavior is unchanged.

trackSupportsDynamicGroups moves into registry as parseDynamicGroups,
emptying newgroup.go (newGroupRequestValue was already inlined), so both it
and newgroup_internal_test.go are deleted; their tests move to registry's
dynamic_groups_test.go, with the dynamic-groups test rewritten to exercise
the public SetProperties / DynamicGroups path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The previous parseDynamicGroups walked the whole Track Properties block to
extract one field. Caching a second property that way would mean either a
second full-block walk or a copy-pasted parse loop — an easy trap.

Restructure so the block is parsed exactly once into a decodedProperties
value: decodeTrackProperties walks the KV pairs and dispatches each property
the relay acts on to a small per-value decoder. Adding a cached property is
now a field + a switch case + an accessor, never a second pass over the
bytes. A structural block-parse failure is recorded once as parseErr and
surfaced by every accessor, so per-property error handling doesn't repeat it.

Moves the decode into a dedicated registry/properties.go and adds a
malformed-block test case alongside the existing §12.6 coverage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
gocritic's singleCaseSwitch flags the dispatch switch while only one property
is decoded. Rewrite as an if; the comment notes it becomes a switch once a
second property is added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@floatdrop floatdrop merged commit f1de434 into draft-18 Jun 26, 2026
9 checks passed
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