Publishing replacement files and measuring cost
What this concept is
Compaction has two contracts: produce equivalent content, then publish that content without losing the last recoverable version. Correct bytes in a temporary file do not by themselves establish crash-safe publication.
Why it matters here
Overwriting the only live log in place can destroy both old and new state when interrupted. The supplied temporary-file check only reopens serialized bytes during an ordinary run. It deliberately does not simulate filesystem ordering or power loss.
Concrete example
Write a complete candidate while retaining the old log. Before publication, recovery should select the old generation. After publication, recovery should select the new complete generation. A half-written candidate must never become authoritative. Removing the old file before establishing the new generation creates a gap where neither is usable.
Common confusion / misconception
Rename visibility and persistence across a machine crash are different properties. A successful language-level write may still leave data buffered. Precise ordering depends on the operating system, filesystem and device; do not infer it from a passing in-memory recovery test.
How to use it
For your file adapter, document temporary-file creation, content write, file synchronization, publication, directory metadata synchronization where required, and old-generation cleanup. Consult platform documentation and state assumptions. Make a crash matrix for before/after each stage: authoritative generation, orphan candidates and recovery action. Test process interruptions separately and label them accurately. Do not promote a candidate merely because it has the newest filename.
Check yourself
Which stage makes the replacement visible, and which evidence supports its persistence? What happens if readers still hold the old file or offsets when cleanup starts?
Mini drill or application
Measure input log bytes, compacted output bytes and peak simultaneous old-plus-new bytes. Define logical update bytes explicitly, then report rewrite bytes divided by that denominator. Keep read, write and space amplification separate. Compare two histories with the same final map but different overwrite rates; correctness can match while cost differs.
Read this only if stuck
Use Database Internals for storage publication and SQLite atomic commit for why flushes and hardware assumptions matter. SQLite’s protocol is a comparison, not a proof for your custom replacement algorithm.