Expand description
The Spine: every layer header of the stream in one shared mmap file.
spine.bin is Slot::WalStart + 8 pages of 16 KiB. Slot 0 carries the
superblock, slots 1..=11 carry one header page per layer, slot 12 opens
the write-ahead region. A process that owns the stream writes a header
when its aggregates change; the MCP/CLI readers and the live-viewer
process read those pages without going through the writer at all.
§The publish protocol, in one paragraph
A page write is a 16 KiB copy_from_slice. It is not an atomic
operation, and Mutex<MmapMut> only serialises handles of one
process: two processes mapping the same file have two mutexes, so they
have no happens-before relation and a reader can copy a half-written page
or pair a new stream header with an older one. That tearing is what the
seqlock in this file exists to remove, and nothing else here claims to.
The superblock page reserves SEQ_SLOT as its publish counter, exactly
the way crate::consciousness_seqlock::MmapSnapshot reserves
sequence: AtomicU64 at offset 0 of its own file. A publisher makes the
counter odd, writes the bracketed payload, then stores the next even
value with Ordering::Release; a reader loads with Ordering::Acquire,
spins while odd, copies, and retries if the counter moved. The reader
therefore never returns a payload from inside a publish window, and it
does not need the mutex to find that out.
§What the counter does and does not cover
Every header write participates in the counter. Spine::begin_publish
holds one mapping mutex and one publisher lock across a read-modify-write
batch; its first write opens the window, and commit (or drop) closes it.
Spine::read_store_snapshot validates all eleven header prefixes and the
superblock in one window. Spine::read_snapshot is the cheaper stream-only
view. Separate legacy read_* calls do not form a validated snapshot.
A window guarantees a coherent copy, not rollback or durability. Dropping a batch during unwinding publishes whatever was written before the panic; crash recovery likewise cannot reconstruct the pre-crash state. Aggregates refreshed less frequently than the stream may legitimately be older.
§Who is allowed to be inside a window
A seqlock only helps if at most one writer is in a window at a time; two
overlapping windows can leave a reader validating a counter that neither
writer owns. So publishing also takes flock(LOCK_EX) on spine.publish
(see Spine::begin_publish), which is the piece shared pages cannot
provide: mutual exclusion between publishers in different processes.
A second lock file answers a different question. spine.lock is held
shared for the whole life of a writer handle, and exclusively by
first-time layout and by Spine::resize, because remapping the file
invalidates the pages every other handle is reading. It cannot double as
the publish lock: a handle holding it shared would deadlock against itself
trying to take it exclusively for one tick.
flock is advisory, is not available on Windows, and does not exist on
every filesystem; all of those degrade to “publishing is serialised per
handle only”. That is a real weakening of the guarantee, so it is
reported by Spine::publish_lock_is_advisory instead of being hidden.
Lock order is mapping mutex, then publisher lock. flock belongs to the
open file description, not the thread: taking it before the mutex would
let a second thread on the same handle unlock the first thread’s publish.
The advisory lock is released before the mapping mutex on exit.
Structs§
- Archetype
Header - Attention
Header - Cache
Header - Emotion
Header - Graph
Header - Hebbian
Header - Merkle
Header - Meta
Header - Mirror
Header - Publish
- One exclusive read-modify-write batch. Do not call methods on the owning
Spinewhile this guard lives: its mapping mutex is non-reentrant. Use the guard’sread_*/write_*methods instead. Reads alone do not advance the counter; the first write opens the window and commit/drop closes it. - Publish
Guard - One publisher’s turn.
Dropreleases the advisory lock, so a publish that panics part-way through cannot leave the store un-writable. - Publish
Snapshot - One published snapshot: the stream header plus the superblock payload
that was in the file at the same moment — the two things the seqlock
brackets. Their agreement is the guarantee; see
Spine::read_snapshot. - Resonance
Header - Spine
- Spine file handle.
Clone-like sharing is byArcinsidecrate::consciousness_stream; a second process opens its own handle over the same file and coordinates through the seqlock. - Store
Snapshot - All header pages and the publish record copied under one counter value.
Layer aggregates can be older than the stream, but none was copied midway
through a write. Use a single
Publishbatch to update related headers. - Stream
Header - Superblock
- Superblock, as it lives in the first
SUPERBLOCK_BYTESbytes of page 0.
Enums§
Constants§
- ATTENTION_
LAYERS - HEADER_
SIZE - MAGIC
- N_
LAYERS - PAGE_
SIZE - PUBLISH_
LOCK_ FILE_ NAME - Name of the file whose advisory lock serialises publishers.
- SEQ_
SLOT - Byte offset of the seqlock publish counter inside the superblock page (page 0, so this is also the file offset). 8-byte aligned by construction because mappings start on a page boundary.
- SNAPSHOT_
MAX_ RETRIES - Read attempts on a publish window that keeps moving under us before the
reader gives up and reports
None. Spins for the first 64, then yields, so the budget is a measure of patience rather than of CPU burned competing with the writer. It is large because an attempt costs a lock hand-over when a reader shares its handle with other readers: measured against three threads hammering one file, a 1024-attempt budget gave up on 0.09% of reads even though the writer’s window is never longer than a microsecond, purely from losing the lock. At this budget it gives up on none. - SNAPSHOT_
MAX_ WAIT_ MS - …and the shortest time it will keep trying, in milliseconds. An attempt is cheap, so on an oversubscribed machine the count can run out while the reader has merely been off-CPU; the deadline is what distinguishes “the writer is relentless” from “I was not scheduled”. Measured on a 2-core box with three load tests and a spawned writer running at once: count alone gave up on about 1 read in 60 000, this gives up on none.
- SNAPSHOT_
PREFIX_ BYTES - Bytes copied from each header page by a validated snapshot. The largest encoded header is Emotion (108 bytes); no page padding needs to be read. This is a format bound, not a measured performance claim.
- SUPERBLOCK_
BYTES - Bytes of the superblock page that are part of the published payload: the
fixed-size header fields, padded out so the payload ends where the counter
begins.
Spine::write_slotaccepts a whole page for this slot but publishes only these bytes, precisely so that a page-sized write cannot reach intoSEQ_SLOTand reset the counter under a reader. - SUPERBLOCK_
VERSION - Superblock format version.
- WRITER_
LOCK_ FILE_ NAME - Name of the file whose advisory lock marks live writers for
resize.
Functions§
- format_
summary - Human-readable dump of the spine.