diff --git a/crates/tj-core/src/memory.rs b/crates/tj-core/src/memory.rs index 6ae32bb..395831f 100644 --- a/crates/tj-core/src/memory.rs +++ b/crates/tj-core/src/memory.rs @@ -48,6 +48,11 @@ pub fn open(path: impl AsRef) -> anyhow::Result { std::fs::create_dir_all(parent)?; } let conn = Connection::open(path)?; + // busy_timeout FIRST: the one-time WAL conversion takes a brief exclusive lock + // on the first open of a fresh/rollback-mode DB; with the timeout already in + // effect, two processes first-opening at once wait instead of hitting + // SQLITE_BUSY on the conversion itself. + conn.execute_batch("PRAGMA busy_timeout=5000; PRAGMA journal_mode=WAL;")?; conn.execute_batch(SCHEMA)?; Ok(conn) } @@ -372,4 +377,18 @@ mod tests { assert_eq!(search(&global, &q, "other-model", 5).unwrap().len(), 0); assert_eq!(search(&global, &q, emb.model_id(), 5).unwrap().len(), 1); } + + #[test] + fn open_sets_wal_and_busy_timeout() { + let d = tempfile::TempDir::new().unwrap(); + let conn = open(d.path().join("memory.sqlite")).unwrap(); + let mode: String = conn + .query_row("PRAGMA journal_mode", [], |r| r.get(0)) + .unwrap(); + assert_eq!(mode, "wal"); + let timeout: i64 = conn + .query_row("PRAGMA busy_timeout", [], |r| r.get(0)) + .unwrap(); + assert!(timeout > 0, "busy_timeout must be > 0, got {timeout}"); + } }