Skip to content

Fix read-only open during checkpoint from reading inconsistent state#615

Open
ericyuanhui wants to merge 1 commit into
LadybugDB:mainfrom
ericyuanhui:main_test
Open

Fix read-only open during checkpoint from reading inconsistent state#615
ericyuanhui wants to merge 1 commit into
LadybugDB:mainfrom
ericyuanhui:main_test

Conversation

@ericyuanhui

Copy link
Copy Markdown
Contributor

Summary
This change fixes a bug where opening the database in read-only mode could race with an in-progress checkpoint and end up reading inconsistent on-disk state. In that situation, recovery could observe intermediate checkpoint artifacts and continue loading from partially updated metadata, which could lead to crashes such as segmentation faults.
To address that, the fix makes checkpoint progress explicit and blocks read-only recovery from entering that unsafe window. It adds coordination around checkpoint execution so read-only opens can detect that a checkpoint is underway and fail fast instead of trying to recover from an intermediate state. It also adds defensive validation when reading checkpoint metadata so invalid or out-of-range page information is rejected with a controlled error rather than being used blindly. In addition, it cleans up a related resource-handling issue in file locking so failed lock attempts do not leak OS handles.
In short, the change turns a potentially unsafe concurrent recovery path into a safe, well-defined failure mode, and adds extra validation to prevent corrupted or partial checkpoint state from causing low-level crashes.

What Changed
Added two checkpoint lock files:*.checkpoint.intent.lock
*.checkpoint.apply.lock

Added checkpoint lock acquisition/release in Checkpointeracquire at checkpoint start
release on cleanup and rollback

Added eager creation of checkpoint lock files for non-read-only persistent databases
Added read-only recovery protection in WALReplayerif a checkpoint is in progress, opening in read-only mode now throws a RuntimeException
read-only recovery no longer proceeds through shadow file / checkpoint WAL intermediate states

Added defensive validation when reading checkpoint headersvalidate catalog page range
validate metadata page range
validate dataFileNumPages against actual file size

Fixed file descriptor / handle leaks when file locking fails in LocalFileSystem
Updated WAL testsReadOnlyRecoveryWithShadowFile now expects failure in read-only mode
added ReadOnlyRecoveryWithCheckpointWAL

Signed-off-by: ericyuanhui <285521263@qq.com>
tableEpochWatermarksByManager;
std::unordered_map<catalog::Catalog*, uint64_t> catalogVersionAtCheckpointByCatalog;
std::unordered_map<StorageManager*, uint64_t> pageManagerVersionAtCheckpointByManager;
std::unique_ptr<common::FileInfo> checkpointIntentLockFile;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you describe the thought process here? Why not lock the main database file instead of creating new intent/apply files?

@adsharma

Copy link
Copy Markdown
Contributor

Note that DuckDB and SQLite take different approaches here:

https://claude.ai/share/9ce5d5a8-bf34-46cb-87e7-9f1636491c4f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants