fix(recovery): tolerate -shm sidecars when WAL is safe (issue #51) - #53
Merged
Conversation
The recover --dry-run command would fail with "unexpected SQLite sidecar namespace entry" when recovering against a WAL-mode database that had a -shm file, even with a zero-byte -wal file indicating no pending changes. The chicken-and-egg bug: startup index_prepare opens the database (creating -shm), then recovery rejects the sidecar it just created. **Root cause**: ensureSourceSidecarsSafe rejected -shm unconditionally, without considering whether the database had active writers. **Fix (approach B)**: Tolerate -shm files when the -wal is zero bytes or absent, matching the existing logic for -wal files. The safety property is preserved: if WAL has no pending changes, no active writer is modifying the database. This mirrors SQLite's own reasoning about when WAL sidecars are safe. **Safety**: A zero-byte -wal file guarantees no uncheckpointed changes. A -shm file alone does not prove an active connection, so when -wal is safe, -shm is also safe to tolerate. Added three new unit tests: - TestEnsureSourceSidecarsToleratesSHMWithZeroWAL - TestEnsureSourceSidecarsToleratesSHMWithoutWAL - TestEnsureSourceSidecarsRejectsSHMWithNonZeroWAL Added CLI integration test: - TestRecoverDryRunWithWALSidecars: verifies recover --dry-run succeeds against a WAL-mode database with -shm sidecar Updated existing test: - TestRecoverSQLiteSidecarPolicy/empty_active_shm_tolerated_before_replacement: changed from expecting rejection to expecting tolerance (reflects the fix) Closes #51 Claude-Session: https://claude.ai/code/session_019LDXzStaKrArqJKvy4z3eF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root Cause
The
recover --dry-runcommand fails with "unexpected SQLite sidecar namespace entry" when recovering against a WAL-mode database with a -shm file, even when the -wal file is zero bytes (indicating no pending changes).The chicken-and-egg bug:
index_prepare) opens the database → creates -shm sidecarensureSourceSidecarsSafeRoot cause:
ensureSourceSidecarsSaferejected -shm unconditionally, without considering whether the database had active writers. A zero-byte -wal file guarantees no uncheckpointed changes, meaning no active writer is modifying the database.Solution (Approach B)
Modified
ensureSourceSidecarsSafeto tolerate -shm files when the -wal is zero bytes or absent, matching the existing logic for -wal files. The safety property is preserved: if WAL has no pending changes, -shm is safe to tolerate.This is narrower and more surgical than approach (A) which would skip the entire startup phase for recover commands.
Safety Property
Tests
Added unit tests (internal/recovery/recovery_test.go):
TestEnsureSourceSidecarsToleratesZeroByteWAL: confirms zero-byte -wal is toleratedTestEnsureSourceSidecarsToleratesSHMWithZeroWAL: new fix - tolerates -shm when -wal is zeroTestEnsureSourceSidecarsToleratesSHMWithoutWAL: new fix - tolerates -shm when -wal is absentTestEnsureSourceSidecarsRejectsSHMWithNonZeroWAL: verifies -shm is still rejected when -wal has pending changesAdded CLI integration test (cmd/backscroll/main_test.go):
TestRecoverDryRunWithWALSidecars: reproduces and verifies issue bug: recover --from <active-db> rejects the -shm sidecar its own startup creates #51 fix - recover --dry-run succeeds against a WAL-mode database with -shm sidecarUpdated existing test:
TestRecoverSQLiteSidecarPolicy/empty_active_shm_tolerated_before_replacement: changed from expecting rejection to expecting tolerance (now verifies the fix)Verification
All tests pass, coverage maintained above 85% gate.
Closes #51
https://claude.ai/code/session_019LDXzStaKrArqJKvy4z3eF