# txn-db v0.2.0 — Foundation

**The first release with working transactions.** v0.2.0 lands the public API,
the MVCC core, snapshot isolation, and write-write conflict detection over an
in-memory version store. The Tier-1 surface — `Db`, `Transaction`, `Snapshot` —
is settled and will not change shape before 1.0. This is the foundation the
serializable, durable, and garbage-collected phases build on.

## What is txn-db?

A multi-version concurrency control (MVCC) transaction engine: the layer that
turns a key-value store into a transactional database. Every write produces a
new version tagged with a commit timestamp, so readers get a stable snapshot
without ever blocking writers, and writers detect conflicts at commit time
instead of holding locks for the lifetime of a transaction. It is a *layer*, not
a store — the version store is a trait, so the engine composes on top of any
backend that can keep timestamped versions of a key.

## What's new in 0.2.0

### The Tier-1 surface — `Db` / `Transaction` / `Snapshot`

The whole common case is begin, read and write through the transaction, commit:

```rust
use txn_db::Db;

let db = Db::new();

let mut tx = db.begin();
tx.put(b"user:1:name".to_vec(), b"ada".to_vec());
tx.put(b"user:1:role".to_vec(), b"admin".to_vec());
tx.commit()?;

let tx = db.begin();
assert_eq!(tx.get(b"user:1:name")?.as_deref(), Some(&b"ada"[..]));
# Ok::<(), txn_db::TxnError>(())
```

`Db` is a cheap, clonable handle over shared state — clone it per thread. There
are no generics to name in the common case: the backing store defaults to the
in-memory implementation. Keys and values are byte strings; `put` and `delete`
accept anything convertible into `Arc<[u8]>`, so owned buffers move in without a
copy, and `get` returns an `Arc<[u8]>` that clones by reference count.

### Snapshot isolation

A transaction reads the database as of the instant it began. Commits by other
transactions afterward are invisible to it, and its own buffered writes are
visible only to itself until it commits (read-your-own-writes). A `Snapshot` is
the read-only counterpart: a consistent point-in-time view that stays stable as
the database moves on.

```rust
use txn_db::Db;

let db = Db::new();
let mut tx = db.begin();
tx.put(b"k".to_vec(), b"v1".to_vec());
tx.commit()?;

let snap = db.snapshot();             // capture this instant
let mut tx = db.begin();
tx.put(b"k".to_vec(), b"v2".to_vec());
tx.commit()?;                         // move forward

assert_eq!(snap.get(b"k")?.as_deref(), Some(&b"v1"[..]));  // unmoved
# Ok::<(), txn_db::TxnError>(())
```

### Write-write conflict detection

At commit the engine applies first-committer-wins: if any key a transaction
wrote was changed by another transaction that committed after this one's
snapshot, the commit is rejected with a retryable `TxnError::Conflict` and none
of its writes are applied. That rule is what prevents lost updates.

```rust
use txn_db::Db;

let db = Db::new();
let mut a = db.begin();
let mut b = db.begin();
a.put(b"counter".to_vec(), b"1".to_vec());
b.put(b"counter".to_vec(), b"2".to_vec());

a.commit()?;                          // first committer wins
let err = b.commit().unwrap_err();    // second is rejected
assert!(err.is_retryable());          // retry against the fresh snapshot
# Ok::<(), txn_db::TxnError>(())
```

The conflict error carries only the length of the conflicting key, never its
bytes, so it is safe to log even when keys hold sensitive data.

### The `VersionStore` seam

The backing store is the `VersionStore` trait (`get`, `latest_commit_ts`,
`apply`). The transaction layer supplies all of the isolation logic; an
implementation only has to keep timestamped versions and answer the snapshot
query. `MemoryStore` ships as the default — version chains kept in commit order
with binary-search snapshot reads. A custom store plugs in through
`Db::with_store` and the transaction semantics compose on top unchanged.

### Error type

`TxnError` is a `#[non_exhaustive]` domain error built on `error-forge`, with the
retryable `Conflict` variant, a `Store` variant through which custom backends
surface failures, and an `is_retryable` helper for the retry loop.

## Testing

The v0.2 isolation contract is verified with property-based and concurrency
tests, not just examples:

- **Reference-model equivalence** — an arbitrary sequence of puts and deletes
  leaves the database matching a straightforward model.
- **Snapshot stability** — a snapshot returns the same values no matter how much
  commits afterward.
- **Write-write conflict** — two transactions from one snapshot writing the same
  key: the first wins, the second gets a retryable conflict, the winner's value
  survives.
- **Read-your-own-writes** — pending puts and deletes are visible within the
  transaction.
- **Lost-update prevention** — eight threads run 200 read-modify-write
  increments each through a retry loop; the final counter is exactly 1600.
- **Reader isolation** — a long-lived snapshot is unaffected by concurrent
  writers.

## Breaking changes

**None.** v0.2.0 is the first release with a public API; v0.1.0 was a scaffold
with no domain logic.

## Verification

Run on Windows x86_64, Rust stable 1.95.x and MSRV 1.85; the configured CI
matrix runs the same commands on Linux, macOS, and Windows:

```bash
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features
cargo +1.85 clippy --all-targets --all-features -- -D warnings
cargo +1.85 test --all-features
cargo build --examples
cargo build --benches
cargo deny check
cargo audit
```

All green. Counts at this tag (`--all-features`): 23 unit + 6 integration
(4 property + 2 concurrency) + 28 doctests.

## What's next

- **0.3.0 — Concurrency control + serializable (SSI).** Read/write-set tracking,
  optional serializable isolation under the `serializable` feature, and a
  lock-free / sharded commit path with a `loom` model check.

## Installation

```toml
[dependencies]
txn-db = "0.2"
```

MSRV: Rust 1.85 (the 2024 edition).

## Documentation

- [README](https://github.com/jamesgober/txn-db/blob/main/README.md)
- [API Reference](https://github.com/jamesgober/txn-db/blob/main/docs/API.md)
- [CHANGELOG](https://github.com/jamesgober/txn-db/blob/main/CHANGELOG.md)

---

**Full diff:** [`v0.1.0...v0.2.0`](https://github.com/jamesgober/txn-db/compare/v0.1.0...v0.2.0).
**Changelog:** [`CHANGELOG.md`](https://github.com/jamesgober/txn-db/blob/main/CHANGELOG.md#020---2026-06-06).
