Handle async prefetch failures safely - #15167
Open
xingbowang wants to merge 1 commit into
Open
Conversation
Summary: FilePrefetchBuffer owns the I/O handles, callback state, and scratch buffers used by asynchronous prefetch reads. Poll and AbortIO are runtime operations whose successful return establishes callback completion; an error does not. Problem: cancellation results were guarded only by assertions. Release builds could ignore an AbortIO failure and clear or destroy request state that an outstanding callback still referenced. Poll failure likewise destroyed the handle even though completion was not guaranteed. Separately, callback completion status was ignored, including synchronous inline completion, and failure to submit a later buffer could leave earlier requests from the same multi-buffer prefetch active. Impact: callbacks could access released FilePrefetchBuffer state, resulting in use-after-free, crashes, or memory corruption. Async read errors could be masked and failed or partial buffer state treated as usable. A failed multi-buffer operation could also leave sibling I/O running after the caller had received an error. Fix: make cancellation and outdated-data helpers return Status and propagate poll, abort, and submission failures without releasing live handles, buffers, or callback state. Poll errors preserve the request for a later poll or abort. The destructor attempts AbortIO, falls back to Poll, and terminates with diagnostics if neither can establish safe completion. Record callback status only when completion fails, consume it after Poll confirms callback completion, clear failed buffers, and handle default inline ReadAsync completion immediately. When a later multi-buffer submission fails, remove the failed buffer and abort earlier sibling requests. Expected cancellation status is discarded safely, while successful requests retain the allocation-free path. Synchronous fallback, EOF behavior, and public APIs remain unchanged. Tests: add a controlled async filesystem covering AbortAllIOs and outdated-I/O failure propagation, Poll failure lifetime preservation, destructor fallback, inline and background completion errors, and later-submission cleanup. The complete prefetch_test suite passes normally and with ASSERT_STATUS_CHECKED=1; source and whitespace checks pass as well.
✅ clang-tidy: No findings on changed linesCompleted in 184.2s. |
✅ Claude Code ReviewAuto-triggered after CI passed — reviewing commit 578a70a SummarySolid defensive hardening of async prefetch failure paths. The design is sound: propagating Status from abort/poll/clear operations, handling inline completion, preserving handles on poll failure, and adding destructor fallback logic all address real use-after-free and silent-error risks. High-severity findings (2):
Full review (click to expand)Findings🔴 HIGHH1. Poll failure leaves
|
| Context | Does code execute? | Assumptions hold? | Action needed? |
|---|---|---|---|
| Default FS (no io_uring) | YES — inline completion | YES — nullptr io_handle correctly detected | Safe |
| PosixFS with io_uring | YES — primary target | YES | Safe |
| ReadOnly DB | YES — prefetch for reads | YES | Safe |
| Compaction (num_buffers_=1) | YES but limited | YES — sync paths unchanged | Safe |
| BlobDB | YES — blob_source.cc | YES | Safe |
| WritePreparedTxnDB | No direct interaction | N/A | Safe |
Positive Observations
- Correct design principle: Recognizes that AbortIO/Poll failure means callbacks may be outstanding — handle/buffer/callback state must not be released. Prevents real use-after-free.
- Zero-allocation happy path:
async_read_error_asunique_ptr<IOStatus>avoids allocation for successful reads. - Comprehensive tests: 8 new tests covering abort failure, poll failure, inline/background completion failure, multi-buffer submission failure, and destructor fallback.
- Consistent error propagation: All void-to-Status changes propagate correctly through the call chain.
- Destructor safety: AbortIO -> Poll -> terminate with diagnostics is the correct defensive design.
ℹ️ About this response
Generated by Claude Code.
Review methodology: claude_md/ci_review_prompt.md
Limitations:
- Claude may miss context from files not in the diff
- Large PRs may be truncated
- Always apply human judgment to AI suggestions
Commands:
/claude-review [context]— Request a code review/claude-query <question>— Ask about the PR or codebase
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.
Summary
FilePrefetchBuffer owns the I/O handles, callback state, and scratch buffers used by asynchronous prefetch reads. Poll and AbortIO are runtime operations whose successful return establishes callback completion; an error does not.
Problem: cancellation results were guarded only by assertions. Release builds could ignore an AbortIO failure and clear or destroy request state that an outstanding callback still referenced. Poll failure likewise destroyed the handle even though completion was not guaranteed. Separately, callback completion status was ignored, including synchronous inline completion, and failure to submit a later buffer could leave earlier requests from the same multi-buffer prefetch active.
Impact: callbacks could access released FilePrefetchBuffer state, resulting in use-after-free, crashes, or memory corruption. Async read errors could be masked and failed or partial buffer state treated as usable. A failed multi-buffer operation could also leave sibling I/O running after the caller had received an error.
Fix: make cancellation and outdated-data helpers return Status and propagate poll, abort, and submission failures without releasing live handles, buffers, or callback state. Poll errors preserve the request for a later poll or abort. The destructor attempts AbortIO, falls back to Poll, and terminates with diagnostics if neither can establish safe completion.
Record callback status only when completion fails, consume it after Poll confirms callback completion, clear failed buffers, and handle default inline ReadAsync completion immediately. When a later multi-buffer submission fails, remove the failed buffer and abort earlier sibling requests. Expected cancellation status is discarded safely, while successful requests retain the allocation-free path. Synchronous fallback, EOF behavior, and public APIs remain unchanged.
Tests: add a controlled async filesystem covering AbortAllIOs and outdated-I/O failure propagation, Poll failure lifetime preservation, destructor fallback, inline and background completion errors, and later-submission cleanup. The complete prefetch_test suite passes normally and with ASSERT_STATUS_CHECKED=1; source and whitespace checks pass as well.
Test plan
prefetch_testsuite.prefetch_testsuite withASSERT_STATUS_CHECKED=1.