Skip to content

fix(router): timer-driven reorder flush so a stalled leg degrades gracefully - #4233

Merged
0pcom merged 1 commit into
skycoin:developfrom
0pcom:fix-reorder-timer-flush
Aug 26, 2026
Merged

fix(router): timer-driven reorder flush so a stalled leg degrades gracefully#4233
0pcom merged 1 commit into
skycoin:developfrom
0pcom:fix-reorder-timer-flush

Conversation

@0pcom

@0pcom 0pcom commented Aug 26, 2026

Copy link
Copy Markdown
Collaborator

The per-frame reorder skip-flush only ran inside reorder.Insert, firing on the next out-of-order packet to arrive. A leg that goes fully silent delivers nothing to trigger it, so the frontier gap ages unbounded and the stream wedges to zero — observed live as a reorder gap_age of ~10s while a download stalled and the connection dropped mid-transfer.

Adds a periodic release: FlushIfStalled() runs the same skip gate (skip-capable + gap held past reorderTimeout) without a triggering insert; the mux wrapper advances the SACK tracker like deliverData; a 500ms reorder-flush service loop pushes released payloads to readCh on the same watched-close path as handleDataPacket. No-op for non-per-frame groups (gated on skipCapable).

Net: a silent/dead legs gap is released within ~one reorderTimeout of going quiet, the buffer delivers past it, and SACK/TCP recovers the skipped sequences — the proxy degrades to the surviving legs rate instead of wedging. This is the graceful-degradation half of the mux-stability work. Developed with AI assistance (Claude).

…cefully

The per-frame reorder skip-flush only ran INSIDE reorder.Insert — it fired on the
next out-of-order packet to arrive. A leg that goes fully silent (dead/black-holing)
delivers nothing to trigger it, so the frontier gap ages unbounded and the stream
wedges to zero (observed live: reorder gap_age ~10s while the download stalled and
the connection dropped mid-transfer).

Add a periodic release: reorderBuffer.FlushIfStalled() runs the same skip gate
(skipCapable && gap held past reorderTimeout) without needing a triggering insert;
routeMux.flushStalledReorder() wraps it + advances the SACK tracker like
deliverData; RouteGroup.reorderFlushServiceFn pushes released payloads to readCh on
the same watched-close path as handleDataPacket, driven by a 500ms service loop
(shorter than the 1.5s reorderTimeout). A no-op for non-per-frame groups
(gated on skipCapable), so it is safe to start unconditionally.

Net: a silent/dead leg's gap is released within ~one reorderTimeout of going quiet,
the buffer delivers past it, and SACK/TCP recovers the skipped seqs — the proxy
degrades to the surviving legs' rate instead of wedging. Graceful degradation.
@0pcom
0pcom merged commit fa4428a into skycoin:develop Aug 26, 2026
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