SQLite engine open: SqliteOpts, connection architecture, spawn_blocking seam posture (task sqlite-engine-open-opts)

- SqliteOpts (poll_interval: Option<Duration>, None = 1 ms shipping
  default ADR-023 §4; max_readers, DEFAULT_MAX_READERS = 8; opts
  exemption from non_exhaustive per ADR-017 §3)
- open(path, opts) -> Box<dyn Store>: writer slot, reader pool,
  SharedUpdateWatcher with fallible spawn mapped W-2-style into
  Error::Database; plain-path posture (ADR-023 §3) pinned by test
- Substrate delta D-30: open_conn_bootstrapped — every connection
  (writer and pooled readers) carries the full bootstrap surface
  (pragmas, notify, alkstore functions, schema) per engine-sqlite.md;
  lineage opened readers pragmas-only. Registered in PROVENANCE.md
- spawn_blocking seam helper + error mappings (string/rusqlite ->
  Database, source chains preserved); helper cfg(test)-gated until
  sqlite-engine-seam-tx wires the trait impls
- Store trait stubbed with Database errors (no panics); close()/Drop
  join the watcher, clear subscribers (death-guard), close pool+writer
- 15 new tests (open boot, watcher fanout/death-close, cadence
  accounting, plain-path literal filename, :memory:, pool bounding,
  drop teardown, seam smoke incl. panic mapping); gates green
This commit is contained in:
glm-5.3-flash committed 2026-10-08 11:25:16 +00:00
1 parent 5474141f2b
commit 7d400906f5
11 files changed
+937 -13

No files matched your search

+71 -1
View File
@@ -324,6 +324,27 @@ pub(crate) fn open_conn(path: &str, install_notify: bool) -> Result<Connection,
Ok(conn)
}
/// Open a connection carrying the engine's full per-connection
/// bootstrap: pragmas, notify machinery, this substrate's function
/// set, and schema bootstrap. The engine's `open` constructor runs
/// this on the writer and each pooled reader (engine-sqlite.md's
/// connection architecture: "each connection runs the substrate's
/// bootstrap at open").
///
/// D-30: the lineage's pools open readers through bare `open_conn`
/// (pragmas + notify only), the function set + schema living only on
/// the writer. This substrate extends the pool open path with
/// `attach_alkstore_functions` + `bootstrap_schema` — the engine's
/// reader-slot operations (claim/ack, stream reads, lock ops,
/// scheduler checks) run this substrate's SQL functions on pooled
/// connections, so every pooled connection must carry them.
pub(crate) fn open_conn_bootstrapped(path: &str) -> Result<Connection, Error> {
let conn = open_conn(path, true)?;
super::ops::attach_alkstore_functions(&conn)?;
bootstrap_schema(&conn)?;
Ok(conn)
}
pub(crate) struct Writer {
slot: Mutex<Option<Connection>>,
available: Condvar,
@@ -411,7 +432,7 @@ impl Readers {
*out += 1;
drop(out);
drop(pool);
match open_conn(&self.path, false) {
match open_conn_bootstrapped(&self.path) {
Ok(conn) => {
if self.closed.load(Ordering::Acquire) {
*self.outstanding.lock() -= 1;
@@ -577,6 +598,55 @@ mod writer_reader_tests {
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn open_conn_bootstrapped_carries_the_full_surface_on_every_connection() {
let dir = std::env::temp_dir().join(format!(
"alkstore-bootstrapped-{}-{:?}",
std::process::id(),
std::thread::current().id()
));
std::fs::create_dir_all(&dir).unwrap();
let path = dir.join("bootstrapped.db");
let first = open_conn_bootstrapped(path.to_str().unwrap()).unwrap();
drop(first);
for i in 0..3 {
let conn = open_conn_bootstrapped(path.to_str().unwrap())
.unwrap_or_else(|e| panic!("bootstrapped open {i} failed: {e}"));
let mode: String = conn
.pragma_query_value(None, "journal_mode", |r| r.get(0))
.unwrap();
assert!(mode.eq_ignore_ascii_case("wal"), "open {i}: not WAL");
let notify_fn: i64 = conn
.query_row("SELECT notify('__alkstore_probe', 'x')", [], |r| r.get(0))
.unwrap_or(0);
assert!(notify_fn >= 1, "open {i}: notify function missing");
let tables: i64 = conn
.query_row(
"SELECT count(*) FROM sqlite_master
WHERE type = 'table' AND name LIKE '__alkstore_%'",
[],
|r| r.get(0),
)
.unwrap();
assert!(
tables >= 7,
"open {i}: bootstrap schema missing (saw {tables} tables)"
);
let publish_ready: i64 = conn
.query_row(
"SELECT alkstore_stream_publish('__alkstore_probe', NULL, '{}')",
[],
|r| r.get(0),
)
.unwrap_or(0);
assert!(publish_ready >= 1, "open {i}: function set missing");
drop(conn);
}
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn concurrent_opens_never_return_database_is_locked() {
const ROUNDS: usize = 8;