Nine tasks against the wave-1 contract surface as reviewed (no amendments from the gate): - engine-mem / engine-local (parallel, dependency-free): the two engines; local owns the stage-hygiene exact-count tests and the Drop-cancellation story the wave-1 review recorded - store-construction: the Store type, constructor modes, size-threshold dispatch; binds the conformance factory's Store associated type - store-read-paths ∥ gc-protocol: read ops with the ADR-012 §6.1 fall-through rule; the ADR-005 in-process protocol (pins, liveness, delete windows, abort-as-data, GcRefuse with the full protection set) - store-put-paths: the two put paths behind one signature, ADR-003's three numbered rules, pin-before-publish, Batch, kv-only rejection - suite-column-mem → suite-column-local: the reference column, then the dual-tier dispatch-coverage shape mirroring it - review-wave-2: the gate (facade/dispatch/GC vs ADR-003/005/012) Verification: dependency graph validated (all ids resolve, no cycles, topological order clean); docs-only change. Refs: docs/plans/implementation.md §Wave 2
6.1 KiB
6.1 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| gc-protocol | In-process GC protocol — pins, liveness, delete windows, sweep, direct-delete refusal | pending |
|
broad | high | phase | implementation |
|
Description
Implement the in-process GC protocol (ADR-005; abort-as-data per
ADR-012 §1; non-SQL window staging per ADR-012 §5) on the Store type
— the architecture's most intricate state machine, in its single-node
form. The fleet extension (DB-backed pins, sweep lease, SQL
arbitration) is wave 6; this task is the protocol the fleet form
extends without changing its invariants.
- Pin registry (ADR-005 §Marks 2): per-key refcounts under the
arbitration lock the sweep consults.
Pinguards minted by the put path (store-put-pathswires the call sites; the registry and minting land here); a dedup re-put refcounts the existing entry — a dedup put's guard protects exactly as a fresh put's does.Pindrop decrements. Named design point: the guard's back-reference shape (how the publicPin/Batchtypes reach the registry — the wave-1 types carry only the key today) and the lock granularity (parking_lotshort-held per AGENTS convention 3, poisoning viaunwrap_or_else(|e| e.into_inner())). Batchmachinery: a batch's pins drop together on batch commit or batch drop, in one ordered step under the arbitration lock; no early single-pin release. The conversion ordering rule (ADR-005, pinned in facade.rs docs): a pin's drop and its replacement's registration into a liveness source are one ordered step under the same lock — the registry needs the API shape that makes the ordered step expressible.- Registered liveness sources (
register_liveness_source, the live-shared seam — ADR-005 §Decision): named design point — the source trait/callback shape. Live-shared means consulted at mark time and at delete-time arbitration, never snapshotted at registration (POC #1 finding 7's install-implies-copy failure is the pinning reason). - Protect callback: consulted pre-sweep; may add externally-known
hashes or abort the run — abort is report data
(
GcAbortCause::ProtectFailed), never an error (ADR-012 §1). sweep() → Result<SweepReport, Error>— the delete-window protocol (ADR-005 §Sweep):- mark: enumerate the whole pool (both tiers' complete
list()unioned); compute the live set from all three sources (registered sources, pins, protect callback); stage the candidate-dead set. - delete window: per candidate, arbitrate under the pin/ liveness lock at delete time (not once upfront) — pinned or re-observed-live cancels the candidate; otherwise proceed.
- commit: remaining candidates deleted in batches (~100/batch, iroh's proven shape); window closed.
Ok(SweepReport)always — sweeps are never errors; every abort is data inaborted: Option<GcAbortCause>(exactly three causes;NoLivenessSourcesis the safe default when zero sources are registered — nothing deleted). Exact counts in the report fields.- Non-SQL window staging (ADR-012 §5):
local/memstage candidates in-process and execute the window protocol inline in the same sweep — there is no durable window table on non-SQL engines, and the "executor is the next sweep" clause (ADR-012 §6.7) does not apply to them. - The test-asserted property (ADR-005): a visible pool entry is never deleted while liveness protects it, and an in-flight put is never deleted by a sweep started before it committed — concurrency tests (sweep racing a pinned put) assert it.
- mark: enumerate the whole pool (both tiers' complete
- Direct
delete(key)(wired through the fall-through dispatch — arbitration-then-delete where the entry lives): refuses any protected key — pinned, registered-source-live, or protect-callback-named (the full protection set, ADR-012 §6.4) — with the typedError::GcRefuse, nothing deleted; unprotected keys delete; absent keys carryErr(Missing). The refusal is decided at the facade (the altitude discipline:GcRefusenever fires below the facade). has/getduring a window observe no torn state — existence flips atomically per key (immutable entries); document the posture the engines' CAS semantics already give.
Acceptance Criteria
- Pin registry with per-key refcounts under the arbitration lock;
dedup re-puts refcount;
Pin/Batchdrops release through it (batch drops in one ordered step) register_liveness_sourcelive-shared (consulted at mark and at delete-time arbitration, never snapshotted); source shape decided and recorded- Protect callback with abort-as-data (
ProtectFailed);NoLivenessSourcessafe default;sweep()returnsOk(SweepReport)on every abort — never an abort error - Delete-window protocol: mark → arbitrate-at-delete-time →
batched commit (~100/batch), with exact-count
SweepReportfields (candidates_staged/deleted/cancelled_by_arbitration) - Direct
deleterefuses the full protection set withGcRefuseand deletes unprotected keys through the fall-through dispatch - Concurrency tests: sweep vs in-flight pinned put (the pin-before-publish property from the sweep side), exact-count outcomes, abort shapes
cargo testgreen;cargo test --features memandcargo test --all-featuresgreen; clippy/fmt gates green
References
- docs/architecture/decisions/005-pooled-cas-and-gc-mechanism.md (the protocol + invariants)
- docs/architecture/gc-and-namespaces.md (§Mark-and-sweep GC; §Delete windows)
- docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §1 (abort-as-data), §5 (non-SQL staging), §6.4 (full protection set)
- docs/architecture/store-api.md (§Lifecycle — sweep shape; §Invariants 4/5)
- src/facade.rs (the pinned Pin/Batch/SweepReport lifecycle contracts this wires)
- docs/research/poc-trait-dispatch-findings.md (findings 3/7/8)
Notes
To be filled by implementation agent
Summary
To be filled on completion