8000 fix(durability): fsync parent directory after creating .graph/WAL and deleting WAL (#389) by adityamukho · Pull Request #404 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

fix(durability): fsync parent directory after creating .graph/WAL and deleting WAL (#389) - #404

Merged
adityamukho merged 1 commit into
mainfrom
fix/389-parent-dir-fsync
Sep 26, 2026
Merged

adityamukho merged 1 commit into
mainfrom
fix/389-parent-dir-fsync

Conversation

@adityamukho
Copy link
Copy Markdown
Collaborator

Closes #389.

Problem

On POSIX, a created or deleted file survives a power loss only after its parent directory is fsynced. Minigraf only ever called sync_all()/sync_data() on file handles (confirmed: no directory sync anywhere in src/), so a power loss could lose a new .graph or <db>.wal, or bring back a WAL that checkpoint() deleted.

Fix

New storage::dir_sync::sync_parent_dir(child) — opens the parent directory and calls sync_all() on Unix; no-op on Windows and other targets. Called:

Where When
FileBackend::open_with after writing the header of a new/empty .graph
WalWriter::open_or_create after creating the WAL; also after re-initializing a headerless WAL left by a crash
WalWriter::delete_file after a successful remove_file

Errors propagate like the existing file sync_all() calls. Reopening an existing, initialized file does no directory sync.

Tests

A test-only thread-local log records every sync with whether the child file existed at that moment, so tests verify both that the sync happens and its order (exists after create, gone after delete). 10 new unit tests; suite: 1192 passed, 8 ignored.

The resurrected-WAL replay path the issue flagged as untested is already covered by tests/edge_cases_test.rs::test_stale_wal_after_checkpoint_is_idempotent (replay skips entries ≤ last_checkpointed_tx_count).

🤖 Generated with Claude Code

https://claude.ai/code/session_01BedF9ZmqVZLkvDwn91fuKy

…/WAL and deleting the WAL (#389)

On POSIX a created or deleted file survives a power loss only once its
parent directory is fsynced. Minigraf fsynced file contents but never a
directory, so a power loss could lose a freshly created .graph or
<db>.wal, or resurrect a WAL that checkpoint() had deleted.

Add storage::dir_sync::sync_parent_dir (open parent dir + sync_all on
Unix; no-op elsewhere) and call it:
- in FileBackend::open_with after writing the header of a new/empty file
- in WalWriter::open_or_create after creating the WAL, and after
  re-initializing a headerless WAL left by a crash
- in WalWriter::delete_file after a successful remove

A test-only thread-local log records each sync and whether the child
existed at that moment, so unit tests check both that the sync happens
and that it follows the create/remove.

Resurrected-WAL replay idempotence was already covered by
tests/edge_cases_test.rs::test_stale_wal_after_checkpoint_is_idempotent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BedF9ZmqVZLkvDwn91fuKy
@adityamukho adityamukho added this to the v2.0.2 milestone Sep 26, 2026
@adityamukho adityamukho added bug Something isn't working durability Data durability concern labels Sep 26, 2026
@codecov
codecov Bot commented Sep 26, 2026
Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@adityamukho
adityamukho merged commit da6c4ff into main Sep 26, 2026
17 checks passed
@adityamukho
adityamukho deleted the fix/389-parent-dir-fsync branch September 26, 2026 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working durability Data durability concern

Projects

None yet

Development

Successfully merging this pull request may close these issues.

durability: fsync the parent directory after creating the .graph/WAL and after deleting the WAL

1 participant

0