A SQLite target for the engine's record store seam
(vaelii.impl.protocols/RecordStore) — the durable ground truth a KB is
recovered from: canonical sentexes and justifications, keyed by integer handle,
in a single SQLite file.
This is the other SQLite lane, and the one the snapshot sink argues around.
A records store over a networked database pays a round trip per probe — two
orders of magnitude off local, which is why that lane stays a snapshot.
Embedded SQLite is not networked: the driver runs in-process against a file,
a warm point read is single-digit microseconds (measured ~6µs against the disk
store's ~3µs), so a live records backend is a real third option beside :memory
and :disk — an always-current, single-file, SQL-inspectable store, where the
disk backend is a bespoke mmap pair and the snapshot is a frozen image you
re-export.
The seam is 17 ops (put-/get-/delete- for sentexes, justifications and
provenance; next-id; the *-ids enumerations; premise marking). Here:
record (id, kind, frame, premise, strength) — the
handle is the primary key, kind splits sentexes (0) from justifications (1),
and frame is the whole record nippy-frozen, so a fetch thaws back
type-identical (AtomicSentex stays an AtomicSentex);strength column as the
authoritative value and is assoced back onto the thawed record on read — so
mark-premise is a one-row column update, never a frame rewrite, and the
column and frame cannot drift because the column always wins;next-id walks an in-memory counter, and a
monotonic high_water row (bumped inside each put's transaction, reconciled
with the live max on open) survives a delete-of-the-max-handle across a
reopen — the disk store gets the same guarantee from an idx file that never
shrinks.Point the store at a file-backed db-spec ({:dbtype "sqlite" :dbname "kb.db"}). It holds one long-lived connection for its lifetime under
WAL + synchronous=NORMAL — the disk store's durability shape (buffered writes,
periodic fsync, a crash loses at most the last unsynced writes, never
consistency). A JDBC connection is not thread-safe, so every op serializes on a
lock, with a synchronized access-ordered LRU in front so a hot read never
reaches SQLite or the lock. close/clear-records! release it. It is
java.io.Closeable.
Apache-2.0, and an adapter: it implements the SSPL engine's
vaelii.impl.protocols/RecordStore and is never depended on by it. Core wires
it in by a lazy requiring-resolve, the same way it reaches the dense TMS, so
the engine never loads the SQLite driver unless a KB asks for this backend.
A SQLite target for the engine's **record store** seam
(`vaelii.impl.protocols/RecordStore`) — the durable ground truth a KB is
recovered from: canonical sentexes and justifications, keyed by integer handle,
in a single SQLite file.
This is the **other SQLite lane**, and the one the snapshot sink argues around.
A records store over a *networked* database pays a round trip per probe — two
orders of magnitude off local, which is why that lane stays a snapshot.
**Embedded SQLite is not networked**: the driver runs in-process against a file,
a warm point read is single-digit microseconds (measured ~6µs against the disk
store's ~3µs), so a live records backend is a real third option beside `:memory`
and `:disk` — an always-current, single-file, SQL-inspectable store, where the
disk backend is a bespoke mmap pair and the snapshot is a frozen image you
re-export.
## The shape
The seam is 17 ops (`put-`/`get-`/`delete-` for sentexes, justifications and
provenance; `next-id`; the `*-ids` enumerations; premise marking). Here:
* every record is one row in `record (id, kind, frame, premise, strength)` — the
handle is the primary key, `kind` splits sentexes (0) from justifications (1),
and `frame` is the **whole record** nippy-frozen, so a fetch thaws back
type-identical (`AtomicSentex` stays an `AtomicSentex`);
* a sentex's **assumption strength** rides the `strength` column as the
authoritative value and is `assoc`ed back onto the thawed record on read — so
`mark-premise` is a one-row column update, never a frame rewrite, and the
column and frame cannot drift because the column always wins;
* **handles are never reissued.** `next-id` walks an in-memory counter, and a
monotonic `high_water` row (bumped inside each put's transaction, reconciled
with the live max on open) survives a delete-of-the-max-handle across a
reopen — the disk store gets the same guarantee from an idx file that never
shrinks.
## The file
Point the store at a **file-backed** db-spec (`{:dbtype "sqlite" :dbname
"kb.db"}`). It holds **one long-lived connection** for its lifetime under
WAL + `synchronous=NORMAL` — the disk store's durability shape (buffered writes,
periodic fsync, a crash loses at most the last unsynced writes, never
consistency). A JDBC connection is not thread-safe, so every op serializes on a
lock, with a synchronized access-ordered LRU in front so a hot read never
reaches SQLite or the lock. `close`/`clear-records!` release it. It is
`java.io.Closeable`.
## Boundary
Apache-2.0, and an **adapter**: it implements the SSPL engine's
`vaelii.impl.protocols/RecordStore` and is never depended on by it. Core wires
it in by a lazy `requiring-resolve`, the same way it reaches the dense TMS, so
the engine never loads the SQLite driver unless a KB asks for this backend.(ensure-schema! conn)Create the record, provenance and meta tables (and the premise index) if absent.
Idempotent. Runs on conn in autocommit before any op.
Create the record, provenance and meta tables (and the premise index) if absent. Idempotent. Runs on `conn` in autocommit before any op.
(sqlite-record-store ds)(sqlite-record-store ds
{:keys [cache-capacity]
:or {cache-capacity default-cache-capacity}})A durable RecordStore over the SQLite database ds (a next.jdbc db-spec or
datasource — use a file db-spec, not :memory:, since the store keeps one
connection and a fresh reopen must see the same database).
Opens one connection for the store's lifetime under WAL + synchronous=NORMAL,
creates the schema if absent, and loads the handle counter so recovery reopens
where the last run stopped. :cache-capacity sizes the per-kind fetch LRU
(default 65536). The store is java.io.Closeable; close releases the
connection.
A durable `RecordStore` over the SQLite database `ds` (a next.jdbc db-spec or datasource — use a **file** db-spec, not `:memory:`, since the store keeps one connection and a fresh reopen must see the same database). Opens one connection for the store's lifetime under WAL + `synchronous=NORMAL`, creates the schema if absent, and loads the handle counter so recovery reopens where the last run stopped. `:cache-capacity` sizes the per-kind fetch LRU (default 65536). The store is `java.io.Closeable`; `close` releases the connection.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |