Skip to main content

UnitOfWork

Struct UnitOfWork 

Source
pub struct UnitOfWork { /* private fields */ }
Expand description

A batch of writes across several tables that lands whole or not at all (ADR 0012). Operations are collected with put/patch/delete and nothing touches a table until commit(), which runs the six steps documented in docs/architecture.md: resolve, barrier, prepare, journal, write, cleanup. &mut Table borrows held for the call are the barrier — no separate write queue to drain, since nothing else can hold those tables mutably at the same time.

commit() borrows the unit rather than consuming it, so a refused commit can be retried on the same unit once its cause is fixed — the same contract as the TS UnitOfWork. Staging is append-only in both engines: fixing a refusal means fixing what it named, not unstaging an op.

Implementations§

Source§

impl UnitOfWork

Source

pub fn new() -> Self

Source

pub fn operations(&self) -> usize

Source

pub fn tables(&self) -> &[String]

Source

pub fn put(&mut self, table: &str, document: Value) -> &mut Self

Source

pub fn patch( &mut self, table: &str, key: impl Into<String>, changes: Value, ) -> &mut Self

Source

pub fn delete(&mut self, table: &str, key: impl Into<String>) -> &mut Self

Source

pub fn preview( &self, table_name: &str, key: &str, table: &Table, ) -> Result<StagedView, TableError>

Reads a key through the unit: a value staged for table since the unit started, falling back to table’s committed state for a key the unit does not touch. put and patch ops are applied in staging order, patch merging over whatever the unit has staged so far (or the committed record, on the first touch) exactly as Table::patch would.

Source

pub fn get( &self, table_name: &str, key: &str, table: &Table, ) -> Result<Option<HaysonRecord>, TableError>

Source

pub fn query( &self, table_name: &str, table: &Table, spec: &QuerySpec, ) -> Result<QueryResult, TableError>

Runs spec as the unit will leave table: the ops staged for table_name so far are resolved into a StagedIndex, the query is planned over the committed candidates the overlay has not taken over plus the staged records that can still match, and the answer is tested against staged records and committed ones alike. A search is scored over the overlaid corpus, so a staged record joins the ranking and not merely the result set.

The plan carries a PlanOverlay reporting what the staged half contributed — how many staged records joined the candidates, how many committed ones the overlay suppressed, and whether the scores behind them were recomputed.

Source

pub fn commit( &mut self, tables: &mut HashMap<String, Table>, journal_path: &Path, ) -> Result<UnitOfWorkResult, TxnError>

Runs every staged operation, or none of them, across tables.

  1. resolve — an op naming a table missing from tables fails before anything else runs;
  2. barrier — the &mut Table borrows this call holds for its whole body;
  3. prepare — Table::prepare_txn_ops on every table, in staging order; the first rejected op fails the call with nothing appended anywhere;
  4. journal — every prepared line, across every table, written to journal_path in one atomic::write_atomic call;
  5. write — Table::apply_txn_entries per table, in staging order;
  6. cleanup — the journal file removed.

A refusal raised by steps 1–3 leaves the unit live and fully staged, so the caller can fix whatever the refusal named and call commit again on the same unit — nothing was written, and only monotonic _seq counters were burned. From step 4 on the unit is spent whatever happens, because a journal that reached the disk is finished by recover_incomplete, and a second run of the same operations would apply them twice.

Steps 1–3, 4 and 5–6 are also callable one at a time as UnitOfWork::prepare, UnitOfWork::journal and apply_prepared; this is those three back to back. A caller that holds the tables behind a lock uses the split so it can let go of that lock across step 4, which touches no table — see the concurrency section of docs/architecture.md.

Source

pub fn prepare( &mut self, tables: &mut HashMap<String, Table>, ) -> Result<PreparedUnit, TxnError>

Steps 1–3 of UnitOfWork::commit: resolve, prepare, and the triggers the prepared entries fire. Mutates only the _seq counters of the tables it touches; nothing is appended, no registry moves and no file is written, so a refusal here still leaves the unit staged and retriable.

Source

pub fn journal( &mut self, prepared: &PreparedUnit, journal_path: &Path, ) -> Result<(), TxnError>

Step 4 of UnitOfWork::commit: every prepared line, across every table, written to journal_path and fsynced in one atomic::write_atomic call. Reads no table and mutates none, which is what lets a caller run it without the lock that guards them — the writes are still invisible to a reader at this point, because nothing has been applied yet.

Retires the unit: from the moment the journal is on disk the operations land whether this process finishes them or the next open() does, so a second run would apply them twice.

Trait Implementations§

Source§

impl Default for UnitOfWork

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.