This is an automated email from the ASF dual-hosted git repository.

clintropolis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 65c3ec382f4 fix: replica counting fix for partial load reverts (#19912)
65c3ec382f4 is described below

commit 65c3ec382f4c7a8a7fd3133f6ecd2ceeb0b18c11
Author: Clint Wylie <[email protected]>
AuthorDate: Thu Aug 6 19:01:33 2026 -0700

    fix: replica counting fix for partial load reverts (#19912)
---
 .../loading/SegmentReplicaCountMap.java            | 30 +++++++++++++++++-----
 1 file changed, 24 insertions(+), 6 deletions(-)

diff --git 
a/server/src/main/java/org/apache/druid/server/coordinator/loading/SegmentReplicaCountMap.java
 
b/server/src/main/java/org/apache/druid/server/coordinator/loading/SegmentReplicaCountMap.java
index df694086885..7058c261d88 100644
--- 
a/server/src/main/java/org/apache/druid/server/coordinator/loading/SegmentReplicaCountMap.java
+++ 
b/server/src/main/java/org/apache/druid/server/coordinator/loading/SegmentReplicaCountMap.java
@@ -23,6 +23,7 @@ import com.google.common.collect.Sets;
 import org.apache.druid.client.DataSegmentAndLoadProfile;
 import org.apache.druid.client.ImmutableDruidServer;
 import org.apache.druid.server.coordinator.DruidCluster;
+import org.apache.druid.server.coordinator.ServerHolder;
 import org.apache.druid.timeline.DataSegment;
 import org.apache.druid.timeline.SegmentId;
 
@@ -55,13 +56,13 @@ public class SegmentReplicaCountMap
             serverHolder -> {
               // Add segments already loaded on this server.
               final Collection<DataSegment> servedSegments = 
serverHolder.getServedSegments();
-              final Set<SegmentId> servedSegmentIds = 
Sets.newHashSetWithExpectedSize(servedSegments.size());
+              final Set<SegmentId> partiallyLoadedIds = 
Sets.newHashSetWithExpectedSize(servedSegments.size());
               for (DataSegment segment : servedSegments) {
-                servedSegmentIds.add(segment.getId());
                 final SegmentReplicaCount replicaCount = 
computeIfAbsent(segment.getId(), tier);
                 if (DataSegmentAndLoadProfile.profileOf(segment) == null) {
                   replicaCount.incrementLoaded();
                 } else {
+                  partiallyLoadedIds.add(segment.getId());
                   replicaCount.incrementLoadedWithPartialProfile();
                 }
               }
@@ -69,10 +70,7 @@ public class SegmentReplicaCountMap
               // Add segments queued for load, drop or move on this server
               serverHolder.getQueuedSegments().forEach(
                   (segment, state) -> {
-                    // A load queued on a server that is already serving the 
segment is an in-place reload, not an
-                    // additional replica: the replica exists and was counted 
above, and the reload only changes which
-                    // parts of it the server holds.
-                    if (state == SegmentAction.LOAD && 
servedSegmentIds.contains(segment.getId())) {
+                    if (isPartialLoadRevert(serverHolder, segment, state, 
partiallyLoadedIds)) {
                       return;
                     }
                     computeIfAbsent(segment.getId(), 
tier).incrementQueued(state);
@@ -99,6 +97,26 @@ public class SegmentReplicaCountMap
     });
   }
 
+  /**
+   * Whether a queued operation is the in-place reload that
+   * {@link StrategicSegmentAssigner#revertPartialProfileReplica} queues to 
release a partial-load rule that no longer
+   * applies. Such a reload refreshes an existing replica rather than adding 
one, so counting it as {@code loading}
+   * would push {@code projectedReplicas} past the requirement; {@code 
updateReplicasInTier} would then "correct" the
+   * phantom surplus by canceling the very reload it queued last run, and 
requeue it in the same run, churning
+   * forever against a backlogged peon.
+   */
+  private static boolean isPartialLoadRevert(
+      ServerHolder serverHolder,
+      DataSegment segment,
+      SegmentAction state,
+      Set<SegmentId> partiallyLoadedIds
+  )
+  {
+    return state == SegmentAction.LOAD
+           && partiallyLoadedIds.contains(segment.getId())
+           && serverHolder.getInFlightProfile(segment) == null;
+  }
+
   SegmentReplicaCount get(SegmentId segmentId, String tier)
   {
     SegmentReplicaCount count = replicaCounts.getOrDefault(segmentId, 
Collections.emptyMap())


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

Reply via email to