Skip to content

fix(quic): release retired streams after sparse acknowledgements - #26

Merged
hatoo merged 1 commit into
masterfrom
codex/fix-quic-sparse-ack-retirement-20261012
Oct 12, 2026
Merged

hatoo merged 1 commit into
masterfrom
codex/fix-quic-sparse-ack-retirement-20261012

Conversation

@hatoo

@hatoo hatoo commented Oct 12, 2026

Copy link
Copy Markdown
Owner

When a request's suffix (including FIN) is acknowledged before its prefix, SendStream forgets the suffix ACK. SentPackets has already removed that packet, so a later cumulative ACK cannot supply the missing callback. The fully acknowledged, retired request keeps its stream slot and send buffer until the connection closes.

Remember sorted, merged ACK intervals beyond the contiguous prefix, then release them when the earlier gap closes. In-order ACKs allocate no interval storage. Sparse ACKs also remove acknowledged bytes from queued retransmissions; late loss cannot restore acknowledged data or FIN. Reset and pooled-buffer reuse clear the interval state.

Validation:

  • Eight new regressions plus an updated sparse-ACK regression cover packet-level retirement, sparse stream slots, overlap/adjacency, duplicates, late loss, FIN-only ACKs, unsent trailing bytes, append compaction, reset, reuse, and a 65,536-event independent byte-set model. Five focused checks fail on the unchanged baseline.
  • 442 unit tests and 57 end-to-end tests pass in debug, release, Rust 1.91, and musl; the two existing ignored tests remain unchanged. Formatting and strict all-target Clippy pass. The suite includes independent Quinn patterned-body loss, reordering, duplicate, and flow-control checks.
  • A deterministic replay through the actual Connection::on_ack path processes 512 complete 64 KiB requests, acknowledging each suffix first. Retained completed streams fall from 512 to 0 and their send-buffer capacity from 32 MiB to 0; one 64 KiB buffer remains pooled. With an unacknowledged older stream, only that stream remains live. Baseline/candidate and reversed-order replays give identical counts. Per-stream send state grows from 88 to 112 bytes on x86-64.
  • Immutable release CLIs, matched compiler/profile/dependency fingerprints, fixed hfast and Quinn peers (quinn-proto 0.11.19), warmups, three alternating pairs and three reversed pairs: 13,568,172 successes, zero errors, and 5,234,506,932 independently validated upload bytes.

Network timing guards are recorded below; this is a correctness/resource-retention fix with no throughput or equivalence claim. Small WSL effects remain uncertain.

Workload (c1 except final row) Median RPS change, primary / reversed Client CPU change, primary / reversed
8 MiB upload, p1, 16 MiB stream window -4.174% / -3.766% -0.363% / -1.972%
8 MiB upload, p8, 16 MiB window +6.735% / +10.695% -13.452% / -15.800%
1 MiB upload, p8, 16 MiB window -0.139% / +0.514% -0.127% / -2.068%
1 MiB upload, p8, 64 KiB window +12.186% / +3.981% -11.715% / -5.624%
1 MiB upload, p8, 2 KiB window +0.860% / -1.047% -1.015% / +0.318%
GET, p1 +0.980% / +0.970% -0.889% / -1.263%
GET, c16/p128 -1.895% / +5.306% +1.866% / +0.298%

Reproduce the committed regressions with cargo test quic::. Network guards use benchmarks/compare-h3-request-bodies.py and the unchanged benchmarks/quic-send-buffer-cases.json, following benchmarks/quic-send-buffer.md. Baseline: 126d3a4. Local detailed replay sources, manifests, and raw results are indexed by workspace experiment c122.

@hatoo
hatoo enabled auto-merge (squash) October 12, 2026 04:20
@hatoo
hatoo merged commit 18c8ecc into master Oct 12, 2026
4 checks passed
@hatoo
hatoo deleted the codex/fix-quic-sparse-ack-retirement-20261012 branch October 12, 2026 04:25
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