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


##########
indexing-service/src/main/java/org/apache/druid/indexing/overlord/hrtr/HttpRemoteTaskRunner.java:
##########
@@ -1097,6 +1105,14 @@ private void pendingTasksExecutionLoop()
         ImmutableWorkerInfo immutableWorker = null;
 
         synchronized (statusLock) {
+          // Compute the eligible-worker snapshot ONCE per pass instead of 
rebuilding it for every
+          // pending task. Within a single synchronized(statusLock) pass no 
worker reservation is made
+          // until the break below, so getWorkersEligibleToRunTasks() is 
invariant across the inner
+          // loop. Rebuilding it per pending task made this loop 
O(pendingTasks x workers x
+          // tasksPerWorker) and held statusLock for long periods under a 
large pending backlog,
+          // which stalled TaskQueue.add/manage and task submission 
cluster-wide.
+          final ImmutableMap<String, ImmutableWorkerInfo> eligibleWorkers =

Review Comment:
   [P2] Avoid snapshotting workers when the queue is empty
   
   With an empty `pendingTaskIds` (the normal idle state), this new code still 
materializes `getWorkersEligibleToRunTasks()` while holding `statusLock`, even 
though the loop will immediately wait at line 1178. That operation walks every 
initialized worker and rebuilds its task-derived `ImmutableWorkerInfo`; 
previously it was only reached after a pending task was found. On a large 
worker/task set, every wake (including worker-sync notifications) now 
needlessly holds `statusLock`, delaying `TaskQueue.add/manage` and status 
callbacks. Check for pending work before materializing the snapshot.



##########
indexing-service/src/main/java/org/apache/druid/indexing/overlord/hrtr/HttpRemoteTaskRunner.java:
##########
@@ -1097,6 +1105,14 @@ private void pendingTasksExecutionLoop()
         ImmutableWorkerInfo immutableWorker = null;
 
         synchronized (statusLock) {
+          // Compute the eligible-worker snapshot ONCE per pass instead of 
rebuilding it for every
+          // pending task. Within a single synchronized(statusLock) pass no 
worker reservation is made
+          // until the break below, so getWorkersEligibleToRunTasks() is 
invariant across the inner
+          // loop. Rebuilding it per pending task made this loop 
O(pendingTasks x workers x
+          // tasksPerWorker) and held statusLock for long periods under a 
large pending backlog,
+          // which stalled TaskQueue.add/manage and task submission 
cluster-wide.
+          final ImmutableMap<String, ImmutableWorkerInfo> eligibleWorkers =
+              ImmutableMap.copyOf(getWorkersEligibleToRunTasks());

Review Comment:
   [P2] Do not reuse a stale capacity snapshot
   
   `WorkerHolder` publishes task announcements into `tasksSnapshotRef` from its 
sync executor before `taskAddedOrUpdated` can acquire `statusLock`, so a 
worker's capacity can change while this pass scans the pending queue. Reusing 
this pass-start snapshot lets a later task be selected for a worker that has 
since become full (for example, a recovered or other-runner task not 
represented in `workersWithUnacknowledgedTask`). `runTaskOnWorker` only 
rechecks removal/lazy/blacklist and the worker endpoint accepts assignments 
without a capacity check, so this can oversubscribe a worker. Refresh or 
validate the worker snapshot immediately before reserving/assigning, or 
otherwise make the capacity check and reservation atomic.



-- 
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