Crate ministate

Crate ministate 

Source
Expand description

A minimal, in-memory state manager with durable WAL logging.

ministate provides a simple yet robust way to maintain mutable application state that survives process restarts, using an append-only Write-Ahead Log (WAL). It builds directly on ministore for reliable, human-readable journaling.

§Core Features

  • In-memory state: Fast reads via RwLock, full Clone on demand.
  • Durable mutations: Every change is first written to disk (fsync-ed) before being applied.
  • Crash recovery: On startup, the state is reconstructed by replaying the WAL from the beginning.
  • Logical ordering: Each mutation is assigned a monotonically increasing sequence number.

§Optional Snapshot Support (snapshot feature)

When the snapshot Cargo feature is enabled, ministate integrates with [minisnap] to:

  • Save full state snapshots to disk for faster recovery.
  • Enable future WAL compaction (truncating the log prefix after a snapshot is taken).

⚠️ Snapshotting is explicit — you must call create_snapshot() manually. WAL compaction is not yet implemented but will be added in a future release.

§Concurrency Model

  • Reads: Concurrent via snapshot() (uses RwLock::read).
  • Writes: Serialized via apply() (uses RwLock::write).
  • No hidden threads: All I/O is explicit and await-driven.

§Guarantees

  • Durability: If apply().await returns Ok(_), the mutation is guaranteed to be on disk.
  • Atomicity: The in-memory state is updated only if the WAL write succeeds.
  • Ordering: Mutations are applied in the exact order they appear in the WAL.
  • Recoverability: Full state restoration is possible from the WAL alone (or WAL + snapshot).

§Use Cases

  • Stateful services that must recover after a crash (e.g., component registries, deployment specs).
  • Embedded systems with limited resources but strict durability requirements.
  • Local coordination primitives (e.g., leader election state, queue metadata).

§Example

use ministate::{Mutator, StateManager};
use serde::{Deserialize, Serialize};

#[derive(Default, Clone, Serialize, Deserialize)]
struct Counter { value: u32 }

#[derive(Serialize, Deserialize)]
struct Inc { by: u32 }

impl Mutator<Counter> for Inc {
    fn apply(&self, state: &mut Counter) {
        state.value += self.by;
    }
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let tmp = tempfile::tempdir()?;
    let dir = tmp.path();

    let mgr = StateManager::open(dir, "counter.wal.jsonl").await?;
    mgr.apply(Inc { by: 10 }).await?;
    assert_eq!(mgr.snapshot().await.value, 10);
    Ok(())
}

Structs§

StateManager
Manages in-memory state with durable WAL logging.

Enums§

MiniStateError

Traits§

Mutator
A mutation that can be applied to a state S.