Repository navigation
Open
Labels
bugSomething isn't workingSomething isn't working
Description
Summary
FileStore can lose an acknowledged step or apply steps twice after a failed write or a crash, which contradicts its docs. Three separate gaps below, all reproduced on main @ 8770dcf. Line references are to durable/filestore.go. These come from FileStore's multi-file writes, so a backend that commits atomically isn't affected. I'll follow up with failing tests and a fix in one PR, after the first #214 fixes land.
Findings (in fix order)
- A torn journal line loses acknowledged steps. A failed write can leave a partial line, and nothing truncates it, so the next
Appendmerges into it and returns success. On reopen the merged line fails to parse and is skipped (:254). No crash is needed: on an HFS+ volume,Handle.Firehit a real disk-full error, the nextFiresucceeded, and the instance recovered at 1 where live was 3. Because the skip continues rather than stops, as:43says, recovered steps can have gaps such as[0 1 3]. A retry of a lost step is reported as applied (:333). A laterCheckpointin the same process heals it, because it rewrites the journal from memory.TestFileStore_TornTrailingRecord_RecoversCleanlynever reopens after the merge, so it misses this. -
checkpoint.snapandcheckpoint.metaaren't atomic together. The snapshot is renamed at:420and the meta at:423, so a process kill or failed meta write between them pairs the new snapshot with the old step. Recovery then replays steps the snapshot already holds: a self-loop machine recovered 14 where live was 7, and a machine with a real initial transition failedRecoverwith "invalid transition". The Atomicity contract instore.goand:45-48say this can't happen.TestFileStore_MissingCheckpointMeta_TreatedAsNoCheckpointcovers only a missing meta file. - The journal and the applied ledger can disagree.
Appendwrites the journal at:349and the ledger at:358, and reopen doesn't seed the ledger from the journal.- After a kill between the two, a retry of the same record returns
ErrStepOutOfOrderrather than the idempotent no-op the Store contract promises. Only direct Store callers see this:Recoverreplays the step and carries on. - A failed ledger write, with no crash, leaves the step out of memory too, so a retry writes it twice. Through stateless
Runner.Firethis gave a count of 3 after 2 acknowledgements. - A torn ledger line also loses the next step's key.
- After a kill between the two, a retry of the same record returns
Notes
- A fix on load, truncating a torn tail and reconciling the ledger with the journal, may cover the first and third findings together.
- These stay
FileStoretests: the shared conformance suite proposed in durable: export a Store conformance suite for out-of-tree backends #223 has no crash injection.
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity
joshua-temple commentedon Nov 10, 2026
One more case for the third finding, reproduced on
main@ 494c78a (after #229):Loadreturns two different records for step 1, and replay applies both.Appendstep 0, makeapplied.logunwritable,Appendstep 1 "b" (fails),Appendstep 1 "c" (succeeds), then reopen andLoad. Result: "journal holds 2 different records for step 1".