Skip to content

fix(sf-335): keep Batched as production WAL fsync default + reconcile durability docs - #102

Merged
ivkan merged 4 commits into
mainfrom
fix/sf-335-wal-fsync-default
Jul 1, 2026
Merged

fix(sf-335): keep Batched as production WAL fsync default + reconcile durability docs#102
ivkan merged 4 commits into
mainfrom
fix/sf-335-wal-fsync-default

Conversation

@ivkan

@ivkan ivkan commented Jul 1, 2026

Copy link
Copy Markdown
Member

Summary

Makes the production-default WAL fsync-policy call and closes the durability claim/behavior gap (HN-blocker, from TODO-554).

Decision (evidence-gated, /xask-validated): KEEP WalFsyncPolicy::Batched as the demo-tier default. The durability chain (SPEC-331/332/333a/b) was proven under PerOp, but the shipped default is Batched — which acks a write after appending its WAL frame and fsyncs only on a ~10 ms group-commit timer (or 100-frame flush). A kill -9 inside that window drops acked-but-unfsynced writes. Rather than pay a ~40× throughput cost by default, we keep Batched and make its non-durability truthful and loud everywhere, with TOPGUN_WAL_FSYNC_POLICY=per_op as the acked-implies-durable opt-out.

Changes

  • wal/mod.rsWalFsyncPolicy enum + per-variant doc-comments rewritten to state exact kill -9 behavior (dropped "good balance of safety" weasel wording); added an #[ignore]d reproducible measure_fsync_policy_append_cost microbenchmark.
  • write_behind.rswal_fsync_policy field doc rewritten (dropped the backwards "Do NOT change to PerOp"; states the non-durable window + per_op opt-out). Default value unchanged.
  • topgun_server.rs — boot warn! for the non-durable defaults (Batched, None) on a durable (non-Null) backend, so the crash-durability caveat is visible at startup. Startup log already surfaces wal_fsync_policy.
  • CLAUDE.md — Production Defaults documents TOPGUN_WAL_FSYNC_POLICY + a "WAL fsync durability" section stating the exact kill -9 guarantee; de-overpromised the acked-write note.
  • performance.mdx — env-var row + reconciled durability note (surfaces the per_op escape hatch).

baseline.json untouched (default stayed Batched; no threshold flip).

Measurement

Direct WalWriter::append microbenchmark (the load-harness runs on NullDataStore — no WAL — so it cannot measure the fsync delta):

policy ops/sec p50 (µs) p99 (µs)
PerOp ~200 ~5011 ~8892
Batched ~8000 ~24 ~4647
None ~90–120K ~7 ~20

Batched ≈ 40× PerOp throughput — but this is a macOS F_FULLFSYNC artifact; on Linux fdatasync/NVMe the penalty is materially smaller (unmeasured — measure before quoting publicly).

Verification

  • cargo build --release -p topgun-server ✓ · cargo clippy --all-targets --all-features -p topgun-server -- -D warnings = 0 ✓ · cargo fmt --check ✓ · cargo test --release -p topgun-server --lib = 1529 passed / 0 failed / 1 ignored ✓
  • pnpm -r build · pnpm lint · pnpm format:check · pnpm --filter apps-docs-astro build
  • Cross-vendor /xask (keep-Batched concurred) + /xreview (execution + review-gate passes; all findings reconciled).

Scope fence

Does NOT re-implement SPEC-330 env/parse/fatal plumbing; does NOT touch TODO-339 shutdown-drain; does NOT change the Batched fsync mechanism (10 ms timer / 100-frame threshold). 3 Rust source files ≤ 5-file cap.

ivkan added 4 commits July 1, 2026 13:09
…urability doc-comments + boot warn + reproducible measurement

- Decision (evidence-gated, /xask-validated): keep WalFsyncPolicy::Batched
  as the production default. A direct WalWriter::append microbenchmark shows
  PerOp costs ~40-45x single-partition append throughput and adds ~5ms p50
  latency (macOS F_FULLFSYNC full device barrier) vs Batched — too high to
  impose by default on a single-node demo-tier server. PerOp stays one env
  var away (TOPGUN_WAL_FSYNC_POLICY=per_op) for acked-implies-durable.
- Rewrite write_behind.rs doc-comment: the old 'Do NOT change to PerOp' text
  misframed PerOp as risky when Batched is the non-durable one under kill -9.
- Rewrite WalFsyncPolicy enum + variant doc-comments: drop 'good balance of
  safety' weasel wording; state the kill -9 window truthfully per variant.
- Add a startup warn! when the Batched default is active on a durable backend
  so the crash-loss caveat is impossible to miss at boot.
- Add an #[ignore]-d measure_fsync_policy_append_cost bench test making the
  PerOp-vs-Batched-vs-None measurement reproducible on demand.
… claims with the Batched default

- CLAUDE.md Production Defaults: add TOPGUN_WAL_FSYNC_POLICY row + a 'what the
  default guarantees under kill -9' paragraph (Batched is NOT acked==durable;
  per_op is, at ~40x throughput cost on macOS — Linux penalty smaller, not yet
  measured). Note the boot warn + startup-log field. Keep the write-behind ~1s
  flush note (TODO-339) as a distinct layer.
- deploy/performance.mdx: add the env-var row + surface the per_op escape hatch
  in the durability note (audit found zero user-facing overclaims to retract;
  this adds the how-to-get-durability guidance).
…rement assert

- Broaden the boot warn to also fire (more strongly) when TOPGUN_WAL_FSYNC_POLICY=none
  on a durable backend: None never fsyncs, so acked writes are not crash-safe at all —
  strictly worse than the Batched default it previously warned about, yet was silent.
  PerOp stays silent (acked == durable). (xreview MED)
- Measurement test: assert all policies measured >0 ops before computing the ratio
  (no div-by-zero/infx), and tighten the sanity floor from 'perop <= none*1.5' to
  'perop <= none' so a silently-skipped PerOp fsync (PerOp >= None) trips it. (xreview LOW x2)

Rejected (verified against source): xreview HIGH (env parse unwired) — parse site
write_behind.rs:217-231 exists + tested :2416-2452 (SPEC-330); xreview MED (!Null != durable)
— StorageBackend is {Null,Redb,Postgres}, both non-Null variants are durable, matches the
existing :840/:842 idiom.
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying topgun with  Cloudflare Pages  Cloudflare Pages

Latest commit: dd8af7c
Status: ✅  Deploy successful!
Preview URL: https://f9d02da8.topgun-f45.pages.dev
Branch Preview URL: https://fix-sf-335-wal-fsync-default.topgun-f45.pages.dev

View logs

@ivkan
ivkan merged commit 6fbf5e5 into main Jul 1, 2026
20 checks passed
@ivkan
ivkan deleted the fix/sf-335-wal-fsync-default branch July 1, 2026 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant