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

houston pushed a commit to branch branch_10x
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/branch_10x by this push:
     new 4875f99b41d SOLR-18081: ShardRequestTracker should use a unique key 
for requests (#4068)
4875f99b41d is described below

commit 4875f99b41dbe69d609af85fa0b3e78108943ece
Author: Houston Putman <[email protected]>
AuthorDate: Thu Jan 29 08:48:25 2026 -0800

    SOLR-18081: ShardRequestTracker should use a unique key for requests (#4068)
    
    (cherry picked from commit d766e9e723033d29e092242d5bba268e1590ea3a)
---
 ...lr-18081-shard-request-tracker-replica-name.yml |   9 +
 .../solr/cloud/api/collections/AddReplicaCmd.java  |   3 +-
 .../solr/cloud/api/collections/BackupCmd.java      |   4 +-
 .../solr/cloud/api/collections/CollApiCmds.java    |   3 +-
 .../api/collections/CollectionHandlingUtils.java   | 187 ++++++++++++++++-----
 .../cloud/api/collections/CreateCollectionCmd.java |   3 +-
 .../cloud/api/collections/CreateSnapshotCmd.java   |   2 +-
 .../cloud/api/collections/DeleteReplicaCmd.java    |   2 +-
 .../cloud/api/collections/DeleteSnapshotCmd.java   |   2 +-
 .../solr/cloud/api/collections/MigrateCmd.java     |  14 +-
 .../solr/cloud/api/collections/SplitShardCmd.java  |   9 +-
 .../solr/handler/component/ShardRequest.java       |   7 +
 .../AsyncCallRequestStatusResponseTest.java        |   5 +-
 13 files changed, 184 insertions(+), 66 deletions(-)

diff --git 
a/changelog/unreleased/solr-18081-shard-request-tracker-replica-name.yml 
b/changelog/unreleased/solr-18081-shard-request-tracker-replica-name.yml
new file mode 100644
index 00000000000..b5b390ccce6
--- /dev/null
+++ b/changelog/unreleased/solr-18081-shard-request-tracker-replica-name.yml
@@ -0,0 +1,9 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: ShardRequestTracker now indexes Admin API results by node and replica 
rather than just node. This fixes situations where multiple sub-requests are 
sent to a single node.
+type: fixed # added, changed, fixed, deprecated, removed, dependency_update, 
security, other
+authors:
+  - name: Houston Putman
+    nick: HoustonPutman
+links:
+  - name: SOLR-18081
+    url: https://issues.apache.org/jira/browse/SOLR-18081
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/AddReplicaCmd.java 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/AddReplicaCmd.java
index a13bce718d8..91392c11146 100644
--- 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/AddReplicaCmd.java
+++ 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/AddReplicaCmd.java
@@ -175,7 +175,8 @@ public class AddReplicaCmd implements 
CollApiCmds.CollectionApiCommand {
       ModifiableSolrParams params =
           getReplicaParams(
               message, collectionName, coll, skipCreateReplicaInClusterState, 
createReplica);
-      shardRequestTracker.sendShardRequest(createReplica.node, params, 
shardHandler);
+      shardRequestTracker.sendShardRequest(
+          createReplica.node, createReplica.coreNodeName, params, 
shardHandler);
     }
 
     Runnable runnable =
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/BackupCmd.java 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/BackupCmd.java
index 60ec1cb7e6c..04b2a1417bb 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/BackupCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/BackupCmd.java
@@ -350,7 +350,7 @@ public class BackupCmd implements 
CollApiCmds.CollectionApiCommand {
               slice.getName(), backupManager.getBackupId().getId());
       params.set(CoreAdminParams.SHARD_BACKUP_ID, 
shardBackupId.getIdAsString());
 
-      shardRequestTracker.sendShardRequest(replica.getNodeName(), params, 
shardHandler);
+      shardRequestTracker.sendShardRequest(replica, params, shardHandler);
       log.debug("Sent backup request to core={} for backupName={}", coreName, 
backupName);
     }
     log.debug("Sent backup requests to all shard leaders for backupName={}", 
backupName);
@@ -532,7 +532,7 @@ public class BackupCmd implements 
CollApiCmds.CollectionApiCommand {
         params.set(CoreAdminParams.COMMIT_NAME, snapshotMeta.get().getName());
       }
 
-      shardRequestTracker.sendShardRequest(replica.getNodeName(), params, 
shardHandler);
+      shardRequestTracker.sendShardRequest(replica, params, shardHandler);
       log.debug("Sent backup request to core={} for backupName={}", coreName, 
backupName);
     }
     log.debug("Sent backup requests to all shard leaders for backupName={}", 
backupName);
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/CollApiCmds.java 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/CollApiCmds.java
index 454b5363841..3840683d6ef 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/CollApiCmds.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/CollApiCmds.java
@@ -314,7 +314,8 @@ public class CollApiCmds {
 
       String baseUrl = 
ccc.getZkStateReader().getBaseUrlForNodeName(message.getStr(NODE_NAME_PROP));
       ShardRequest sreq = new ShardRequest();
-      sreq.nodeName = message.getStr(ZkStateReader.CORE_NAME_PROP);
+      sreq.nodeName = message.getStr(NODE_NAME_PROP);
+      sreq.coreNodeName = message.getStr(CORE_NODE_NAME_PROP);
       // yes, they must use same admin handler path everywhere...
       params.set("qt", ccc.getAdminPath());
       sreq.purpose = ShardRequest.PURPOSE_PRIVATE;
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/CollectionHandlingUtils.java
 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/CollectionHandlingUtils.java
index 74232b11ddd..b51562aa5ff 100644
--- 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/CollectionHandlingUtils.java
+++ 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/CollectionHandlingUtils.java
@@ -224,7 +224,6 @@ public class CollectionHandlingUtils {
       String slice,
       Replica parentShardLeader) {
     log.debug("Calling soft commit to make sub shard updates visible");
-    String coreUrl = parentShardLeader.getCoreUrl();
     // HttpShardHandler is hard coded to send a QueryRequest hence we go direct
     // and we force open a searcher so that we have documents to show upon 
switching states
     UpdateResponse updateResponse = null;
@@ -232,13 +231,27 @@ public class CollectionHandlingUtils {
       updateResponse =
           softCommit(solrClient, parentShardLeader.getBaseUrl(), 
parentShardLeader.getCoreName());
       CollectionHandlingUtils.processResponse(
-          results, null, coreUrl, updateResponse, slice, 
Collections.emptySet());
+          results,
+          null,
+          parentShardLeader.getNodeName(),
+          parentShardLeader.getName(),
+          updateResponse,
+          slice,
+          Collections.emptySet(),
+          null);
     } catch (Exception e) {
       CollectionHandlingUtils.processResponse(
-          results, e, coreUrl, updateResponse, slice, Collections.emptySet());
+          results,
+          e,
+          parentShardLeader.getNodeName(),
+          parentShardLeader.getCoreName(),
+          updateResponse,
+          slice,
+          Collections.emptySet(),
+          null);
       throw new SolrException(
           SolrException.ErrorCode.SERVER_ERROR,
-          "Unable to call distrib softCommit on: " + coreUrl,
+          "Unable to call distrib softCommit on: " + 
parentShardLeader.getCoreUrl(),
           e);
     }
   }
@@ -419,22 +432,27 @@ public class CollectionHandlingUtils {
   }
 
   static void processResponse(
-      NamedList<Object> results, ShardResponse srsp, Set<String> 
okayExceptions) {
+      NamedList<Object> results, ShardResponse srsp, Set<String> 
okayExceptions, String asyncId) {
     Throwable e = srsp.getException();
     String nodeName = srsp.getNodeName();
+    // Use core or coreNodeName if given as a param, otherwise use nodeName
+    String coreNodeName = srsp.getShardRequest().coreNodeName;
     SolrResponse solrResponse = srsp.getSolrResponse();
     String shard = srsp.getShard();
 
-    processResponse(results, e, nodeName, solrResponse, shard, okayExceptions);
+    processResponse(
+        results, e, nodeName, coreNodeName, solrResponse, shard, 
okayExceptions, asyncId);
   }
 
   static void processResponse(
       NamedList<Object> results,
       Throwable e,
       String nodeName,
+      String coreNodeName,
       SolrResponse solrResponse,
       String shard,
-      Set<String> okayExceptions) {
+      Set<String> okayExceptions,
+      String asyncId) {
     String rootThrowable = null;
     if (e instanceof RemoteSolrException remoteSolrException) {
       rootThrowable = remoteSolrException.getRootThrowable();
@@ -442,9 +460,10 @@ public class CollectionHandlingUtils {
 
     if (e != null && (rootThrowable == null || 
!okayExceptions.contains(rootThrowable))) {
       log.error("Error from shard: {}", shard, e);
-      addFailure(results, nodeName, e.getClass().getName() + ":" + 
e.getMessage());
-    } else {
-      addSuccess(results, nodeName, solrResponse.getResponse());
+      addFailure(results, nodeName, coreNodeName, e);
+    } else if (asyncId == null) {
+      // Do not add a success for async requests, that will be done when the 
async result is found
+      addSuccess(results, nodeName, coreNodeName, solrResponse.getResponse());
     }
   }
 
@@ -468,24 +487,38 @@ public class CollectionHandlingUtils {
     results.add("exception", nl);
   }
 
-  private static void addFailure(NamedList<Object> results, String key, Object 
value) {
+  public static String requestKey(Replica replica) {
+    return requestKey(replica.getNodeName(), replica.getName());
+  }
+
+  public static String requestKey(String nodeName, String coreNodeName) {
+    if (coreNodeName == null) {
+      return nodeName;
+    } else {
+      return nodeName + "/" + coreNodeName;
+    }
+  }
+
+  private static void addFailure(
+      NamedList<Object> results, String nodeName, String coreNodeName, Object 
value) {
     @SuppressWarnings("unchecked")
     SimpleOrderedMap<Object> failure = (SimpleOrderedMap<Object>) 
results.get("failure");
     if (failure == null) {
       failure = new SimpleOrderedMap<>();
       results.add("failure", failure);
     }
-    failure.add(key, value);
+    failure.add(requestKey(nodeName, coreNodeName), value);
   }
 
-  private static void addSuccess(NamedList<Object> results, String key, Object 
value) {
+  private static void addSuccess(
+      NamedList<Object> results, String nodeName, String coreNodeName, Object 
value) {
     @SuppressWarnings("unchecked")
     SimpleOrderedMap<Object> success = (SimpleOrderedMap<Object>) 
results.get("success");
     if (success == null) {
       success = new SimpleOrderedMap<>();
       results.add("success", success);
     }
-    success.add(key, value);
+    success.add(requestKey(nodeName, coreNodeName), value);
   }
 
   private static NamedList<Object> waitForCoreAdminAsyncCallToComplete(
@@ -493,6 +526,7 @@ public class CollectionHandlingUtils {
       String adminPath,
       ZkStateReader zkStateReader,
       String nodeName,
+      String coreNodeName,
       String requestId) {
     ShardHandler shardHandler = shardHandlerFactory.getShardHandler();
     ModifiableSolrParams params = new ModifiableSolrParams();
@@ -508,6 +542,8 @@ public class CollectionHandlingUtils {
       sreq.shards = new String[] {replica};
       sreq.actualShards = sreq.shards;
       sreq.params = params;
+      sreq.nodeName = nodeName;
+      sreq.coreNodeName = coreNodeName;
 
       shardHandler.submit(sreq, replica, sreq.params);
 
@@ -515,8 +551,6 @@ public class CollectionHandlingUtils {
       do {
         srsp = shardHandler.takeCompletedOrError();
         if (srsp != null) {
-          NamedList<Object> results = new NamedList<>();
-          processResponse(results, srsp, Collections.emptySet());
           if (srsp.getSolrResponse().getResponse() == null) {
             NamedList<Object> response = new NamedList<>();
             response.add("STATUS", "failed");
@@ -524,6 +558,16 @@ public class CollectionHandlingUtils {
           }
 
           String r = (String) 
srsp.getSolrResponse().getResponse().get("STATUS");
+          if (r == null) {
+            // For Collections API Calls
+            r = (String) 
srsp.getSolrResponse().getResponse()._get("status/state");
+          }
+          if (r == null) {
+            throw new SolrException(
+                SolrException.ErrorCode.SERVER_ERROR,
+                "Could not find status of async command in response: "
+                    + srsp.getSolrResponse().getResponse().toString());
+          }
           if (r.equals("running")) {
             log.debug("The task is still RUNNING, continuing to wait.");
             try {
@@ -533,6 +577,15 @@ public class CollectionHandlingUtils {
             }
             continue;
 
+          } else if (r.equals("submitted")) {
+            log.debug("The task is still SUBMITTED, continuing to wait.");
+            try {
+              Thread.sleep(1000);
+            } catch (InterruptedException e) {
+              Thread.currentThread().interrupt();
+            }
+            continue;
+
           } else if (r.equals("completed")) {
             log.debug("The task is COMPLETED, returning");
             return srsp.getSolrResponse().getResponse();
@@ -571,21 +624,28 @@ public class CollectionHandlingUtils {
 
   public static ShardRequestTracker syncRequestTracker(
       AdminCmdContext adminCmdContext, CollectionCommandContext ccc) {
-    return requestTracker(null, ccc);
+    return syncRequestTracker(adminCmdContext, ccc.getAdminPath(), ccc);
+  }
+
+  public static ShardRequestTracker syncRequestTracker(
+      AdminCmdContext adminCmdContext, String adminPath, 
CollectionCommandContext ccc) {
+    return requestTracker(null, adminPath, ccc);
   }
 
   public static ShardRequestTracker asyncRequestTracker(
       AdminCmdContext adminCmdContext, CollectionCommandContext ccc) {
-    return requestTracker(adminCmdContext.getAsyncId(), ccc);
+    return asyncRequestTracker(adminCmdContext, ccc.getAdminPath(), ccc);
+  }
+
+  public static ShardRequestTracker asyncRequestTracker(
+      AdminCmdContext adminCmdContext, String adminPath, 
CollectionCommandContext ccc) {
+    return requestTracker(adminCmdContext.getAsyncId(), adminPath, ccc);
   }
 
   protected static ShardRequestTracker requestTracker(
-      String asyncId, CollectionCommandContext ccc) {
+      String asyncId, String adminPath, CollectionCommandContext ccc) {
     return new ShardRequestTracker(
-        asyncId,
-        ccc.getAdminPath(),
-        ccc.getZkStateReader(),
-        ccc.newShardHandler().getShardHandlerFactory());
+        asyncId, adminPath, ccc.getZkStateReader(), 
ccc.newShardHandler().getShardHandlerFactory());
   }
 
   public static class ShardRequestTracker {
@@ -593,7 +653,7 @@ public class CollectionHandlingUtils {
     private final String adminPath;
     private final ZkStateReader zkStateReader;
     private final ShardHandlerFactory shardHandlerFactory;
-    private final NamedList<String> shardAsyncIdByNode = new 
NamedList<String>();
+    private final List<AsyncCmdInfo> shardAsyncCmds = new ArrayList<>();
 
     public ShardRequestTracker(
         String asyncId,
@@ -621,14 +681,13 @@ public class CollectionHandlingUtils {
       for (Replica replica : slice.getReplicas()) {
         if ((stateMatcher == null
             || 
Replica.State.getState(replica.getStr(ZkStateReader.STATE_PROP)) == 
stateMatcher)) {
-          if 
(clusterState.liveNodesContain(replica.getStr(ZkStateReader.NODE_NAME_PROP))) {
+          if (clusterState.liveNodesContain(replica.getNodeName())) {
             // For thread safety, only simple clone the ModifiableSolrParams
             ModifiableSolrParams cloneParams = new ModifiableSolrParams();
             cloneParams.add(params);
-            cloneParams.set(CoreAdminParams.CORE, 
replica.getStr(ZkStateReader.CORE_NAME_PROP));
+            cloneParams.set(CoreAdminParams.CORE, replica.getCoreName());
 
-            sendShardRequest(
-                replica.getStr(ZkStateReader.NODE_NAME_PROP), cloneParams, 
shardHandler);
+            sendShardRequest(replica.getNodeName(), replica.getName(), 
cloneParams, shardHandler);
           } else {
             notLiveReplicas.add(replica);
           }
@@ -638,12 +697,22 @@ public class CollectionHandlingUtils {
     }
 
     public void sendShardRequest(
-        String nodeName, ModifiableSolrParams params, ShardHandler 
shardHandler) {
-      sendShardRequest(nodeName, params, shardHandler, adminPath, 
zkStateReader);
+        Replica replica, ModifiableSolrParams params, ShardHandler 
shardHandler) {
+      sendShardRequest(
+          replica.getNodeName(), replica.getName(), params, shardHandler, 
adminPath, zkStateReader);
+    }
+
+    public void sendShardRequest(
+        String nodeName,
+        String coreNodeName,
+        ModifiableSolrParams params,
+        ShardHandler shardHandler) {
+      sendShardRequest(nodeName, coreNodeName, params, shardHandler, 
adminPath, zkStateReader);
     }
 
     public void sendShardRequest(
         String nodeName,
+        String coreNodeName,
         ModifiableSolrParams params,
         ShardHandler shardHandler,
         String adminPath,
@@ -652,7 +721,7 @@ public class CollectionHandlingUtils {
         String coreAdminAsyncId = asyncId + Math.abs(System.nanoTime());
         params.set(ASYNC, coreAdminAsyncId);
         // Track async requests
-        shardAsyncIdByNode.add(nodeName, coreAdminAsyncId);
+        shardAsyncCmds.add(AsyncCmdInfo.from(nodeName, coreNodeName, 
coreAdminAsyncId));
       }
 
       ShardRequest sreq = new ShardRequest();
@@ -662,6 +731,7 @@ public class CollectionHandlingUtils {
       sreq.shards = new String[] {replica};
       sreq.actualShards = sreq.shards;
       sreq.nodeName = nodeName;
+      sreq.coreNodeName = coreNodeName;
       sreq.params = params;
 
       shardHandler.submit(sreq, replica, sreq.params);
@@ -684,9 +754,12 @@ public class CollectionHandlingUtils {
       // Processes all shard responses
       ShardResponse srsp;
       do {
-        srsp = shardHandler.takeCompletedOrError();
+        srsp =
+            abortOnError
+                ? shardHandler.takeCompletedOrError()
+                : shardHandler.takeCompletedIncludingErrors();
         if (srsp != null) {
-          processResponse(results, srsp, okayExceptions);
+          processResponse(results, srsp, okayExceptions, asyncId);
           Throwable exception = srsp.getException();
           if (abortOnError && exception != null) {
             // drain pending requests
@@ -702,25 +775,53 @@ public class CollectionHandlingUtils {
       if (asyncId != null) {
         // TODO: Shouldn't we abort with msgOnError exception when failure?
         waitForAsyncCallsToComplete(results);
-        shardAsyncIdByNode.clear();
+        shardAsyncCmds.clear();
       }
     }
 
     private void waitForAsyncCallsToComplete(NamedList<Object> results) {
-      for (Map.Entry<String, String> nodeToAsync : shardAsyncIdByNode) {
-        final String node = nodeToAsync.getKey();
-        final String shardAsyncId = nodeToAsync.getValue();
-        log.debug("I am Waiting for :{}/{}", node, shardAsyncId);
+      for (AsyncCmdInfo asyncCmdInfo : shardAsyncCmds) {
+        Object failure =
+            results._get("failure/" + requestKey(asyncCmdInfo.nodeName, 
asyncCmdInfo.coreNodeName));
+        // Do not wait for Async calls that have already failed
+        if (failure != null) {
+          return;
+        }
+        final String node = asyncCmdInfo.nodeName;
+        final String coreNodeName = asyncCmdInfo.coreNodeName;
+        final String shardAsyncId = asyncCmdInfo.asyncId;
+        log.info("I am Waiting for: {}/{}/{}", node, coreNodeName, 
shardAsyncId);
         NamedList<Object> reqResult =
             waitForCoreAdminAsyncCallToComplete(
-                shardHandlerFactory, adminPath, zkStateReader, node, 
shardAsyncId);
-        if ("failed".equalsIgnoreCase(((String) reqResult.get("STATUS")))) {
-          log.error("Error from shard {}: {}", node, reqResult);
-          addFailure(results, node, reqResult);
+                shardHandlerFactory, adminPath, zkStateReader, node, 
coreNodeName, shardAsyncId);
+        String status = (String) reqResult.get("STATUS");
+        if (status == null) {
+          // For Collections API Calls
+          status = (String) reqResult._get("status/state");
+        }
+        if ("failed".equalsIgnoreCase(status)) {
+          log.error("Error from shard {}/{}: {}", node, coreNodeName, 
reqResult);
+          addFailure(results, node, coreNodeName, reqResult);
         } else {
-          addSuccess(results, node, reqResult);
+          addSuccess(results, node, coreNodeName, reqResult);
         }
       }
     }
   }
+
+  private static class AsyncCmdInfo {
+    protected final String nodeName;
+    protected final String coreNodeName;
+    protected final String asyncId;
+
+    public AsyncCmdInfo(String nodeName, String coreNodeName, String asyncId) {
+      this.nodeName = nodeName;
+      this.coreNodeName = coreNodeName;
+      this.asyncId = asyncId;
+    }
+
+    public static AsyncCmdInfo from(String nodeName, String coreNodeName, 
String asyncId) {
+      return new AsyncCmdInfo(nodeName, coreNodeName, asyncId);
+    }
+  }
 }
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java
 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java
index f9aab00769d..ff2d92378f3 100644
--- 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java
+++ 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateCollectionCmd.java
@@ -411,7 +411,8 @@ public class CreateCollectionCmd implements 
CollApiCmds.CollectionApiCommand {
         ModifiableSolrParams params = e.getValue();
         String nodeName = nodeNames.get(e.getKey());
         params.set(CoreAdminParams.CORE_NODE_NAME, 
replicas.get(e.getKey()).getName());
-        shardRequestTracker.sendShardRequest(nodeName, params, shardHandler);
+        shardRequestTracker.sendShardRequest(
+            nodeName, replicas.get(e.getKey()).getCoreName(), params, 
shardHandler);
       }
 
       shardRequestTracker.processResponses(
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateSnapshotCmd.java
 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateSnapshotCmd.java
index 97e24fc8279..db4918f7759 100644
--- 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateSnapshotCmd.java
+++ 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/CreateSnapshotCmd.java
@@ -119,7 +119,7 @@ public class CreateSnapshotCmd implements 
CollApiCmds.CollectionApiCommand {
         params.set(CORE_NAME_PROP, coreName);
         params.set(CoreAdminParams.COMMIT_NAME, commitName);
 
-        shardRequestTracker.sendShardRequest(replica.getNodeName(), params, 
shardHandler);
+        shardRequestTracker.sendShardRequest(replica, params, shardHandler);
         log.debug(
             "Sent createsnapshot request to core={} with commitName={}", 
coreName, commitName);
 
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteReplicaCmd.java
 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteReplicaCmd.java
index 5246401db6e..a2ad2cdd5b5 100644
--- 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteReplicaCmd.java
+++ 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteReplicaCmd.java
@@ -313,7 +313,7 @@ public class DeleteReplicaCmd implements 
CollectionApiCommand {
     final ShardRequestTracker shardRequestTracker =
         CollectionHandlingUtils.asyncRequestTracker(adminCmdContext, ccc);
     if (isLive) {
-      shardRequestTracker.sendShardRequest(replica.getNodeName(), params, 
shardHandler);
+      shardRequestTracker.sendShardRequest(replica, params, shardHandler);
     }
 
     Callable<Boolean> callable =
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteSnapshotCmd.java
 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteSnapshotCmd.java
index ffb93c48fc2..af321c7b670 100644
--- 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteSnapshotCmd.java
+++ 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteSnapshotCmd.java
@@ -123,7 +123,7 @@ public class DeleteSnapshotCmd implements 
CollApiCmds.CollectionApiCommand {
 
           log.info(
               "Sending deletesnapshot request to core={} with commitName={}", 
coreName, commitName);
-          shardRequestTracker.sendShardRequest(replica.getNodeName(), params, 
shardHandler);
+          shardRequestTracker.sendShardRequest(replica, params, shardHandler);
         }
       }
     }
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/MigrateCmd.java 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/MigrateCmd.java
index ba56c8ab9dd..2869f9866b6 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/MigrateCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/MigrateCmd.java
@@ -232,7 +232,7 @@ public class MigrateCmd implements 
CollApiCmds.CollectionApiCommand {
     {
       final ShardRequestTracker shardRequestTracker =
           CollectionHandlingUtils.asyncRequestTracker(adminCmdContext, ccc);
-      shardRequestTracker.sendShardRequest(targetLeader.getNodeName(), params, 
shardHandler);
+      shardRequestTracker.sendShardRequest(targetLeader, params, shardHandler);
 
       shardRequestTracker.processResponses(
           results, shardHandler, true, "MIGRATE failed to request node to 
buffer updates");
@@ -358,7 +358,7 @@ public class MigrateCmd implements 
CollApiCmds.CollectionApiCommand {
           CollectionHandlingUtils.syncRequestTracker(adminCmdContext, ccc);
       // we don't want this to happen asynchronously
       syncRequestTracker.sendShardRequest(
-          tempSourceLeader.getNodeName(), new 
ModifiableSolrParams(cmd.getParams()), shardHandler);
+          tempSourceLeader, new ModifiableSolrParams(cmd.getParams()), 
shardHandler);
 
       syncRequestTracker.processResponses(
           results,
@@ -376,12 +376,10 @@ public class MigrateCmd implements 
CollApiCmds.CollectionApiCommand {
     params.set(CoreAdminParams.RANGES, splitRange.toString());
     params.set("split.key", splitKey);
 
-    String tempNodeName = sourceLeader.getNodeName();
-
     {
       final ShardRequestTracker shardRequestTracker =
           CollectionHandlingUtils.asyncRequestTracker(adminCmdContext, ccc);
-      shardRequestTracker.sendShardRequest(tempNodeName, params, shardHandler);
+      shardRequestTracker.sendShardRequest(sourceLeader, params, shardHandler);
       shardRequestTracker.processResponses(
           results, shardHandler, true, "MIGRATE failed to invoke SPLIT core 
admin command");
     }
@@ -447,7 +445,7 @@ public class MigrateCmd implements 
CollApiCmds.CollectionApiCommand {
     {
       final ShardRequestTracker shardRequestTracker =
           CollectionHandlingUtils.asyncRequestTracker(adminCmdContext, ccc);
-      shardRequestTracker.sendShardRequest(tempSourceLeader.getNodeName(), 
params, shardHandler);
+      shardRequestTracker.sendShardRequest(tempSourceLeader, params, 
shardHandler);
 
       shardRequestTracker.processResponses(
           results,
@@ -468,7 +466,7 @@ public class MigrateCmd implements 
CollApiCmds.CollectionApiCommand {
       final ShardRequestTracker shardRequestTracker =
           CollectionHandlingUtils.asyncRequestTracker(adminCmdContext, ccc);
 
-      shardRequestTracker.sendShardRequest(targetLeader.getNodeName(), params, 
shardHandler);
+      shardRequestTracker.sendShardRequest(targetLeader, params, shardHandler);
       String msg =
           "MIGRATE failed to merge "
               + tempCollectionReplica2
@@ -487,7 +485,7 @@ public class MigrateCmd implements 
CollApiCmds.CollectionApiCommand {
     {
       final ShardRequestTracker shardRequestTracker =
           CollectionHandlingUtils.asyncRequestTracker(adminCmdContext, ccc);
-      shardRequestTracker.sendShardRequest(targetLeader.getNodeName(), params, 
shardHandler);
+      shardRequestTracker.sendShardRequest(targetLeader, params, shardHandler);
       shardRequestTracker.processResponses(
           results, shardHandler, true, "MIGRATE failed to request node to 
apply buffered updates");
     }
diff --git 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
index 3298ecba2bc..200c9a6607d 100644
--- 
a/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
+++ 
b/solr/core/src/java/org/apache/solr/cloud/api/collections/SplitShardCmd.java
@@ -279,8 +279,7 @@ public class SplitShardCmd implements 
CollApiCmds.CollectionApiCommand {
         {
           final ShardRequestTracker shardRequestTracker =
               CollectionHandlingUtils.syncRequestTracker(adminCmdContext, ccc);
-          shardRequestTracker.sendShardRequest(
-              parentShardLeader.getNodeName(), params, shardHandler);
+          shardRequestTracker.sendShardRequest(parentShardLeader, params, 
shardHandler);
           SimpleOrderedMap<Object> getRangesResults = new SimpleOrderedMap<>();
           String msgOnError = "SPLITSHARD failed to invoke SPLIT.getRanges 
core admin command";
           shardRequestTracker.processResponses(getRangesResults, shardHandler, 
true, msgOnError);
@@ -463,7 +462,7 @@ public class SplitShardCmd implements 
CollApiCmds.CollectionApiCommand {
           cmd.setOnlyIfLeader(true);
 
           ModifiableSolrParams p = new ModifiableSolrParams(cmd.getParams());
-          shardRequestTracker.sendShardRequest(nodeName, p, shardHandler);
+          shardRequestTracker.sendShardRequest(nodeName, subShardName, p, 
shardHandler);
         }
 
         String msgOnError = "SPLITSHARD timed out waiting for subshard leaders 
to come up";
@@ -502,7 +501,7 @@ public class SplitShardCmd implements 
CollApiCmds.CollectionApiCommand {
       {
         final ShardRequestTracker shardRequestTracker =
             CollectionHandlingUtils.asyncRequestTracker(adminCmdContext, ccc);
-        shardRequestTracker.sendShardRequest(parentShardLeader.getNodeName(), 
params, shardHandler);
+        shardRequestTracker.sendShardRequest(parentShardLeader, params, 
shardHandler);
 
         String msgOnError = "SPLITSHARD failed to invoke SPLIT core admin 
command";
         shardRequestTracker.processResponses(results, shardHandler, true, 
msgOnError);
@@ -531,7 +530,7 @@ public class SplitShardCmd implements 
CollApiCmds.CollectionApiCommand {
               CoreAdminParams.CoreAdminAction.REQUESTAPPLYUPDATES.toString());
           params.set(CoreAdminParams.NAME, subShardName);
 
-          shardRequestTracker.sendShardRequest(nodeName, params, shardHandler);
+          shardRequestTracker.sendShardRequest(nodeName, subShardName, params, 
shardHandler);
         }
 
         String msgOnError =
diff --git 
a/solr/core/src/java/org/apache/solr/handler/component/ShardRequest.java 
b/solr/core/src/java/org/apache/solr/handler/component/ShardRequest.java
index d7d7da04f22..5222b38abee 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/ShardRequest.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/ShardRequest.java
@@ -18,6 +18,7 @@ package org.apache.solr.handler.component;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import org.apache.solr.common.params.ModifiableSolrParams;
 
 // todo... when finalized make accessors
@@ -56,6 +57,12 @@ public class ShardRequest {
   /** may be null */
   public String nodeName;
 
+  /** may be null */
+  public String coreNodeName;
+
+  /** may be null */
+  public Map<String, String> headers;
+
   // TODO: one could store a list of numbers to correlate where returned docs
   // go in the top-level response rather than looking up by id...
   // this would work well if we ever transitioned to using internal ids and
diff --git 
a/solr/core/src/test/org/apache/solr/cloud/api/collections/AsyncCallRequestStatusResponseTest.java
 
b/solr/core/src/test/org/apache/solr/cloud/api/collections/AsyncCallRequestStatusResponseTest.java
index 4c4f476e48e..ca683c4d764 100644
--- 
a/solr/core/src/test/org/apache/solr/cloud/api/collections/AsyncCallRequestStatusResponseTest.java
+++ 
b/solr/core/src/test/org/apache/solr/cloud/api/collections/AsyncCallRequestStatusResponseTest.java
@@ -68,8 +68,9 @@ public class AsyncCallRequestStatusResponseTest extends 
SolrCloudTestCase {
       final NamedList<?> success = (NamedList<?>) r.get("success");
       assertNotNull("Expected 'success' response" + r, success);
 
-      final int actualSuccessElems = 2 * (numShards * numReplicas);
-      // every replica responds once on submit and once on complete
+      final int actualSuccessElems = numShards * numReplicas;
+      // every replica responds either once on submit (failure) or once on 
complete (if submit
+      // succeeds)
       assertEquals(
           "Expected " + actualSuccessElems + " elements in the success 
element" + success.jsonStr(),
           actualSuccessElems,

Reply via email to