feat(store): the sweep's durable form — staged candidates, next-sweep execution
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.
This commit is contained in:
1 parent
2993df0e36
commit
fb8326c4d5
3 files changed
+737
-42
No files matched your search
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: store-sweep-durable-window
|
||||
name: the sweep's durable-window form — staged candidates, next-sweep execution
|
||||
status: pending
|
||||
status: completed
|
||||
depends_on: [store-sqlite-construction]
|
||||
scope: moderate
|
||||
risk: medium
|
||||
@@ -94,6 +94,71 @@ window, single-node:
|
||||
|
||||
> 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`'s
|
||||
`match &self.kv`): `KvEngine::Sqlite(engine)` runs the durable form,
|
||||
`KvEngine::Mem(_)` runs the inline form. The two durable helpers are
|
||||
generic over `W: EngineWindowState` (the seam has `Backend`
|
||||
associated types, so a `&dyn` handout is not object-safe — the
|
||||
concrete `&SqliteBackend` passes 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 in `sweep_window` above
|
||||
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 carry `consult_protect = false` — the inline form's
|
||||
same posture.
|
||||
- **Malformed window rows are fatal** (`Error::KeyInvalid` via the
|
||||
shared `typed_keys` boundary) — the pool-list discipline extended to
|
||||
the window read.
|
||||
- **`visible_after` overflow is `Err(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). The
|
||||
`sweep()` doc states the exact-count invariants relative to each
|
||||
form's schedule.
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
> 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_window` branches on the delete window's host — the kv-engine
|
||||
enum (`KvEngine::Sqlite` → durable; `KvEngine::Mem` → inline,
|
||||
extracted verbatim). Under the lease: the protect consult (abort
|
||||
`ProtectFailed` precedes any execution), then for the durable form
|
||||
**execute overdue** — `window_take(now)` → execution-time
|
||||
re-arbitration through `arbitrated_delete(key, false)` in
|
||||
~100-key batches (vanishes count as cancelled) — then **mark**
|
||||
(unchanged), then **stage** at `visible_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`/`SweeperLock` abort before
|
||||
anything is executed or staged; the `ProtectFailed` test proves the
|
||||
overdue set is left waiting in the window (abort precedes
|
||||
`window_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).
|
||||
Reference in new issue
Block a user