Skip to content

fix(cache): collapse the double whole-capsule pull into one shared single-flight gate (#1614) - #142

Merged
MichaelTaylor3d merged 2 commits into
mainfrom
fix/1614-dedupe-whole-capsule-pull
Aug 2, 2026
Merged

fix(cache): collapse the double whole-capsule pull into one shared single-flight gate (#1614)#142
MichaelTaylor3d merged 2 commits into
mainfrom
fix/1614-dedupe-whole-capsule-pull

Conversation

@MichaelTaylor3d

Copy link
Copy Markdown
Contributor

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_capsulegap_fill_generationcache_fetch_and_cachesync_module_from, tracked in Node::backfilling), and Leg B, the PR#108 P2P reshare (fetch_resourcespawn_capsule_reshareCapsuleWarmer::warm, tracked in WarmRegistry). Two in-flight registries blind to each other → two transports, two whole-.dig writes → 2× bandwidth/disk/CPU on the flywheel's core loop. (Integrity was never at risk — both writers write_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::warmRefused(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's format!("{store}:{root}") == WarmRegistry's key), so the collapse is race-free by construction.

  • lib.rsbackfilling: Mutex<HashSet<String>>capsule_acquisition: Arc<WarmRegistry> (+ capsule_acquisition_gate() accessor); all 7 constructor sites updated.
  • capsule_store.rsmaybe_backfill_capsule claims 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.rswire_capsule_reshare takes the Arc<WarmRegistry> and the production call site passes the Node's capsule_acquisition_gate(), so both legs share one instance.
  • module_reshare.rsWarmRegistry::claim + WarmClaim raised to pub(crate).
  • content_serve.rs untouched — the dedup is internal to the gate; the #1654 land_origin fold and tier ordering are preserved.

The max_concurrent = 4 cap now bounds total concurrent whole-capsule pulls across both transports (a beneficial tightening).

Verification

  • New/migrated tests pass: 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 migrated backfill_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.md entry 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].version 0.74.4 → 0.74.5.


Generated by Claude Code

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
MichaelTaylor3d force-pushed the fix/1614-dedupe-whole-capsule-pull branch from c4c36c9 to 5d98005 Compare August 2, 2026 11:33
…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
MichaelTaylor3d force-pushed the fix/1614-dedupe-whole-capsule-pull branch from 5d98005 to 77c5e5c Compare August 2, 2026 11:48
@MichaelTaylor3d
MichaelTaylor3d merged commit 7a8d2b8 into main Aug 2, 2026
15 checks passed
@MichaelTaylor3d
MichaelTaylor3d deleted the fix/1614-dedupe-whole-capsule-pull branch August 2, 2026 12:28
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