Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 25 additions & 4 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,16 @@ directory entry is fsynced before any write to it is acknowledged. Writers
stall (100ms poll on the progress signal) when frozen memtables pile past
`max_immutable_memtables` or L0 exceeds `l0_stall_trigger`.

**Fresh-store bulk bootstrap.** `Db::create_from_sorted` is the one path that
does not use the write pipeline above. Before background threads or a public
handle exist, it validates a strictly increasing stream of unique user keys,
applies the same inline/vlog placement, and writes fragmented tables directly
into one bottom-level run. Vlog payloads and tables are synced before a single
manifest flip publishes the base and its flush watermark. A failure before
that flip leaves the previously published empty store, never a partial base.
The API refuses any destination that already contains a database or unrelated
files; it cannot bypass MVCC, triggers, or replication on a live store.

## 3. Tables (sorted-run fragments)

`[data block]* [filter block] [index block] [stats block] [footer 48B]`,
Expand Down Expand Up @@ -104,8 +114,19 @@ vlog-file set; it is published under the state lock and pinned by `Arc`.
Installation removes exactly the pinned inputs, so flushes prepending to
L0 mid-merge are safe. Full-tier merges preserve the newest-first
recency invariant.
- **Bottom level**: whenever it holds ≥ 2 runs, everything merges into one
(leveling at the bottom).
- **Bottom level**: whenever it holds ≥ 2 runs, the run adjacent to the
leveled base merges into only the base fragments overlapping its key
range. Untouched fragments survive by identity. A bottom past its byte
budget deepens by moving its runs into a new manifest level without
rewriting table files; repeated moves find a level whose budget fits.
- **Priority scheduler**: a rewrite consumes at most
`compaction_slice_bytes` of input before returning to the picker (the
current user key always finishes). A newly eligible upper level suspends
the deeper job; after the upper job installs, the immutable deep inputs
resume. Jobs still install atomically, and exact-input removal preserves
every run installed while they were suspended. `compact_all` uses this
same scheduler with force thresholds instead of owning an exclusive
full-store merge path.
- **Point lookup**: memtable → frozen → runs newest-first; each run binary
searches its single candidate fragment after a bloom + range check; the
first version with `seqno <= snap` wins; a run whose versions are all
Expand Down Expand Up @@ -449,8 +470,8 @@ Lock order (strict): `write_mu → manifest → state → snapshots`, with
`gc_mu`/`compaction_mu` outermost within their flows. Never hold the state
guard while taking the manifest lock (a stats() violation deadlocked
exactly as predicted and is fixed). `compaction_mu` serializes the
maintenance thread and user `compact_all` — two concurrent pickers would
merge the same inputs.
maintenance thread and user `compact_all`; the one scheduler may suspend a
deep job between bounded slices, but never executes two jobs concurrently.

## 12. Testing

Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,26 @@ let a = db.fork_at("replica-a", s)?;
let b = db.fork_at("replica-b", s)?; // same cut as replica-a
```

## Bulk bootstrap

When the complete initial keyspace is already available in strictly sorted,
unique-key order, `Db::create_from_sorted` streams it directly into a fresh
store's bottom-level run:

```rust
let entries = vec![(b"acct/1", b"100"), (b"acct/2", b"250")];
let db = Db::create_from_sorted("./import", Options::default(), entries)?;
```

The builder preserves the configured compression, Bloom filters, value
separation, vlog rotation, and SST fragment sizing. It makes the whole base
visible with one manifest update and does not write it through the WAL,
memtable, L0, or compaction. This is a creation primitive, not a live-ingest
path: the destination must be absent or empty, keys must be valid user keys,
and duplicates or out-of-order input are rejected. Fallible source iterators
can use `Db::create_from_sorted_fallible`; an input error never publishes a
partial base.

## What MVCC is (and isn't) for

MVCC is how the engine gives you consistency — it is **not** an
Expand Down
1 change: 1 addition & 0 deletions crates/fluent31/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ crc32fast = "1"
# deterministic store identity (identity.rs): truncated SHA-256 lineage hash
sha2 = "0.10"
lz4_flex = { version = "0.11", default-features = false, features = ["std", "safe-encode", "safe-decode"] }
zstd = { version = "0.13", default-features = false }
wasmtime = { version = "46.0.1", default-features = false, features = ["runtime", "cranelift", "wat"], optional = true }

[target.'cfg(target_os = "linux")'.dependencies]
Expand Down
Loading