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