You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by no...@apache.org on 2024/05/13 17:10:42 UTC

(solr) 01/01: Removed "state" and "leader" attributes from replicas of PRS collection

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

noble pushed a commit to branch jira/17272
in repository https://gitbox.apache.org/repos/asf/solr.git

commit 24b3708fadc1feee813331bdc18c5ca680c77111
Author: noblepaul <no...@gmail.com>
AuthorDate: Tue May 14 03:10:26 2024 +1000

    Removed "state" and "leader" attributes from replicas of PRS collection
---
 .../apache/solr/cloud/overseer/SliceMutator.java   |  4 ++
 .../java/org/apache/solr/common/cloud/Replica.java | 14 +++++--
 .../cloud/PerReplicaStatesIntegrationTest.java     | 48 ++++++++++++++++++++--
 3 files changed, 58 insertions(+), 8 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/cloud/overseer/SliceMutator.java b/solr/core/src/java/org/apache/solr/cloud/overseer/SliceMutator.java
index c016fa5489b..d5170c66474 100644
--- a/solr/core/src/java/org/apache/solr/cloud/overseer/SliceMutator.java
+++ b/solr/core/src/java/org/apache/solr/cloud/overseer/SliceMutator.java
@@ -159,6 +159,10 @@ public class SliceMutator {
       log.error("Could not mark shard leader for non existing collection: {}", collectionName);
       return ZkStateWriter.NO_OP;
     }
+    if (coll.isPerReplicaState()) {
+      log.debug("Do not mark shard leader for PRS collection: {}", collectionName);
+      return ZkStateWriter.NO_OP;
+    }
 
     Map<String, Slice> slices = coll.getSlicesMap();
     Slice slice = slices.get(sliceName);
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/Replica.java b/solr/solrj/src/java/org/apache/solr/common/cloud/Replica.java
index 0d4cd3afffb..ede575f3189 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/Replica.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/Replica.java
@@ -25,6 +25,8 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Supplier;
+
 import org.apache.solr.common.MapWriter;
 import org.apache.solr.common.params.CollectionAdminParams;
 import org.apache.solr.common.util.StrUtils;
@@ -249,7 +251,9 @@ public class Replica extends ZkNodeProps implements MapWriter {
     Objects.requireNonNull(this.collection, "'collection' must not be null");
     Objects.requireNonNull(this.shard, "'shard' must not be null");
     Objects.requireNonNull(this.type, "'type' must not be null");
-    Objects.requireNonNull(this.state, "'state' must not be null");
+    if (perReplicaStatesRef == null) {// PRS collection
+      Objects.requireNonNull(this.state, "'state' must not be null");
+    }
     Objects.requireNonNull(this.node, "'node' must not be null");
 
     String baseUrl = (String) propMap.get(ReplicaStateProps.BASE_URL);
@@ -259,7 +263,9 @@ public class Replica extends ZkNodeProps implements MapWriter {
     propMap.put(ReplicaStateProps.NODE_NAME, node);
     propMap.put(ReplicaStateProps.CORE_NAME, core);
     propMap.put(ReplicaStateProps.TYPE, type.toString());
-    propMap.put(ReplicaStateProps.STATE, state.toString());
+    if (perReplicaStatesRef == null) {//PRS collection
+      propMap.put(ReplicaStateProps.STATE, state.toString());
+    }
   }
 
   public String getCollection() {
@@ -412,8 +418,8 @@ public class Replica extends ZkNodeProps implements MapWriter {
     ew.putIfNotNull(ReplicaStateProps.CORE_NAME, core)
         .putIfNotNull(ReplicaStateProps.NODE_NAME, node)
         .putIfNotNull(ReplicaStateProps.TYPE, type.toString())
-        .putIfNotNull(ReplicaStateProps.STATE, getState().toString())
-        .putIfNotNull(ReplicaStateProps.LEADER, () -> isLeader() ? "true" : null)
+        .putIfNotNull(ReplicaStateProps.STATE, () -> perReplicaStatesRef == null ? getState().toString() : null)
+        .putIfNotNull(ReplicaStateProps.LEADER, () -> perReplicaStatesRef != null || !isLeader() ? null : "true")
         .putIfNotNull(
             ReplicaStateProps.FORCE_SET_STATE, propMap.get(ReplicaStateProps.FORCE_SET_STATE))
         .putIfNotNull(ReplicaStateProps.BASE_URL, propMap.get(ReplicaStateProps.BASE_URL));
diff --git a/solr/solrj/src/test/org/apache/solr/common/cloud/PerReplicaStatesIntegrationTest.java b/solr/solrj/src/test/org/apache/solr/common/cloud/PerReplicaStatesIntegrationTest.java
index e75100f1a50..3512e74c6f3 100644
--- a/solr/solrj/src/test/org/apache/solr/common/cloud/PerReplicaStatesIntegrationTest.java
+++ b/solr/solrj/src/test/org/apache/solr/common/cloud/PerReplicaStatesIntegrationTest.java
@@ -40,6 +40,7 @@ import org.slf4j.LoggerFactory;
 /** This test would be faster if we simulated the zk state instead. */
 @LogLevel(
     "org.apache.solr.common.cloud.ZkStateReader=DEBUG;"
+        + "org.apache.solr.cloud.overseer.ZkStateWriter=DEBUG;"
         + "org.apache.solr.handler.admin.CollectionsHandler=DEBUG;"
         + "org.apache.solr.common.cloud.PerReplicaStatesOps=DEBUG;"
         + "org.apache.solr.cloud.Overseer=INFO;"
@@ -315,7 +316,8 @@ public class PerReplicaStatesIntegrationTest extends SolrCloudTestCase {
       CollectionAdminRequest.createCollection(PRS_COLL, "conf", 10, 1)
           .setPerReplicaState(Boolean.TRUE)
           .process(cluster.getSolrClient());
-      stat = cluster.getZkClient().exists(DocCollection.getCollectionPath(PRS_COLL), null, true);
+      String PRS_PATH = DocCollection.getCollectionPath(PRS_COLL);
+      stat = cluster.getZkClient().exists(PRS_PATH, null, true);
       // +1 after all replica are added with on state.json write to CreateCollectionCmd.setData()
       assertEquals(1, stat.getVersion());
       // For each replica:
@@ -330,7 +332,7 @@ public class PerReplicaStatesIntegrationTest extends SolrCloudTestCase {
           CollectionAdminRequest.addReplicaToShard(PRS_COLL, "shard1")
               .process(cluster.getSolrClient());
       cluster.waitForActiveCollection(PRS_COLL, 10, 11);
-      stat = cluster.getZkClient().exists(DocCollection.getCollectionPath(PRS_COLL), null, true);
+      stat = cluster.getZkClient().exists(PRS_PATH, null, true);
       // For the new replica:
       // +2 for state.json overseer writes, even though there's no longer PRS updates from
       // overseer, current code would still do a "TOUCH" on the PRS entry
@@ -350,7 +352,7 @@ public class PerReplicaStatesIntegrationTest extends SolrCloudTestCase {
       CollectionAdminRequest.deleteReplica(PRS_COLL, "shard1", addedReplica.getName())
           .process(cluster.getSolrClient());
       cluster.waitForActiveCollection(PRS_COLL, 10, 10);
-      stat = cluster.getZkClient().exists(DocCollection.getCollectionPath(PRS_COLL), null, true);
+      stat = cluster.getZkClient().exists(PRS_PATH, null, true);
       // For replica deletion
       // +1 for ZkController#unregister, which delete the PRS entry from data node
       // overseer, current code would still do a "TOUCH" on the PRS entry
@@ -359,11 +361,49 @@ public class PerReplicaStatesIntegrationTest extends SolrCloudTestCase {
       for (JettySolrRunner j : cluster.getJettySolrRunners()) {
         j.stop();
         j.start(true);
-        stat = cluster.getZkClient().exists(DocCollection.getCollectionPath(PRS_COLL), null, true);
+        stat = cluster.getZkClient().exists(PRS_PATH, null, true);
         // ensure restart does not update the state.json, after addReplica/deleteReplica, 2 more
         // updates hence at version 3 on state.json version
         assertEquals(3, stat.getVersion());
       }
+
+      // test for leader election
+      Replica leader =
+          cluster.getZkStateReader().clusterState.getCollection(PRS_COLL).getLeader("shard2");
+
+      JettySolrRunner j2 = cluster.startJettySolrRunner();
+      response =
+          CollectionAdminRequest.addReplicaToShard(PRS_COLL, "shard2")
+              .setNode(j2.getNodeName())
+              .process(cluster.getSolrClient());
+
+      // wait for the new replica to be active
+      cluster.waitForActiveCollection(PRS_COLL, 10, 11);
+      stat = cluster.getZkClient().exists(PRS_PATH, null, true);
+      // +1 for a new replica
+      assertEquals(4, stat.getVersion());
+      DocCollection c = cluster.getZkStateReader().getCollection(PRS_COLL);
+      Replica newreplica = c.getReplica((s, replica) -> replica.node.equals(j2.getNodeName()));
+
+      // let's stop the old leader
+      JettySolrRunner oldJetty = cluster.getReplicaJetty(leader);
+      oldJetty.stop();
+
+      cluster
+          .getZkStateReader()
+          .waitForState(
+              PRS_COLL,
+              10,
+              TimeUnit.SECONDS,
+              (liveNodes, collectionState) ->
+                  PerReplicaStatesOps.fetch(PRS_PATH, cluster.getZkClient(), null)
+                      .states
+                      .get(newreplica.name)
+                      .isLeader);
+      PerReplicaStates prs = PerReplicaStatesOps.fetch(PRS_PATH, cluster.getZkClient(), null);
+      stat = cluster.getZkClient().exists(PRS_PATH, null, true);
+      // the version should not have updated
+      assertEquals(4, stat.getVersion());
     } finally {
       cluster.shutdown();
     }