The default in-memory backends for the two storage protocols, selected at KB
construction. The engine above the protocols never touches a concrete store, so a
KB built on these runs the whole engine with no external dependency; the on-disk
backend (vaelii.impl.disk) is the durable alternative.
The record store implements RecordStore directly over maps. The index reuses
vaelii.impl.kv/KvIndexStore — the one trie/roots/index implementation — over a
MemoryKvBackend: one map keyed by the structured key vectors (equal vectors are
equal keys), holding a Long at each counter key and a set at each set key.
kv-intersect is a clojure.set/intersection; kv-members returns the stored set
by reference (no serialization, no copy).
Durable-within-the-JVM semantics by space number. Two KBs constructed over the
same :space number must share state, or the persistence/recovery tests (a second KB
restarted over the same databases) would find an empty store. A process-global
registry keyed by space number provides that: (memory-record-store {:space 15}) twice
returns records backed by one state atom. clear-records! / clear-index!
empty a space. (State lives only for the life of the JVM; the on-disk backend is what
survives a process restart.)
Single-writer. Pure runs one writer (docs/storage.md, "The single-writer
contract"), so each store is one atom mutated by swap!; reads deref a snapshot
and are lock-free. Interleaved writers would not be serializable.
The default in-memory backends for the two storage protocols, selected at KB
construction. The engine above the protocols never touches a concrete store, so a
KB built on these runs the whole engine with no external dependency; the on-disk
backend (`vaelii.impl.disk`) is the durable alternative.
The record store implements `RecordStore` directly over maps. The index reuses
`vaelii.impl.kv/KvIndexStore` — the one trie/roots/index implementation — over a
`MemoryKvBackend`: one map keyed by the structured key vectors (equal vectors are
equal keys), holding a `Long` at each counter key and a set at each set key.
`kv-intersect` is a `clojure.set/intersection`; `kv-members` returns the stored set
by reference (no serialization, no copy).
**Durable-within-the-JVM semantics by space number.** Two KBs constructed over the
same `:space` number must share state, or the persistence/recovery tests (a second KB
restarted over the same databases) would find an empty store. A process-global
registry keyed by space number provides that: `(memory-record-store {:space 15})` twice
returns records backed by *one* state atom. `clear-records!` / `clear-index!`
empty a space. (State lives only for the life of the JVM; the on-disk backend is what
survives a process restart.)
**Single-writer.** Pure runs one writer (docs/storage.md, "The single-writer
contract"), so each store is one atom mutated by `swap!`; reads deref a snapshot
and are lock-free. Interleaved *writers* would not be serializable.During a bulk load, a volatile! holding a transient of one MemoryKvBackend's
state map. While bound, this backend's writes land on that transient (assoc! —
no per-op HAMT path copy) and the whole load is one persistent! at the end, instead
of a swap! per fact. nil (the default) leaves every op on the persistent atom
exactly as before, so nothing outside a bulk load pays for it — and reads are left
untouched in both modes (they read the backing atom), so the query hot path is
unchanged. The backing atom is therefore stale for the life of the load: correct only
because the sole mid-load reader (note-opposed's [:false b] probe) reads the always
-empty negative side, and every real read happens after the closing persistent!. Use
with-bulk-writes for a positive/monotonic, distinct load; a corpus with (not …)
facts must rebuild-opposed! after it (the atom the opposed set is derived from was
stale during the load).
During a bulk load, a `volatile!` holding a **transient** of one MemoryKvBackend's state map. While bound, this backend's *writes* land on that transient (`assoc!` — no per-op HAMT path copy) and the whole load is one `persistent!` at the end, instead of a `swap!` per fact. nil (the default) leaves every op on the persistent atom exactly as before, so nothing outside a bulk load pays for it — and *reads* are left untouched in both modes (they read the backing atom), so the query hot path is unchanged. The backing atom is therefore stale for the life of the load: correct only because the sole mid-load reader (`note-opposed`'s `[:false b]` probe) reads the always -empty negative side, and every real read happens after the closing `persistent!`. Use `with-bulk-writes` for a positive/monotonic, distinct load; a corpus with `(not …)` facts must `rebuild-opposed!` after it (the atom the opposed set is derived from was stale during the load).
(memory-index-store opts)An in-memory IndexStore — KvIndexStore over a MemoryKvBackend.
An in-memory `IndexStore` — `KvIndexStore` over a `MemoryKvBackend`.
(memory-kv-backend {:keys [space] :or {space 1}})An in-memory KvBackend. Only :space in opts matters (it selects the shared
state atom, so two index stores over the same space number share one map).
An in-memory `KvBackend`. Only `:space` in `opts` matters (it selects the shared state atom, so two index stores over the same space number share one map).
(memory-record-store {:keys [space] :or {space 0}})An in-memory RecordStore. Only :space in opts matters (it selects the shared
state atom).
An in-memory `RecordStore`. Only `:space` in `opts` matters (it selects the shared state atom).
(with-bulk-writes backend & body)Run body with backend's index writes accumulated on one TRANSIENT of its state
map, persisted back in a single step at the end — the write-side fast path for a bulk
load (millions of trie assoc!s with no per-op HAMT path copy, one persistent!
instead of a swap! per fact). A no-op wrapper unless backend is a MemoryKvBackend,
so a non-memory store (disk) just runs body on its own batched path. See *bulk-txn*
for the read-staleness contract: a positive/monotonic, distinct load only; a corpus
with (not …) facts must rebuild-opposed! after.
Run `body` with `backend`'s index writes accumulated on one TRANSIENT of its state map, persisted back in a single step at the end — the write-side fast path for a bulk load (millions of trie `assoc!`s with no per-op HAMT path copy, one `persistent!` instead of a `swap!` per fact). A no-op wrapper unless `backend` is a MemoryKvBackend, so a non-memory store (disk) just runs `body` on its own batched path. See `*bulk-txn*` for the read-staleness contract: a positive/monotonic, distinct load only; a corpus with `(not …)` facts must `rebuild-opposed!` after.
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 |