trine-kv 0.2.0

Embedded LSM MVCC key-value database.
Documentation
# Trine KV

Trine KV is an embedded Rust key-value database for applications that need
ordered local storage without running a separate server. It gives simple code a
default bucket, and lets larger applications add named buckets with their own
prefix, filter, compression, and large-value settings.

The crate is implemented and verified by the repository test suite, benchmark
harness, and durability notes. To see the main path work end to end:

```text
cargo run --example quickstart
```

Then read [docs/usage.md](docs/usage.md) for the API path and
[docs/durability.md](docs/durability.md) for persistence guarantees and limits.
Release packaging notes live in [docs/release.md](docs/release.md).

## Common Capabilities

- Async-first default-bucket reads and writes with `Db::put`, `Db::get`,
  `Db::range`, and `Db::prefix`.
- Explicit sync adapters with `*_sync` names, such as `Db::open_sync`,
  `db.put_sync`, `bucket.get_sync`, and `db.flush_sync`.
- Optional named buckets through `db.bucket("users").await?` when data needs
  logical separation or independent tuning.
- Atomic write batches across the default bucket and named buckets.
- MVCC snapshots that keep old reads stable while newer writes commit.
- Snapshot-bound point readers that can avoid copying inline table values when
  callers can work with borrowed bytes.
- Optimistic transactions with point and range conflict checks.
- Ordered range scans and prefix scans.
- Value-lazy range and prefix scans for large-value workloads that need keys
  before reading blob bytes.
- Persistent mode with WAL replay, manifest recovery, directory locking,
  safe native defaults, background maintenance, backpressure, flush,
  compaction, and read-only open.
- Explicit in-memory mode for tests, examples, and short-lived data that should
  disappear when the `Db` is dropped.
- Async open/read/write/scan/transaction/maintenance entry points for hosts
  that need to drive storage cooperatively. Native async persistent APIs enter
  storage waits through Trine's storage boundary and use runtime task
  boundaries for synchronous maintenance/WAL internals.
- Block-based SSTables with partitioned index/filter blocks, data-block hash
  lookup for point reads, high-priority metadata caching, compression, and
  linear/binary/auto index seek policies.
- Large values can be separated into Titan-like blob files with `BlobIndex`
  records in SSTables.
- Automatic blob Level Merge can rewrite retained large values into output blob
  files during compaction when it improves locality or removes stale blob refs.
- Snapshot-safe blob GC rewrites still-live large values out of stale blob
  files and delays old-file deletion while a read can still reach them.
- Live stats report table, cache, filter, blob read, blob byte, and blob GC
  counters.
- Explicit WASI and browser persistent options. WASI uses a host-preopened
  filesystem path on WASI targets and supports `Db::open` through the
  host storage boundary. Browser persistence uses the async API and the browser
  persistent backend on `wasm32-unknown-unknown`.

## Install

Add Trine KV from [crates.io](https://crates.io/crates/trine-kv):

```text
cargo add trine-kv
```

`cargo install` is for crates that provide command-line binaries. Trine KV is a
library crate, so application projects should depend on it instead.

For local development, depend on a path:

```toml
[dependencies]
trine-kv = { path = "../trine-kv" }
```

## Common API Example

```rust
use trine_kv::{Db, KeyRange, TransactionOptions, WriteBatch, WriteOptions};

async fn run() -> trine_kv::Result<()> {
    let db = Db::open("./trine-data").await?;

    // Simple applications can use the built-in default bucket directly.
    db.put(b"settings:theme", b"dark").await?;
    assert_eq!(db.get(b"settings:theme").await?, Some(b"dark".to_vec()));

    // Named buckets are created on demand when you need logical separation.
    let users = db.bucket("users").await?;
    users.put(b"user:001", b"Ada").await?;

    // Snapshots keep a stable read sequence while newer writes continue.
    let snapshot = db.snapshot();
    users.put(b"user:002", b"Lin").await?;
    assert_eq!(snapshot.get(&users, b"user:002").await?, None);

    // Batches can atomically span buckets.
    let mut batch = WriteBatch::new();
    batch.put(b"audit:001", b"user-created");
    batch.put_bucket("users", b"user:003", b"Grace")?;
    db.write(batch, WriteOptions::default()).await?;

    // Transactions validate their read set when they commit.
    let mut txn = db.transaction(TransactionOptions::default());
    assert_eq!(
        txn.get_bucket("users", b"user:001").await?,
        Some(b"Ada".to_vec())
    );
    txn.put_bucket("users", b"user:004", b"Barbara")?;
    txn.commit().await?;

    let mut rows = users
        .range(&KeyRange::half_open(b"user:001", b"user:999"))
        .await?;
    let mut row_count = 0;
    while rows.next().await?.is_some() {
        row_count += 1;
    }
    assert_eq!(row_count, 4);

    Ok(())
}
```

For the runnable async-first persistent path, use:

```text
cargo run --example quickstart
```

For tests or short-lived data, opt into memory mode explicitly:

```rust
use trine_kv::{Db, DbOptions};

let db = Db::open(DbOptions::memory()).await?;
```

For the explicit sync-adapter path, use:

```text
cargo run --example sync_quickstart
```

## Common Commands

```text
cargo fmt --check
cargo clippy
cargo test
cargo run --example quickstart
cargo run --example sync_quickstart
cargo run --example user_store
cargo run --example event_index
cargo bench --bench v1_bench
```

## Examples

- `quickstart`: first pass through `Db::open`, async writes, lazy scans,
  transaction commit, maintenance, read-only reopen, and storage runtime stats.
- `sync_quickstart`: first pass through the explicit sync adapters, including
  persistent open, buckets, scans, transactions, flush, reopen, and stats.
- `user_store`: wraps Trine KV behind a small repository-style API.
- `event_index`: stores event payloads and a secondary account index with one
  atomic write batch.

## Documentation

- [Usage guide]docs/usage.md
- [Durability notes]docs/durability.md
- [Release packaging]docs/release.md
- [0.1 benchmark baseline]docs/benchmarks/0.1-baseline.md
- [Large-value direct read tuning]docs/benchmarks/v1-large-value-direct-read.md
- [Blob maintenance and lazy value benchmark]docs/benchmarks/v1-blob-level-merge-lazy-gc.md
- [Read-pruning measurement]docs/benchmarks/v1-read-pruning-measurement.md
- [Cold table open read]docs/benchmarks/v1-cold-table-open-read.md
- [Cold manifest/open reopen]docs/benchmarks/v1-cold-manifest-open-reopen.md
- [Read-only cold reopen]docs/benchmarks/v1-read-only-cold-reopen.md
- [Read-only cold open breakdown]docs/benchmarks/v1-read-only-cold-open-breakdown.md
- [Batched point reads]docs/benchmarks/v1-batched-point-reads.md
- [Get-many internal batching]docs/benchmarks/v1-get-many-internal-batching.md

## Current Boundaries

- Persistent mode uses a single local database directory.
- Native persistent open defaults to `SyncAll` for confirmed writes. `Buffered`
  is an explicit advanced mode for data that can tolerate losing recent writes
  after a crash or power loss.
- WASI and browser persistent backends do not claim `SyncData` or `SyncAll`.
- WASI persistent `Db::open` uses the host-preopened filesystem on WASI
  targets; current WASI file work completes inline and does not advertise
  platform async I/O.
- Browser persistence is async-only: use `Db::open` plus async mutation
  and maintenance methods. Synchronous browser persistent open, mutation, and
  maintenance `*_sync` APIs return typed unsupported errors.
- Read-only open is for inspecting a stable directory state; the `0.1` line
  does not define live multi-process reads against an active writer.
- Repair is intentionally narrow and only removes known safe temporary files
  when explicitly requested.