SQLite engine integration: lint removal, contract-suite adoption, backlog column (task sqlite-engine-integration)
- Remove the wave-2 lint suppressions from substrate/mod.rs; the six genuinely dead surfaces the removal exposed are cut, not suppressed, and registered D-32..D-36 in PROVENANCE.md (arg_opt_i64, ops::now_unix, queue_next_claim_at, Writer::try_acquire, UpdateWatcher::spawn, SharedUpdateWatcher::new); test-observation items (subscriber_count, the poll-interval default re-export) are honestly #[cfg(test)]-gated - Contract suite: eight new version-stamped backlog rows (extent-clamp + boundary totality, duration-refusal, encode_payload round-trip, PayloadTooLarge-never-produced SQLite arm, drop=rollback no-ghosts, in-tx read-your-own-writes, enqueue-opts resolution, receiver close/save arms) - Fix the exemplar row's real-engine sequencing defect: the held tx handle across the with_tx leg deadlocked any single-writer factory (mock-invisible; ADR-007's parking is the pinned behavior) - SQLite factory: SqliteFactory in the new tests/contract_suite.rs target; all nine rows green against it; the factory contract (isolation + idempotent teardown) pinned - Engine lib docs: the single-host and writer-parking posture statements surfaced under # Posture - Gates: build/test/clippy -D warnings/fmt green; coverage 93.6% lines, misses confined to error arms
This commit is contained in:
1 parent
8502a51af7
commit
a82c543b40
12 files changed
+1067
-245
No files matched your search
@@ -242,23 +242,16 @@ pub(crate) struct UpdateWatcher {
|
||||
const UPDATE_WATCHER_IDENTITY_INTERVAL: Duration = Duration::from_millis(100);
|
||||
|
||||
impl UpdateWatcher {
|
||||
/// Spawn a watcher thread on `db_path`. `on_change` is called once
|
||||
/// per observed commit. The thread runs until [`UpdateWatcher`] is
|
||||
/// dropped or [`stop`](Self::stop) is called.
|
||||
/// Spawn a watcher thread on `db_path` with an explicit poll
|
||||
/// cadence. `on_change` is called once per observed commit. The
|
||||
/// thread runs until [`UpdateWatcher`] is dropped or
|
||||
/// [`stop`](Self::stop) is called.
|
||||
///
|
||||
/// Fallible (W-2 — ADR-012 §4): errors if the thread cannot be
|
||||
/// spawned; the engine surfaces the failure at store-open time.
|
||||
/// Baseline-capture failures inside the thread (open failures, a
|
||||
/// vanished db file) leave the sender dropped and the loop itself
|
||||
/// retrying per W-1's bounded backoff — not a spawn failure.
|
||||
pub(crate) fn spawn<F>(db_path: PathBuf, on_change: F) -> Result<Self, String>
|
||||
where
|
||||
F: Fn() + Send + 'static,
|
||||
{
|
||||
Self::spawn_with_config(db_path, on_change, WatcherConfig::default())
|
||||
}
|
||||
|
||||
/// Like [`spawn`](Self::spawn) but with an explicit poll cadence.
|
||||
pub(crate) fn spawn_with_config<F>(
|
||||
db_path: PathBuf,
|
||||
on_change: F,
|
||||
@@ -356,15 +349,11 @@ pub(crate) struct SharedUpdateWatcher {
|
||||
}
|
||||
|
||||
impl SharedUpdateWatcher {
|
||||
/// Spawn the shared poll thread for `db_path`.
|
||||
/// Spawn the shared poll thread for `db_path` with an explicit
|
||||
/// poll cadence.
|
||||
///
|
||||
/// Fallible (W-2 — ADR-012 §4): the engine surfaces the failure at
|
||||
/// store-open time.
|
||||
pub(crate) fn new(db_path: PathBuf) -> Result<Self, String> {
|
||||
Self::new_with_config(db_path, WatcherConfig::default())
|
||||
}
|
||||
|
||||
/// Like [`new`](Self::new) but with an explicit poll cadence.
|
||||
pub(crate) fn new_with_config(db_path: PathBuf, config: WatcherConfig) -> Result<Self, String> {
|
||||
let senders: Arc<Mutex<HashMap<u64, SyncSender<()>>>> =
|
||||
Arc::new(Mutex::new(HashMap::new()));
|
||||
@@ -413,6 +402,7 @@ impl SharedUpdateWatcher {
|
||||
self.senders.lock().remove(&id);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) fn subscriber_count(&self) -> usize {
|
||||
self.senders.lock().len()
|
||||
}
|
||||
@@ -501,7 +491,8 @@ mod watcher_tests {
|
||||
let tmp = temp_db("shared-fanout");
|
||||
wal_db(&tmp);
|
||||
|
||||
let shared = SharedUpdateWatcher::new(tmp.clone()).unwrap();
|
||||
let shared =
|
||||
SharedUpdateWatcher::new_with_config(tmp.clone(), WatcherConfig::default()).unwrap();
|
||||
let subs: Vec<(u64, std::sync::mpsc::Receiver<()>)> =
|
||||
(0..50).map(|_| shared.subscribe()).collect();
|
||||
|
||||
@@ -539,7 +530,8 @@ mod watcher_tests {
|
||||
let tmp = temp_db("unsub");
|
||||
wal_db(&tmp);
|
||||
|
||||
let shared = SharedUpdateWatcher::new(tmp.clone()).unwrap();
|
||||
let shared =
|
||||
SharedUpdateWatcher::new_with_config(tmp.clone(), WatcherConfig::default()).unwrap();
|
||||
let (id, rx) = shared.subscribe();
|
||||
assert_eq!(shared.subscriber_count(), 1);
|
||||
|
||||
@@ -570,7 +562,8 @@ mod watcher_tests {
|
||||
let tmp = temp_db("death-signal");
|
||||
wal_db(&tmp);
|
||||
|
||||
let shared = SharedUpdateWatcher::new(tmp.clone()).unwrap();
|
||||
let shared =
|
||||
SharedUpdateWatcher::new_with_config(tmp.clone(), WatcherConfig::default()).unwrap();
|
||||
let (_id, rx) = shared.subscribe();
|
||||
|
||||
// Let the watcher snapshot the initial identity.
|
||||
@@ -610,7 +603,8 @@ mod watcher_tests {
|
||||
let tmp = temp_db("watcher-replace");
|
||||
wal_db(&tmp);
|
||||
|
||||
let watcher = UpdateWatcher::spawn(tmp.clone(), || {}).unwrap();
|
||||
let watcher =
|
||||
UpdateWatcher::spawn_with_config(tmp.clone(), || {}, WatcherConfig::default()).unwrap();
|
||||
|
||||
std::thread::sleep(Duration::from_millis(200));
|
||||
|
||||
@@ -637,7 +631,8 @@ mod watcher_tests {
|
||||
let tmp = temp_db("prune");
|
||||
wal_db(&tmp);
|
||||
|
||||
let shared = SharedUpdateWatcher::new(tmp.clone()).unwrap();
|
||||
let shared =
|
||||
SharedUpdateWatcher::new_with_config(tmp.clone(), WatcherConfig::default()).unwrap();
|
||||
{
|
||||
let _subs: Vec<_> = (0..10).map(|_| shared.subscribe()).collect();
|
||||
assert_eq!(shared.subscriber_count(), 10);
|
||||
|
||||
Reference in new issue
Block a user