Skip to content

Commit 6452bd3

Browse files
mtopolnikclaude
andcommitted
Fix awaitEmpty() race in InFlightWindow
awaitEmpty() had a TOCTOU race between its error check and in-flight count check. When the I/O thread called fail() (setting lastError) and then acknowledgeUpTo() (draining the window to zero) before the flush thread was scheduled, the while loop exited on the count condition without re-entering the body to call checkError(). This caused flaky failures in testErrorPropagation_asyncMultipleBatchesInFlight. Add a final checkError() after the while loop. Correctness relies on the happens-before chain through the volatile highestAcked field: the I/O thread's lastError.set() precedes its highestAcked write, and the flush thread's highestAcked read precedes its lastError.get(), so the error is guaranteed to be visible. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a1850ca commit 6452bd3

1 file changed

Lines changed: 5 additions & 0 deletions

File tree

core/src/main/java/io/questdb/client/cutlass/qwp/client/InFlightWindow.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,11 @@ public void awaitEmpty() {
287287
}
288288
}
289289

290+
// The I/O thread may have called fail() and then acknowledgeUpTo()
291+
// before this thread was scheduled, draining the window while an
292+
// error is pending. Check one final time after the window is empty.
293+
checkError();
294+
290295
LOG.debug("Window empty, all batches ACKed");
291296
} finally {
292297
waitingForEmpty = null;

0 commit comments

Comments
 (0)