Repository navigation
Conversation
WAL::waitForDurabilityNoLock flushed the WAL writer before entering the try that poisons the WAL when a sync fails. On a full disk the flush threw without poisoning the WAL, so syncInProgress stayed set and the next commit waited for that sync forever. The bytes also stayed in BufferedFileWriter's buffer: its destructor wrote them when the database closed, so a commit reported as failed could reach the WAL, and when that write failed too, it threw out of the destructor and aborted the process. - A failed write while appending a commit, flushing it or flushing a checkpoint record now poisons the WAL, as a failed sync does; poisoning also wakes the commits waiting for the sync. - BufferedFileWriter::flush drops its bytes even when the write fails, so neither a later flush nor the destructor writes the bytes of a commit reported as failed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
logAndFlushCheckpointToFrozen poisoned the WAL when the flush of its CHECKPOINT record failed, but reported a sync failure. That flush now goes through failWriteNoLock like the active WAL's writes. BufferedFileWriter::flush also stops zeroing its whole buffer after every write: only the bytes before bufferOffset are written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
This work was produced with the help of language models.
Fixes #1397.
On a full disk, a write whose WAL append failed reported
IO exception: Cannot write to file. ... Error: File too large, and the WAL was unusable after it: the next commit never returned, and closing the database aborted the process.WAL::waitForDurabilityNoLockflushed the writer before entering thetrythat poisons the WAL when a sync fails, so the failed flush left the WAL unpoisoned andsyncInProgressset, and the next commit waited for that sync forever. The bytes stayed inBufferedFileWriter's buffer, and its destructor wrote them when the database closed: a commit the client saw fail could reach the WAL, and when that write failed too, it threw out of the destructor.Fix.
WAL write failed; database is in a panic state and refuses further writes until restart. Poisoning also clearssyncInProgressand wakes the waiting commits. A failed write of the frozen WAL'sCHECKPOINTrecord, which already poisoned the WAL, is now reported the same way instead of as a failed sync.BufferedFileWriter::flushdrops its bytes even when the write fails, so neither a later flush nor the destructor writes them. Its other users, the frozen WAL's writer and the shadow file's record trailer, never flush the same writer again after a failure. It also no longer zeroes the whole buffer after every write.throwOnWalReplayFailureoff) drops a torn tail and keeps every commit whose records were written in full. When one flush carries several commits and the write stops partway, an earlier one of them can be kept although its client got the error.Tests. Five
WalTestcases (test/transaction/wal_test.cpp) make the test file system's writes fail. InWALWriteFailurePoisonsWALthe error onmainis a bareIO exceptionand the next commit would wait forever;WALAppendFailurePoisonsWALfails a commit larger than the writer's buffer while it is appended; inFailedWALWriteIsNotWrittenOnCloseclosing onmainwrites the failed commit's 81 bytes into the WAL;CheckpointRecordWriteFailurePoisonsWALcovers the checkpoint record andFrozenCheckpointRecordWriteFailurePoisonsWALthe frozen WAL's. With #1397's script the second write now fails at once, the close finishes, and the database reopens without the failed write. Full ctest: 3191/3191.Touches
WAL::logCommittedWAL, as #1380 does; merging the two keeps both changes.