Skip to main content

Crate etchdb

Crate etchdb 

Source
Expand description

etch — a fast, embedded database for Rust.

In-memory state backed by a Write-Ahead Log (WAL) with postcard binary format. Reads are zero-copy borrows via RwLock. Writes are atomic and crash-safe.

§Architecture

Store<T, B>
  ├── RwLock<T>        ← in-memory state, zero-copy reads
  ├── Mutex<()>        ← serializes writers (reads unblocked during persist)
  └── Backend<T>       ← pluggable: WalBackend, NullBackend, or bring your own

§Quick start

use etchdb::{Store, Replayable, Op, Overlay, Transactable, apply_overlay_btree};
use serde::{Serialize, Deserialize};
use std::collections::BTreeMap;

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
struct AppState {
    items: BTreeMap<String, Item>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Item { name: String }

const ITEMS: u8 = 0;

impl Replayable for AppState {
    fn apply(&mut self, ops: &[Op]) -> etchdb::Result<()> {
        for op in ops { etchdb::apply_op(&mut self.items, op)?; }
        Ok(())
    }
}

struct AppTx<'a> {
    committed: &'a AppState,
    items: Overlay<String, Item>,
    ops: Vec<Op>,
}

impl<'a> AppTx<'a> {
    fn insert(&mut self, key: &str, item: Item) {
        self.ops.push(Op::Put {
            collection: ITEMS,
            key: key.as_bytes().to_vec(),
            value: postcard::to_allocvec(&item).expect("serialize"),
        });
        self.items.put(key.to_string(), item);
    }
}

struct AppOverlay { items: Overlay<String, Item> }

impl Transactable for AppState {
    type Tx<'a> = AppTx<'a>;
    type Overlay = AppOverlay;
    fn begin_tx(&self) -> AppTx<'_> {
        AppTx { committed: self, items: Overlay::new(), ops: Vec::new() }
    }
    fn finish_tx(tx: AppTx<'_>) -> (Vec<Op>, AppOverlay) {
        (tx.ops, AppOverlay { items: tx.items })
    }
    fn apply_overlay(&mut self, overlay: AppOverlay) {
        etchdb::apply_overlay_btree(&mut self.items, overlay.items);
    }
}

let store = Store::<AppState>::memory();

store.write(|tx| {
    tx.insert("k1", Item { name: "first".into() });
    Ok(())
}).unwrap();

let state = store.read();
assert_eq!(state.items["k1"].name, "first");

Re-exports§

pub use backend::Backend;
pub use backend::NullBackend;
pub use error::Error;
pub use error::Result;
pub use store::FlushPolicy;
pub use store::Ref;
pub use store::Store;
pub use wal::Collection;
pub use wal::EtchKey;
pub use wal::IncrementalSave;
pub use wal::MapRead;
pub use wal::Op;
pub use wal::Overlay;
pub use wal::Replayable;
pub use wal::Transactable;
pub use wal::WalBackend;
pub use wal::apply_op;
pub use wal::apply_op_bytes;
pub use wal::apply_op_hash;
pub use wal::apply_op_hash_bytes;
pub use wal::apply_op_hash_with;
pub use wal::apply_op_with;
pub use wal::apply_overlay_btree;
pub use wal::apply_overlay_hash;

Modules§

backend
Persistence backend trait and built-in implementations.
error
Error types for etch.
store
Core persistence engine.
wal
Write-Ahead Log (WAL) for incremental persistence.

Derive Macros§

Replayable
Re-export derive macros so users can use etchdb::{Replayable, Transactable} for both the trait and the derive macro (same pattern as serde). Derive Replayable for a struct with #[etch(collection = N)] fields.
Transactable
Re-export derive macros so users can use etchdb::{Replayable, Transactable} for both the trait and the derive macro (same pattern as serde). Derive Transactable for a struct with #[etch(collection = N)] fields.