Skip to content

fix(persistence): adopt atomic_write_durable at 8 remaining bare-write sites (task #49)#304

Merged
pilotspacex-byte merged 1 commit into
mainfrom
fix/atomic-write-adoption
Jul 13, 2026
Merged

fix(persistence): adopt atomic_write_durable at 8 remaining bare-write sites (task #49)#304
pilotspacex-byte merged 1 commit into
mainfrom
fix/atomic-write-adoption

Conversation

@pilotspacex-byte

Copy link
Copy Markdown
Contributor

Summary

Task #49 (kernel M4 prep): eight durable-state writers still hand-rolled their own write sequence instead of the shared K3 primitive (atomic_write_durable, PR #296: temp → sync_all → rename → dir-fsync).

Site Prior gap
ACL SAVE (acl/io.rs, command/acl.rs) zero atomicity — bare write+rename, no fsync at all
CONFIG REWRITE write+rename, no temp fsync, no dir fsync
cluster nodes.conf write+rename, no fsyncs
replication.state write+rename, no fsyncs
CLOG pages wrote directly to the FINAL path — torn page visible to concurrent readers on crash
KV .mpf datafiles (write_datafile/_mixed) wrote directly to final path (File::create truncate)
native RDB save (BGSAVE) missing parent-dir fsync
Redis-format RDB save missing parent-dir fsync

A rename without temp-file + dir fsync can surface as an EMPTY or stale file post-kill-9 on data=ordered ext4/xfs. All sites now route through the shared primitive; each conversion has a regression test (8 new). Skipped: the dead rewrite_aof_sync RDB-preamble path (dead code); AOF/WAL out of scope (own mechanisms).

Gates

Refs: task #49, K3 (PR #296).

…-write sites

Task #49 (kernel M4 prep): eight durable-state writers still hand-rolled
their own tmp-write/rename sequence instead of the shared K3 primitive
(src/persistence/atomic.rs, PR #296). ACL SAVE (both acl::io::acl_save
and the ACL SAVE command handler) had zero atomicity at all -- a bare
fs::write + rename with no fsync whatsoever. CONFIG REWRITE, cluster
nodes.conf (save_nodes_conf), and replication.state
(save_replication_state) all did write+rename but skipped both the
temp-file fsync and the parent-directory fsync, so a kill-9 immediately
after rename() returns can still revert the directory entry to stale or
empty contents on data=ordered ext4/xfs. persistence::clog::write_clog_page
and persistence::kv_page::write_datafile / write_datafile_mixed wrote
directly to the FINAL path with no temp file or rename at all (only a
trailing sync_all/fsync_file), so a crash mid-write could leave a torn
CLOG page or KV heap data file visible to a concurrent reader. The native
RDB save paths used by BGSAVE (persistence::rdb::save /
save_from_snapshot, persistence::redis_rdb::save) also lacked the
parent-directory fsync step.

All eight sites now route through atomic_write_durable (temp file ->
sync_all -> rename -> parent-dir fsync), matching the pattern already
proven at the graph CSR / text sidecar / vector Stack-B call sites from
PR #296. Each conversion is paired with a "no leftover temp file after a
successful write" regression test (8 new tests total).

Out of scope per task brief: AOF appends, WAL segments (own framing/fsync
mechanisms), and the legacy #[allow(dead_code)] rewrite_aof_sync
RDB-preamble path (dead code, not a live BGSAVE path).

Verified: cargo test --lib (default features + runtime-tokio,jemalloc),
cargo fmt --check, cargo clippy -D warnings (both feature sets).

author: Tin Dang
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@pilotspacex-byte, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 9 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f8718991-27db-4812-bf56-96720c3abc19

📥 Commits

Reviewing files that changed from the base of the PR and between b5b17ba and 166980b.

📒 Files selected for processing (10)
  • CHANGELOG.md
  • src/acl/io.rs
  • src/cluster/migration.rs
  • src/command/acl.rs
  • src/command/config.rs
  • src/persistence/clog.rs
  • src/persistence/kv_page.rs
  • src/persistence/rdb.rs
  • src/persistence/redis_rdb.rs
  • src/replication/state.rs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/atomic-write-adoption

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pilotspacex-byte
pilotspacex-byte merged commit 4e0688e into main Jul 13, 2026
10 checks passed
@TinDang97
TinDang97 deleted the fix/atomic-write-adoption branch July 13, 2026 09:27
pilotspacex-byte added a commit that referenced this pull request Jul 16, 2026
… change needed (#347)

Task #49 (v0.8 item 1, kernel review) asked to adopt `atomic_write_durable`
at the remaining bare-write persistence sites: ACL SAVE, cluster
nodes.conf, CONFIG REWRITE, replication state, native BGSAVE (RDB),
clog, kv_page.

Audited every site against current HEAD (site-by-site, not a blanket
grep pass):

- src/acl/io.rs::acl_save -- atomic_write_durable
- src/command/acl.rs SAVE handler -- routes through acl::io::acl_save
  (same call site, not a second hand-rolled sequence)
- src/cluster/migration.rs::save_nodes_conf -- atomic_write_durable
- src/command/config.rs::config_rewrite -- atomic_write_durable
- src/replication/state.rs::save_replication_state -- atomic_write_durable
- src/persistence/rdb.rs::save / save_from_snapshot -- atomic_write_durable
- src/persistence/redis_rdb.rs::save -- atomic_write_durable
- src/persistence/clog.rs::write_clog_page -- atomic_write_durable
- src/persistence/kv_page.rs::write_datafile / write_datafile_mixed --
  atomic_write_durable

All nine call sites across the seven named categories were already
converted in PR #304 (merged 2026-07-13, commit 4e0688e), which is an
ancestor of current HEAD, and its CHANGELOG entry is filed under the
v0.7.0 release section (not Unreleased) -- the fix shipped in v0.7.0.
`git log 4e0688e..HEAD` on every touched file shows no subsequent
commit reverted or bypassed the conversion.

Also checked adjacent hand-rolled writers for regression risk:
storage/tiered/warm_tier.rs (staging-dir -> final-dir rename is its own
documented directory-level atomicity protocol; per-file .mpf writes
inside the staging dir are covered by that rename, not a bare-write
gap) and storage/tiered/kv_spill.rs::write_kv_spill_batch (already
hand-rolled tmp+fsync+rename+dir-fsync correctly; not one of the 7
named sites). Both correctly out of scope -- no change made.

The only real gap found was in documentation: docs/roadmap/ROADMAP.md's
Rev 2 pass (task #68, commit 82b3bca, dated 2026-07-15 -- one day
after PR #304 merged and the same day v0.7.0/v0.7.1 released) had
re-listed task #49 as an open v0.8 gap (gap table, v0.8.0 item 1, debt
register) without cross-checking it against the already-shipped
v0.7.0 CHANGELOG entry. This commit corrects the roadmap: the gap-table
row is removed, the v0.8.0 §4 item and the §5 debt-register row are
struck through with a "shipped v0.7.0 / PR #304" note (not deleted, to
preserve the audit trail), and a dated correction note is added
alongside the existing Rev 2 note. CHANGELOG.md [Unreleased] gets a
matching Documentation entry recording the audit and its outcome.

No src/ changes. No new tests -- the eight regression tests from PR #304
already cover every conversion ("no leftover temp file after a
successful write" per site); re-ran the full lib test suite locally to
confirm they still pass with no regression since the merge.

author: Tin Dang <tindang.ht97@gmail.com>

Co-authored-by: Tin Dang <tindang.ht97@gmail.com>
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.

2 participants