Skip to main content

TxnError

Enum TxnError 

Source
#[non_exhaustive]
pub enum TxnError { Conflict { key_len: usize, }, Store { context: &'static str, detail: String, }, Durability { detail: String, }, }
Expand description

Everything that can go wrong while running a transaction.

The type is #[non_exhaustive]: later versions may add variants without a major bump, so a match over it must include a wildcard arm. Each variant documents what the caller should do when they encounter it.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Conflict

A write-write conflict aborted the transaction at commit time.

Under snapshot isolation the database applies first-committer-wins: when a transaction commits, every key it wrote is checked against the version store, and if any of those keys was written by a different transaction that committed after this one took its snapshot, this commit is rejected. None of its writes are applied.

This is the mechanism that prevents lost updates, and it is a normal part of operating under optimistic concurrency control. The correct response is to retry: begin a fresh transaction, re-read, re-apply the logic, and commit again. TxnError::is_retryable returns true for this variant.

Only the length of the conflicting key is carried, never its bytes, so the error is safe to log even when keys hold sensitive data.

Fields

§key_len: usize

Length in bytes of the key whose conflict aborted the commit.

§

Store

The backing version store failed to service a read or apply a write.

The in-memory store that ships with txn-db never produces this; it is the channel through which a custom VersionStore — for example one backed by an on-disk engine — surfaces a failure through the same Result. context names the operation that was attempted (such as "read visible version"); detail carries the store’s own message. Whether to retry depends on the store, so this variant is reported as non-fatal and left for the caller to judge.

Fields

§context: &'static str

The operation the store was performing when it failed.

§detail: String

The store’s human-readable description of the failure.

§

Durability

The durable commit log failed, or a record read back from it was not intact.

Produced only with the durability feature: when appending or syncing a commit record fails, or when recovery on Db::open reads a record whose bytes do not decode. A commit that fails to become durable is not acknowledged — the contract that an acknowledged commit survives a crash holds — but the failure is fatal in the sense that the database’s durability guarantee is in question, so treat it as unrecoverable rather than retrying blindly.

Fields

§detail: String

A human-readable description of the durability failure.

Implementations§

Source§

impl TxnError

Source

pub fn conflict(key_len: usize) -> Self

Build a TxnError::Conflict for a key of the given length.

A custom VersionStore returns this from try_commit when validation detects that a written or read key changed after the transaction’s snapshot. Pass the conflicting key’s length; its bytes are deliberately not carried, so the error stays safe to log. The shipped in-memory store uses this internally.

§Examples
use txn_db::TxnError;

let err = TxnError::conflict(b"account:42".len());
assert!(err.is_retryable());
Source

pub fn store(context: &'static str, detail: impl Display) -> Self

Build a TxnError::Store from a static context and a store message.

Intended for VersionStore implementations that can fail; the in-memory store never calls it.

Source

pub fn is_retryable(&self) -> bool

Returns true if re-running the transaction is the right response.

A Conflict is retryable: another transaction won the race, and a fresh attempt against the newer snapshot will typically succeed. Backing-store failures are reported as not retryable here because their recoverability is store-specific; inspect the variant when a store can distinguish transient from permanent faults.

§Examples
use txn_db::{Db, TxnError};

let db = Db::new();

// The common retry loop: keep trying while the commit is retryable.
let outcome = loop {
    let mut tx = db.begin();
    let current = tx.get(b"counter")?.map_or(0u64, |v| {
        let mut buf = [0u8; 8];
        buf.copy_from_slice(&v);
        u64::from_le_bytes(buf)
    });
    tx.put(b"counter".to_vec(), (current + 1).to_le_bytes().to_vec());
    match tx.commit() {
        Ok(ts) => break ts,
        Err(e) if e.is_retryable() => continue,
        Err(e) => return Err(e),
    }
};

Trait Implementations§

Source§

impl Clone for TxnError

Source§

fn clone(&self) -> TxnError

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for TxnError

Source§

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

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

impl Display for TxnError

Source§

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

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

impl Eq for TxnError

Source§

impl Error for TxnError

1.30.0 · Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl ForgeError for TxnError

Source§

fn is_fatal(&self) -> bool

A Conflict is the retry signal and a Store failure is the store’s to classify, so neither is fatal. A Durability failure puts the crash guarantee in doubt and is reported as fatal.

Source§

fn kind(&self) -> &'static str

Returns the kind of error, typically matching the enum variant
Source§

fn caption(&self) -> &'static str

Returns a human-readable caption for the error
Source§

fn is_retryable(&self) -> bool

Returns true if the operation can be retried
Source§

fn status_code(&self) -> u16

Returns an appropriate HTTP status code for the error
Source§

fn exit_code(&self) -> i32

Returns an appropriate process exit code for the error
Source§

fn user_message(&self) -> String

Returns a user-facing message that can be shown to end users
Source§

fn dev_message(&self) -> String

Returns a detailed technical message for developers/logs
Source§

fn backtrace(&self) -> Option<&Backtrace>

Returns a backtrace if available
Source§

fn register(&self)

Registers the error with the central error registry
Source§

impl PartialEq for TxnError

Source§

fn eq(&self, other: &TxnError) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl StructuralPartialEq for TxnError

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> ForgeErrorRecovery for T
where T: ForgeError,

Source§

fn create_retry_policy(&self, max_retries: usize) -> RetryPolicy

Create a retry policy optimized for this error type
Source§

fn retry<F, T, E>(&self, max_retries: usize, operation: F) -> Result<T, E>
where F: FnMut() -> Result<T, E>, E: ForgeError,

Execute a fallible operation with retries if this error type is retryable
Source§

fn create_circuit_breaker(&self, name: impl Into<String>) -> CircuitBreaker

Create a circuit breaker for operations that might result in this error type
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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
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<E> WithErrorCode<E> for E

Source§

fn with_code(self, code: impl Into<String>) -> CodedError<E>

Attach an error code to an error