nx_atomic_rewrite.nx
buildroot/runtime/nx_atomic_rewrite.nx
about
nx_atomic_rewrite.nx -- WMS-R3: a GENERIC, callable atomic whole-file rewrite
primitive. The reusable twin of the seg-store commit idiom (ss_writefile +
sys_renameat + ss_syncdir), lifted out of the segment/manifest model into a
plain (path, bytes, n) API so ANY whole-file rewriter (e.g. nx_reconcile's
assignment_queue.tsv rewrite, capability ladders, status snapshots) can stop
truncating-in-place.
ROOT CAUSE this closes: an in-place rewrite opens O_WRONLY|O_CREAT|O_TRUNC
(0x241), which TRUNCATES the live file to 0 BEFORE the new bytes land, then
streams a write-loop. A crash anywhere in that loop leaves the live file
truncated/torn. O_APPEND atomicity does NOT help -- it only makes ONE
write() atomic, never a truncate-then-rewrite sequence.
THE FIX (atomic_rewrite): stage the FULL new contents into a SIBLING temp
file (same directory => same filesystem => renameat(2) is atomic), fsync the
temp so its bytes are durable, then renameat(tmp -> path) -- the single
atomic COMMIT POINT (a concurrent reader sees the whole old file or the whole
new file, never a torn read), then fsync the parent directory so the rename
itself survives power loss. A crash BEFORE the rename leaves the live file
completely untouched (only the temp is partial, and the temp is never read).
REUSE: idiom lifted verbatim from nx_seg_store.nx ss_writefile (write-loop +
sys_fsync), ss_syncdir (dir fsync), and the temp->rename commit discipline.
SOVEREIGN: nx_syscalls only; no gcc / 3rd-party. license_tier: ORIGINAL
dependencies 1 imports · 1 importers
imports: nx_syscalls.nx
imported by: _atomic_rewrite_gate.nx
structs
| none |
consts
| 26 | const K_MAGIC_1024: i64 = 1024 |
functions
| 29 | func ar_len(s: *u8) -> i64 |
| 41 | func ar_tmpname(path: *u8, out: *u8) -> i64 |
| 54 | func ar_syncdir(path: *u8) -> i64 |
| 83 | func atomic_rewrite(path: *u8, bytes: *u8, n: i64) -> i64 |
| 107 | func ar_crashwrite(path: *u8, bytes: *u8, n: i64) -> i64 |
| 130 | func ar_unsafe_inplace(path: *u8, bytes: *u8, n: i64) -> i64 |