{"id":51514759,"url":"https://github.com/jamesgober/wal-db","last_synced_at":"2026-07-08T10:01:47.401Z","repository":{"id":362658182,"uuid":"1253906505","full_name":"jamesgober/wal-db","owner":"jamesgober","description":"Write-ahead log primitive for Rust storage engines - durable, recoverable, lock-free.","archived":false,"fork":false,"pushed_at":"2026-06-05T11:33:35.000Z","size":169,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-05T12:08:50.810Z","etag":null,"topics":["database","durability","recovery","reps","rust","wal","write-ahead-log"],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jamesgober.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE-APACHE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-29T23:47:44.000Z","updated_at":"2026-06-05T11:09:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jamesgober/wal-db","commit_stats":null,"previous_names":["jamesgober/wal-db"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/jamesgober/wal-db","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fwal-db","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fwal-db/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fwal-db/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fwal-db/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jamesgober","download_url":"https://codeload.github.com/jamesgober/wal-db/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jamesgober%2Fwal-db/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35260671,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-08T02:00:06.796Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","durability","recovery","reps","rust","wal","write-ahead-log"],"created_at":"2026-07-08T10:01:45.038Z","updated_at":"2026-07-08T10:01:47.377Z","avatar_url":"https://github.com/jamesgober.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003e\n    \u003cimg width=\"99\" alt=\"Rust logo\" src=\"https://raw.githubusercontent.com/jamesgober/rust-collection/72baabd71f00e14aa9184efcb16fa3deddda3a0a/assets/rust-logo.svg\"\u003e\n    \u003cbr\u003e\n    \u003cb\u003ewal-db\u003c/b\u003e\n    \u003cbr\u003e\n    \u003csub\u003e\u003csup\u003eWRITE-AHEAD LOG PRIMITIVE\u003c/sup\u003e\u003c/sub\u003e\n\u003c/h1\u003e\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://crates.io/crates/wal-db\"\u003e\u003cimg alt=\"Crates.io\" src=\"https://img.shields.io/crates/v/wal-db\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://crates.io/crates/wal-db\" alt=\"Download wal-db\"\u003e\u003cimg alt=\"Crates.io Downloads\" src=\"https://img.shields.io/crates/d/wal-db?color=%230099ff\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://docs.rs/wal-db\" title=\"wal-db Documentation\"\u003e\u003cimg alt=\"docs.rs\" src=\"https://img.shields.io/docsrs/wal-db\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/jamesgober/wal-db/actions\"\u003e\u003cimg alt=\"GitHub CI\" src=\"https://github.com/jamesgober/wal-db/actions/workflows/ci.yml/badge.svg\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/rust-lang/rfcs/blob/master/text/2495-min-rust-version.md\" title=\"MSRV\"\u003e\u003cimg alt=\"MSRV\" src=\"https://img.shields.io/badge/MSRV-1.85%2B-blue\"\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n\u003cbr\u003e\n\n\u003cdiv align=\"left\"\u003e\n    \u003cp\u003e\n        \u003cstrong\u003ewal-db\u003c/strong\u003e is a \u003cb\u003ewrite-ahead log primitive\u003c/b\u003e for Rust storage engines. It is the durability substrate underneath every database, transaction system, and distributed log in the portfolio — \u003ccode\u003elsm-db\u003c/code\u003e, \u003ccode\u003etxn-db\u003c/code\u003e, \u003ccode\u003eraft-io\u003c/code\u003e, and Hive DB all build on it. The append path is \u003cb\u003elock-free\u003c/b\u003e, durability is \u003cb\u003eexplicit\u003c/b\u003e and \u003cb\u003eplatform-correct\u003c/b\u003e on Linux, macOS, and Windows, recovery is \u003cb\u003eprovable\u003c/b\u003e from a torn write, and concurrent commits \u003cb\u003ecoalesce into a single fsync\u003c/b\u003e.\n    \u003c/p\u003e\n    \u003cp\u003e\n        A WAL is the workhorse no database can avoid: every state change is appended to a durable log \u003cem\u003ebefore\u003c/em\u003e it is acknowledged, and the log is the source of truth used to rebuild state after a crash. Most Rust databases ship their WAL privately inside the engine; \u003ccode\u003ewal-db\u003c/code\u003e publishes it as a clean, composable primitive so multiple storage engines (LSM, B-tree, document store) can share a single, well-tested implementation.\n    \u003c/p\u003e\n    \u003cp\u003e\n        The common case is four calls — \u003ccode\u003eopen\u003c/code\u003e, \u003ccode\u003eappend\u003c/code\u003e, \u003ccode\u003esync\u003c/code\u003e, \u003ccode\u003eiter\u003c/code\u003e. The core is synchronous; async is left to the consumer, where it belongs.\n    \u003c/p\u003e\n    \u003cbr\u003e\n    \u003chr\u003e\n    \u003cp\u003e\n        \u003cstrong\u003eMSRV is 1.85+\u003c/strong\u003e (Rust 2024 edition). Lock-free append. Group commit. Explicit fsync. Crash-safe recovery.\n    \u003c/p\u003e\n    \u003cblockquote\u003e\n        \u003cstrong\u003eStatus: \u003ccode\u003e1.0\u003c/code\u003e — stable.\u003c/strong\u003e The public API is frozen until \u003ccode\u003e2.0\u003c/code\u003e and the \u003ca href=\"./docs/ON_DISK_FORMAT.md\"\u003eon-disk format\u003c/a\u003e is frozen for the 1.x line. Full feature set — lock-free append, group commit, segment rotation, suffix and prefix compaction — hardened with a fuzz harness, loom model checks, adversarial recovery tests, injected I/O-failure tests, and property tests, and measured against a hand-rolled WAL (\u003ca href=\"./docs/BENCHMARKS.md\"\u003ebenchmarks\u003c/a\u003e). See \u003ca href=\"./CHANGELOG.md\"\u003e\u003ccode\u003eCHANGELOG.md\u003c/code\u003e\u003c/a\u003e for detail.\n    \u003c/blockquote\u003e\n\u003c/div\u003e\n\n\u003chr\u003e\n\u003cbr\u003e\n\n\u003ch2\u003eWhat it does\u003c/h2\u003e\n\n- **Append-only durable log** of arbitrary byte records\n- **Lock-free multi-writer append** — many threads append at once with no global lock\n- **Group commit** — concurrent `sync` calls coalesce into one fsync, amortising the durability cost\n- **Segment rotation** — optionally stripe the log across bounded segment files for bounded recovery and archival\n- **Explicit durability barriers** — `append` is in-memory-fast; `sync` is the durability point\n- **Platform-correct flush** — `fdatasync` on Linux, `FlushFileBuffers` on Windows, `fcntl(F_FULLFSYNC)` on macOS\n- **Torn-write detection** — a CRC32C checksum per record; recovery stops at the first damaged record\n- **Self-healing recovery** — a torn tail from a crash mid-append is truncated on open, leaving a clean boundary\n- **Fuzz-hardened recovery** — arbitrary bytes never panic or over-allocate; a continuous `cargo-fuzz` harness proves it\n- **Recovery policies** — stop at the first damaged record, or skip past it for forensic partial recovery\n- **LSN seeking \u0026 truncation** — replay from any LSN (`iter_from`); drop everything after one (`truncate_after`) or, on a segmented log, reclaim everything before one (`truncate_before`) for compaction\n- **Iterator-based replay** — walk the log forward to rebuild state\n- **Typed records (optional)** — serialise any value via `pack-io` behind a feature; the byte-record API is unchanged when off\n- **Pluggable storage backend** — file-backed by default; injectable for in-memory testing and custom stores\n\n\u003cbr\u003e\n\n## The durability contract\n\nTwo operations, two distinct guarantees. Confusing them is the single most common way to lose data with a WAL, so `wal-db` keeps them explicit:\n\n- **`append`** returns when the record is in the operating system's page cache. A crash after `append` but before `sync` may lose that record.\n- **`sync`** returns only when every record appended before it is on stable storage and will survive a power loss.\n\nThat flush is not the same call on every platform, and getting it wrong is silent:\n\n| Platform | Durability call |\n|----------|-----------------|\n| Linux    | `fdatasync` |\n| Windows  | `FlushFileBuffers` |\n| macOS    | `fcntl(F_FULLFSYNC)` — **not** plain `fsync`, which leaves data in the drive's write cache |\n\n\u003cbr\u003e\n\n## Installation\n\n```toml\n[dependencies]\nwal-db = \"1.0\"\n```\n\n\u003cbr\u003e\n\n## Quick Start\n\n```rust\nuse wal_db::Wal;\n\n# fn apply(_lsn: wal_db::Lsn, _bytes: \u0026[u8]) -\u003e Result\u003c(), wal_db::WalError\u003e { Ok(()) }\n// Open (or create) the log.\nlet wal = Wal::open(\"/var/lib/myapp/app.wal\")?;\n\n// Append returns once the record is in the OS page cache. It does not flush.\nlet lsn = wal.append(b\"a state change\")?;\n\n// Sync is the durability barrier: it returns once the record is on stable storage.\nwal.sync()?;\n\n// On restart, replay the log from the start to rebuild state.\nfor entry in wal.iter()? {\n    let entry = entry?;\n    apply(entry.lsn(), entry.data())?;\n}\n```\n\n\u003cbr\u003e\n\n## Recovery\n\nEvery record carries a CRC32C checksum over its own bytes. On `open`, the log scans forward and stops at the first record that is incomplete or fails its checksum — a torn write left by a crash mid-append — and truncates that tail. The records before it are kept; the next append continues from a clean boundary with no gap in the sequence numbers. A corrupt length prefix can never trigger a wild allocation: lengths are validated against the configured maximum before a single payload byte is read.\n\n```rust\nuse wal_db::Wal;\n\n# fn main() -\u003e Result\u003c(), wal_db::WalError\u003e {\n# let dir = tempfile::tempdir().map_err(wal_db::WalError::from)?;\n# let path = dir.path().join(\"app.wal\");\n// After a crash, reopening the log truncates any torn tail automatically.\nlet wal = Wal::open(\u0026path)?;\n\n// Iteration yields a Result per record; a damaged record surfaces once, then ends.\nfor entry in wal.iter()? {\n    match entry {\n        Ok(record) =\u003e { /* apply record.data() at record.lsn() */ }\n        Err(e) =\u003e eprintln!(\"recovery stopped: {e}\"),\n    }\n}\n# Ok(())\n# }\n```\n\n\u003cbr\u003e\n\n## Configuration\n\nTunables live on `WalConfig`, a builder passed to `Wal::open_with`:\n\n```rust\nuse wal_db::{Wal, WalConfig};\n\n# fn main() -\u003e Result\u003c(), wal_db::WalError\u003e {\n# let dir = tempfile::tempdir().map_err(wal_db::WalError::from)?;\n# let path = dir.path().join(\"app.wal\");\nlet config = WalConfig::new().with_max_record_size(1024 * 1024); // cap records at 1 MiB\nlet wal = Wal::open_with(\u0026path, config)?;\n# let _ = wal;\n# Ok(())\n# }\n```\n\n\u003cbr\u003e\n\n## Concurrency and group commit\n\n`Wal` is built for many writers. `append` is lock-free: each call reserves its byte range with a single atomic step — that range's start offset *is* the record's LSN — then writes its record without blocking the others. Share one `Wal` behind an `Arc` and append from every thread.\n\nDurability is where threads cooperate. When several call `sync` at once they coalesce into a single fsync — **group commit** — so the cost of making data durable is amortised across everyone committing together rather than paid N times. `append_and_sync` does an append and a group-commit-aware sync in one call:\n\n```rust\nuse std::sync::Arc;\nuse std::thread;\nuse wal_db::{MemStore, Wal};\n\n# fn main() -\u003e Result\u003c(), wal_db::WalError\u003e {\nlet wal = Arc::new(Wal::with_store(MemStore::new())?);\n\nlet workers: Vec\u003c_\u003e = (0..4)\n    .map(|t| {\n        let wal = Arc::clone(\u0026wal);\n        thread::spawn(move || {\n            for i in 0..100 {\n                // Each thread appends and commits; the fsyncs coalesce.\n                wal.append_and_sync(format!(\"worker {t} record {i}\").as_bytes()).unwrap();\n            }\n        })\n    })\n    .collect();\nfor w in workers {\n    w.join().unwrap();\n}\n\nassert_eq!(wal.iter()?.count(), 400);\n# Ok(())\n# }\n```\n\n\u003e **LSNs are byte offsets.** The LSN returned by `append` is the record's position in the log — monotonic and unique, but not consecutive. The first record is `0`; the next sits at its end. This is what lets the append path reserve with a single atomic and never reorder. See [`docs/ON_DISK_FORMAT.md`](./docs/ON_DISK_FORMAT.md).\n\n\u003cbr\u003e\n\n## Custom backends\n\n`Wal::open` uses the file-backed `FileStore`. Any type implementing the `WalStore` trait can stand in — an in-memory store for tests, or an alternative storage layer. The crate ships `MemStore` for the in-memory case:\n\n```rust\nuse wal_db::{MemStore, Wal};\n\n# fn main() -\u003e Result\u003c(), wal_db::WalError\u003e {\nlet wal = Wal::with_store(MemStore::new())?;\nlet lsn = wal.append(b\"no filesystem involved\")?;\nassert_eq!(lsn.get(), 0);\n# Ok(())\n# }\n```\n\n\u003cbr\u003e\n\n## Segments\n\nBy default a log is a single file. For bounded recovery time and archival, stripe it across fixed-size segment files in a directory instead — `Wal::open_segmented`. The log stays one continuous byte stream; records span segment boundaries freely (the same scheme PostgreSQL uses), so nothing about the API or the records changes:\n\n```rust\nuse wal_db::Wal;\n\n# fn main() -\u003e Result\u003c(), wal_db::WalError\u003e {\n# let dir = tempfile::tempdir().map_err(wal_db::WalError::from)?;\n// 16 MiB segments. Old, superseded segment files can be archived or pruned.\nlet wal = Wal::open_segmented(dir.path(), 16 * 1024 * 1024)?;\nwal.append(b\"striped across files\")?;\nwal.sync()?;\n# Ok(())\n# }\n```\n\n\u003cbr\u003e\n\n## Typed records\n\nBy default a record is bytes. With the `pack-io` feature, a record can be any type that derives `Serialize`/`Deserialize` — `append_typed` writes it, `Record::decode` reads it back. The derives come from the re-exported `wal_db::pack_io`, so no extra dependency is needed.\n\n```toml\n[dependencies]\nwal-db = { version = \"1.0\", features = [\"pack-io\"] }\n```\n\n```rust\nuse wal_db::{MemStore, Wal};\nuse wal_db::pack_io::{Serialize, Deserialize};\n\n#[derive(Serialize, Deserialize, PartialEq, Debug)]\nstruct Event { id: u64, name: String }\n\n# fn main() -\u003e Result\u003c(), wal_db::WalError\u003e {\nlet wal = Wal::with_store(MemStore::new())?;\nwal.append_typed(\u0026Event { id: 1, name: \"start\".into() })?;\n\nlet event: Event = wal.iter()?.next().unwrap()?.decode()?;\nassert_eq!(event, Event { id: 1, name: \"start\".into() });\n# Ok(())\n# }\n```\n\n\u003cbr\u003e\n\n## Recovery policies\n\n`Wal::open` always truncates a torn tail so the append boundary is clean. For corruption *inside* an already-recovered log — bit rot, say — a `WalConfig` recovery policy controls how iteration reacts:\n\n```rust\nuse wal_db::{RecoveryPolicy, Wal, WalConfig};\n\n# fn main() -\u003e Result\u003c(), wal_db::WalError\u003e {\n# let dir = tempfile::tempdir().map_err(wal_db::WalError::from)?;\n# let path = dir.path().join(\"app.wal\");\n// Default: stop at the first damaged record. Or skip past it for partial recovery:\nlet config = WalConfig::new().with_recovery_policy(RecoveryPolicy::SkipBadRecords);\nlet wal = Wal::open_with(\u0026path, config)?;\n\nfor entry in wal.iter()? {\n    match entry {\n        Ok(record) =\u003e { /* use it */ }\n        Err(e) =\u003e eprintln!(\"skipped a damaged record: {e}\"), // iteration continues\n    }\n}\n# Ok(())\n# }\n```\n\n\u003cbr\u003e\n\n## Seeking and compaction\n\nAn LSN is a byte offset, so replaying from a checkpoint is O(1) — `iter_from` starts at the LSN instead of scanning from the beginning. `truncate_after` drops everything *after* a record (rolling back a tail, the way a Raft log does on a conflict), and on a segmented log `truncate_before` reclaims everything *before* a record (prefix compaction once it has been applied and flushed elsewhere). Both preserve the LSNs of surviving records:\n\n```rust\nuse wal_db::Wal;\n\n# fn main() -\u003e Result\u003c(), wal_db::WalError\u003e {\n# let dir = tempfile::tempdir().map_err(wal_db::WalError::from)?;\n# let path = dir.path().join(\"app.wal\");\nlet wal = Wal::open(\u0026path)?;\nlet _ = wal.append(b\"applied\")?;\nlet checkpoint = wal.append(b\"also applied\")?;\nlet _ = wal.append(b\"not yet applied\")?;\n\n// Replay only what came at or after the checkpoint.\nfor entry in wal.iter_from(checkpoint)? { let _ = entry?; }\n\n// Or compact: keep up to the checkpoint, drop the rest (made durable).\nwal.truncate_after(checkpoint)?;\n# Ok(())\n# }\n```\n\n\u003cbr\u003e\n\n## Async\n\nThe core is synchronous on purpose — a WAL's calls map to blocking syscalls (`write`, `fsync`), and a runtime is the consumer's choice, not the library's. From an async context, offload to a blocking pool:\n\n```rust,ignore\nlet wal = wal.clone(); // Arc\u003cWal\u003e\nlet lsn = tokio::task::spawn_blocking(move || wal.append_and_sync(b\"record\")).await??;\n```\n\n\u003cbr\u003e\n\n## Performance\n\nNumbers from the criterion suite on the development machine, 256-byte records. They are honest measurements, not marketing — the commit figures are bounded by this machine's fsync latency and scale with faster storage and more writers. Full detail and method in [`docs/BENCHMARKS.md`](./docs/BENCHMARKS.md).\n\n| Benchmark | Result | What it measures |\n|-----------|--------|------------------|\n| LSN reservation | ~4 ns | the single atomic that allocates an LSN and reserves a byte range |\n| `append/single` | ~105 ns | the lock-free hot path: reserve, frame, write one record to memory, no syscall |\n| `append/multi` (8, file) | ~160 K/s | file-backed multi-writer append — syscall-bound (one `pwrite` each) |\n| `commit/group` (8 writers) | **~1.9× a hand-rolled inline WAL** | concurrent append-and-sync; group commit coalesces the fsyncs |\n| `recovery/replay` (10k) | ~215 K records/s | reopen and replay a file-backed log |\n\nA file-backed append is syscall-bound, not lock-bound — the `pwrite` the durability contract requires dominates the negligible commit-watermark lock — so the throughput lever is **group commit**, which beats the inline WAL an engine hand-rolls before it has batching. Run them yourself:\n\n```bash\ncargo bench --bench wal_bench   # append, commit, recovery, reservation\ncargo bench --bench compare     # wal-db vs a hand-rolled inline WAL\n```\n\n\u003cbr\u003e\n\n## Examples\n\n| Example | Run | Shows |\n|---------|-----|-------|\n| [`basic`](./examples/basic.rs) | `cargo run --example basic` | the four-call API: open, append, sync, replay |\n| [`recovery`](./examples/recovery.rs) | `cargo run --example recovery` | a simulated torn write and self-healing recovery |\n| [`concurrent`](./examples/concurrent.rs) | `cargo run --example concurrent` | many writers, one log, group commit |\n| [`checkpoint`](./examples/checkpoint.rs) | `cargo run --example checkpoint` | replay from a checkpoint (`iter_from`) and truncate back to one (`truncate_after`) |\n| [`typed`](./examples/typed.rs) | `cargo run --example typed --features pack-io` | typed records via `pack-io` |\n\n\u003cbr\u003e\n\n## Testing\n\n```bash\ncargo test --all-features                       # unit, integration, doc tests\ncargo test --test torn_write                    # torn-write recovery property test\ncargo test --test durability                    # durability across a real process restart\ncargo test --test segmented                     # segment rotation and spanning records\nRUSTFLAGS=\"--cfg loom\" cargo test --test loom_wal  # model-checked concurrency\ncargo +nightly fuzz run recover                 # fuzz the recovery path\ncargo bench --bench wal_bench                    # append and commit throughput\n```\n\nThe `loom` run model-checks the lock-free append and the group-commit handshake: it explores every meaningful thread interleaving and asserts no overlapping records, no reorder, and at most one fsync per syncer. The `fuzz` run feeds arbitrary bytes to the recovery path and proves it never panics or over-allocates.\n\n\u003chr\u003e\n\u003cbr\u003e\n\n## Where It Fits\n\n`wal-db` is the durability substrate. It is consumed by:\n- [`lsm-db`](https://github.com/jamesgober/lsm-db) — memtable durability\n- [`txn-db`](https://github.com/jamesgober/txn-db) — transaction log\n- [`raft-io`](https://github.com/jamesgober/raft-io) — Raft log persistence\n- Hive DB — primary write-ahead log\n\nIt stays foreign-compatible: usable standalone in any project that needs a durable append-only log.\n\n\u003cbr\u003e\n\n## Cross-Platform Support\n\n**Tier 1 Support:**\n- Linux (x86_64, aarch64) — `fdatasync`\n- macOS (x86_64, Apple Silicon) — `fcntl(F_FULLFSYNC)` for true durability\n- Windows (x86_64) — `FlushFileBuffers`\n\nDurability semantics are equivalent across platforms; the CI matrix runs the full suite — including the cross-process durability test — on each.\n\n\u003cbr\u003e\n\n## Contributing\n\nBefore opening a PR, `cargo fmt --all`, `cargo clippy --all-targets --all-features -- -D warnings`, and `cargo test --all-features` must be clean. Any change touching the durability path requires a torn-write recovery test and a benchmark.\n\n\u003cbr\u003e\n\n\u003cdiv id=\"license\"\u003e\n    \u003ch2\u003eLicense\u003c/h2\u003e\n    \u003cp\u003eLicensed under either of\u003c/p\u003e\n    \u003cul\u003e\n        \u003cli\u003e\u003cb\u003eApache License, Version 2.0\u003c/b\u003e — see \u003ca href=\"./LICENSE-APACHE\"\u003eLICENSE-APACHE\u003c/a\u003e\u003c/li\u003e\n        \u003cli\u003e\u003cb\u003eMIT License\u003c/b\u003e — see \u003ca href=\"./LICENSE-MIT\"\u003eLICENSE-MIT\u003c/a\u003e\u003c/li\u003e\n    \u003c/ul\u003e\n    \u003cp\u003eat your option.\u003c/p\u003e\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n  \u003ch2\u003e\u003c/h2\u003e\n  \u003csup\u003eCOPYRIGHT \u003csmall\u003e\u0026copy;\u003c/small\u003e 2026 \u003cstrong\u003eJAMES GOBER.\u003c/strong\u003e\u003c/sup\u003e\n\u003c/div\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesgober%2Fwal-db","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjamesgober%2Fwal-db","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjamesgober%2Fwal-db/lists"}