Rindle docs and package mapSkip to main content

OneShotBackend

Trait OneShotBackend 

pub trait OneShotBackend {
    // Required methods
    fn begin_public_operation(&mut self) -> Result<(), WritePlaneError>;
    fn public_batch_statement(
        &mut self,
        statement: &SqlStatementRequest,
        remaining_result_bytes: usize,
    ) -> Result<StatementResult, WritePlaneError>;
    fn rollback_public_operation(&mut self);
    fn commit_public_operation(
        &mut self,
        outcome_key: &str,
        request_identity: &str,
    ) -> Result<PublicOperationCommit, WritePlaneError>;
    fn stored_public_outcome(
        &mut self,
        outcome_key: &str,
    ) -> Result<Option<StoredPublicOutcome>, WritePlaneError>;
    fn public_operation_floor_ms(&mut self) -> Result<i64, WritePlaneError>;
    fn resolve_public_run_id_cursor(
        &mut self,
        run_id: &str,
    ) -> Result<Option<String>, WritePlaneError>;
    fn apply_public_ddl(
        &mut self,
        statement: &SqlStatementRequest,
        outcome_key: &str,
        request_identity: &str,
        result_byte_limit: usize,
    ) -> Result<PublicOperationCommit, WritePlaneError>;
    fn with_migration_barrier(
        &mut self,
        f: &mut dyn FnMut(&mut dyn MigrationSection) -> Result<PublicMigrateAck, WritePlaneError>,
    ) -> Result<PublicMigrateAck, WritePlaneError>;
}
Expand description

The backend contract of the one-shot public SQL surface. The master implements it over its session-transaction primitives; a standalone daemon implements it over its own store (303 S5). Every method returns pre-classified WritePlaneError — classification happens once, host-side, and there is no conversion back out (decision C3).

The result-buffer invariant (extraction plan §2): the backend accumulates each successful statement’s result from begin_public_operation on; an OCC retry inside commit_public_operation re-runs the recorded statements and replaces the buffer wholesale; commit returns that final buffer and stores exactly it in the outcome row. rollback_public_operation clears the buffer; begin starts it empty. The per-statement results returned to the coordinator feed byte accounting and error surfacing only — they are never the response payload.

Required Methods§

fn begin_public_operation(&mut self) -> Result<(), WritePlaneError>

Open the one-shot write transaction: serializable isolation, no raw-exec guard (every statement installs the public authorizer itself). NOT the interactive begin_public — that path’s error currency is lossy for a failed BEGIN, and a one-shot BEGIN failure must keep its SQLITE_ERROR/sqlite_code bytes. On Err there is nothing to roll back: the coordinator does NOT call rollback_public_operation after a failed begin.

fn public_batch_statement( &mut self, statement: &SqlStatementRequest, remaining_result_bytes: usize, ) -> Result<StatementResult, WritePlaneError>

Run one statement inside the open one-shot transaction. Two flags distinguish this from the interactive public statement, invisible at the call site and load-bearing: the statement takes no per-statement savepoint (the whole transaction rolls back on any error), and it records the SQL replay so a busy-snapshot commit retry can re-run silently while no result has been observed. remaining_result_bytes bounds this statement’s encoded result within the operation-wide cap.

fn rollback_public_operation(&mut self)

Roll back the open one-shot transaction and clear the result buffer. Infallible and idempotent — a no-op when nothing is open (best-effort ROLLBACK; a failure poisons the connection for the next write and surfaces there). The coordinator calls this exactly once on any statement or accounting error.

fn commit_public_operation( &mut self, outcome_key: &str, request_identity: &str, ) -> Result<PublicOperationCommit, WritePlaneError>

Commit the open one-shot transaction, writing the outcome row — keyed outcome_key, carrying request_identity and the buffered result set — co-transactionally with the effects. Returns commit’s buffered results (the invariant above). On Err the backend has rolled back; the coordinator then re-reads the stored outcome, because a concurrent same-key winner’s co-transactional row is authoritative.

fn stored_public_outcome( &mut self, outcome_key: &str, ) -> Result<Option<StoredPublicOutcome>, WritePlaneError>

Read one stored outcome row — a record read only, no decisions (those are stored_public_operation’s).

fn public_operation_floor_ms(&mut self) -> Result<i64, WritePlaneError>

The operation-namespace retention floor, computed against the host’s own clock (the coordinator reads no clock). A replayed key minted at or below this floor fails closed.

fn resolve_public_run_id_cursor( &mut self, run_id: &str, ) -> Result<Option<String>, WritePlaneError>

The ONLY host leg of outcome-cursor resolution (decision C4): resolve a legacy run_id-only outcome row to its commit cursor (the master’s journal scan). Stored-cursor short-circuit and the GC-race re-read live in the coordinator’s spine, so a store whose outcome rows always carry their cursor may simply return Ok(None) — a stored cursor returns before this is ever called.

fn apply_public_ddl( &mut self, statement: &SqlStatementRequest, outcome_key: &str, request_identity: &str, result_byte_limit: usize, ) -> Result<PublicOperationCommit, WritePlaneError>

Apply one fresh public DDL statement as its own atomic autocommit unit (decision C5). The host owns the critical section — the master takes its maintenance lock and refuses while interactive writers hold the pool open (Conflict) — and runs the budget-wrapped DDL inside it. Contract: every validation runs INSIDE the transaction, before the outcome row is inserted co-transactionally and the unit commits — the zero-capture refusal (MIGRATION_DDL_ONLY), the destructive-DDL (227) guards, schema-registry validation, the broken-foreign-keys refusal, and the result_byte_limit cap on the encoded result. A store whose DDL API cannot run a final in-transaction validation cannot implement this method yet (303 S4’s written obligation).

The coordinator’s replay check runs OUTSIDE this critical section, so a concurrent same-key DDL may win between the miss and this apply: the winner’s unique co-transactional outcome insert makes this attempt fail, and the coordinator re-reads the stored outcome on every Err. On Err the backend has rolled back — there is no open unit for the coordinator to clean up.

fn with_migration_barrier( &mut self, f: &mut dyn FnMut(&mut dyn MigrationSection) -> Result<PublicMigrateAck, WritePlaneError>, ) -> Result<PublicMigrateAck, WritePlaneError>

Run the public migration critical section (extraction plan C6): the host owns WHERE the section is — it takes its migration exclusion and refuses Conflict while the writer pool cannot quiesce, BEFORE invoking f — and the coordinator closure owns everything inside it, over the MigrationSection view. Because the quiesce gate precedes the closure, this surface refuses-before-replaying by construction (the DDL one-shot’s opposite replays-before-refusing order lives in C5’s optimistic flow).

The exclusion domain is ALL migrations, deploy included: on the master the maintenance lock already serializes both modes over the one shared tag namespace, and any host that runs a separately-implemented deploy migration path MUST route it through this same barrier, or a deploy migration could interleave with a public section (303 S4’s written obligation). Not reentrant — one section at a time.

Implementors§