Repository navigation
Conversation
…e WAL With throwOnWalReplayFailure false, the engine default, opening a database with enableChecksums set the other way from its WAL's header deleted the WAL and every commit in it. dryReplay checked the flag inside the catch that treats read errors as a torn tail, so the mismatch looked like a WAL without a complete commit. The flag is now read with the plain reader before that try, the way attached-graph recovery already reads it, and a mismatch throws in both modes, leaving the WAL untouched. A header too short to hold the flag still takes the lenient path. This covers the main and the frozen checkpoint WAL, and read-only opens. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The frozen-WAL mismatch test now writes its WAL with the checksum setting flipped, so together with the active-WAL test both directions of a mismatch run in CI. The comment on tryReadWALChecksumFlag now says which caller setting rethrows a torn header. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
||
| static void checkWALHeader(const WALHeader& header, bool enableChecksums) { | ||
| if (enableChecksums != header.enableChecksums) { | ||
| static void checkWALChecksumFlag(bool walEnableChecksums, bool enableChecksums) { |
There was a problem hiding this comment.
Low (non-blocking, both call sites verified correct): two bare bools (walEnableChecksums, enableChecksums) read naturally in either order. Consider an enum or keeping the header-typed parameter so a swap is a compile error.
There was a problem hiding this comment.
Done in e1210ec: tryReadWALHeader returns the header and checkWALHeader(const WALHeader&, bool) takes it, so the two flags can no longer be swapped silently.
|
[ release notes are generated from PR descriptions, so no separate action needed ] One callout from review (inline nit posted separately): Intended behavior break — release note needed: opens that previously succeeded with |
|
Thanks — the body now has a Behavior change paragraph: read-write and read-only opens on the lenient default now throw instead of opening without the WAL's commits. |
Two bare bools could be swapped at a call site without a compile error; checkWALHeader takes the header again and tryReadWALHeader returns it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This work was produced with the help of language models.
Fixes #1357.
Opening a database with
enableChecksumsset the other way from its WAL's header deleted the WAL, and every commit in it, whenthrowOnWalReplayFailurewas false, the engine default.dryReplaychecked the flag inside thetrywhosecatch (...)turns read errors into a torn tail, so the mismatch was taken for a WAL without a complete commit. The flag is now read with the plain reader before thattry, the way attached-graph recovery already reads it (tryReadWALChecksumFlag). The checksum writer puts each object's checksum after its bytes, so the header sits at the same offset in both modes. A mismatch throws the existing enableChecksums error in both modes and leaves the WAL untouched. A header too short to hold the flag holds no commit, so it still takes the lenient path. The main WAL and the frozen checkpoint WAL both go throughdryReplay; graph WALs already take the flag from their own header.The
enableChecksumscomment onSystemConfiganddocs/checkpoint_recovery.mdnow say that the setting must match the WAL.Behavior change. With
throwOnWalReplayFailurefalse, the C++ and C API default, an open with the otherenableChecksumssetting used to succeed and silently drop every commit in the WAL. It now throws the enableChecksums error, for read-write and read-only opens alike, so an embedder on the lenient default sees a new error where it got an open but empty database. Reopening with the matching setting recovers the commits.Tests.
WalTest.WALChecksumConfigMismatchNoThrowexpected the open to succeed with no tables left. It now expects the enableChecksums error from a read-only and a read-write open, the WAL's bytes unchanged, and both tables back after reopening with the right setting.FrozenWALRecoveryTest.FrozenWALWithOtherChecksumSettingIsKeptchecks the same, without the read-only open, for a frozen checkpoint WAL of 100 inserts, whichmaindeleted. It writes the WAL with the setting flipped, so the two tests cover both directions. Both fail onmain.WalTest.TornWALHeaderNoThrowcuts the WAL to 10 bytes, shorter than the 16-byte database ID, and opens with the other setting: the open succeeds with no tables, as onmain. Full ctest (Release, runtime checks on): 3166 passed.