Repository navigation
Conversation
There was a problem hiding this comment.
Code Review
This pull request modifies MutationBatcher::OnBulkApplyDone to satisfy completion, admission, and pending request promises outside of the mutex lock mu_ and without accessing this afterward. This prevents potential deadlocks or use-after-free issues if a continuation or waiting thread destroys the MutationBatcher instance. Additionally, range-based loops were updated to use explicit types instead of auto to comply with the style guide. Comprehensive unit tests were added to cover various edge cases, including multi-threaded destruction and continuation behavior under flow control limits. I have no further feedback to provide as the changes are well-implemented and adhere to the repository's style guidelines.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #16659 +/- ##
==========================================
- Coverage 92.53% 92.50% -0.03%
==========================================
Files 2269 2269
Lines 222896 223147 +251
==========================================
+ Hits 206250 206433 +183
- Misses 16646 16714 +68 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
a8b1b05 to
be779f5
Compare
Findings & Edge Cases to Consider1. [Medium]
|
be779f5 to
f2fe7b4
Compare
|
Thanks for catching those interactions! Addressed all 3 points in
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors the lifetime and synchronization management of MutationBatcher during asynchronous operations. It introduces a shared WaitState structure (held via std::shared_ptr) to track pending work and promises for AsyncWaitForNoPendingRequests(). This allows OnBulkApplyDone to safely satisfy admission and completion promises outside of the main class lock (mu_) and without accessing this, preventing premature destruction or race conditions when user callbacks destroy the MutationBatcher or submit follow-up work. Additionally, several comprehensive unit tests have been added to verify these concurrent behaviors and edge cases. I have no further feedback to provide on these changes.
f2fe7b4 to
de0580e
Compare
Update MutationBatcher::OnBulkApplyDone and AsyncWaitForNoPendingRequests so batch flow-control counters are updated before invoking completion callbacks without premature wait resolution or shutdown UAF: - Decrement flow-control and pending-mutation counters under mu_ and run TryAdmit(cq) before satisfying admission_promises and completion_promises, without touching this afterwards. - Track in-flight mutations, outstanding batches, and active completion-callback batches in a shared_ptr<WaitState> so AsyncWaitForNoPendingRequests() only resolves after all completion callbacks (and any follow-up AsyncApply() work submitted inside them, or concurrent batches across CQ threads) have finished, even if a callback destroys MutationBatcher. - Simplify MutationBatcher::SatisfyPromises to remove unreachable no_more_pending_promises dead code while keeping the symbol for ABI compatibility.
de0580e to
c44e491
Compare
Summary
MutationBatcher::OnBulkApplyDonepreviously calledcompletion_promise.set_value(...)before acquiringmu_to decrementoutstanding_size_,outstanding_mutations_,num_requests_pending_, andnum_outstanding_batches_and admit queued mutations:.then()flow-control deadlock: A synchronous continuation attached tocompletion_future.then(...)observed un-decremented flow-control counters, blocking follow-upAsyncApply()admission at the batch/mutation limit.MutationBatcheras soon as the finalcompletion_futureresolved,OnBulkApplyDonesubsequently dereferencedthis->mu_and member fields on a destroyedMutationBatcher.Changes
(CompletionPromise, Status)pairs during batch result processing, then lockmu_, update flow-control counters, runTryAdmit(cq), releasemu_, and satisfyadmission_promisesandcompletion_promiseswithout touchingthisagain.std::shared_ptr<WaitState>soAsyncWaitForNoPendingRequests()only resolves after all batch completion callbacks (and any follow-upAsyncApply()work submitted inside them, or concurrent batches completing across CQ threads) have finished, even if a callback destroysMutationBatcher.no_more_pending_promisesdead code fromMutationBatcher::SatisfyPromiseswhile preserving the symbol for ABI compatibility.google/cloud/bigtable/mutation_batcher_test.cccoveringAsyncWaitForNoPendingRequests()across multi-mutation batches, follow-upAsyncApply()inside.then(), concurrent multi-batch completions, flow-control admission inside.then(), and destroyingMutationBatcherfrom completion continuations or waiting threads.