The first durable delete window (single-node), beside the inline form: - sweep_window branches on the delete window's host — the kv-engine enum (KvEngine::Sqlite -> durable; KvEngine::Mem -> inline body, extracted verbatim so the wave-2 mem/local suites stay green unchanged) - the durable form, per sweep under the lease and after the shared protect consult: window_take(now) executes the overdue set with execution-time re-arbitration through the same arbitrated_delete path (consult_protect = false — the sweep's protect consult covers its execution phase; vanished candidates settle into the cancelled count), then marks unchanged, then stages the candidate-dead set at visible_after = mark_end + window (the constructor-tunable delay; ZERO = execute-on-next-sweep) - report counts exact relative to the schedule (staged-this-sweep vs executed-this-sweep); aborts execute nothing, stage nothing, delete nothing - unit tests: two-sweep exact-count shapes at delay 0, future-delay staging with idempotent re-stage, the race across the delay (put during the window survives; the unpinned twin deletes), the vanished-candidate form, and the three abort shapes on sqlite Verification: cargo test (default 69 lib tests), --all-features (124), --no-default-features --features mem (101), clippy -D warnings (default and --all-features), cargo fmt --check — all green.
8.4 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | |||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| store-sweep-durable-window | the sweep's durable-window form — staged candidates, next-sweep execution | completed |
|
moderate | medium | phase | implementation |
|
Description
Grow the sweep's SQL-backed form (ADR-008 §2; ADR-012 §5/§6.7)
beside the inline form in src/store.rs — the first durable delete
window, single-node:
- The branch: the sweep runs the durable form when the kv engine
hosts the window (sqlite — the one-window-host posture); the inline
form is preserved verbatim for non-SQL engines (mem/local — the
wave-2 sweep tests stay green unchanged). The branch keys off the
engine representation (the
KvEnginematch), never off a flag. - The single-node posture is unchanged (ADR-008 §2): pins, RAII
guards, and the arbitration lock stay in-process (
GcHome) — only the persistence of the delete window (the staged-candidate table) is engine rows. - The durable form's protocol (per sweep, under the lease):
- Execute overdue (before/alongside marking — ADR-012 §6.7):
window_take(now)returns the overdue keys; each is re-arbitrated at execution time through the samearbitrated_deletepath and deleted in batches. The protect- consult posture on this path is a recorded design point (the sweep's protect consult covers its execution phase — the same reasoning that keeps the inline form's candidates atconsult_protect = false). A vanished candidate (deleted during the delay by a direct delete) settles into the cancelled count — the vanished-candidate accounting carries over. - Mark: enumerate the pool, compute the live set, compute the candidate-dead set (unchanged).
- Stage:
window_stage(candidates)atvisible_after = mark_end + window— the constructor-tunable delay (ADR-008 §2; the store carries the value its constructor took). - Report:
candidates_staged= candidates staged this sweep;deleted/cancelled_by_arbitration= the executed overdue set. Exact-count invariants are asserted relative to this schedule (ADR-012 §6.7) — staged-this-sweep and executed-this-sweep are different sets (the delay separates them); the suite's sqlite column asserts the two-sweep shapes (suite-column-sqlite).
- Execute overdue (before/alongside marking — ADR-012 §6.7):
- Abort shapes unchanged:
NoLivenessSources/ProtectFailed/SweeperLockabort before anything is staged or executed (nothing deleted,Ok(SweepReport)); operational failures (engine I/O) are theErrhalf (ADR-012 §1). - The sweep-vs-put race under the durable form: a put landing during the window delay pins in-process (pin-before-publish); the execution-time re-arbitration sees the pin and cancels the candidate — the test-asserted property (a visible entry is never deleted while liveness protects it; an in-flight put is never deleted by a sweep started before it committed) holds across the delay, and is unit-tested in that form.
- Unit tests in
store.rs: two-sweep exact-count shapes (sweep 1 stages N at delay 0 → sweep 2 executes exactly N — deleted + cancelled == N against the staged set); the race across the delay (put during the window survives; the unpinned twin deletes); the abort shapes on a sqlite store; the vanished-candidate form; the inline form untouched (the mem/local suites stay green).
Acceptance Criteria
- The sweep branches on window hosting; the inline form's behavior and its wave-2 tests unchanged
- Durable form: overdue rows execute with execution-time
re-arbitration before/alongside marking; candidates stage at
visible_after = mark_end + window - Report counts exact relative to the schedule (unit-tested two-sweep shapes); aborts delete nothing
- The race property unit-tested across the delay (a put landing during the window survives the next sweep's execution)
- The protect-consult posture on overdue execution recorded
cargo test(default) green;cargo clippy --all-targets -- -D warningsandcargo fmt --checkgreen
References
- src/store.rs (the sweep —
sweep/sweep_window/arbitrated_delete) - docs/architecture/decisions/005-pooled-cas-and-gc-mechanism.md (§Sweep — the protocol)
- docs/architecture/decisions/008-trait-size-probe-fleet-gc-and-large-engines.md §2 (the staged re-arbitrated delete; the delay)
- docs/architecture/decisions/012-pre-decomposition-consistency-rulings.md §1 (abort-as-data), §5 (single-node posture unchanged), §6.7 (the executor is the next sweep)
- docs/architecture/decisions/013-family-composition-reactive-boundary-and-feature-graph.md §2 (the lease semantics)
- src/gc.rs (
GcHomearbitration;EngineWindowStatethe store core calls)
Notes
To be filled by implementation agent
The durable form's shape as it landed:
- The branch is the kv-engine enum match itself (
sweep_window'smatch &self.kv):KvEngine::Sqlite(engine)runs the durable form,KvEngine::Mem(_)runs the inline form. The two durable helpers are generic overW: EngineWindowState(the seam hasBackendassociated types, so a&dynhandout is not object-safe — the concrete&SqliteBackendpasses directly). Wave 5's pg-lo slots one more match arm in. - The inline body was extracted verbatim into
sweep_window_inline(the wave-2/all-features mem+local suites run green unchanged); the protect consult stays insweep_windowabove the branch, shared by both forms. - The protect-consult posture on overdue execution is recorded as a
doc point on
execute_overdue_window: the consult already ran for the sweep (its abort,ProtectFailed, precedes execution) and its coverage extends to the executor phase, so the overdue re-arbitrations carryconsult_protect = false— the inline form's same posture. - Malformed window rows are fatal (
Error::KeyInvalidvia the sharedtyped_keysboundary) — the pool-list discipline extended to the window read. visible_afteroverflow isErr(Error::Io)(checked clock add); no panics on the library path.- Report shape:
candidates_staged= staged this sweep;deleted/cancelled_by_arbitration= the overdue set executed this sweep (a vanished candidate settles into the cancelled count). Thesweep()doc states the exact-count invariants relative to each form's schedule.
Summary
To be filled on completion
The sweep's durable SQL-backed form landed beside the inline form in
src/store.rs (the first durable delete window, single-node; ADR-008
§2 staged re-arbitrated delete, ADR-012 §5/§6.7 the-executor-is-the-
next-sweep):
sweep_windowbranches on the delete window's host — the kv-engine enum (KvEngine::Sqlite→ durable;KvEngine::Mem→ inline, extracted verbatim). Under the lease: the protect consult (abortProtectFailedprecedes any execution), then for the durable form execute overdue —window_take(now)→ execution-time re-arbitration througharbitrated_delete(key, false)in ~100-key batches (vanishes count as cancelled) — then mark (unchanged), then stage atvisible_after = mark_end + window(the constructor-tunable delay;Duration::ZERO= execute-on-next- sweep). Report counts exact relative to the schedule.- Abort shapes unchanged and unit-tested on sqlite:
NoLivenessSources/ProtectFailed/SweeperLockabort before anything is executed or staged; theProtectFailedtest proves the overdue set is left waiting in the window (abort precedeswindow_take). - Unit tests (
sqlite_window_tests): two-sweep exact counts at delay 0 (sweep 1 stages both tiers' dead entries without executing; sweep 2 executes exactly the staged set), future-delay staging (no execution before the window closes; re-stage is idempotent), the race across the delay (a put landing during the window survives via the execution-time re-arbitration; the unpinned twin deletes; the cancelled candidate re-stages and executes once unpinned), the vanished-candidate form, and the three abort shapes.
Verification: cargo test (69 lib + 5 integration, default), 124
tests --all-features, 101 tests --no-default-features --features mem, cargo clippy --all-targets -- -D warnings (default and
--all-features), and cargo fmt --check all green; the mem/local
wave-2 suites pass unchanged (the inline form untouched).