FrankChen021 commented on code in PR #20589:
URL: https://github.com/apache/druid/pull/20589#discussion_r4336952832


##########
multi-stage-query/src/main/java/org/apache/druid/msq/querykit/ReadableInputQueue.java:
##########
@@ -343,11 +357,15 @@ private ListenableFuture<NumberedReadableInput> 
nextSegmentInput()
 
   /**
    * Load the next segment from {@link #loadableSegments} and return a future 
to its reference. Returns null
-   * if {@link #loadableSegments} is empty.
+   * if {@link #loadableSegments} is empty, or if {@link #canSkipRemaining} is 
true.
    */
   @Nullable
   private ListenableFuture<NumberedReadableInput> loadNextSegment()
   {
+    if (canSkipRemaining.getAsBoolean()) {

Review Comment:
   [P2] Queue stop races segment acquisition
   
   **Finding:** The canSkipRemaining check occurs before the queue monitor, 
while the segment is polled and acquired later. Another processor can reach the 
shared limit between those operations, allowing a new partial or full segment 
load to start after the queue should have stopped. Such loads remain held until 
cleanup, so the hook does not reliably avoid the I/O and resource pressure it 
targets.
   
   **Suggestion:** Coordinate input admission with the shared limit using an 
atomic claim or cancellation state, rechecking immediately before acquisition 
and releasing any load that loses the race.



##########
multi-stage-query/src/main/java/org/apache/druid/msq/querykit/scan/ScanQueryFrameProcessor.java:
##########
@@ -485,8 +489,9 @@ private void populateFrameWriterAndFlushIfNeeded() throws 
IOException
         cursorOffset.increment();
         
partitionBoostVirtualColumn.setValue(partitionBoostVirtualColumn.getValue() + 
1);
 
-        // Flush if we reached cursorPushDownLimit.
-        flush = cursorPushDownLimit >= 0 && cursorRowsRead >= 
cursorPushDownLimit;
+        // Flush if we reached cursorPushDownLimit or the shared limit.
+        flush = (cursorPushDownLimit >= 0 && cursorRowsRead >= 
cursorPushDownLimit)
+                || isSharedLimitReached(frameWriter.getNumRows());

Review Comment:
   [P2] Shared limit admission is not atomic
   
   **Finding:** The check reads the shared count, but the count is updated only 
after the frame is written. Multiple processors can therefore observe the same 
remaining budget, fill their frames, and then add all rows. With concurrent 
segment processors and frames larger than the remaining limit, the scan stage 
emits and shuffles substantially more than offset plus limit; the downstream 
limit stage masks the final row-count error, but the intended performance 
optimization is defeated.
   
   **Suggestion:** Use an atomic reservation or serialized shared-limit 
admission when accepting or committing rows, and add a multi-processor 
regression test that exercises concurrent overshoot.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to