You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2020/09/07 17:27:56 UTC

[lucene-solr] branch jira/solr-14749 updated: SOLR-14749: Illustrate how ClusterSingleton registration can work, and how to process ClusterEvent-s.

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

ab pushed a commit to branch jira/solr-14749
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/jira/solr-14749 by this push:
     new 8dfff7a  SOLR-14749: Illustrate how ClusterSingleton registration can work, and how to process ClusterEvent-s.
8dfff7a is described below

commit 8dfff7affe42592ebc90f365b8c07ed6b5507da0
Author: Andrzej Bialecki <ab...@apache.org>
AuthorDate: Mon Sep 7 19:27:03 2020 +0200

    SOLR-14749: Illustrate how ClusterSingleton registration can work, and how to
    process ClusterEvent-s.
---
 .../src/java/org/apache/solr/cloud/Overseer.java   | 33 ++++++++--------------
 .../events/impl/AutoAddReplicasEventListener.java  |  6 ++--
 .../events/impl/ClusterEventProducerImpl.java      |  2 +-
 .../java/org/apache/solr/core/CoreContainer.java   | 27 ++++++++++++++++++
 .../test/org/apache/solr/cloud/OverseerTest.java   |  4 +++
 5 files changed, 48 insertions(+), 24 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/cloud/Overseer.java b/solr/core/src/java/org/apache/solr/cloud/Overseer.java
index f35e29f..3b80371 100644
--- a/solr/core/src/java/org/apache/solr/cloud/Overseer.java
+++ b/solr/core/src/java/org/apache/solr/cloud/Overseer.java
@@ -47,6 +47,7 @@ import org.apache.solr.cloud.overseer.ReplicaMutator;
 import org.apache.solr.cloud.overseer.SliceMutator;
 import org.apache.solr.cloud.overseer.ZkStateWriter;
 import org.apache.solr.cloud.overseer.ZkWriteCommand;
+import org.apache.solr.cluster.events.ClusterEventListener;
 import org.apache.solr.common.AlreadyClosedException;
 import org.apache.solr.common.SolrCloseable;
 import org.apache.solr.common.SolrException;
@@ -66,11 +67,9 @@ import org.apache.solr.common.util.Pair;
 import org.apache.solr.common.util.Utils;
 import org.apache.solr.core.CloudConfig;
 import org.apache.solr.core.CoreContainer;
-import org.apache.solr.core.PluginBag;
 import org.apache.solr.handler.admin.CollectionsHandler;
 import org.apache.solr.handler.component.HttpShardHandler;
 import org.apache.solr.logging.MDCLoggingContext;
-import org.apache.solr.request.SolrRequestHandler;
 import org.apache.solr.update.UpdateShardHandler;
 import org.apache.zookeeper.CreateMode;
 import org.apache.zookeeper.KeeperException;
@@ -783,18 +782,14 @@ public class Overseer implements SolrCloseable {
    * Start {@link ClusterSingleton} plugins when we become the leader.
    */
   private void startClusterSingletons() {
-    PluginBag<SolrRequestHandler> handlers = getCoreContainer().getRequestHandlers();
-    if (handlers == null) {
-      return;
-    }
-    handlers.keySet().forEach(handlerName -> {
-      SolrRequestHandler handler = handlers.get(handlerName);
-      if (handler instanceof ClusterSingleton) {
-        try {
-          ((ClusterSingleton) handler).start();
-        } catch (Exception e) {
-          log.warn("Exception starting ClusterSingleton " + handler, e);
+    getCoreContainer().getContainerSingletons().forEach((name, singleton) -> {
+      try {
+        singleton.start();
+        if (singleton instanceof ClusterEventListener) {
+          getCoreContainer().getClusterEventProducer().registerListener((ClusterEventListener) singleton);
         }
+      } catch (Exception e) {
+        log.warn("Exception starting ClusterSingleton {}: {}", singleton, e);
       }
     });
   }
@@ -803,15 +798,11 @@ public class Overseer implements SolrCloseable {
    * Stop {@link ClusterSingleton} plugins when we lose leadership.
    */
   private void stopClusterSingletons() {
-    PluginBag<SolrRequestHandler> handlers = getCoreContainer().getRequestHandlers();
-    if (handlers == null) {
-      return;
-    }
-    handlers.keySet().forEach(handlerName -> {
-      SolrRequestHandler handler = handlers.get(handlerName);
-      if (handler instanceof ClusterSingleton) {
-        ((ClusterSingleton) handler).stop();
+    getCoreContainer().getContainerSingletons().forEach((name, singleton) -> {
+      if (singleton instanceof ClusterEventListener) {
+        getCoreContainer().getClusterEventProducer().unregisterListener((ClusterEventListener) singleton);
       }
+      singleton.stop();
     });
   }
 
diff --git a/solr/core/src/java/org/apache/solr/cluster/events/impl/AutoAddReplicasEventListener.java b/solr/core/src/java/org/apache/solr/cluster/events/impl/AutoAddReplicasEventListener.java
index a10b846..2fa6475 100644
--- a/solr/core/src/java/org/apache/solr/cluster/events/impl/AutoAddReplicasEventListener.java
+++ b/solr/core/src/java/org/apache/solr/cluster/events/impl/AutoAddReplicasEventListener.java
@@ -30,7 +30,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- *
+ * XXX nocommit.
+ * This is an (incomplete) illustration how to re-implement the combination of 8x
+ * NodeLostTrigger and AutoAddReplicasPlanAction to maintain the collection's replication factor.
  */
 public class AutoAddReplicasEventListener implements ClusterSingleton, ClusterEventListener {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -67,7 +69,7 @@ public class AutoAddReplicasEventListener implements ClusterSingleton, ClusterEv
         handleNodeDown(event);
         break;
       case NODE_UP:
-        // ignore?
+        // ignore? rebalance replicas?
         break;
       case REPLICA_DOWN:
         handleReplicaDown(event);
diff --git a/solr/core/src/java/org/apache/solr/cluster/events/impl/ClusterEventProducerImpl.java b/solr/core/src/java/org/apache/solr/cluster/events/impl/ClusterEventProducerImpl.java
index 9fc218c..f0ea7f1 100644
--- a/solr/core/src/java/org/apache/solr/cluster/events/impl/ClusterEventProducerImpl.java
+++ b/solr/core/src/java/org/apache/solr/cluster/events/impl/ClusterEventProducerImpl.java
@@ -63,12 +63,12 @@ public class ClusterEventProducerImpl implements ClusterEventProducer, ClusterSi
 
   public ClusterEventProducerImpl(CoreContainer coreContainer) {
     this.cc = coreContainer;
-    this.zkController = this.cc.getZkController();
   }
 
   // ClusterSingleton lifecycle methods
   @Override
   public void start() {
+    this.zkController = this.cc.getZkController();
     if (zkController == null) {
       liveNodesListener = null;
       return;
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index dd1b963..a952b7a 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -68,8 +68,11 @@ import org.apache.solr.client.solrj.impl.SolrHttpClientContextBuilder.Credential
 import org.apache.solr.client.solrj.io.SolrClientCache;
 import org.apache.solr.client.solrj.util.SolrIdentifierValidator;
 import org.apache.solr.cloud.CloudDescriptor;
+import org.apache.solr.cloud.ClusterSingleton;
 import org.apache.solr.cloud.OverseerTaskQueue;
 import org.apache.solr.cloud.ZkController;
+import org.apache.solr.cluster.events.ClusterEventProducer;
+import org.apache.solr.cluster.events.impl.ClusterEventProducerImpl;
 import org.apache.solr.common.AlreadyClosedException;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
@@ -174,6 +177,7 @@ public class CoreContainer {
   public final Supplier<SolrZkClient> zkClientSupplier = () -> getZkController().getZkClient();
 
   private final CustomContainerPlugins customContainerPlugins =  new CustomContainerPlugins(this, containerHandlers.getApiBag());
+  private final Map<String, ClusterSingleton> containerSingletons = new HashMap<>();
 
   protected final Map<String, CoreLoadFailure> coreInitFailures = new ConcurrentHashMap<>();
 
@@ -241,6 +245,8 @@ public class CoreContainer {
 
   private volatile SolrClientCache solrClientCache;
 
+  private volatile ClusterEventProducer clusterEventProducer;
+
   private final ObjectCache objectCache = new ObjectCache();
 
   private PackageStoreAPI packageStoreAPI;
@@ -885,6 +891,19 @@ public class CoreContainer {
       ContainerPluginsApi containerPluginsApi = new ContainerPluginsApi(this);
       containerHandlers.getApiBag().registerObject(containerPluginsApi.readAPI);
       containerHandlers.getApiBag().registerObject(containerPluginsApi.editAPI);
+      // create the default ClusterEventProducer
+      // XXX can we load it as a pluggable component? or configurable?
+      clusterEventProducer = new ClusterEventProducerImpl(this);
+      // register ClusterSingleton handlers
+      // XXX register also other ClusterSingleton-s from packages - how?
+      containerHandlers.keySet().forEach(handlerName -> {
+        SolrRequestHandler handler = containerHandlers.get(handlerName);
+        if (handler instanceof ClusterSingleton) {
+          containerSingletons.put(handlerName, (ClusterSingleton) handler);
+        }
+      });
+      // our default clusterEventProducer is also a ClusterSingleton
+      containerSingletons.put("clusterEventProducer", (ClusterSingleton) clusterEventProducer);
       zkSys.getZkController().checkOverseerDesignate();
     }
     // This is a bit redundant but these are two distinct concepts for all they're accomplished at the same time.
@@ -2083,6 +2102,14 @@ public class CoreContainer {
     return customContainerPlugins;
   }
 
+  public Map<String, ClusterSingleton> getContainerSingletons() {
+    return Collections.unmodifiableMap(containerSingletons);
+  }
+
+  public ClusterEventProducer getClusterEventProducer() {
+    return clusterEventProducer;
+  }
+
   static {
     ExecutorUtil.addThreadLocalProvider(SolrRequestInfo.getInheritableThreadLocalProvider());
   }
diff --git a/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java b/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
index ebb6c75..cf30ca9 100644
--- a/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/OverseerTest.java
@@ -56,6 +56,7 @@ import org.apache.solr.client.solrj.impl.SolrClientCloudManager;
 import org.apache.solr.cloud.overseer.NodeMutator;
 import org.apache.solr.cloud.overseer.OverseerAction;
 import org.apache.solr.cloud.overseer.ZkWriteCommand;
+import org.apache.solr.cluster.events.impl.ClusterEventProducerImpl;
 import org.apache.solr.common.AlreadyClosedException;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ClusterState;
@@ -1428,6 +1429,9 @@ public class OverseerTest extends SolrTestCaseJ4 {
         Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS));
     when(mockAlwaysUpCoreContainer.isShutDown()).thenReturn(testDone);  // Allow retry on session expiry
     when(mockAlwaysUpCoreContainer.getResourceLoader()).thenReturn(new SolrResourceLoader());
+    FieldSetter.setField(mockAlwaysUpCoreContainer, CoreContainer.class.getDeclaredField("containerSingletons"), Collections.emptyMap());
+    ClusterEventProducerImpl clusterEventProducer = new ClusterEventProducerImpl(mockAlwaysUpCoreContainer);
+    when(mockAlwaysUpCoreContainer.getClusterEventProducer()).thenReturn(clusterEventProducer);
     FieldSetter.setField(zkController, ZkController.class.getDeclaredField("zkClient"), zkClient);
     FieldSetter.setField(zkController, ZkController.class.getDeclaredField("cc"), mockAlwaysUpCoreContainer);
     when(zkController.getCoreContainer()).thenReturn(mockAlwaysUpCoreContainer);