Repository navigation
[Router] Ask the fleet when a graft's splice goes unwitnessed (10/13) - #40696
Merged
Merged
Conversation
This was referenced Sep 22, 2026
Kangyan-Zhou
added this pull request to stack #40701
September 22, 2026 06:31
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-10-splice-probe
branch
from
September 27, 2026 02:28
0ffb8ac to
81ca8d2
Compare
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-10-splice-probe
branch
from
September 27, 2026 06:15
81ca8d2 to
9d05305
Compare
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-10-splice-probe
branch
from
September 27, 2026 07:04
9d05305 to
7190013
Compare
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-10-splice-probe
branch
from
September 27, 2026 09:07
7190013 to
46d56e2
Compare
ShangmingCai
force-pushed
the
router-peer-bootstrap-10-splice-probe
branch
3 times, most recently
from
September 28, 2026 10:49
3e766a2 to
75a6693
Compare
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-10-splice-probe
branch
from
September 28, 2026 21:53
75a6693 to
8ca6f8b
Compare
Kangyan-Zhou
force-pushed
the
router-peer-bootstrap-10-splice-probe
branch
from
September 29, 2026 21:48
8ca6f8b to
6cbe2de
Compare
ShangmingCai
force-pushed
the
router-peer-bootstrap-10-splice-probe
branch
from
September 30, 2026 08:34
6cbe2de to
8d488bc
Compare
Base automatically changed from
router-peer-bootstrap-9-shared-fetch
to
main
September 30, 2026 10:07
A graft whose held queue was empty leaves its watermark unchecked until a live batch arrives, and nothing guarantees one ever does. An idle rank would serve grafted state forever with its continuity unproven, and a `BlockRemoved` lost in the subscribe window would survive as a permanent false cache hit that no later event corrects. Silence is not evidence, so the bounded wait ends in a QUESTION, not a verdict. Reaching the deferred path means nothing arrived between subscribing and grafting, and the subscriber is live before the fetch — so silence is far more often "this rank published nothing" than "we lost a delta". Discarding on a timer would cost every quiet fleet its warm tree, which is the regression this feature exists to prevent. So the pump asks the fleet whether the publisher moved past the watermark. Any peer's cursor is admissible: sequence numbers are the publisher's, so a peer reporting one above ours proves a batch was emitted that we never saw. A peer too cold to bootstrap from is still a valid witness, which is why the probe reads the wire cursor directly instead of vetting. It asks for the cursor table alone, not a snapshot — the question is answered completely by one integer per rank, and fetching a tree to read it made the proof cost scale with the tree, so a fleet large enough to need bootstrap was also the fleet that could not afford to prove it. Only a witness ABOVE the watermark discards. A graft no batch and no peer can speak to is KEPT, tallied `warm_unwitnessed` rather than `warm`, after `MAX_UNKNOWN_PROBES` unanswerable rounds — without a stop, a single-replica deployment would re-probe forever and its verdict would never resolve in the metrics. The probe runs off-pump because it does network I/O; the verdict comes back over the pump's own control channel so the tree write stays on the single writer. An outstanding probe blocks relaunch inside its timeout and stops blocking past it: a verdict that never lands (a panicked probe task, say) would otherwise freeze the rank in `Recovered` with no outcome ever recorded. Also re-attaches `demote_unproven_rank`'s doc comment, which sat above `requeue_gapped_rank` describing the wrong function. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YZorgAox1CpLNHSjzpcxdb
…robe A splice probe answers for the graft it was launched about. Once a batch 0 has replaced that graft with a restarted engine's stream, a verdict still in flight, whose witnesses count in the dead numbering, must not demote the new stream's state. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0169aRN6guH335zF1pG456FC
ShangmingCai
force-pushed
the
router-peer-bootstrap-10-splice-probe
branch
from
September 30, 2026 10:07
8d488bc to
d847fdd
Compare
ShangmingCai
marked this pull request as ready for review
September 30, 2026 10:08
ShangmingCai
approved these changes
Sep 30, 2026
This was referenced Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack 10 of 13. Base:
router-peer-bootstrap-9-shared-fetch. 5 files changed, 833 insertions(+), 11 deletions(-)The stack
export_snapshot/restore_snapshot; nothing calls them yetGET /internal/kv_snapshot— the producer half; nothing consumes it yet--kv-peer-selector, the peer registry, the_peersgauges; no behaviour changeBootstrapTracker+ the fetch client; the consumer's state and transportVettedSnapshot::from_wire— the only bridge from wire bytes to the treePendingrank's batches and grafts a snapshot handed to itmatch_prefixanswers as the source/readyzholds until bootstrap settles;--kv-bootstrap-seed-required; the metricsEach PR's base is the branch below it, so every diff shown here is that
PR's own change. Review bottom-up; GitHub retargets each child to
mainasits parent merges.
What the series does
A router replica subscribes to each worker's KV topic mid-stream, so every
block already resident in the engine's radix cache is invisible to it — and
engines publish
BlockStoredonly as they insert, so a prefix cached hoursago is never re-announced. A cache-blind replica then scatters the prefixes the
warm replicas were keeping consolidated, degrading the engines' locality for
the whole fleet; a rolling update does that to every replica in turn. This
series makes a booting replica pull a tree snapshot from a warm sibling over
HTTP and graft it beneath its live delta stream. Off unless
--kv-peer-selectoris set.
Supersedes #39750, which carried the same work as one branch on a stale base.
What this change does
A graft whose held queue was empty leaves its watermark unchecked until a live
batch arrives, and nothing guarantees one ever does. An idle rank would serve
grafted state forever with its continuity unproven, and a
BlockRemovedlost inthe subscribe window would survive as a permanent false cache hit that no later
event corrects.
Silence is not evidence, so the bounded wait ends in a QUESTION, not a verdict.
Reaching the deferred path means nothing arrived between subscribing and
grafting, and the subscriber is live before the fetch — so silence is far more
often "this rank published nothing" than "we lost a delta". Discarding on a timer
would cost every quiet fleet its warm tree, which is the regression this feature
exists to prevent.
So the pump asks the fleet whether the publisher moved past the watermark. Any
peer's cursor is admissible: sequence numbers are the publisher's, so a peer
reporting one above ours proves a batch was emitted that we never saw. A peer too
cold to bootstrap from is still a valid witness, which is why the probe reads the
wire cursor directly instead of vetting. It asks for the cursor table alone, not
a snapshot — the question is answered completely by one integer per rank, and
fetching a tree to read it made the proof cost scale with the tree, so a fleet
large enough to need bootstrap was also the fleet that could not afford to prove
it.
A peer counts as a witness for a rank only when its table names that rank AT OR
ABOVE the watermark: a peer that never saw the rank, or whose cursor is below
the watermark (a stalled subscription, a reset we missed), cannot say what came
after, and counting it would manufacture a "no advance" out of ignorance. A
peer whose table carries a
SNAPSHOT_FORMATthis build does not recognise isskipped, the same rule vetting applies. A witness ABOVE the watermark resolves
the rank as
Advanced, which goes through the sameresolve_gapas thefirst-batch check — discard the graft, and one retry if the tracker allows it.
A graft no batch and no peer can speak to is KEPT, tallied
warm_unwitnessedrather than
warm, afterMAX_UNKNOWN_PROBESunanswerable rounds — without astop, a single-replica deployment would re-probe forever and its verdict would
never resolve in the metrics.
The probe runs off-pump because it does network I/O; the verdicts come back over
the pump's own control channel so the tree write stays on the single writer. It
runs as ONE pass per sweep tick for every due rank, fetching each peer's cursor
table at most once and judging every rank against it, so idle ranks do not
multiply the fleet's work. A pass is capped by
SPLICE_PROBE_BUDGET, one tickshort of the proof timeout, so passes never overlap and a hung peer cannot
stack up concurrent passes; a peer not reached inside the budget is simply not
a witness this pass. Each verdict carries the graft's watermark as well as its
epoch: a gap retry re-grafts under the same incarnation, so a stale verdict
about the previous graft is recognised and ignored. A verdict that never lands
(a panicked probe task, say) does not freeze the rank: it is re-probed once
the timeout since the last launch elapses.
Fresh-engine fix
Rebased onto the fixed #40693–#40695; the only code conflict was placing
demote_unproven_ranknext toresolve_from_origin. The pump's batch-0 restart arm removes the rank'sawaiting_splice_proofentry, so a probe verdict still in flight for the replaced graft is dropped.probe::tests::pump_drops_a_probe_verdict_about_a_graft_a_restart_replacedpins that.Tests
cargo fmt --check,cargo clippy --all-targets -- -D warnings, and the lib +component + proxy suites all pass on this branch on its own, not only on the
tip of the stack.
Review pass
Reviewed with
/code-review --fixand/simplify; fixes were folded into this PR's own commit and the stack was re-verified tier by tier (cargo fmt --check,cargo clippy --all-targets -D warnings, lib + component + proxy tests on every branch).state/kv_events/index/probe.rs(new), plusindex.rs; no file the stack creates exceeds ~1,300 lines.🤖 Generated with Claude Code
https://claude.ai/code/session_016HmJvHV7QDPk3qAjQYzthd
CI States
Latest PR Test (Base): ✅ Run #36700533783
Latest PR Test (Extra): ❌ Run #36700533552
Latest PR Test (AMD ROCm 10): ➖ No AMD PR run found for this commit.