64 lines
2.6 KiB
Markdown
64 lines
2.6 KiB
Markdown
---
|
|
id: sqlite-engine-locks
|
|
name: SQLite engine — named locks (`try_lock`, `Lock` handle, duration guards)
|
|
status: pending
|
|
depends_on: [sqlite-engine-seam-tx]
|
|
scope: narrow
|
|
risk: low
|
|
impact: component
|
|
level: implementation
|
|
tags: [wave-3, sqlite-engine]
|
|
---
|
|
|
|
## Description
|
|
|
|
Implement `Store::try_lock` and the `Lock` trait over the substrate's
|
|
lock ops (`lock_acquire`, `lock_release`, `lock_renew`):
|
|
|
|
- `try_lock(name, owner, ttl)` — validated entry point (name:
|
|
shared-namespace rules; owner: non-empty only); `None` = someone
|
|
holds it (no-work is a value). Returns the boxed `Lock` handle.
|
|
- **Duration guard (ADR-023 §2)**: `ttl <= 0` is a rejection —
|
|
`Err`, opaque `Database` shape — enforced at the trait-impl entry,
|
|
before the substrate. The substrate's `lock_renew` already guards
|
|
`ttl_s <= 0` (its message preserved in the source chain where it
|
|
fires); `lock_acquire` does not — the engine guards both call sites
|
|
uniformly so the rule is contract-side, not substrate-side (the pg
|
|
engine implements the same rule with no inherited guard at all).
|
|
- `Lock::renew(ttl)` — same duration guard; a new full TTL window
|
|
from now; `false` = lost it (expired and re-acquired elsewhere).
|
|
- `Lock::release(self)` — consuming; `true` = was held; `false` =
|
|
already expired/re-acquired (no-op, not an error).
|
|
- Exclusion lapses silently at TTL expiry (no revocation event) —
|
|
the substrate's expired-row delete on next acquire is the
|
|
mechanism; pin the lapse-then-reacquire shape in tests.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- [ ] `try_lock` grants exclusively (second acquirer gets `None`);
|
|
release makes it acquirable again
|
|
- [ ] Duration guards: `try_lock`/`renew` with `ttl <= 0` return
|
|
opaque `Err` (`Database`) — never a granted lock, never a
|
|
panic; substrate guard message preserved in the source chain on
|
|
`renew` — pinned per ADR-023 §2's backlog row
|
|
- [ ] `renew` extends from now (full window, not additive); foreign
|
|
owner cannot renew; `false` on lapsed/re-acquired
|
|
- [ ] `release` removes only the owner's row; `false` = no-op shape
|
|
- [ ] TTL lapse: after expiry, another owner acquires (silent lapse)
|
|
- [ ] `cargo test -p alkstore-sqlite`, clippy `-D warnings`, fmt clean
|
|
|
|
## References
|
|
|
|
- docs/architecture/core-contract.md (locks section, numeric-domain rules)
|
|
- docs/architecture/decisions/008-contract-v1-pinning.md §7
|
|
- docs/architecture/decisions/019-mechanism-handle-surfaces.md §1
|
|
- docs/architecture/decisions/023-fourth-review-round.md §2
|
|
- alkstore-sqlite/src/substrate/ops.rs (lock_* fns)
|
|
|
|
## Notes
|
|
|
|
> To be filled by implementation agent
|
|
|
|
## Summary
|
|
|
|
> To be filled on completion |