You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by js...@apache.org on 2023/07/06 19:22:24 UTC

[solr] branch main updated: SOLR-16867: Updating to handle multiple coordinator nodes (#1757)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new fb3ff24bf79 SOLR-16867: Updating to handle multiple coordinator nodes (#1757)
fb3ff24bf79 is described below

commit fb3ff24bf79505b8c82222d5c2e419b04dbc81fa
Author: Justin Sweeney <ju...@fullstory.com>
AuthorDate: Thu Jul 6 15:22:18 2023 -0400

    SOLR-16867: Updating to handle multiple coordinator nodes (#1757)
    
    * SOLR-16867: Updating to handle multiple coordinator nodes
    
    * Tidying code
    
    * Incorporating watch removal
---
 .../solr/servlet/CoordinatorHttpSolrCall.java      | 52 +++++++++--------
 .../apache/solr/search/TestCoordinatorRole.java    | 66 ++++++++++++++++++++++
 2 files changed, 96 insertions(+), 22 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/servlet/CoordinatorHttpSolrCall.java b/solr/core/src/java/org/apache/solr/servlet/CoordinatorHttpSolrCall.java
index ee30474a506..169a2a02032 100644
--- a/solr/core/src/java/org/apache/solr/servlet/CoordinatorHttpSolrCall.java
+++ b/solr/core/src/java/org/apache/solr/servlet/CoordinatorHttpSolrCall.java
@@ -18,6 +18,7 @@
 package org.apache.solr.servlet;
 
 import java.lang.invoke.MethodHandles;
+import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
@@ -83,20 +84,35 @@ public class CoordinatorHttpSolrCall extends HttpSolrCall {
       ZkStateReader zkStateReader = solrCall.cores.getZkController().getZkStateReader();
       ClusterState clusterState = zkStateReader.getClusterState();
       DocCollection coll = clusterState.getCollectionOrNull(collectionName, true);
+      SolrCore core = null;
       if (coll != null) {
         String confName = coll.getConfigName();
         String syntheticCollectionName = SYNTHETIC_COLL_PREFIX + confName;
 
         DocCollection syntheticColl = clusterState.getCollectionOrNull(syntheticCollectionName);
         if (syntheticColl == null) {
-          // no such collection. let's create one
+          // no synthetic collection for this config, let's create one
           if (log.isInfoEnabled()) {
             log.info(
                 "synthetic collection: {} does not exist, creating.. ", syntheticCollectionName);
           }
           createColl(syntheticCollectionName, solrCall.cores, confName);
+          syntheticColl =
+              zkStateReader.getClusterState().getCollectionOrNull(syntheticCollectionName);
         }
-        SolrCore core = solrCall.getCoreByCollection(syntheticCollectionName, isPreferLeader);
+        List<Replica> nodeNameSyntheticReplicas =
+            syntheticColl.getReplicas(solrCall.cores.getZkController().getNodeName());
+        if (nodeNameSyntheticReplicas == null || nodeNameSyntheticReplicas.isEmpty()) {
+          // this node does not have a replica. add one
+          if (log.isInfoEnabled()) {
+            log.info(
+                "this node does not have a replica of the synthetic collection: {} , adding replica ",
+                syntheticCollectionName);
+          }
+
+          addReplica(syntheticCollectionName, solrCall.cores);
+        }
+        core = solrCall.getCoreByCollection(syntheticCollectionName, isPreferLeader);
         if (core != null) {
           factory.collectionVsCoreNameMapping.put(collectionName, core.getName());
           // for the watcher, only remove on collection deletion (ie collection == null), since
@@ -118,16 +134,6 @@ public class CoordinatorHttpSolrCall extends HttpSolrCall {
           if (log.isDebugEnabled()) {
             log.debug("coordinator node, returns synthetic core: {}", core.getName());
           }
-        } else {
-          // this node does not have a replica. add one
-          if (log.isInfoEnabled()) {
-            log.info(
-                "this node does not have a replica of the synthetic collection: {} , adding replica ",
-                syntheticCollectionName);
-          }
-
-          addReplica(syntheticCollectionName, solrCall.cores);
-          core = solrCall.getCoreByCollection(syntheticCollectionName, isPreferLeader);
         }
         setMDCLoggingContext(collectionName);
         return core;
@@ -152,15 +158,13 @@ public class CoordinatorHttpSolrCall extends HttpSolrCall {
   private static void addReplica(String syntheticCollectionName, CoreContainer cores) {
     SolrQueryResponse rsp = new SolrQueryResponse();
     try {
+      CollectionAdminRequest.AddReplica addReplicaRequest =
+          CollectionAdminRequest.addReplicaToShard(syntheticCollectionName, "shard1")
+              .setCreateNodeSet(cores.getZkController().getNodeName());
+      addReplicaRequest.setWaitForFinalState(true);
       cores
           .getCollectionsHandler()
-          .handleRequestBody(
-              new LocalSolrQueryRequest(
-                  null,
-                  CollectionAdminRequest.addReplicaToShard(syntheticCollectionName, "shard1")
-                      .setCreateNodeSet(cores.getZkController().getNodeName())
-                      .getParams()),
-              rsp);
+          .handleRequestBody(new LocalSolrQueryRequest(null, addReplicaRequest.getParams()), rsp);
       if (rsp.getValues().get("success") == null) {
         throw new SolrException(
             SolrException.ErrorCode.SERVER_ERROR,
@@ -178,10 +182,11 @@ public class CoordinatorHttpSolrCall extends HttpSolrCall {
       String syntheticCollectionName, CoreContainer cores, String confName) {
     SolrQueryResponse rsp = new SolrQueryResponse();
     try {
-      SolrParams params =
+      CollectionAdminRequest.Create collCreationRequest =
           CollectionAdminRequest.createCollection(syntheticCollectionName, confName, 1, 1)
-              .setCreateNodeSet(cores.getZkController().getNodeName())
-              .getParams();
+              .setCreateNodeSet(cores.getZkController().getNodeName());
+      collCreationRequest.setWaitForFinalState(true);
+      SolrParams params = collCreationRequest.getParams();
       if (log.isInfoEnabled()) {
         log.info("sending collection admin command : {}", Utils.toJSONString(params));
       }
@@ -247,6 +252,9 @@ public class CoordinatorHttpSolrCall extends HttpSolrCall {
         boolean retry) {
       if ((path.startsWith("/____v2/") || path.equals("/____v2"))) {
         return new CoordinatorV2HttpSolrCall(this, filter, cores, request, response, retry);
+      } else if (path.startsWith("/" + SYNTHETIC_COLL_PREFIX)) {
+        return SolrDispatchFilter.HttpSolrCallFactory.super.createInstance(
+            filter, path, cores, request, response, retry);
       } else {
         return new CoordinatorHttpSolrCall(this, filter, cores, request, response, retry);
       }
diff --git a/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java b/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java
index 14d866d1f3a..a0b1d1bef99 100644
--- a/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java
+++ b/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java
@@ -111,6 +111,72 @@ public class TestCoordinatorRole extends SolrCloudTestCase {
     }
   }
 
+  public void testMultiCollectionMultiNode() throws Exception {
+    MiniSolrCloudCluster cluster =
+        configureCluster(4).addConfig("conf", configset("cloud-minimal")).configure();
+    try {
+      CloudSolrClient client = cluster.getSolrClient();
+      String COLLECTION_NAME = "test_coll";
+      String SYNTHETIC_COLLECTION = CoordinatorHttpSolrCall.SYNTHETIC_COLL_PREFIX + "conf";
+      for (int j = 1; j <= 10; j++) {
+        String collname = COLLECTION_NAME + "_" + j;
+        CollectionAdminRequest.createCollection(collname, "conf", 2, 2)
+            .process(cluster.getSolrClient());
+        cluster.waitForActiveCollection(collname, 2, 4);
+        UpdateRequest ur = new UpdateRequest();
+        for (int i = 0; i < 10; i++) {
+          SolrInputDocument doc2 = new SolrInputDocument();
+          doc2.addField("id", "" + i);
+          ur.add(doc2);
+        }
+
+        ur.commit(client, collname);
+        QueryResponse rsp = client.query(collname, new SolrQuery("*:*"));
+        assertEquals(10, rsp.getResults().getNumFound());
+      }
+
+      System.setProperty(NodeRoles.NODE_ROLES_PROP, "coordinator:on");
+      final JettySolrRunner coordinatorJetty1;
+      final JettySolrRunner coordinatorJetty2;
+      try {
+        coordinatorJetty1 = cluster.startJettySolrRunner();
+        coordinatorJetty2 = cluster.startJettySolrRunner();
+      } finally {
+        System.clearProperty(NodeRoles.NODE_ROLES_PROP);
+      }
+      for (int j = 1; j <= 10; j++) {
+        String collname = COLLECTION_NAME + "_" + j;
+        QueryResponse rslt =
+            new QueryRequest(new SolrQuery("*:*"))
+                .setPreferredNodes(List.of(coordinatorJetty1.getNodeName()))
+                .process(client, collname);
+
+        assertEquals(10, rslt.getResults().size());
+      }
+
+      for (int j = 1; j <= 10; j++) {
+        String collname = COLLECTION_NAME + "_" + j;
+        QueryResponse rslt =
+            new QueryRequest(new SolrQuery("*:*"))
+                .setPreferredNodes(List.of(coordinatorJetty2.getNodeName()))
+                .process(client, collname);
+
+        assertEquals(10, rslt.getResults().size());
+      }
+
+      DocCollection collection =
+          cluster.getSolrClient().getClusterStateProvider().getCollection(SYNTHETIC_COLLECTION);
+      assertNotNull(collection);
+
+      int coordNode1NumCores = coordinatorJetty1.getCoreContainer().getNumAllCores();
+      assertEquals("Unexpected number of cores found for coordinator node", 1, coordNode1NumCores);
+      int coordNode2NumCores = coordinatorJetty2.getCoreContainer().getNumAllCores();
+      assertEquals("Unexpected number of cores found for coordinator node", 1, coordNode2NumCores);
+    } finally {
+      cluster.shutdown();
+    }
+  }
+
   public void testNRTRestart() throws Exception {
     // we restart jetty and expect to find on disk data - need a local fs directory
     useFactory(null);