Public API, uniform over both access modes:
Entity navigation (entity/touch) is a peer-only feature; client-mode calls raise :client/peer-only.
Public API, uniform over both access modes:
- peer (embedded): (connect {:storage :memory}) / {:storage :file :path}
- client (remote): (client/connect {:host ... :port ...}) from
kala.client — pass that connection to these same
functions and every operation travels through the transactor.
Entity navigation (entity/touch) is a peer-only feature; client-mode
calls raise :client/peer-only.Remote client library: the same core operation surface as the embedded peer — db, transact, q, pull, datoms, and the time-travel reads — served through a running transactor over the wire protocol (docs/wire-protocol.md).
A client connection holds one socket; operations are serialized on it. (api/db conn) returns a RemoteDb marker pinned to the transactor's current t; as-of/since/history derive further markers; transact reports carry :db-before/:db-after markers at the surrounding ts. Entity navigation is a peer-only feature and is rejected explicitly in client mode.
Remote client library: the same core operation surface as the embedded peer — db, transact, q, pull, datoms, and the time-travel reads — served through a running transactor over the wire protocol (docs/wire-protocol.md). A client connection holds one socket; operations are serialized on it. (api/db conn) returns a RemoteDb marker pinned to the transactor's current t; as-of/since/history derive further markers; transact reports carry :db-before/:db-after markers at the surrounding ts. Entity navigation is a peer-only feature and is rejected explicitly in client mode.
Datom representation, the bootstrap schema, index construction, and the read interfaces over immutable db values. Entity-id packing lives in kala.eid — a pure-arithmetic leaf this namespace places bootstrap schema entities through; the allocation counter is db-value state kala.tx advances. The transaction pipeline lives in kala.tx; time travel and log replay in kala.time-travel. No I/O here: storage sits behind the Storage protocol (seam 2). Reads go through immutable db values — plain maps keyed :kala.core/*, which every kala module shares.
Datom representation, the bootstrap schema, index construction, and the read interfaces over immutable db values. Entity-id packing lives in kala.eid — a pure-arithmetic leaf this namespace places bootstrap schema entities through; the allocation counter is db-value state kala.tx advances. The transaction pipeline lives in kala.tx; time travel and log replay in kala.time-travel. No I/O here: storage sits behind the Storage protocol (seam 2). Reads go through immutable db values — plain maps keyed :kala.core/*, which every kala module shares.
Entity ids: one positive long packing a partition, a block, and an index. Partition 0 holds the bootstrap schema (attributes and their enums), partition 1 holds transacted entities, partition 2 holds transaction entities, which pack t into the payload bits.
This namespace is a pure-arithmetic leaf: it requires nothing and never sees a db value. Callers own the allocation counter — kala.tx keeps ::core/next-idx in the db value and advances it through alloc-user-eid, and replay restores that counter with user-alloc-index. tx entity ids are monotonic in t: kala.time-travel's since compares them as packed longs and relies on it.
Entity ids: one positive long packing a partition, a block, and an index. Partition 0 holds the bootstrap schema (attributes and their enums), partition 1 holds transacted entities, partition 2 holds transaction entities, which pack t into the payload bits. This namespace is a pure-arithmetic leaf: it requires nothing and never sees a db value. Callers own the allocation counter — kala.tx keeps ::core/next-idx in the db value and advances it through alloc-user-eid, and replay restores that counter with user-alloc-index. tx entity ids are monotonic in t: kala.time-travel's since compares them as packed longs and relies on it.
Lazy entity navigation: keyword access through the cached bridge with entities returned for ref attributes, reverse navigation via :ns/_attr over VAET, and touch for expanding an entity (including its component tree) into a plain map. Idents resolve to schema maps at each read; the bridge returns raw attr-id datoms.
Lazy entity navigation: keyword access through the cached bridge with entities returned for ref attributes, reverse navigation via :ns/_attr over VAET, and touch for expanding an entity (including its component tree) into a plain map. Idents resolve to schema maps at each read; the bridge returns raw attr-id datoms.
Pull API: shape documents from entities with attribute specs, wildcards, nested and reverse map specs, and the :default / :missing / :limit / :as options.
Pull API: shape documents from entities with attribute specs, wildcards, nested and reverse map specs, and the :default / :missing / :limit / :as options.
Datalog query engine: pattern clauses with constants and variables, joins through ref attributes (forward and reverse), predicates and function expressions in :where, user-defined rules (including recursion) supplied through the % input, :in bindings (scalar, tuple, collection, relation, database), find specs (relation, collection, scalar, single string), and aggregates with :with-aware grouping.
Datalog query engine: pattern clauses with constants and variables, joins through ref attributes (forward and reverse), predicates and function expressions in :where, user-defined rules (including recursion) supplied through the % input, :in bindings (scalar, tuple, collection, relation, database), find specs (relation, collection, scalar, single string), and aggregates with :with-aware grouping.
The storage protocol (spec seam 2): content-addressed segments plus an ordered, append-only transaction log keyed by t. Implementations must make a log append durable before acknowledging it; adapters beyond memory (local file in TT8) implement this same contract. The log's monotonicity guard lives here too, so every backend raises the same error shape.
The storage protocol (spec seam 2): content-addressed segments plus an ordered, append-only transaction log keyed by t. Implementations must make a log append durable before acknowledging it; adapters beyond memory (local file in TT8) implement this same contract. The log's monotonicity guard lives here too, so every backend raises the same error shape.
Durable directory-backed Storage adapter. Layout:
<root>/segments/<url-encoded-id> content files <root>/log/<zero-padded-t>.dat one file per log entry
Appends write to a temp file, fsync, atomically rename, then fsync the parent directory — durability before ack, surviving both process kill and machine crash. A fresh adapter over the same directory sees every acked entry, so crash recovery is: open, rebuild, continue.
Segment ids round-trip through URL-encoding of (str id); note that filesystems with case-insensitive names (e.g. macOS APFS defaults) will conflate ids differing only by case.
Durable directory-backed Storage adapter. Layout: <root>/segments/<url-encoded-id> content files <root>/log/<zero-padded-t>.dat one file per log entry Appends write to a temp file, fsync, atomically rename, then fsync the parent directory — durability before ack, surviving both process kill and machine crash. A fresh adapter over the same directory sees every acked entry, so crash recovery is: open, rebuild, continue. Segment ids round-trip through URL-encoding of (str id); note that filesystems with case-insensitive names (e.g. macOS APFS defaults) will conflate ids differing only by case.
Volatile in-memory Storage adapter for development and testing.
Volatile in-memory Storage adapter for development and testing.
Time travel over the storage log: replay, as-of snapshots, since views, history, and speculative with(). Rebuilding a db re-applies every log entry through the transaction pipeline's index and schema primitives, so a rebuilt db value equals the live one.
Time travel over the storage log: replay, as-of snapshots, since views, history, and speculative with(). Rebuilding a db re-applies every log entry through the transaction pipeline's index and schema primitives, so a rebuilt db value equals the live one.
The standalone transactor: a TCP server owning the database's single writer. Peers and clients speak the wire protocol (docs/wire-protocol.md); writes serialize through one lock into a single total order, then commit to durable storage. Reads run against the transactor's db value, pinned to a t (as-of), a since view, or history when the request asks.
The standalone transactor: a TCP server owning the database's single writer. Peers and clients speak the wire protocol (docs/wire-protocol.md); writes serialize through one lock into a single total order, then commit to durable storage. Reads run against the transactor's db value, pinned to a t (as-of), a since view, or history when the request asks.
The transaction pipeline: op validation and resolution, tempid/upsert
machinery, entity-map expansion, transaction-function invocation, schema
re-derivation (schema is data), and the transact/with entry points. No
I/O beyond the Storage protocol's append-log at the very end of
transact.
Db values keep their shape from kala.core — plain maps keyed :kala.core/*, referenced here through the ::core/ alias. Index maintenance goes through core's index-specs table and slice primitive; nothing index-shaped is re-implemented here.
The transaction pipeline: op validation and resolution, tempid/upsert machinery, entity-map expansion, transaction-function invocation, schema re-derivation (schema is data), and the transact/with entry points. No I/O beyond the Storage protocol's append-log at the very end of `transact`. Db values keep their shape from kala.core — plain maps keyed :kala.core/*, referenced here through the ::core/ alias. Index maintenance goes through core's index-specs table and slice primitive; nothing index-shaped is re-implemented here.
The value-keyed weak cache: ADR-0002's rule that caches live outside immutable db values, written once. A cache is an opaque synchronized weak table keyed by equality — equal db values legitimately share entries, and an entry's whole set dies with the last strong reference to its key.
The invariant callers must keep: a stored value must not strongly refer to its own weak key, or the key is never reclaimable. A db value carries its storage handle, so a replay cache strips the handle before storing and re-assocs the live one on the way out; read views over a db value reference only datoms, so they need no stripping.
The value-keyed weak cache: ADR-0002's rule that caches live outside immutable db values, written once. A cache is an opaque synchronized weak table keyed by equality — equal db values legitimately share entries, and an entry's whole set dies with the last strong reference to its key. The invariant callers must keep: a stored value must not strongly refer to its own weak key, or the key is never reclaimable. A db value carries its storage handle, so a replay cache strips the handle before storing and re-assocs the live one on the way out; read views over a db value reference only datoms, so they need no stripping.
Wire framing and codec for the transactor protocol: each message is a 4-byte big-endian length followed by UTF-8 EDN. Byte arrays (the one EDN gap) travel as #dos/b64 base64 tags; #inst and #uuid use the default EDN readers. The protocol's op table lives here too — the single source the connection loop, handle-op, the client, and docs/wire-protocol.md all read (#26).
Wire framing and codec for the transactor protocol: each message is a 4-byte big-endian length followed by UTF-8 EDN. Byte arrays (the one EDN gap) travel as #dos/b64 base64 tags; #inst and #uuid use the default EDN readers. The protocol's op table lives here too — the single source the connection loop, handle-op, the client, and docs/wire-protocol.md all read (#26).
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 |