The STORE OF RECORD of one live view: an append-only NDJSON file per view.
A live view is a STREAM, and nothing else in this process keeps one. The channel bus is a ring of 2000 events and the session journal is truncated per turn and past 16 MB, so a log that ran for twenty minutes would already be gone by the time the human scrolls back to its beginning. Here every line the engine ACCEPTED is on disk, in the order it accepted them.
One file, three kinds of line: the OPEN line is the view as it was declared, one PATCH line per accepted patch, and the CLOSE line is the verdict. A patch is appended BEFORE it is published, so a crash keeps everything the engine accepted rather than everything a surface managed to paint, and the file is opened in APPEND mode, so a resumed process never truncates a view it did not open.
Lines are wire JSON, which is what lets the file BE the artifact instead of a
re-encoded copy of one, and what lets a reader hand a patch line straight back
to view/normalize-patch: every live vocabulary is a closed table read in
either spelling.
The STORE OF RECORD of one live view: an append-only NDJSON file per view. A live view is a STREAM, and nothing else in this process keeps one. The channel bus is a ring of 2000 events and the session journal is truncated per turn and past 16 MB, so a log that ran for twenty minutes would already be gone by the time the human scrolls back to its beginning. Here every line the engine ACCEPTED is on disk, in the order it accepted them. One file, three kinds of line: the OPEN line is the view as it was declared, one PATCH line per accepted patch, and the CLOSE line is the verdict. A patch is appended BEFORE it is published, so a crash keeps everything the engine accepted rather than everything a surface managed to paint, and the file is opened in APPEND mode, so a resumed process never truncates a view it did not open. Lines are wire JSON, which is what lets the file BE the artifact instead of a re-encoded copy of one, and what lets a reader hand a patch line straight back to `view/normalize-patch`: every live vocabulary is a closed table read in either spelling.
(append! file patch)Record one ACCEPTED patch. Called after the materializer took it and before any surface is told, so the file is never behind a screen.
Record one ACCEPTED patch. Called after the materializer took it and before any surface is told, so the file is never behind a screen.
(close! file result)Seal the record with the verdict the model reads.
Seal the record with the verdict the model reads.
(log-range file node-id from limit & [query])Read a bounded page from a log's record, including output outside its live window.
Optional query is a literal, case-insensitive substring (empty matches all).
from is a zero-based MATCH offset, :line-numbers are original one-based
positions, :matched counts matches and :total counts all retained lines.
Clear/remove resets both counts. Reads open and closed records in one streamed
pass, retaining only the requested page.
Read a bounded page from a log's record, including output outside its live window. Optional `query` is a literal, case-insensitive substring (empty matches all). `from` is a zero-based MATCH offset, `:line-numbers` are original one-based positions, `:matched` counts matches and `:total` counts all retained lines. Clear/remove resets both counts. Reads open and closed records in one streamed pass, retaining only the requested page.
(open! view)Start the record of view and return the file it is kept in. The whole
declared view is the first line, so a reader that has the file needs nothing
else to rebuild what the patches were applied to.
Start the record of `view` and return the file it is kept in. The whole declared view is the first line, so a reader that has the file needs nothing else to rebuild what the patches were applied to.
(read-range file from limit)limit lines of the record from 0-based from, each decoded into the
engine's keyword-keyed shape.
A range past the end is an empty vector rather than a refusal: a surface asking for scrollback a crash never wrote is asking an honest question, and a view that is still open has no last line to bound the ask with.
`limit` lines of the record from 0-based `from`, each decoded into the engine's keyword-keyed shape. A range past the end is an empty vector rather than a refusal: a surface asking for scrollback a crash never wrote is asking an honest question, and a view that is still open has no last line to bound the ask with.
(record-uri session-id view-id)Where the artifact of a settled view POINTS: vis-live://<session-id>/<view-id>.
Addressed by IDENTITY, not by path. A file:// URI would put an absolute path of
the machine that wrote it into a row that outlives it, and would only ever resolve
for an operator who happened to register a file backend — so the artifact of a view
would read back as a 404 on the very runs it exists for. This scheme is owned here,
so the bytes come back through view-file wherever the records now live.
Where the artifact of a settled view POINTS: `vis-live://<session-id>/<view-id>`. Addressed by IDENTITY, not by path. A `file://` URI would put an absolute path of the machine that wrote it into a row that outlives it, and would only ever resolve for an operator who happened to register a file backend — so the artifact of a view would read back as a 404 on the very runs it exists for. This scheme is owned here, so the bytes come back through [[view-file]] wherever the records now live.
(stats file)How much of the run the record in file holds: :size bytes and :line-count
NDJSON lines. {:size 0 :line-count 0} for a record nothing ever wrote.
Read at CLOSE, BEFORE the trailer, so what it counts is the run — the declared view and every accepted patch — and not the verdict that seals it. One streamed pass; the log itself never comes into memory, which is the whole reason the artifact addresses this file instead of carrying it.
How much of the run the record in `file` holds: `:size` bytes and `:line-count`
NDJSON lines. `{:size 0 :line-count 0}` for a record nothing ever wrote.
Read at CLOSE, BEFORE the trailer, so what it counts is the run — the declared
view and every accepted patch — and not the verdict that seals it. One streamed
pass; the log itself never comes into memory, which is the whole reason the
artifact addresses this file instead of carrying it.(verdict file)The verdict the record in file ENDS with, or nil while the view is still
open.
The registry drops a view the moment it closes, so this file is the only place left that knows HOW it ended. An extension that pushes into a view the human interrupted reads its reason here rather than being told merely that the view is gone — and it costs one streamed pass, never the whole log in memory.
The verdict the record in `file` ENDS with, or nil while the view is still open. The registry drops a view the moment it closes, so this file is the only place left that knows HOW it ended. An extension that pushes into a view the human interrupted reads its reason here rather than being told merely that the view is gone — and it costs one streamed pass, never the whole log in memory.
(view-file session-id view-id)The record of view view-id, kept under the session that opened it.
The record of view `view-id`, kept under the session that opened it.
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 |