Skip to main content

Crate indexmap_store

Crate indexmap_store 

Source
Expand description

Mutable, persistent key-value store backed by an in-memory IndexMap and an append-only write-ahead log on disk.

Design:

  • Reads, lookups, and iteration go through the in-memory map — O(1) hashed access while preserving insertion order.
  • Every mutation appends one length-prefixed record to a single log file. Records are written through a BufWriter so bulk writes coalesce into page-sized syscalls. With sync_on_write = false (the default) the OS page cache absorbs writes; turn it on for fsync-per-op durability.
  • Recovery reads the log front-to-back, replays records into the map, and truncates a torn tail so a crash mid-record never bricks the store.
  • When the log grows past a configurable threshold and accumulates enough dead records (updates/deletes that supersede earlier entries), the store rewrites a minimal snapshot to a temp file and atomically renames it into place.

The store owns the file; concurrent writers are not supported.

§Quick start

use indexmap_store::IndexMapStore;

let dir = tempfile::tempdir().unwrap();
let path = dir.path().join("users.log");

let mut store: IndexMapStore<String, u64> = IndexMapStore::open(&path)?;
store.insert("alice".into(), 1)?;
store.insert("bob".into(), 2)?;
store.modify(&"alice".into(), |v| *v += 100)?;
store.remove(&"bob".into())?;
store.flush()?;

assert_eq!(store.get(&"alice".into()), Some(&101));
assert_eq!(store.len(), 1);

// Reopen: state is recovered from the log.
drop(store);
let store: IndexMapStore<String, u64> = IndexMapStore::open(&path)?;
assert_eq!(store.get(&"alice".into()), Some(&101));

§Custom configuration

use indexmap_store::{IndexMapStore, StoreConfig};

let dir = tempfile::tempdir().unwrap();
let cfg = StoreConfig {
    sync_on_write: true,        // fsync every mutation
    min_compact_bytes: 4 << 20, // wait until log > 4 MiB before compacting
    compact_ratio: 3.0,         // compact when total_records >= 3 * live
    buf_capacity: 64 * 1024,
};
let mut store: IndexMapStore<u32, String> =
    IndexMapStore::open_with(dir.path().join("kv.log"), cfg)?;
store.insert(1, "one".into())?;

§Iteration preserves insertion order

use indexmap_store::IndexMapStore;

let dir = tempfile::tempdir().unwrap();
let mut store: IndexMapStore<String, i32> =
    IndexMapStore::open(dir.path().join("ord.log"))?;
for (k, v) in [("c", 3), ("a", 1), ("b", 2)] {
    store.insert(k.into(), v)?;
}
let keys: Vec<_> = store.keys().cloned().collect();
assert_eq!(keys, ["c", "a", "b"]);

Structs§

IndexMapStore
A mutable, persistent IndexMap.
StoreConfig
Configuration for an IndexMapStore.