L1 · the SessionStore PORT, the event taxonomy, and the pure fold (02). The
loop talks to this protocol and nothing below it — swap MemoryStore for a
Phase-2 SQLiteStore with zero loop changes. apply-event is PURE (no IO):
store impls call it on the write path; a Phase-2 recovery path folds the log
with it. Depends only on the PURE payload ns (for payload-ref?), never on
payload-io — so there is no cycle.
L1 · the SessionStore PORT, the event taxonomy, and the pure fold (02). The loop talks to this protocol and nothing below it — swap MemoryStore for a Phase-2 SQLiteStore with zero loop changes. `apply-event` is PURE (no IO): store impls call it on the write path; a Phase-2 recovery path folds the log with it. Depends only on the PURE `payload` ns (for `payload-ref?`), never on `payload-io` — so there is no cycle.
(apply-event view {:keys [event/type] :as ev})(view event) → view'. PURE. The single source of truth for how an event
advances the view (02 §6). Events carry results, never recipes.
`(view event) → view'`. PURE. The single source of truth for how an event advances the view (02 §6). Events carry results, never recipes.
(collect-refs data)Every payload-ref reachable in data (a view, an event, an entity).
Every payload-ref reachable in `data` (a view, an event, an entity).
(current-head view)The folded current head map, or nil before the first published boundary.
The folded current head map, or nil before the first published boundary.
(edge-with-id edge)Content-address a lineage edge. The id hashes the edge content without :edge/id, matching the immutable-head convention.
Content-address a lineage edge. The id hashes the edge content without :edge/id, matching the immutable-head convention.
(head-by-id view head-id)The immutable head with head-id in a folded view.
The immutable head with `head-id` in a folded view.
(head-with-id head)Build a content-addressed immutable head from head content. The id hashes the canonical head content without :head/id, so it is reproducible.
Build a content-addressed immutable head from head content. The id hashes the canonical head content without :head/id, so it is reproducible.
(kept-messages view)The messages surviving compaction (a PURE view derivation, shared by
request-assembly and compaction — 05 §4, 07 §4): the :message of every
message-bearing event (:message/appended | :session/compacted) in
(:events view) whose :event/id >= :compact-from-event-id (nil ⇒ all).
⛔ Pruned over the LOG, not over :messages — message entities carry no
:event/id, and the compact frame's own event-id == the boundary, so it and
everything after survive.
The messages surviving compaction (a PURE view derivation, shared by request-assembly and compaction — 05 §4, 07 §4): the `:message` of every message-bearing event (`:message/appended` | `:session/compacted`) in `(:events view)` whose `:event/id` >= `:compact-from-event-id` (nil ⇒ all). ⛔ Pruned over the LOG, not over `:messages` — message entities carry no `:event/id`, and the compact frame's own event-id == the boundary, so it and everything after survive.
(next-head-range view to-event-id)The event range a newly published head should cover, ending at to-event-id.
The first head covers from event 1; later heads start after their basis range.
The event range a newly published head should cover, ending at `to-event-id`. The first head covers from event 1; later heads start after their basis range.
(prepare-head view sid head)Prepare a head for publication against the current folded view. Validates the optimistic basis when :head/expected-basis is present.
Prepare a head for publication against the current folded view. Validates the optimistic basis when :head/expected-basis is present.
(subscribe! store sid callback)→ unsubscribe fn. Delivers each event + transient delta (09).
→ unsubscribe fn. Delivers each event + transient delta (09).
(peek-next-id store sid counter-key)The id append-event! WILL assign next for counter-key. VALID ONLY on the single writer thread.
The id append-event! WILL assign next for counter-key. VALID ONLY on the single writer thread.
(current-view store sid)STRONG read-your-writes snapshot of the folded view. MUST NOT delegate to read-state. The loop + api read state ONLY through this.
STRONG read-your-writes snapshot of the folded view. MUST NOT delegate to read-state. The loop + api read state ONLY through this.
(create-session! store session-map)Idempotent + atomic. Insert a fresh per-session slot keyed by :session/id IF ABSENT; a 2nd call returns the existing handle, never nuking state. Returns a SessionHandle (02 §5).
Idempotent + atomic. Insert a fresh per-session slot keyed by :session/id IF ABSENT; a 2nd call returns the existing handle, never nuking state. Returns a SessionHandle (02 §5).
(append-event! store sid event)THE write op. Under the per-session STORE LOCK: stamp :event/id + :event/at (always) and any creating-event entity id, PERSIST, then (on success) fold via apply-event into the view cache, then schedule a NON-BLOCKING live notification out of the lock. Returns the stamped event.
THE write op. Under the per-session STORE LOCK: stamp :event/id + :event/at (always) and any creating-event entity id, PERSIST, then (on success) fold via apply-event into the view cache, then schedule a NON-BLOCKING live notification out of the lock. Returns the stamped event.
(read-payload* store ref)Dereference a tagged ref to its value via global content lookup.
Dereference a tagged ref to its value via global content lookup.
(append-lineage-edge! store sid edge)Phase 4: content-address and append one invocation/derivation lineage edge as a durable :lineage/edge-added event in session sid's log. Returns the stamped edge event.
Phase 4: content-address and append one invocation/derivation lineage edge as a durable :lineage/edge-added event in session sid's log. Returns the stamped edge event.
(intern-payload! store value opts)Content-address value into the GLOBAL blob store (id = sha256 over canonical-bytes). Returns a tagged opaque payload-ref. IDEMPOTENT (dedup). No sid: blobs are global Merkle nodes.
Content-address value into the GLOBAL blob store (id = sha256 over canonical-bytes). Returns a tagged opaque payload-ref. IDEMPOTENT (dedup). No sid: blobs are global Merkle nodes.
(publish-head! store sid head)Phase 4: atomically publish an immutable content-addressed head. Under the same per-session STORE LOCK as append-event!: validate optional :head/expected-basis against the folded :current-head, compute :head/basis, :head/event-range, and :head/id, persist a :head/published event, fold it, notify live, and return the head.
Phase 4: atomically publish an immutable content-addressed head. Under the same per-session STORE LOCK as append-event!: validate optional :head/expected-basis against the folded :current-head, compute :head/basis, :head/event-range, and :head/id, persist a :head/published event, fold it, notify live, and return the head.
(notify-transient store sid item)Publish a TRANSIENT live signal (no :event/id; never persisted/folded).
Publish a TRANSIENT live signal (no :event/id; never persisted/folded).
(read-state store sid)RELAXED snapshot for external/cross-process consumers. Non-blocking.
RELAXED snapshot for external/cross-process consumers. Non-blocking.
(append-events! store sid events)Batch variant: assign consecutive ids + persist + fold in ONE critical section. MemoryStore may delegate to append-event! in a loop.
Batch variant: assign consecutive ids + persist + fold in ONE critical section. MemoryStore may delegate to append-event! in a loop.
(events-since store sid event-id)→ ordered events with :event/id > event-id (backlog catch-up, 09).
→ ordered events with :event/id > event-id (backlog catch-up, 09).
(verify-no-dangling-refs store sid)The (hopefully empty) vector of payload-refs in the session view that do not resolve in the store. A non-empty result violates the storage invariant — a blob write must precede the event that references it (02 §3, §8).
The (hopefully empty) vector of payload-refs in the session view that do not resolve in the store. A non-empty result violates the storage invariant — a blob write must precede the event that references it (02 §3, §8).
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 |