Module session
Expand description
The shared interactive-mutation-session engine (REPLICATOR-INTERACTIVE-TXN-DESIGN.md §4).
One server-agnostic home for the session state machine both write masters serve: the
single-session invariant, the parked FIFO and its drain ordering, the daemon-owned deadline
with RAII rollback, session-id minting/matching, absorbed replay and 410 Gone, and the
wire (de)serializers. rindled (rindle-server) and the replicator write-master
(rindle-replicator) each implement SessionBackend over their own transaction
representation and SessionResponder over their own deferred responder; the subtle
scheduling logic is written and tested once, and the api-server receives byte-identical
replies from either master (the §7 “indistinguishable masters” invariant — which is why the
serializers live here too, not per-server).
This module is transport-free by design: no HTTP types, only serde_json bodies plus a
status code. It is the extraction of rindle-server/src/net.rs’s session handlers
(DAEMON-INTERACTIVE-TXN-DESIGN.md §4.2), ported branch-for-branch; rindled’s wire tests
(rindle-replicator/tests/session_wire.rs and
rindle-server/tests/standalone_wire.rs) gate the two hosts.
The ONE-SHOT write types live here too (SqlTxn/SqlTxnOutput + parse_sql_txn/
sql_txn_output_json, REPLICATOR-INTERACTIVE-TXN-DESIGN.md §11.3): a one-shot is a
session compressed into a single call, and both masters answering the same
/execute-sql-txn shapes through the same types is how the one-shot and session paths
stay unable to drift.
Structs§
- Commit
Tail - The commit-time bookkeeping the backend writes co-transactionally: a client session’s lmid upsert, a foreign session’s producer watermark. Folded into ONE backend call — not engine-driven steps — because the replicator’s divergence guard must measure the user statements’ captures BEFORE the lmid row lands in the capture buffer; only the backend can order that (REPLICATOR-INTERACTIVE-TXN-DESIGN.md §4.2).
- Lmid
Advance - The client watermark after a write/rejection:
lmidis the stored high-water mark. - Producer
Write - A foreign (non-client) writer’s durable identity: a stable, low-cardinality
idplus that producer’s own gapless sequence (design 306 §4). The same(producer, sequence)model Kafka uses — dedup AND ordering, bounded by producer count rather than by write volume. - Read
Rows - A session read’s
{cols, rows}result. - Session
Commit - What a backend’s
commitreports:applied: falseis the zero-capture no-op (a foreign session whose statements changed nothing durable — the backend rolled back instead of committing, mirroring the one-shot path). - Session
Engine - The shared session engine: owns session metadata + the parked queue + id minting + the
deadline; drives a
SessionBackendfor everything that touches the transaction. Generic over the server’s parked one-shot commandCand its deferred responderR. - Session
Reply - A rendered session reply: status + JSON body, shaped ON the engine thread (replies have
several shapes —
begin’s session-or-absorbed,query’s{cols, rows}— so the engine shapes them and the server’s completion path only writes the socket). - SqlStatement
- One
{sql, params}statement off the wire — the shape shared by a sessionbegin’s accumulated prefix,execstatements,queryreads, and a one-shotSqlTxn’s statements. - SqlTxn
- One approved SQL write transaction — the one-shot (
/execute-sql-txn) flavor, i.e. a mutation session compressed into a single call. Aclient_id+midcarries the optimistic-client discipline (≤ lmidabsorbed,lmid+1applies + the co-transactional lmid upsert, a gap rejects); a foreign write may instead carry aproducerwatermark, which runs the SAME rule against its own namespace. The two are mutually exclusive on the wire. How a txn runs stays per-server (group-commit fold, capture, broadcast) — only the accepted shape is shared. - SqlTxn
Output - The outcome of a one-shot
SqlTxn(or a mutation rejection) — and the exact shape a session commit answers, from either master.applied: falseis an absorbed replay (mid ≤ lmid,seq ≤ last_seq) or a zero-effect no-op: nothing committed, no txn identity.
Enums§
- Parked
Next - What the drain pump hands back: a parked one-shot for the server to run, or “stop” (queue
empty, or a parked
beginjust opened the next session). - Session
Error - The engine’s error type — only the variants the state machine distinguishes and the wire
renders. Each backend maps its native error in at the boundary (
SessionBackendmethods return these), keeping the engine monomorphic;MutationGap’sDisplayis byte-identical torindle-server’sServerError::MutationGapso the extraction changes no response body. - Session
Op - One
/mutate-session/*request, parsed on the intake thread.Beginoptionally carries the accumulated write prefix and the first read, so a lazy-upgrading mutator’s first interactive read costs ONE round trip over the batch path (DAEMON-INTERACTIVE-TXN-DESIGN.md §4.1). - TxnWire
Id - The backend’s opaque transaction identity on the wire. The two masters already differ here
for one-shots — rindled reports the cluster commit (
cv+txId), the replicator its change-log cursor (cursor) — and the JS client reads neither; carrying the split as an explicit variant keeps the shared serializer honest instead of papering over it (REPLICATOR-INTERACTIVE-TXN-DESIGN.md §7).
Constants§
- DEFAULT_
SESSION_ DEADLINE - The default daemon-owned session lease (DAEMON-INTERACTIVE-TXN-DESIGN.md §4.3): a wedged or dead api-server costs the write head at most this long. Shared so both masters enforce the same bound by default; each server’s config can override it.
Traits§
- Session
Backend - A single serialized write backend that can host ONE interactive mutation session at a time,
with the open transaction held as backend state (rindled’s
ClusterWriteTxnis an owned handle; the replicator’s txn is inseparable fromWriteMaster’s connection + capture ctx + broadcast — a stateful trait fits both). - Session
Responder - The server’s deferred-respond handle: consumes itself answering the client exactly once, off the engine thread (each server wraps its own responder + completion channel).
Functions§
- absorbed_
reply - A
beginabsorbed by mid dedup: the/execute-sql-txnreplay shape plusabsorbed: true, so the caller both skips the mutator and treats the reply as the authoritative outcome. - check_
read_ js_ safe - The strict-i64 guard for the LEGACY bare-cell read wire (design 226 §8): an
unguarded session’s reply goes through
session_read_json, whose bare cells rideowned_to_json— anIntoutside ±(2^53−1) would flatten to a roundedf64. The contract is a typed error, never a rounded number, so the read fails like any other statement error (the tagged/v1/sqlwire carries such cells exactly; guarded sessions therefore skip this). Mirrors the napi/wasm mandatorystrict_i64walk — the daemon HTTP JSON wire is a JS boundary too. - error_
reply - Render an error as the
{error}body + shared status (http_errorparity). - execute_
one_ shot - Execute one mutation transaction through the shared admission and commit-tail discipline.
Hosts provide only their storage operations through
SessionBackend; absorbed replay, gap rejection, rollback-on-statement-error, LMID advancement, and the foreign-write producer watermark stay identical to interactive sessions by construction. - parse_
session_ op - Parse one
/mutate-session/<op>body (DAEMON-INTERACTIVE-TXN-DESIGN.md §4.1).beginmay carry the accumulated statement prefix and the first read (query: {sql, params});queryis flat{sessionId, sql, params}like/execute-sql-read. - parse_
sql_ txn - Parse a
/execute-sql-txnbody —{ statements, clientID?, mid?, producer? }— the one-shot flavor of the session wire, shared so both masters accept identical bytes. - parse_
statement_ obj - Parse one
{sql, params?}object. - parse_
statements - Parse a body’s
statementsarray ([{sql, params?}, …]). - public_
cancel_ reply - Idempotent cancellation acknowledgement. The replicator router fills
cancelledfrom its out-of-band interrupt registry; a backend without an active operation returnsfalsewithout changing transaction state. - public_
commit_ outcome_ reply - Render a durable public-transaction commit lookup.
Nonemeans the lookup has no terminal record, so a caller that can still reach a live connection-affine session should continue routing the commit there. A found outcome or lookup failure is already terminal and can be answered without occupying a writer connection. - public_
operation_ sequence - Parse the frozen public transaction operation identity without consulting session state. Route intake uses this too, so rollback/cancel and missing-handle terminal paths cannot bypass the canonical positive-decimal contract merely because they do not reach a live session.
- public_
session_ gone - reject_
one_ shot - Process a client mutation as an explicit no-op: apply no user statements, but advance its LMID
in the same captured commit. Replays absorb and gaps reject through the same admission function
as
execute_one_shotand interactive session begin. - session_
gone - The
410 Goneevery op against a non-open session id answers: committed, rolled back, expired, or the daemon restarted — the caller cannot distinguish and does not need to (its redelivery re-enters atbegin, where mid dedup absorbs any committed outcome). - session_
op_ id - The session id an op resolves against, or
Nonefor the two begin flavors (which mint one). Shared because every pooled/planed dispatcher routes ops by this id — the replicator’s connection-affine shards and the standalone daemon’s reader-backed read-only plane must extract it identically or an op could reach a session engine that never minted its id. - session_
read_ json - A session read serialized as the
/execute-sql-readshape —colsin order, each row a bare cell array — so the JS client zips them identically on both paths. - session_
read_ tagged_ json - A session read for a public mutation-facade session: identical
{cols, rows}shape, but each cell uses the tagged value wire (encode_wire_value) so an integer outside ±(2^53−1) survives exactly instead of being flattened to anf64byowned_to_json. A NaN REAL cannot be stored by SQLite and so cannot reach a read; the defensive fallback maps it to null. - sql_
txn_ output_ json - The
/execute-sql-txnoutput shape — the one-shot AND session-commit reply, from either master:applied, the backend’s opaque txn identity (rindled:cv+txId; replicator:cursor; OMITTED when nothing committed), and the client watermark (lmidAdvances+ flatlmid).