InMemoryBolt

class InMemoryBolt<Id : Any, V, Op : Any>(format: BoltArchiveFormat<Id, V, Op>, clock: Clock, segmentFrameBytes: Long = DEFAULT_SEGMENT_FRAME_BYTES, capacityBytes: Long = Long.MAX_VALUE) : Bolt<Op>

A Bolt whose segments live in memory — the reference implementation, and the one every target has, including the browser.

It writes the same bytes a disk-backed backend writes: the same segment header, the same length-prefixed, CRC-checked frames, the same canonical CBOR ops. That is deliberate rather than incidental. A reference implementation that kept ops as objects would leave the archive format unexercised until the first mmap backend existed, which is the worst possible moment to discover a field is missing from a format whose entire premise is that it is expensive to change.

Bounded, and honest about it. capacityBytes caps the whole archive; past it, append returns AppendResult.Failed carrying the dots it could not keep, and availability flips to BoltAvailability.Unavailable. An in-memory archive that grew without limit would be a memory leak wearing an archive's clothes.

On wasmJs this is the only bolt there is, and that is a real limitation

A browser has no filesystem, so neither memory-mapped backend compiles for wasmJs and this one is what runs there. It passes the whole conformance suite on that target — but it does not survive a page reload, which is a strange thing for an archive to be. A bolt exists so a server can hold a year of history beside a phone holding an hour; an in-memory one on a browser tab holds history for exactly as long as the tab does.

So on wasmJs, treat this as a working implementation of the contract rather than as durable retention. Durable retention there needs a different backend — see #2233. It is more tractable than "the browser has no filesystem" suggests: a browser lacks a filesystem, not durable storage, and this repo already ships a tested IndexedDB-backed store elsewhere.

Parameters

format

how ops are classified and encoded — see BoltArchiveFormat.

clock

stamps each frame's arrival time. Required: time is a dependency here, and a bolt that reached for Clock.System itself could not be tested deterministically.

segmentFrameBytes

the frame-byte budget after which a new segment is started. A single frame larger than this still gets archived — it lands alone in its own segment rather than being refused.

capacityBytes

the total byte budget for the whole archive, headers included.

Constructors

Link copied to clipboard
constructor(format: BoltArchiveFormat<Id, V, Op>, clock: Clock, segmentFrameBytes: Long = DEFAULT_SEGMENT_FRAME_BYTES, capacityBytes: Long = Long.MAX_VALUE)

Types

Link copied to clipboard
object Companion

Functions

Link copied to clipboard
open suspend override fun append(ops: List<Op>): AppendResult

Archive ops, discarding any that classify as LogOp.Compact.

Link copied to clipboard
open override fun availability(): BoltAvailability

BoltAvailability.Available exactly while the archive has room for the smallest possible frame, plus the segment header one would need if the active segment is full.

Link copied to clipboard
open override fun durability(): DurabilityState

Always DurabilityState.AsPromised, because this backend promises nothing.

Link copied to clipboard
open override fun replay(scope: ReplayScope): Flow<ReplayEvent<Op>>

A cold Flow of the frames in scope, in append order, terminated by exactly one verdict on how the stream ended — CleanTail or Truncated.