Skip to main content

WriteTxn

Struct WriteTxn 

Source
pub struct WriteTxn<'db> { /* private fields */ }
Expand description

Public write transaction.

Acquired by crate::Db::transaction. Holds the in-process write-serialization mutex + cross-process WRITER_LOCK for its entire lifetime. commit / rollback consume self; dropping without explicitly committing rolls back automatically.

Implementations§

Source§

impl<'db> WriteTxn<'db>

Source

pub fn collection<T: Document>(&mut self) -> Result<Collection<'_, T>>

Open a typed handle to the collection T lives in.

Lazily creates the catalog row + an empty primary B-tree on first call for a given T inside the current process. The catalog mutation is staged in the same WAL transaction as the user’s subsequent writes — a rolled-back txn leaves no half-created collection.

§Errors
  • Error::Busy if the pager / catalog mutex is poisoned.
  • Any error the pager / B-tree / postcard codec returns.
Source

pub fn commit(self) -> Result<()>

Commit the transaction.

#90: flushes every cached CollectionDescriptor back to the catalog (one Catalog::update per touched collection) BEFORE the WAL commit, so the coalesced next_id / primary_root / index-root advances land durably in the same transaction as the document + index writes. A flush failure aborts the commit (the ? propagates and self drops, rolling the WAL back) rather than committing a half-flushed catalog.

#93: AFTER the WAL commit succeeds, fold this txn’s staged reconciled-collection names into the shared per-process reconciled set, so the expensive T::indexes() reconciliation is skipped for those collections on later txns. Promotion is deliberately POST-commit: a rolled-back txn never reaches here, so it cannot poison the shared cache into skipping reconciliation against a catalog whose index rows it just rolled back. A poisoned reconciled mutex maps to Error::Busy (Rule 7) but does NOT un-commit the durable WAL state.

§Errors

As obj_core::WriteTxn::commit, plus any catalog / pager / postcard error surfaced by the descriptor flush, plus Error::Busy if the shared reconciled mutex is poisoned at promotion time (after the commit has already landed durably).

Source

pub fn rollback(self) -> Result<()>

Roll the transaction back.

§Errors

As obj_core::WriteTxn::rollback.

Source

pub fn insert_raw_indexed( &mut self, collection: &str, payload: &[u8], type_version: u32, entries: &[(String, Vec<u8>)], ) -> Result<Id>

Engine API: insert a raw-bytes document into collection AND maintain the named secondary indexes from caller-supplied field-encoded keys. Returns the freshly-allocated Id.

Unlike Self::insert_raw_bytes (primary-only), this is the schema-bearing raw write: the C ABI cannot reflect index keys out of an opaque payload, so the CALLER supplies one (index_name, field_key) entry per index value, where field_key is the order-preserving encoding of the indexed field (produced by obj_core::index::encode_fieldlibobj::obj_index_key_encode wraps it). obj does the kind-specific STORAGE-key composition (append the Id suffix for Standard / Each / Composite; use the field key as-is with the Id as value + enforce uniqueness for Unique), matching the typed path byte-for-byte.

Atomicity: the primary insert + every index maintenance lands inside the same WAL transaction. An unknown index name (Error::IndexNotFound) or a uniqueness violation (Error::UniqueConstraintViolation) surfaces via ? and the surrounding WriteTxn rolls back the staged primary write atomically — no half-written index.

§Errors
Source

pub fn update_raw_indexed( &mut self, collection: &str, id: Id, payload: &[u8], type_version: u32, remove: &[(String, Vec<u8>)], add: &[(String, Vec<u8>)], ) -> Result<()>

Engine API: update the document at id in collection to payload AND move its secondary-index entries from the OLD caller-supplied field keys to the NEW ones.

obj cannot re-derive the OLD index keys from the stored opaque bytes, so the caller MUST supply BOTH the remove set (the field keys the document indexed under before this update) and the add set (the field keys it indexes under after). Each is one (index_name, field_key) entry per index value. The kind-specific composition + uniqueness enforcement matches Self::insert_raw_indexed.

Atomicity: the primary update + every index removal/insertion lands in the same WAL transaction; any error rolls the whole thing back.

§Errors
Source

pub fn delete_raw_indexed( &mut self, collection: &str, id: Id, remove: &[(String, Vec<u8>)], ) -> Result<bool>

Engine API: delete the document at id in collection AND remove its secondary-index entries given the caller- supplied OLD field keys. Returns Ok(true) if the primary record existed, Ok(false) if not.

As with Self::update_raw_indexed, obj cannot re-derive the index keys from stored bytes, so the caller supplies the remove set (one (index_name, field_key) per indexed value). The index removals always run (even on Ok(false)) so a caller can repair a known-stale index entry; this mirrors the typed Collection::delete which also diffs against the supplied OLD key set regardless of primary presence.

§Errors
Source

pub fn reconcile_indexes_raw( &mut self, collection: &str, version: u32, specs: &[IndexSpec], ) -> Result<()>

Engine API: declare / reconcile a runtime obj_core::IndexSpec set into the catalog for collection, making each Active BEFORE any index-maintaining raw write (Self::insert_raw_indexed &c. require the index already Active).

This is the NON-generic equivalent of the #[derive(Document)] reconcile path (WriteTxn::collection::<T>(), which reflects T::indexes()): a caller that has no Rust Document type — the obj-py / FFI index-declaration path (#108) — supplies the specs directly. Both share ONE body (reconcile_specs_once) so the cache / staging / validation / catalog-walk semantics never diverge.

Lazy-creates the collection’s catalog row + empty primary B-tree on first call (as the typed path does), then runs the same shared ∪ staged skip-cache: a SECOND call with the same (collection, version) is a no-op (the underlying Catalog::reconcile_indexes is itself idempotent for matching (name, kind, key_paths)). The catalog mutation is staged in the live WAL transaction — a rolled-back txn leaves no half-declared index, and the per-process reconciled cache is only promoted on a successful Self::commit.

§version (#130)

The skip-cache is keyed by (collection, version), not by collection alone, so a LATER schema version of the same collection that ADDS an index reconciles on its first call rather than being skipped. The caller passes the schema version the specs belong to (e.g. the typed Document::VERSION or the obj-py @document version). One narrow caveat applies when two live versions of one collection declare DIFFERENT (conflicting) index sets and their writes interleave in a single process — see the reconcile_specs_once internal docs. Index ADDITION (the common monotonic case) is fully correct.

§Errors

Auto Trait Implementations§

§

impl<'db> Freeze for WriteTxn<'db>

§

impl<'db> RefUnwindSafe for WriteTxn<'db>

§

impl<'db> Send for WriteTxn<'db>

§

impl<'db> Sync for WriteTxn<'db>

§

impl<'db> Unpin for WriteTxn<'db>

§

impl<'db> UnsafeUnpin for WriteTxn<'db>

§

impl<'db> UnwindSafe for WriteTxn<'db>

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> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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 = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more