nexir-mvcc 0.3.0

Standalone, deterministic Multi-Version Concurrency Control (MVCC) library for building durable databases
Documentation

nexir-mvcc

A standalone, deterministic Multi-Version Concurrency Control (MVCC) core library used by Nexir.

nexir-mvcc provides the versioning, intent, guarded-write, batch mutation, and history-retention primitives required to build a transactional key-value storage layer. It is intentionally limited to the MVCC engine. This repository is not the complete Nexir database and does not include networking, command parsing, consensus, durable storage adapters, idempotency caches, query execution, metrics, or operational services.

Key Features

  • Strict Separation of Concerns: Core logic runs deterministically in memory. All disk/durable state is managed through a clean Backend trait.
  • Timestamp-Based Ordering: Native support for caller-supplied, opaque u128 logical timestamps (start_ts, commit_ts, read_ts).
  • Two-Phase Intent Transactions: First-class support for single-key and multi-key intent transactions via prewrite, commit, abort, prewrite_batch, commit_batch, and abort_batch.
  • Atomic Batches: Support for multi-key prewrite_batch, commit_batch, and abort_batch ensures all-or-nothing transactional guarantees.
  • Direct & Guarded Fast Paths: apply_direct_batch and apply_guarded_batch bypass the intent system for high-performance single-roundtrip writes, complete with Compare-And-Swap (CAS) guard validation.
  • Incremental GC: Deterministic history retention with gc_incremental, cursor resumption, and caller-supplied work budgets.
  • Per-Key GC Planning: Read-only, bounded plans with explicit obsolete timestamps for adapters that own their own work discovery and atomic persistence.
  • Backend Conformance Suite: Built-in test macros via the conformance feature to easily verify that your custom storage layer meets the logical backend contract (note: adapters must still provide their own crash atomicity tests).

Scope and Integration

nexir-mvcc sits between an adapter/runtime layer and a durable backend implementation.

  1. Implement the Backend trait for your storage engine or replicated state machine.
  2. Wrap your Backend in the MvccEngine.
  3. Map external reads, transactions, and conditional writes to the engine methods.

The core intentionally does not own:

  • async runtimes or background tasks,
  • consensus types,
  • durable database bindings,
  • command or document parsing,
  • idempotency/replay caches,
  • production metrics registries.

Adapters own those concerns and must serialize mutation apply for each ordered write domain.

The core treats every CommittedVersion.value as opaque bytes. It decides only generic MVCC visibility, keeper, safe-point, and final-tombstone semantics. Adapters own payload validation, candidate discovery, durable maintenance queues, and the atomic storage batch that applies a plan.

Quick Start

Direct Batch (Single Roundtrip)

use nexir_mvcc::{InMemoryBackend, MvccEngine, PhysicalWrite, Timestamp};

let mut engine = MvccEngine::new(InMemoryBackend::new());

let writes = vec![PhysicalWrite {
    key: b"config_version".to_vec(),
    value: Some(b"1.0".to_vec()),
}];

// Apply directly at timestamp 10
engine.apply_direct_batch(Timestamp(10), writes).unwrap();

let value = engine.read(b"config_version", Timestamp(15)).unwrap();
assert_eq!(value.unwrap(), b"1.0");

Multi-Key Intent Transaction

use nexir_mvcc::{InMemoryBackend, MvccEngine, PhysicalWrite, Timestamp, TxnId};

let mut engine = MvccEngine::new(InMemoryBackend::new());
let txn_id = TxnId(1);
let start_ts = Timestamp(10);

let writes = vec![PhysicalWrite {
    key: b"account_a".to_vec(),
    value: Some(b"900".to_vec()),
}];

// Step 1: prewrite all provisional writes.
engine.prewrite_batch(txn_id, start_ts, writes).unwrap();

// Step 2: commit and make the transaction visible.
engine.commit_batch(txn_id, start_ts, Timestamp(20), vec![b"account_a".to_vec()]).unwrap();

For more advanced use cases, including Read-Modify-Write and Abort idempotency, check the examples/ directory.

Documentation

Testing and Conformance

The crate includes an in-memory backend and an extensive suite of property and failure tests.

To verify your own backend implementation, enable the conformance feature in your Cargo.toml:

[dependencies]
nexir-mvcc = { version = "0.3", features = ["conformance"] }

And run the macro in your tests:

#[cfg(test)]
mod tests {
    use my_crate::MyBackend;

    // Generates a suite of tests that assert atomicity, sorting, and tombstone rules
    nexir_mvcc::test_backend_conformance!(|| MyBackend::new_for_test());
}

Release Checks

Before publishing or cutting a release, run:

cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo doc --no-deps --all-features
cargo package

Performance runs are intentionally separate from correctness gates:

cargo bench --bench perf_truth -- --sample-size 10 --warm-up-time 0.1 --measurement-time 0.1
cargo run --example command_load_sim --release

License

Dual-licensed under either of:

at your option. See NOTICE for Apache-2.0 attribution notice information.