Skip to content

Full crash durability: fsync the directory of every logged FS mutation - #2

Open
johanthoren wants to merge 4 commits into
masterfrom
task/1-crash-durability
Open

Full crash durability: fsync the directory of every logged FS mutation#2
johanthoren wants to merge 4 commits into
masterfrom
task/1-crash-durability

Conversation

@johanthoren

Copy link
Copy Markdown
Owner

Closes #1.

What

Makes every filesystem mutation logmv records crash-durable by fsync'ing the
directory whose entry each mutation changed: log creation, the move/trash
rename, --mkdir creations, and --rmdir removals. Before this, a log line
could outlive the directory entry it recorded across a crash (or the reverse),
because only the log file's contents were synced, never the containing
directories.

How

Pure standard library. No new dependency, no unsafe, no platform cfg for the
sync:

  • New sync_dir(dir) helper: File::open(dir)?.sync_all(). On a directory fd
    that is F_FULLFSYNC on macOS and fsync on Linux, via the same std path the
    log content already uses.
  • Called at the four logged-mutation sites, each placed strictly between the
    committed mutation and the log line that records it, so a crash can never
    leave the log claiming an event whose filesystem effect was lost.
  • Log content durability is unchanged. File::sync_data() is already
    fcntl(F_FULLFSYNC) on macOS in std (library/std/src/sys/fs/unix.rs), so the
    original idea that a hand-rolled F_FULLFSYNC via libc/rustix was needed
    does not hold; no FFI is added.
  • append_log now opens with create_new(true).append(true) and falls back to
    append(true) on AlreadyExists, so it can fsync the log's parent directory
    on first creation only. A side effect is that it refuses to follow a symlink
    at the log path on creation (O_EXCL).

Sync failures after a committed mutation surface loudly through the existing
DriftAfter* errors. No new public error variant, no CLI flag, public API
unchanged.

Known follow-up

The create_new change makes a dangling-symlink log path fail loudly with
ENOENT instead of creating through the link the way create(true) did. That
is a degenerate configuration and arguably safer (it closes a symlink
append-redirect at the log path), but it is a behavior divergence worth
documenting or pinning with a test separately.

Tests

Existing suite green (40 tests). The durability effect is not observable without
power-loss injection, so this is a preserve-behavior change guarded by the
existing suite as non-regression, plus a security audit of the fsync placement
and the error mapping.

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.

Full crash durability: fsync parent dir + F_FULLFSYNC on macOS

1 participant