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