fix(cache): collapse the double whole-capsule pull into one shared single-flight gate (#1614) - #142
Merged
Merged
Conversation
Red anchor for collapsing the double whole-capsule pull (§21 backfill + #1576 reshare) into ONE shared single-flight gate keyed (store,root). Refs #1614 Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d
force-pushed
the
fix/1614-dedupe-whole-capsule-pull
branch
from
August 2, 2026 11:33
c4c36c9 to
5d98005
Compare
…gle-flight gate (#1614) A read miss could pull the SAME (store, root) whole `.dig` down two blind in-flight sets: the §21 authenticated backfill (`maybe_backfill_capsule` -> `gap_fill_generation`, keyed in `Node::backfilling`) AND the #1576 P2P reshare warm (`CapsuleWarmer`, keyed in its own `WarmRegistry`). Two transports for one artifact firing at once = 2x bandwidth/disk/CPU per read. Collapse them onto ONE shared single-flight gate keyed (store,root): - `Node::backfilling` becomes `Node::capsule_acquisition: Arc<WarmRegistry>`. - `wire_capsule_reshare` takes the node's gate (`capsule_acquisition_gate()`) and wires the warmer with that Arc instead of a fresh registry, so both legs test-and-set ONE registry (keys were already byte-identical across the sites). - `maybe_backfill_capsule` claims the shared gate and MOVES the claim guard into the spawned task (releases on completion/drop). Origin/config/held gates still run BEFORE any claim (#1576/#1654), so a gated-out read consumes no slot. - `WarmRegistry::claim`/`WarmClaim` raised to pub(crate). Both legs remain: §21 stays the peerless-network holder-acquisition fallback (the reshare leg has none). The registry's distinct-generation cap now bounds concurrent acquisitions across BOTH legs, not each alone. Tests: cross-leg dedup both directions, ptr_eq that the warmer keeps the passed registry Arc, migrated the `backfilling` unit tests to `capsule_acquisition`. SPEC §21.4/§21.7/§14.3 + DEVELOPMENT_LOG updated. Version 0.74.4 -> 0.74.5. Closes #1614 Co-Authored-By: Claude <noreply@anthropic.com>
MichaelTaylor3d
force-pushed
the
fix/1614-dedupe-whole-capsule-pull
branch
from
August 2, 2026 11:48
5d98005 to
77c5e5c
Compare
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.
What changed
Closes DIG-Network/dig_ecosystem#1614.
On a read miss, two independent whole-capsule pulls fired for the same
(store, root): Leg A, the §21 backfill-on-miss (maybe_backfill_capsule→gap_fill_generation→cache_fetch_and_cache→sync_module_from, tracked inNode::backfilling), and Leg B, the PR#108 P2P reshare (fetch_resource→spawn_capsule_reshare→CapsuleWarmer::warm, tracked inWarmRegistry). Two in-flight registries blind to each other → two transports, two whole-.digwrites → 2× bandwidth/disk/CPU on the flywheel's core loop. (Integrity was never at risk — both writerswrite_atomic+ verify independently — but the cost was double what the SPEC describes.)The fix — one shared single-flight acquisition gate keyed
(store, root)Both legs remain; they now claim against one
WarmRegistry, so exactly one whole-capsule pull runs per(store, root)at a time. This was chosen over retiring §21 because neither leg subsumes the other: the P2P reshare cannot source on a peerless/stranger network (CapsuleWarmer::warm→Refused(PullFailed)with no holders, and it has no §21 fallback), so §21 (rpc.dig.net, the §5.3 read-ladder fallback) must remain the holder-acquisition path there. A shared gate is also race-free and covers both doubles — the Tier-2 peer-serve one and the verify-fail-fallthrough — where a naive single-site edit would miss the second.The keys were already byte-identical across all three sites (
CapsuleKey::Display==maybe_backfill'sformat!("{store}:{root}")==WarmRegistry's key), so the collapse is race-free by construction.lib.rs—backfilling: Mutex<HashSet<String>>→capsule_acquisition: Arc<WarmRegistry>(+capsule_acquisition_gate()accessor); all 7 constructor sites updated.capsule_store.rs—maybe_backfill_capsuleclaims the shared gate, moving the guard into the spawned task; the origin / config /p2p_content/ held gates are unchanged and still precede the claim (load-bearing for #1576/#1654 — never claim ahead of the gates).download.rs/peer.rs—wire_capsule_resharetakes theArc<WarmRegistry>and the production call site passes the Node'scapsule_acquisition_gate(), so both legs share one instance.module_reshare.rs—WarmRegistry::claim+WarmClaimraised topub(crate).content_serve.rsuntouched — the dedup is internal to the gate; the #1654land_originfold and tier ordering are preserved.The
max_concurrent = 4cap now bounds total concurrent whole-capsule pulls across both transports (a beneficial tightening).Verification
capsule_acquisition_gate_is_a_single_shared_registry,backfill_defers_to_an_in_flight_reshare_on_the_shared_gate,reshare_defers_to_an_in_flight_backfill_on_the_shared_gate,a_warmer_shares_the_exact_registry_arc_it_was_built_with(Arc::ptr_eq), plus the migratedbackfill_is_a_noop_without_a_peer_network(the peerless §21-fallback pin),backfill_skips_an_already_held_capsule, and the Local/Peer-origin control pair. The distinct-generation cap now governs both legs transitively (one shared registry).cargo fmt --all -- --check→ exit 0 ·cargo clippy -p dig-node-core --all-targets --all-features -- -D warnings→ clean ·cargo test -p dig-node-core→ all pass except the 9 pre-existing port-binding/dual-stack env tests that fail identically on a clean tree (local-only; green in CI).SPEC.md§21.4 / §21.7 / §14.3 cost-model updated (a single read triggers at most one whole-capsule acquisition, and the two legs dedup against each other under one cap);DEVELOPMENT_LOG.mdentry added. No SYSTEM.md / docs change (internal node behavior).Version
fix:(internal bandwidth/cost fix; no public API / wire / RPC /.dig-format change; both legs still exist) →[workspace.package].version0.74.4 → 0.74.5.Generated by Claude Code