Skip to content

perf(stream): compact relay state and reuse output identities - #478

Merged
timtofan merged 12 commits into
masterfrom
atimofieiev/up-relay-mem-cpu
Nov 4, 2026
Merged

timtofan merged 12 commits into
masterfrom
atimofieiev/up-relay-mem-cpu

Conversation

@timtofan

@timtofan timtofan commented Nov 3, 2026

Copy link
Copy Markdown
Collaborator

Depends on #477

Why

Large relays can retain millions of input IDs across roughly 85 producer connections. Interface slots, duplicated route allocations, per-socket compression scratch, and repeated output-name lookup consume memory and CPU. Overlapping reload processes make retained-state cost especially significant.

Architecture

The listener uses compact pinned-name slots in 128-entry pages, with direct references, predictors, and bitmaps. Admission charges actual page/vector and staging capacity before allocation. Ordinary routes live inside shared name entries; complex rewrite/continued routes retain bounded independent plans.

Each shared input identity also owns an aligned atomic output token. Single-path records borrow it and retain the owning allocation; output generation checks validate reuse. Failed admission remains record-local, and multi-path records keep independent hints. CPU-bounded pools share output compression and frame workspaces; per-connection wire dictionaries remain separate. Handoff writes bounded STATE frames instead of building a whole extra snapshot.

These compact binding, streaming snapshot, and workspace hooks extend the explicitly documented maintained codec delta. Publication of a shared codec or receiver adoption allows that delta to be removed. Wire v1, sender peer estimates, host selection, and delivery guarantees retain their existing contracts.

Before / after

Before After
40-byte input slots in geometric arrays About 25 bytes per ID in 128-entry pages
Ordinary routes allocate separate plans Ordinary routes live in shared entries
Output identity is hashed and resolved per record Single-path records reuse a generation-checked token
Compression/frame scratch scales with output sockets Workspaces scale with CPU concurrency
Handoff accumulates a whole snapshot Snapshot frames stream with bounded scratch

Usage

Existing stream listeners and output senders activate these paths automatically. The ordinary decoder API remains available. docs/stream-input.md documents the opt-in synthetic memory and CPU models, including the producer-pool fixture, scratch paths, and accounting limits. Keep process memory headroom for reload overlap.

Validation

Go 1.27.0 with vendor mode: build, vet, serialized full tests, golangci-lint v2 with the upstream configuration, and race tests on every changed Go package. Tests cover compact/generic decoder parity, admission cleanup, snapshot bytes, shared token lifetime, stale tokens, multi-path routing, and workspace concurrency. External receiver and large process benchmarks are separate opt-in checks; no production measurements are claimed here.

@timtofan
timtofan merged commit 988e3a9 into master Nov 4, 2026
4 checks passed
@timtofan
timtofan deleted the atimofieiev/up-relay-mem-cpu branch November 4, 2026 13:55
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.

3 participants