Skip to main content

WriteTxn

Struct WriteTxn 

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

A write transaction.

Construct via WriteTxn::begin (or, to release a host lock across the blocking acquire, WriteTxn::acquire + WriteTxn::from_acquire). Holds, for its entire lifetime:

  1. A WriteSerialGuard on the env’s in-process write- serialization gate — ensures at most one WriteTxn per env per process.
  2. An optional cross-process WRITER_LOCK byte — ensures at most one WriteTxn across the cluster of processes that have opened the same file.

WriteTxn::commit finalises the transaction through the pager’s WAL; WriteTxn::rollback discards pending writes. Dropping an uncommitted WriteTxn rolls back automatically (and logs a tracing debug event, gated on the tracing feature, so the caller learns about the silent rollback).

Send (issue #18): every field is Send&TxnEnv is Send + Sync, WriteSerialGuard owns an Arc<AtomicBool>, and WriterLock / HeaderSnapshot are Send. Soundness rests on the single-writer invariant: at most one WriteTxn exists per env at a time (the gate enforces it), and every pager access re-locks the pager Mutex per-op, so there is no thread-affine state to violate when the handle moves between threads.

Generic over F: FileBackend (Rule 9: no dyn).

Implementations§

Source§

impl<'db, F: FileBackend> WriteTxn<'db, F>

Source

pub fn begin(env: &'db TxnEnv<F>, timeout: Duration) -> Result<Self>

Begin a new write transaction against env.

Equivalent to Self::from_acquire(env, Self::acquire (env, timeout)?): it performs the two blocking lock acquires (in-process gate, then cross-process WRITER_LOCK) and then assembles the txn. Callers that need to release a host runtime lock (e.g. the Python GIL) across the blocking wait should call Self::acquire / Self::from_acquire directly so the blocking step runs without the host lock held.

§Errors
  • Error::Busy with LockKind::Writer if the cross- process lock did not become available within timeout.
  • Error::Busy with LockKind::WriterInProcess if another thread in the same process is mid-write.
  • Error::Io on lock syscall failure.
Source

pub fn acquire( env: &'db TxnEnv<F>, timeout: Duration, ) -> Result<WriteAcquire<F>>

Perform BOTH blocking write-lock acquires and return a Send token, without touching the pager or borrowing the env’s lifetime beyond the call.

Acquires the in-process serialization gate FIRST (bounded busy- poll against timeout), THEN the cross-process WRITER_LOCK (if env.lock_file is Some). This order is load-bearing: the cross-process OFD lock is per-fd and the whole process shares one lock-file fd, so two same-process threads would BOTH pass the cross-process lock — the in-process gate is the authoritative same-process serializer and must win first. On a cross-process failure the in-process guard is dropped (releasing the gate) before the error returns, exactly as begin did.

The returned WriteAcquire owns both guards and is Send, so the caller may move it across threads (e.g. acquire on a worker thread with the Python GIL released).

§Errors

As Self::begin.

Source

pub fn from_acquire(env: &'db TxnEnv<F>, acq: WriteAcquire<F>) -> Result<Self>

Assemble a WriteTxn from a previously-acquired token. This is the cheap, NON-blocking half of begin: it briefly locks the pager to flip the txn-depth gauge and take the header snapshot, then takes ownership of the token’s guards.

Holding the pager mutex here cannot deadlock: the caller already owns the in-process gate (carried in acq), so no other WriteTxn is alive, and the snapshot is cheap.

§Errors
  • Error::Busy with LockKind::WriterInProcess if the pager mutex is poisoned.
Source

pub fn write_page(&self, id: PageId, page: &Page) -> Result<()>

Write page at id through the pager.

§Errors
Source

pub fn read_page(&self, id: PageId) -> Result<Page>

Read id through the pager (sees pending + committed + main). Used inside a write txn that needs to read-modify- write a page. Returns an owned Page because the borrow chain through the pager’s mutex would otherwise tie the returned reference to the guard.

§Errors

As Pager::read_page.

Source

pub fn alloc_page(&self) -> Result<PageId>

Allocate a new page through the pager.

§Errors

As Pager::alloc_page.

Source

pub fn lock_pager(&self) -> Result<MutexGuard<'_, Pager<F>>>

Acquire the pager mutex. Bubble a poisoned mutex up as WriterInProcess — every txn method that takes the pager goes through here so the failure mode is uniform.

§Errors

Returns Error::Busy with LockKind::WriterInProcess if the mutex is poisoned by a previous panic.

Source

pub fn env(&self) -> &'db TxnEnv<F>

Access the underlying env. Used by callers (e.g. obj crate) that compose typed handles over the raw txn.

Source

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

Commit the transaction. Calls Pager::commit to make the staged writes durable, then releases both lock layers.

§Errors

Returns whatever Pager::commit returns.

Source

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

Roll the transaction back, dropping all pending writes.

§Errors

Returns Error::Busy only if the in-process pager mutex is poisoned; otherwise infallible.

Trait Implementations§

Source§

impl<'db, F: Debug + FileBackend> Debug for WriteTxn<'db, F>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<F: FileBackend> Drop for WriteTxn<'_, F>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

§

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

§

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

§

impl<'db, F> Send for WriteTxn<'db, F>
where F: Send,

§

impl<'db, F> Sync for WriteTxn<'db, F>
where F: Send,

§

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

§

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

§

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

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, 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