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 2018/03/29 19:12:14 UTC
[1/2] lucene-solr:jira/solr-12095: First cut,
some test are still failing.
Repository: lucene-solr
Updated Branches:
refs/heads/jira/solr-12095 [created] 059f495e3
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeLostTrigger.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeLostTrigger.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeLostTrigger.java
index 56a8176..33c2efa 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeLostTrigger.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeLostTrigger.java
@@ -28,12 +28,15 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
import org.apache.solr.cloud.autoscaling.ActionContext;
import org.apache.solr.cloud.autoscaling.AutoScaling;
import org.apache.solr.cloud.autoscaling.NodeLostTrigger;
import org.apache.solr.cloud.autoscaling.TriggerAction;
import org.apache.solr.cloud.autoscaling.TriggerEvent;
+import org.apache.solr.cloud.autoscaling.TriggerValidationException;
import org.apache.solr.common.util.TimeSource;
+import org.apache.solr.core.SolrResourceLoader;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -75,7 +78,8 @@ public class TestNodeLostTrigger extends SimSolrCloudTestCase {
long waitForSeconds = 1 + random().nextInt(5);
Map<String, Object> props = createTriggerProps(waitForSeconds);
- try (NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger")) {
+ trigger.configure(cluster.getLoader(), cluster, props);
trigger.setProcessor(noFirstRunProcessor);
trigger.run();
Iterator<String> it = cluster.getLiveNodesSet().get().iterator();
@@ -120,7 +124,8 @@ public class TestNodeLostTrigger extends SimSolrCloudTestCase {
// remove a node but add it back before the waitFor period expires
// and assert that the trigger doesn't fire at all
- try (NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger")) {
+ trigger.configure(cluster.getLoader(), cluster, props);
final long waitTime = 2;
props.put("waitFor", waitTime);
trigger.setProcessor(noFirstRunProcessor);
@@ -175,7 +180,8 @@ public class TestNodeLostTrigger extends SimSolrCloudTestCase {
action.put("name", "testActionInit");
action.put("class", AssertInitTriggerAction.class.getName());
actions.add(action);
- try (NodeLostTrigger trigger = new NodeLostTrigger("node_added_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeLostTrigger trigger = new NodeLostTrigger("node_added_trigger")) {
+ trigger.configure(cluster.getLoader(), cluster, props);
assertEquals(true, actionConstructorCalled.get());
assertEquals(false, actionInitCalled.get());
assertEquals(false, actionCloseCalled.get());
@@ -192,6 +198,16 @@ public class TestNodeLostTrigger extends SimSolrCloudTestCase {
}
@Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+
+ }
+
+ @Override
+ public void init() {
+ actionInitCalled.compareAndSet(false, true);
+ }
+
+ @Override
public String getName() {
return "";
}
@@ -205,17 +221,13 @@ public class TestNodeLostTrigger extends SimSolrCloudTestCase {
public void close() throws IOException {
actionCloseCalled.compareAndSet(false, true);
}
-
- @Override
- public void init(Map<String, String> args) {
- actionInitCalled.compareAndSet(false, true);
- }
}
@Test
public void testListenerAcceptance() throws Exception {
Map<String, Object> props = createTriggerProps(0);
- try (NodeLostTrigger trigger = new NodeLostTrigger("node_added_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeLostTrigger trigger = new NodeLostTrigger("node_added_trigger")) {
+ trigger.configure(cluster.getLoader(), cluster, props);
trigger.setProcessor(noFirstRunProcessor);
String newNode = cluster.simAddNode();
@@ -258,7 +270,8 @@ public class TestNodeLostTrigger extends SimSolrCloudTestCase {
// remove a node but update the trigger before the waitFor period expires
// and assert that the new trigger still fires
- NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger", props, cluster.getLoader(), cluster);
+ NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger");
+ trigger.configure(cluster.getLoader(), cluster, props);
trigger.setProcessor(noFirstRunProcessor);
trigger.run();
@@ -268,7 +281,8 @@ public class TestNodeLostTrigger extends SimSolrCloudTestCase {
trigger.run(); // this run should detect the lost node
trigger.close(); // close the old trigger
- try (NodeLostTrigger newTrigger = new NodeLostTrigger("some_different_name", props, cluster.getLoader(), cluster)) {
+ try (NodeLostTrigger newTrigger = new NodeLostTrigger("some_different_name")) {
+ newTrigger.configure(cluster.getLoader(), cluster, props);
try {
newTrigger.restoreState(trigger);
fail("Trigger should only be able to restore state from an old trigger of the same name");
@@ -277,7 +291,8 @@ public class TestNodeLostTrigger extends SimSolrCloudTestCase {
}
}
- try (NodeLostTrigger newTrigger = new NodeLostTrigger("node_lost_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeLostTrigger newTrigger = new NodeLostTrigger("node_lost_trigger")) {
+ newTrigger.configure(cluster.getLoader(), cluster, props);
AtomicBoolean fired = new AtomicBoolean(false);
AtomicReference<TriggerEvent> eventRef = new AtomicReference<>();
newTrigger.setProcessor(event -> {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java
index 974e672..7a4e2f6 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestTriggerIntegration.java
@@ -51,10 +51,12 @@ import org.apache.solr.cloud.autoscaling.TriggerEvent;
import org.apache.solr.cloud.autoscaling.TriggerEventQueue;
import org.apache.solr.cloud.autoscaling.TriggerListenerBase;
import org.apache.solr.cloud.autoscaling.CapturedEvent;
+import org.apache.solr.cloud.autoscaling.TriggerValidationException;
import org.apache.solr.common.cloud.LiveNodesListener;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.TimeSource;
+import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.util.LogLevel;
import org.apache.solr.util.TimeOut;
import org.junit.Before;
@@ -569,11 +571,12 @@ public class TestTriggerIntegration extends SimSolrCloudTestCase {
}
@Override
- public void init(Map<String, String> args) {
+ public void init() throws Exception {
log.info("TestTriggerAction init");
+ super.init();
actionInitCalled.countDown();
- super.init(args);
}
+
}
public static class TestEventQueueAction extends TriggerActionBase {
@@ -598,10 +601,10 @@ public class TestTriggerIntegration extends SimSolrCloudTestCase {
}
@Override
- public void init(Map<String, String> args) {
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> args) throws TriggerValidationException {
log.debug("TestTriggerAction init");
actionInitCalled.countDown();
- super.init(args);
+ super.configure(loader, cloudManager, args);
}
}
@@ -759,10 +762,10 @@ public class TestTriggerIntegration extends SimSolrCloudTestCase {
}
@Override
- public void init(Map<String, String> args) {
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> args) throws TriggerValidationException {
log.info("TestEventMarkerAction init");
actionInitCalled.countDown();
- super.init(args);
+ super.configure(loader, cloudManager, args);
}
}
[2/2] lucene-solr:jira/solr-12095: First cut,
some test are still failing.
Posted by ab...@apache.org.
First cut, some test are still failing.
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/059f495e
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/059f495e
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/059f495e
Branch: refs/heads/jira/solr-12095
Commit: 059f495e3765e164cc330dd6ac1cf6dd6a5e6e1f
Parents: 668b817
Author: Andrzej Bialecki <ab...@apache.org>
Authored: Thu Mar 29 21:11:31 2018 +0200
Committer: Andrzej Bialecki <ab...@apache.org>
Committed: Thu Mar 29 21:11:31 2018 +0200
----------------------------------------------------------------------
.../solr/cloud/autoscaling/AutoScaling.java | 40 +++++++--
.../cloud/autoscaling/AutoScalingHandler.java | 18 ++++
.../cloud/autoscaling/ComputePlanAction.java | 8 +-
.../autoscaling/InactiveShardPlanAction.java | 7 +-
.../solr/cloud/autoscaling/MetricTrigger.java | 22 +++--
.../cloud/autoscaling/NodeAddedTrigger.java | 22 ++---
.../solr/cloud/autoscaling/NodeLostTrigger.java | 20 ++---
.../autoscaling/OverseerTriggerThread.java | 12 ++-
.../cloud/autoscaling/ScheduledTrigger.java | 37 ++++----
.../cloud/autoscaling/ScheduledTriggers.java | 2 +-
.../cloud/autoscaling/SearchRateTrigger.java | 28 +++----
.../solr/cloud/autoscaling/TriggerAction.java | 24 +++++-
.../cloud/autoscaling/TriggerActionBase.java | 41 +++++++--
.../solr/cloud/autoscaling/TriggerBase.java | 60 ++++++++-----
.../solr/cloud/autoscaling/TriggerUtils.java | 88 ++++++++++++++++++++
.../autoscaling/TriggerValidationException.java | 68 +++++++++++++++
.../autoscaling/ComputePlanActionTest.java | 16 ++--
.../autoscaling/ExecutePlanActionTest.java | 9 +-
.../cloud/autoscaling/MetricTriggerTest.java | 6 +-
.../cloud/autoscaling/NodeAddedTriggerTest.java | 45 +++++-----
.../cloud/autoscaling/NodeLostTriggerTest.java | 44 ++++++----
.../cloud/autoscaling/ScheduledTriggerTest.java | 12 +--
.../autoscaling/SearchRateTriggerTest.java | 4 +-
.../autoscaling/TriggerIntegrationTest.java | 31 ++++---
.../autoscaling/sim/TestComputePlanAction.java | 18 ++--
.../autoscaling/sim/TestExecutePlanAction.java | 2 +-
.../autoscaling/sim/TestNodeAddedTrigger.java | 43 +++++++---
.../autoscaling/sim/TestNodeLostTrigger.java | 39 ++++++---
.../autoscaling/sim/TestTriggerIntegration.java | 15 ++--
29 files changed, 581 insertions(+), 200 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java
index a3a9aa8..68282a7 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java
@@ -106,10 +106,19 @@ public class AutoScaling {
void restoreState();
/**
+ * Called when trigger is created but before it's initialized or scheduled for use.
+ * This method should also verify that the trigger configuration parameters are correct. It may
+ * be called multiple times.
+ * @param properties configuration properties
+ * @throws TriggerValidationException contains details of invalid configuration parameters.
+ */
+ void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException;
+
+ /**
* Called before a trigger is scheduled. Any heavy object creation or initialisation should
* be done in this method instead of the Trigger's constructor.
*/
- void init();
+ void init() throws Exception;
}
/**
@@ -118,7 +127,7 @@ public class AutoScaling {
public static abstract class TriggerFactory implements Closeable {
protected boolean isClosed = false;
- public abstract Trigger create(TriggerEventType type, String name, Map<String, Object> props);
+ public abstract Trigger create(TriggerEventType type, String name, Map<String, Object> props) throws TriggerValidationException;
@Override
public void close() throws IOException {
@@ -144,24 +153,38 @@ public class AutoScaling {
}
@Override
- public synchronized Trigger create(TriggerEventType type, String name, Map<String, Object> props) {
+ public synchronized Trigger create(TriggerEventType type, String name, Map<String, Object> props) throws TriggerValidationException {
if (isClosed) {
throw new AlreadyClosedException("TriggerFactory has already been closed, cannot create new triggers");
}
+ if (type == null) {
+ throw new IllegalArgumentException("Trigger type must not be null");
+ }
+ if (name == null || name.isEmpty()) {
+ throw new IllegalArgumentException("Trigger name must not be empty");
+ }
+ Trigger t;
switch (type) {
case NODEADDED:
- return new NodeAddedTrigger(name, props, loader, cloudManager);
+ t = new NodeAddedTrigger(name);
+ break;
case NODELOST:
- return new NodeLostTrigger(name, props, loader, cloudManager);
+ t = new NodeLostTrigger(name);
+ break;
case SEARCHRATE:
- return new SearchRateTrigger(name, props, loader, cloudManager);
+ t = new SearchRateTrigger(name);
+ break;
case METRIC:
- return new MetricTrigger(name, props, loader, cloudManager);
+ t = new MetricTrigger(name);
+ break;
case SCHEDULED:
- return new ScheduledTrigger(name, props, loader, cloudManager);
+ t = new ScheduledTrigger(name);
+ break;
default:
throw new IllegalArgumentException("Unknown event type: " + type + " in trigger: " + name);
}
+ t.configure(loader, cloudManager, props);
+ return t;
}
}
@@ -210,4 +233,5 @@ public class AutoScaling {
" }";
public static final Map<String, Object> SCHEDULED_MAINTENANCE_TRIGGER_PROPS = (Map) Utils.fromJSONString(SCHEDULED_MAINTENANCE_TRIGGER_DSL);
+
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
index 5126e2e..f93a828 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
@@ -50,6 +50,7 @@ import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.AutoScalingParams;
import org.apache.solr.common.params.CollectionAdminParams;
import org.apache.solr.common.util.CommandOperation;
+import org.apache.solr.common.util.IOUtils;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.common.util.Utils;
import org.apache.solr.core.SolrResourceLoader;
@@ -79,6 +80,7 @@ public class AutoScalingHandler extends RequestHandlerBase implements Permission
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected final SolrCloudManager cloudManager;
protected final SolrResourceLoader loader;
+ protected final AutoScaling.TriggerFactory triggerFactory;
private final List<Map<String, String>> DEFAULT_ACTIONS = new ArrayList<>(3);
private static Set<String> singletonCommands = Stream.of("set-cluster-preferences", "set-cluster-policy")
.collect(collectingAndThen(toSet(), Collections::unmodifiableSet));
@@ -88,6 +90,7 @@ public class AutoScalingHandler extends RequestHandlerBase implements Permission
public AutoScalingHandler(SolrCloudManager cloudManager, SolrResourceLoader loader) {
this.cloudManager = cloudManager;
this.loader = loader;
+ this.triggerFactory = new AutoScaling.TriggerFactoryImpl(loader, cloudManager);
this.timeSource = cloudManager.getTimeSource();
Map<String, String> map = new HashMap<>(2);
map.put(NAME, "compute_plan");
@@ -531,6 +534,21 @@ public class AutoScalingHandler extends RequestHandlerBase implements Permission
}
}
AutoScalingConfig.TriggerConfig trigger = new AutoScalingConfig.TriggerConfig(triggerName, opCopy.getValuesExcluding("name"));
+ // validate trigger config
+ AutoScaling.Trigger t = null;
+ try {
+ t = triggerFactory.create(trigger.event, trigger.name, trigger.properties);
+ } catch (TriggerValidationException e) {
+ op.addError("Error validating trigger config " + trigger.name + ": " + e.getDetails());
+ return currentConfig;
+ } catch (Exception e) {
+ op.addError("Error validating trigger config " + trigger.name + ": " + e.toString());
+ return currentConfig;
+ } finally {
+ if (t != null) {
+ IOUtils.closeQuietly(t);
+ }
+ }
currentConfig = currentConfig.withTriggerConfig(trigger);
// check that there's a default SystemLogListener, unless user specified another one
return withSystemLogListener(currentConfig, triggerName);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java
index dc3cfd5..55f432c 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java
@@ -40,6 +40,7 @@ import org.apache.solr.common.params.AutoScalingParams;
import org.apache.solr.common.params.CollectionParams;
import org.apache.solr.common.params.CoreAdminParams;
import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.core.SolrResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -55,10 +56,11 @@ public class ComputePlanAction extends TriggerActionBase {
Set<String> collections = new HashSet<>();
+
@Override
- public void init(Map<String, String> args) {
- super.init(args);
- String colString = args.get("collections");
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+ super.configure(loader, cloudManager, properties);
+ String colString = (String) properties.get("collections");
if (colString != null && !colString.isEmpty()) {
collections.addAll(StrUtils.splitSmart(colString, ','));
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java
index 5e962a8..2cbe487 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/InactiveShardPlanAction.java
@@ -29,6 +29,7 @@ import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.core.SolrResourceLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,9 +50,9 @@ public class InactiveShardPlanAction extends TriggerActionBase {
private int cleanupTTL;
@Override
- public void init(Map<String, String> args) {
- super.init(args);
- String cleanupStr = args.getOrDefault(TTL_PROP, String.valueOf(DEFAULT_TTL_SECONDS));
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+ super.configure(loader, cloudManager, properties);
+ String cleanupStr = String.valueOf(properties.getOrDefault(TTL_PROP, String.valueOf(DEFAULT_TTL_SECONDS)));
try {
cleanupTTL = Integer.parseInt(cleanupStr);
} catch (Exception e) {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/MetricTrigger.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/MetricTrigger.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/MetricTrigger.java
index e0dd253..9fdf8dc 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/MetricTrigger.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/MetricTrigger.java
@@ -53,21 +53,31 @@ import static org.apache.solr.common.params.AutoScalingParams.PREFERRED_OP;
public class MetricTrigger extends TriggerBase {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private final String metric;
- private final Number above, below;
- private final String collection, shard, node, preferredOp;
+ private String metric;
+ private Number above, below;
+ private String collection, shard, node, preferredOp;
private final Map<String, Long> lastNodeEvent = new ConcurrentHashMap<>();
- public MetricTrigger(String name, Map<String, Object> properties, SolrResourceLoader loader, SolrCloudManager cloudManager) {
- super(TriggerEventType.METRIC, name, properties, loader, cloudManager);
+ public MetricTrigger(String name) {
+ super(TriggerEventType.METRIC, name);
+ TriggerUtils.requiredProperties(requiredProperties, validProperties, METRIC);
+ TriggerUtils.validProperties(validProperties, ABOVE, BELOW, PREFERRED_OP,
+ AutoScalingParams.COLLECTION,
+ AutoScalingParams.SHARD,
+ AutoScalingParams.NODE);
+ }
+
+ @Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+ super.configure(loader, cloudManager, properties);
this.metric = (String) properties.get(METRIC);
this.above = (Number) properties.get(ABOVE);
this.below = (Number) properties.get(BELOW);
this.collection = (String) properties.getOrDefault(AutoScalingParams.COLLECTION, Policy.ANY);
shard = (String) properties.getOrDefault(AutoScalingParams.SHARD, Policy.ANY);
if (collection.equals(Policy.ANY) && !shard.equals(Policy.ANY)) {
- throw new IllegalArgumentException("When 'shard' is other than #ANY then collection name must be also other than #ANY");
+ throw new TriggerValidationException("shard", "When 'shard' is other than #ANY then collection name must be also other than #ANY");
}
node = (String) properties.getOrDefault(AutoScalingParams.NODE, Policy.ANY);
preferredOp = (String) properties.getOrDefault(PREFERRED_OP, CollectionParams.CollectionAction.MOVEREPLICA.toLower());
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java
index ad89f2a..d83f8b9 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeAddedTrigger.java
@@ -44,22 +44,20 @@ import org.slf4j.LoggerFactory;
public class NodeAddedTrigger extends TriggerBase {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private Set<String> lastLiveNodes;
+ private Set<String> lastLiveNodes = new HashSet<>();
private Map<String, Long> nodeNameVsTimeAdded = new HashMap<>();
- public NodeAddedTrigger(String name, Map<String, Object> properties,
- SolrResourceLoader loader,
- SolrCloudManager cloudManager) {
- super(TriggerEventType.NODEADDED, name, properties, loader, cloudManager);
- lastLiveNodes = new HashSet<>(cloudManager.getClusterStateProvider().getLiveNodes());
- log.debug("Initial livenodes: {}", lastLiveNodes);
- log.debug("NodeAddedTrigger {} instantiated with properties: {}", name, properties);
+ public NodeAddedTrigger(String name) {
+ super(TriggerEventType.NODEADDED, name);
}
@Override
- public void init() {
+ public void init() throws Exception {
super.init();
+ lastLiveNodes = new HashSet<>(cloudManager.getClusterStateProvider().getLiveNodes());
+ log.debug("Initial livenodes: {}", lastLiveNodes);
+ log.debug("NodeAddedTrigger {} instantiated with properties: {}", name, properties);
// pick up added nodes for which marker paths were created
try {
List<String> added = stateManager.listData(ZkStateReader.SOLR_AUTOSCALING_NODE_ADDED_PATH);
@@ -85,8 +83,10 @@ public class NodeAddedTrigger extends TriggerBase {
if (old instanceof NodeAddedTrigger) {
NodeAddedTrigger that = (NodeAddedTrigger) old;
assert this.name.equals(that.name);
- this.lastLiveNodes = new HashSet<>(that.lastLiveNodes);
- this.nodeNameVsTimeAdded = new HashMap<>(that.nodeNameVsTimeAdded);
+ this.lastLiveNodes.clear();
+ this.lastLiveNodes.addAll(that.lastLiveNodes);
+ this.nodeNameVsTimeAdded.clear();
+ this.nodeNameVsTimeAdded.putAll(that.nodeNameVsTimeAdded);
} else {
throw new SolrException(SolrException.ErrorCode.INVALID_STATE,
"Unable to restore state from an unknown type of trigger");
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeLostTrigger.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeLostTrigger.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeLostTrigger.java
index 1e7aec5..5bf243f 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeLostTrigger.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/NodeLostTrigger.java
@@ -43,21 +43,19 @@ import org.slf4j.LoggerFactory;
public class NodeLostTrigger extends TriggerBase {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private Set<String> lastLiveNodes;
+ private Set<String> lastLiveNodes = new HashSet<>();
private Map<String, Long> nodeNameVsTimeRemoved = new HashMap<>();
- public NodeLostTrigger(String name, Map<String, Object> properties,
- SolrResourceLoader loader,
- SolrCloudManager dataProvider) {
- super(TriggerEventType.NODELOST, name, properties, loader, dataProvider);
- lastLiveNodes = new HashSet<>(dataProvider.getClusterStateProvider().getLiveNodes());
- log.debug("Initial livenodes: {}", lastLiveNodes);
+ public NodeLostTrigger(String name) {
+ super(TriggerEventType.NODELOST, name);
}
@Override
- public void init() {
+ public void init() throws Exception {
super.init();
+ lastLiveNodes = new HashSet<>(cloudManager.getClusterStateProvider().getLiveNodes());
+ log.debug("Initial livenodes: {}", lastLiveNodes);
// pick up lost nodes for which marker paths were created
try {
List<String> lost = stateManager.listData(ZkStateReader.SOLR_AUTOSCALING_NODE_LOST_PATH);
@@ -82,8 +80,10 @@ public class NodeLostTrigger extends TriggerBase {
if (old instanceof NodeLostTrigger) {
NodeLostTrigger that = (NodeLostTrigger) old;
assert this.name.equals(that.name);
- this.lastLiveNodes = new HashSet<>(that.lastLiveNodes);
- this.nodeNameVsTimeRemoved = new HashMap<>(that.nodeNameVsTimeRemoved);
+ this.lastLiveNodes.clear();
+ this.lastLiveNodes.addAll(that.lastLiveNodes);
+ this.nodeNameVsTimeRemoved.clear();
+ this.nodeNameVsTimeRemoved.putAll(that.nodeNameVsTimeRemoved);
} else {
throw new SolrException(SolrException.ErrorCode.INVALID_STATE,
"Unable to restore state from an unknown type of trigger");
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/OverseerTriggerThread.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/OverseerTriggerThread.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/OverseerTriggerThread.java
index f97372d..d3fc5b6 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/OverseerTriggerThread.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/OverseerTriggerThread.java
@@ -226,7 +226,11 @@ public class OverseerTriggerThread implements Runnable, SolrCloseable {
if (entry.getValue().getEventType().equals(TriggerEventType.NODEADDED)) {
cleanOldNodeAddedMarkers = false;
}
- scheduledTriggers.add(entry.getValue());
+ try {
+ scheduledTriggers.add(entry.getValue());
+ } catch (Exception e) {
+ log.warn("Exception initializing trigger " + entry.getKey() + ", configuration ignored", e);
+ }
}
} catch (AlreadyClosedException e) {
// this _should_ mean that we're closing, complain loudly if that's not the case
@@ -378,7 +382,11 @@ public class OverseerTriggerThread implements Runnable, SolrCloseable {
AutoScalingConfig.TriggerConfig cfg = entry.getValue();
TriggerEventType eventType = cfg.event;
String triggerName = entry.getKey();
- triggerMap.put(triggerName, triggerFactory.create(eventType, triggerName, cfg.properties));
+ try {
+ triggerMap.put(triggerName, triggerFactory.create(eventType, triggerName, cfg.properties));
+ } catch (TriggerValidationException e) {
+ log.warn("Error in trigger '" + triggerName + "' configuration, trigger config ignored: " + cfg, e);
+ }
}
return triggerMap;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTrigger.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTrigger.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTrigger.java
index bbc9c30..5e25542 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTrigger.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTrigger.java
@@ -33,6 +33,7 @@ import java.util.concurrent.TimeUnit;
import org.apache.solr.client.solrj.cloud.SolrCloudManager;
import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventType;
import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.AutoScalingParams;
import org.apache.solr.common.util.TimeSource;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.util.DateMathParser;
@@ -52,20 +53,25 @@ public class ScheduledTrigger extends TriggerBase {
private static final String LAST_RUN_AT = "lastRunAt";
static final String ACTUAL_EVENT_TIME = "actualEventTime";
- private final String everyStr;
+ private String everyStr;
- private final String graceDurationStr;
+ private String graceDurationStr;
- private final String preferredOp;
+ private String preferredOp;
- private final TimeZone timeZone;
+ private TimeZone timeZone;
private Instant lastRunAt;
- public ScheduledTrigger(String name, Map<String, Object> properties,
- SolrResourceLoader loader, SolrCloudManager cloudManager) {
- super(TriggerEventType.SCHEDULED, name, properties, loader, cloudManager);
+ public ScheduledTrigger(String name) {
+ super(TriggerEventType.SCHEDULED, name);
+ TriggerUtils.requiredProperties(requiredProperties, validProperties, "startTime");
+ TriggerUtils.validProperties(validProperties, "timeZone", "every", "graceDuration", AutoScalingParams.PREFERRED_OP);
+ }
+ @Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+ super.configure(loader, cloudManager, properties);
String timeZoneStr = (String) properties.get("timeZone");
this.timeZone = TimeZoneUtils.parseTimezone(timeZoneStr); // defaults to UTC
@@ -90,18 +96,17 @@ public class ScheduledTrigger extends TriggerBase {
this.lastRunAt = startTime;
}
- private Instant parseStartTime(Date now, String startTimeStr, String timeZoneStr) {
- if (startTimeStr == null) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Parameter 'startTime' cannot be null");
- }
+ private Instant parseStartTime(Date now, String startTimeStr, String timeZoneStr) throws TriggerValidationException {
try {
// try parsing startTime as an ISO-8601 date time string
return DateMathParser.parseMath(now, startTimeStr).toInstant();
} catch (SolrException e) {
- if (e.code() != SolrException.ErrorCode.BAD_REQUEST.code) throw e;
+ if (e.code() != SolrException.ErrorCode.BAD_REQUEST.code) {
+ throw new TriggerValidationException("startTime", "error parsing value '" + startTimeStr + "': " + e.toString());
+ }
}
if (timeZoneStr == null) {
- throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+ throw new TriggerValidationException("timeZone",
"Either 'startTime' should be an ISO-8601 date time string or 'timeZone' must be not be null");
}
TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr);
@@ -111,7 +116,11 @@ public class ScheduledTrigger extends TriggerBase {
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.toFormatter(Locale.ROOT).withZone(timeZone.toZoneId());
- return Instant.from(dateTimeFormatter.parse(startTimeStr));
+ try {
+ return Instant.from(dateTimeFormatter.parse(startTimeStr));
+ } catch (Exception e) {
+ throw new TriggerValidationException("startTime", "error parsing startTime '" + startTimeStr + "': " + e.toString());
+ }
}
@Override
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
index 0e21b04..983b8a5 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ScheduledTriggers.java
@@ -196,7 +196,7 @@ public class ScheduledTriggers implements Closeable {
* @param newTrigger the trigger to be managed
* @throws AlreadyClosedException if this class has already been closed
*/
- public synchronized void add(AutoScaling.Trigger newTrigger) {
+ public synchronized void add(AutoScaling.Trigger newTrigger) throws Exception {
if (isClosed) {
throw new AlreadyClosedException("ScheduledTriggers has been closed and cannot be used anymore");
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java
index 814c676..ffe7ba1 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/SearchRateTrigger.java
@@ -49,43 +49,43 @@ import org.slf4j.LoggerFactory;
public class SearchRateTrigger extends TriggerBase {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private final String handler;
- private final String collection;
- private final String shard;
- private final String node;
- private final double rate;
+ private String handler;
+ private String collection;
+ private String shard;
+ private String node;
+ private double rate;
private final Map<String, Long> lastCollectionEvent = new ConcurrentHashMap<>();
private final Map<String, Long> lastNodeEvent = new ConcurrentHashMap<>();
private final Map<String, Long> lastShardEvent = new ConcurrentHashMap<>();
private final Map<String, Long> lastReplicaEvent = new ConcurrentHashMap<>();
private final Map<String, Object> state = new HashMap<>();
- public SearchRateTrigger(String name, Map<String, Object> properties,
- SolrResourceLoader loader,
- SolrCloudManager cloudManager) {
- super(TriggerEventType.SEARCHRATE, name, properties, loader, cloudManager);
+ public SearchRateTrigger(String name) {
+ super(TriggerEventType.SEARCHRATE, name);
this.state.put("lastCollectionEvent", lastCollectionEvent);
this.state.put("lastNodeEvent", lastNodeEvent);
this.state.put("lastShardEvent", lastShardEvent);
this.state.put("lastReplicaEvent", lastReplicaEvent);
+ TriggerUtils.requiredProperties(requiredProperties, validProperties, "rate");
+ }
+ @Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+ super.configure(loader, cloudManager, properties);
// parse config options
collection = (String)properties.getOrDefault(AutoScalingParams.COLLECTION, Policy.ANY);
shard = (String)properties.getOrDefault(AutoScalingParams.SHARD, Policy.ANY);
if (collection.equals(Policy.ANY) && !shard.equals(Policy.ANY)) {
- throw new IllegalArgumentException("When 'shard' is other than #ANY then collection name must be also other than #ANY");
+ throw new TriggerValidationException("shard", "When 'shard' is other than #ANY then collection name must be also other than #ANY");
}
node = (String)properties.getOrDefault(AutoScalingParams.NODE, Policy.ANY);
handler = (String)properties.getOrDefault(AutoScalingParams.HANDLER, "/select");
- if (properties.get("rate") == null) {
- throw new IllegalArgumentException("No 'rate' specified in configuration");
- }
String rateString = String.valueOf(properties.get("rate"));
try {
rate = Double.parseDouble(rateString);
} catch (Exception e) {
- throw new IllegalArgumentException("Invalid 'rate' configuration value: '" + rateString + "'", e);
+ throw new TriggerValidationException("rate", "Invalid 'rate' configuration value: '" + rateString + "': " + e.toString());
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerAction.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerAction.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerAction.java
index df2022e..b873ee6 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerAction.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerAction.java
@@ -18,13 +18,33 @@
package org.apache.solr.cloud.autoscaling;
import java.io.Closeable;
+import java.util.Map;
-import org.apache.solr.util.plugin.MapInitializedPlugin;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
+import org.apache.solr.core.SolrResourceLoader;
/**
* Interface for actions performed in response to a trigger being activated
*/
-public interface TriggerAction extends MapInitializedPlugin, Closeable {
+public interface TriggerAction extends Closeable {
+
+ /**
+ * Called when action is created but before it's initialized and used.
+ * This method should also verify that the configuration parameters are correct.
+ * It may be called multiple times.
+ * @param loader loader to use for instantiating sub-components
+ * @param cloudManager current instance of SolrCloudManager
+ * @param properties configuration properties
+ * @throws TriggerValidationException contains details of invalid configuration parameters.
+ */
+ void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException;
+
+ /**
+ * Called before an action is first used. Any heavy object creation or initialization should
+ * be done in this method instead of the constructor or {@link #configure(SolrResourceLoader, SolrCloudManager, Map)} method.
+ */
+ void init() throws Exception;
+
String getName();
void process(TriggerEvent event, ActionContext context) throws Exception;
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java
index 75c4a87..ee2ce3c 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerActionBase.java
@@ -17,19 +17,35 @@
package org.apache.solr.cloud.autoscaling;
import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
+
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
+import org.apache.solr.core.SolrResourceLoader;
/**
* Base class for {@link TriggerAction} implementations.
*/
public abstract class TriggerActionBase implements TriggerAction {
- protected Map<String, String> initArgs;
+ protected Map<String, Object> properties = new HashMap<>();
+ protected SolrResourceLoader loader;
+ protected SolrCloudManager cloudManager;
+ protected final Set<String> validProperties = new HashSet<>();
+ protected final Set<String> requiredProperties = new HashSet<>();
+
+ protected TriggerActionBase() {
+ TriggerUtils.validProperties(validProperties, "name");
+ TriggerUtils.requiredProperties(requiredProperties, validProperties, "class");
+ }
@Override
public String getName() {
- if (initArgs != null) {
- return initArgs.get("name");
+ String name = (String) properties.get("name");
+ if (name != null) {
+ return name;
} else {
return getClass().getSimpleName();
}
@@ -41,7 +57,22 @@ public abstract class TriggerActionBase implements TriggerAction {
}
@Override
- public void init(Map<String, String> args) {
- this.initArgs = args;
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+ this.loader = loader;
+ this.cloudManager = cloudManager;
+ if (properties != null) {
+ this.properties.putAll(properties);
+ }
+ // validate the config
+ Map<String, String> results = new HashMap<>();
+ TriggerUtils.checkProperties(this.properties, results, requiredProperties, validProperties);
+ if (!results.isEmpty()) {
+ throw new TriggerValidationException(results);
+ }
+ }
+
+ @Override
+ public void init() throws Exception {
+
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java
index 04fa37e..c03557f 100644
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerBase.java
@@ -21,9 +21,11 @@ import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.lucene.util.IOUtils;
@@ -50,39 +52,66 @@ public abstract class TriggerBase implements AutoScaling.Trigger {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected final String name;
- protected final SolrCloudManager cloudManager;
- protected final DistribStateManager stateManager;
+ protected SolrCloudManager cloudManager;
+ protected SolrResourceLoader loader;
+ protected DistribStateManager stateManager;
protected final Map<String, Object> properties = new HashMap<>();
+ protected final Set<String> validProperties = new HashSet<>();
+ protected final Set<String> requiredProperties = new HashSet<>();
protected final TriggerEventType eventType;
- protected final int waitForSecond;
+ protected int waitForSecond;
protected Map<String,Object> lastState;
protected final AtomicReference<AutoScaling.TriggerEventProcessor> processorRef = new AtomicReference<>();
- protected final List<TriggerAction> actions;
- protected final boolean enabled;
+ protected List<TriggerAction> actions;
+ protected boolean enabled;
protected boolean isClosed;
- protected TriggerBase(TriggerEventType eventType, String name, Map<String, Object> properties, SolrResourceLoader loader, SolrCloudManager cloudManager) {
+ protected TriggerBase(TriggerEventType eventType, String name) {
this.eventType = eventType;
this.name = name;
+
+ // subclasses may modify this set to include other supported properties
+ TriggerUtils.validProperties(validProperties, "name", "event", "enabled", "waitFor", "actions");
+ }
+
+ @Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
this.cloudManager = cloudManager;
+ this.loader = loader;
this.stateManager = cloudManager.getDistribStateManager();
if (properties != null) {
this.properties.putAll(properties);
}
this.enabled = Boolean.parseBoolean(String.valueOf(this.properties.getOrDefault("enabled", "true")));
this.waitForSecond = ((Number) this.properties.getOrDefault("waitFor", -1L)).intValue();
- List<Map<String, String>> o = (List<Map<String, String>>) properties.get("actions");
+ List<Map<String, Object>> o = (List<Map<String, Object>>) properties.get("actions");
if (o != null && !o.isEmpty()) {
actions = new ArrayList<>(3);
- for (Map<String, String> map : o) {
- TriggerAction action = loader.newInstance(map.get("class"), TriggerAction.class);
+ for (Map<String, Object> map : o) {
+ TriggerAction action = null;
+ try {
+ action = loader.newInstance((String)map.get("class"), TriggerAction.class);
+ } catch (Exception e) {
+ throw new TriggerValidationException("action", "exception creating action " + map + ": " + e.toString());
+ }
+ action.configure(loader, cloudManager, map);
actions.add(action);
}
} else {
actions = Collections.emptyList();
}
+
+ Map<String, String> results = new HashMap<>();
+ TriggerUtils.checkProperties(this.properties, results, requiredProperties, validProperties);
+ if (!results.isEmpty()) {
+ throw new TriggerValidationException(results);
+ }
+ }
+
+ @Override
+ public void init() throws Exception {
try {
if (!stateManager.hasData(ZkStateReader.SOLR_AUTOSCALING_TRIGGER_STATE_PATH)) {
stateManager.makePath(ZkStateReader.SOLR_AUTOSCALING_TRIGGER_STATE_PATH);
@@ -91,17 +120,10 @@ public abstract class TriggerBase implements AutoScaling.Trigger {
// ignore
} catch (InterruptedException | KeeperException | IOException e) {
LOG.warn("Exception checking ZK path " + ZkStateReader.SOLR_AUTOSCALING_TRIGGER_STATE_PATH, e);
+ throw e;
}
- }
-
- @Override
- public void init() {
- List<Map<String, String>> o = (List<Map<String, String>>) properties.get("actions");
- if (o != null && !o.isEmpty()) {
- for (int i = 0; i < o.size(); i++) {
- Map<String, String> map = o.get(i);
- actions.get(i).init(map);
- }
+ for (TriggerAction action : actions) {
+ action.init();
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerUtils.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerUtils.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerUtils.java
new file mode 100644
index 0000000..bdc0c11
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.autoscaling;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *
+ */
+public class TriggerUtils {
+ // validation helper methods
+
+ public static void requiredProperties(Set<String> required, Set<String> valid, String... propertyNames) {
+ required.addAll(Arrays.asList(propertyNames));
+ valid.addAll(Arrays.asList(propertyNames));
+ }
+
+ public static void validProperties(Set<String> valid, String... propertyNames) {
+ valid.addAll(Arrays.asList(propertyNames));
+ }
+
+ public static void checkProperties(Map<String, Object> properties, Map<String, String> results, Set<String> required, Set<String> valid) {
+ checkValidPropertyNames(properties, results, valid);
+ checkRequiredPropertyNames(properties, results, required);
+ }
+
+ public static void checkValidPropertyNames(Map<String, Object> properties, Map<String, String> results, Set<String> valid) {
+ Set<String> currentNames = new HashSet<>(properties.keySet());
+ currentNames.removeAll(valid);
+ if (!currentNames.isEmpty()) {
+ for (String name : currentNames) {
+ results.put(name, "unknown property");
+ }
+ }
+ }
+
+ public static void checkRequiredPropertyNames(Map<String, Object> properties, Map<String, String> results, Set<String> required) {
+ Set<String> requiredNames = new HashSet<>(required);
+ requiredNames.removeAll(properties.keySet());
+ if (!requiredNames.isEmpty()) {
+ for (String name : requiredNames) {
+ results.put(name, "missing required property");
+ }
+ }
+ }
+
+ public static void checkProperty(Map<String, Object> properties, Map<String, String> results, String name, boolean required, Class... acceptClasses) {
+ Object value = properties.get(name);
+ if (value == null) {
+ if (required) {
+ results.put(name, "missing required value");
+ } else {
+ return;
+ }
+ }
+ if (acceptClasses == null || acceptClasses.length == 0) {
+ return;
+ }
+ boolean accepted = false;
+ for (Class clz : acceptClasses) {
+ if (clz.isAssignableFrom(value.getClass())) {
+ accepted = true;
+ break;
+ }
+ }
+ if (!accepted) {
+ results.put(name, "value is not an expected type");
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerValidationException.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerValidationException.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerValidationException.java
new file mode 100644
index 0000000..ac2542b
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/cloud/autoscaling/TriggerValidationException.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.cloud.autoscaling;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This class represents errors found when validating trigger configuration.
+ */
+public class TriggerValidationException extends Exception {
+ private Map<String, String> details = new HashMap<>();
+
+ /**
+ * Create an exception.
+ * @param details details of invalid configuration - key is a property name,
+ * value is an error message.
+ */
+ public TriggerValidationException(Map<String, String> details) {
+ super();
+ if (details != null) {
+ this.details.putAll(details);
+ }
+ }
+
+ /**
+ * Create an exception.
+ * @param keyValues zero or even number of arguments representing symbolic key
+ * (eg. property name) and the corresponding validation error message.
+ */
+ public TriggerValidationException(String... keyValues) {
+ super();
+ if (keyValues == null || keyValues.length == 0) {
+ return;
+ }
+ if (keyValues.length % 2 != 0) {
+ throw new IllegalArgumentException("number of arguments representing key & value pairs must be even");
+ }
+ for (int i = 0; i < keyValues.length; i += 2) {
+ details.put(keyValues[i], keyValues[i + 1]);
+ }
+ }
+
+ public Map<String, String> getDetails() {
+ return details;
+ }
+
+ @Override
+ public String toString() {
+ return "TriggerValidationException{" +
+ "details=" + details +
+ '}';
+ }
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/ComputePlanActionTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ComputePlanActionTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ComputePlanActionTest.java
index 943e8fc..5952e40 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ComputePlanActionTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ComputePlanActionTest.java
@@ -47,6 +47,7 @@ import org.apache.solr.common.params.CollectionParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.util.LogLevel;
import org.junit.After;
import org.junit.Before;
@@ -368,6 +369,16 @@ public class ComputePlanActionTest extends SolrCloudTestCase {
static String expectedNode;
@Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+
+ }
+
+ @Override
+ public void init() {
+
+ }
+
+ @Override
public String getName() {
return null;
}
@@ -389,11 +400,6 @@ public class ComputePlanActionTest extends SolrCloudTestCase {
public void close() throws IOException {
}
-
- @Override
- public void init(Map<String, String> args) {
-
- }
}
@Test
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/ExecutePlanActionTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ExecutePlanActionTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ExecutePlanActionTest.java
index 6e4463a..b26da52 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ExecutePlanActionTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ExecutePlanActionTest.java
@@ -27,6 +27,7 @@ import java.util.stream.Collectors;
import com.google.common.collect.Lists;
import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventType;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
@@ -40,6 +41,7 @@ import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.CollectionParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.util.LogLevel;
import org.apache.solr.common.util.TimeSource;
import org.apache.zookeeper.data.Stat;
@@ -60,6 +62,9 @@ public class ExecutePlanActionTest extends SolrCloudTestCase {
private static final int NODE_COUNT = 2;
+ private SolrResourceLoader loader;
+ private SolrCloudManager cloudManager;
+
@BeforeClass
public static void setupCluster() throws Exception {
configureCluster(NODE_COUNT)
@@ -81,6 +86,8 @@ public class ExecutePlanActionTest extends SolrCloudTestCase {
}
}
cluster.waitForAllNodes(30);
+ loader = cluster.getJettySolrRunner(0).getCoreContainer().getResourceLoader();
+ cloudManager = cluster.getJettySolrRunner(0).getCoreContainer().getZkController().getSolrCloudManager();
}
@Test
@@ -109,7 +116,7 @@ public class ExecutePlanActionTest extends SolrCloudTestCase {
JettySolrRunner survivor = otherJetties.get(0);
try (ExecutePlanAction action = new ExecutePlanAction()) {
- action.init(Collections.singletonMap("name", "execute_plan"));
+ action.configure(loader, cloudManager, Collections.singletonMap("name", "execute_plan"));
// used to signal if we found that ExecutePlanAction did in fact create the right znode before executing the operation
AtomicBoolean znodeCreated = new AtomicBoolean(false);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerTest.java
index 93c91c5..f0f9f07 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/MetricTriggerTest.java
@@ -72,7 +72,8 @@ public class MetricTriggerTest extends SolrCloudTestCase {
SolrResourceLoader loader = cluster.getJettySolrRunner(0).getCoreContainer().getResourceLoader();
SolrCloudManager cloudManager = new SolrClientCloudManager(new ZkDistributedQueueFactory(zkClient), cluster.getSolrClient());
- try (MetricTrigger metricTrigger = new MetricTrigger("metricTrigger", props, loader, cloudManager)) {
+ try (MetricTrigger metricTrigger = new MetricTrigger("metricTrigger")) {
+ metricTrigger.configure(loader, cloudManager, props);
metricTrigger.setProcessor(noFirstRunProcessor);
metricTrigger.run();
metricTrigger.setProcessor(event -> events.add(event));
@@ -85,7 +86,8 @@ public class MetricTriggerTest extends SolrCloudTestCase {
events.clear();
tag = "metrics:" + registry + ":ADMIN./admin/file.handlerStart";
props = createTriggerProps(waitForSeconds, tag, null, 100.0d, DEFAULT_TEST_COLLECTION_NAME, null, null);
- try (MetricTrigger metricTrigger = new MetricTrigger("metricTrigger", props, loader, cloudManager)) {
+ try (MetricTrigger metricTrigger = new MetricTrigger("metricTrigger")) {
+ metricTrigger.configure(loader, cloudManager, props);
metricTrigger.setProcessor(noFirstRunProcessor);
metricTrigger.run();
metricTrigger.setProcessor(event -> events.add(event));
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
index d82cec2..0485d4a 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeAddedTriggerTest.java
@@ -27,10 +27,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.common.util.TimeSource;
+import org.apache.solr.core.SolrResourceLoader;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -72,8 +74,8 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
long waitForSeconds = 1 + random().nextInt(5);
Map<String, Object> props = createTriggerProps(waitForSeconds);
- try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
trigger.setProcessor(noFirstRunProcessor);
trigger.run();
@@ -113,8 +115,8 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
// add a new node but remove it before the waitFor period expires
// and assert that the trigger doesn't fire at all
- try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
final long waitTime = 2;
props.put("waitFor", waitTime);
trigger.setProcessor(noFirstRunProcessor);
@@ -159,8 +161,8 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
action.put("name", "testActionInit");
action.put("class", NodeAddedTriggerTest.AssertInitTriggerAction.class.getName());
actions.add(action);
- try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
assertEquals(true, actionConstructorCalled.get());
assertEquals(false, actionInitCalled.get());
assertEquals(false, actionCloseCalled.get());
@@ -177,6 +179,16 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
}
@Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+
+ }
+
+ @Override
+ public void init() {
+ actionInitCalled.compareAndSet(false, true);
+ }
+
+ @Override
public String getName() {
return "";
}
@@ -190,19 +202,14 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
public void close() throws IOException {
actionCloseCalled.compareAndSet(false, true);
}
-
- @Override
- public void init(Map<String, String> args) {
- actionInitCalled.compareAndSet(false, true);
- }
}
@Test
public void testListenerAcceptance() throws Exception {
CoreContainer container = cluster.getJettySolrRunners().get(0).getCoreContainer();
Map<String, Object> props = createTriggerProps(0);
- try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
trigger.setProcessor(noFirstRunProcessor);
trigger.run(); // starts tracking live nodes
@@ -238,8 +245,8 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
// add a new node but update the trigger before the waitFor period expires
// and assert that the new trigger still fires
- NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager());
+ NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger");
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
trigger.setProcessor(noFirstRunProcessor);
trigger.run();
@@ -247,8 +254,8 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
trigger.run(); // this run should detect the new node
trigger.close(); // close the old trigger
- try (NodeAddedTrigger newTrigger = new NodeAddedTrigger("some_different_name", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeAddedTrigger newTrigger = new NodeAddedTrigger("some_different_name")) {
+ newTrigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
try {
newTrigger.restoreState(trigger);
fail("Trigger should only be able to restore state from an old trigger of the same name");
@@ -257,8 +264,8 @@ public class NodeAddedTriggerTest extends SolrCloudTestCase {
}
}
- try (NodeAddedTrigger newTrigger = new NodeAddedTrigger("node_added_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeAddedTrigger newTrigger = new NodeAddedTrigger("node_added_trigger")) {
+ newTrigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
AtomicBoolean fired = new AtomicBoolean(false);
AtomicReference<TriggerEvent> eventRef = new AtomicReference<>();
newTrigger.setProcessor(event -> {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
index d9c9571..07988e1 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/NodeLostTriggerTest.java
@@ -27,10 +27,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.common.util.TimeSource;
+import org.apache.solr.core.SolrResourceLoader;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -73,8 +75,8 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
long waitForSeconds = 1 + random().nextInt(5);
Map<String, Object> props = createTriggerProps(waitForSeconds);
- try (NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger")) {
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
trigger.setProcessor(noFirstRunProcessor);
trigger.run();
String lostNodeName1 = cluster.getJettySolrRunner(1).getNodeName();
@@ -118,8 +120,8 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
// remove a node but add it back before the waitFor period expires
// and assert that the trigger doesn't fire at all
- try (NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger")) {
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
final long waitTime = 2;
props.put("waitFor", waitTime);
trigger.setProcessor(noFirstRunProcessor);
@@ -175,8 +177,8 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
action.put("name", "testActionInit");
action.put("class", AssertInitTriggerAction.class.getName());
actions.add(action);
- try (NodeLostTrigger trigger = new NodeLostTrigger("node_added_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeLostTrigger trigger = new NodeLostTrigger("node_added_trigger")) {
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
assertEquals(true, actionConstructorCalled.get());
assertEquals(false, actionInitCalled.get());
assertEquals(false, actionCloseCalled.get());
@@ -193,6 +195,16 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
}
@Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+
+ }
+
+ @Override
+ public void init() {
+ actionInitCalled.compareAndSet(false, true);
+ }
+
+ @Override
public String getName() {
return "";
}
@@ -207,18 +219,14 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
actionCloseCalled.compareAndSet(false, true);
}
- @Override
- public void init(Map<String, String> args) {
- actionInitCalled.compareAndSet(false, true);
- }
}
@Test
public void testListenerAcceptance() throws Exception {
CoreContainer container = cluster.getJettySolrRunners().get(0).getCoreContainer();
Map<String, Object> props = createTriggerProps(0);
- try (NodeLostTrigger trigger = new NodeLostTrigger("node_added_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeLostTrigger trigger = new NodeLostTrigger("node_added_trigger")) {
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
trigger.setProcessor(noFirstRunProcessor);
JettySolrRunner newNode = cluster.startJettySolrRunner();
@@ -272,8 +280,8 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
// remove a node but update the trigger before the waitFor period expires
// and assert that the new trigger still fires
- NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager());
+ NodeLostTrigger trigger = new NodeLostTrigger("node_lost_trigger");
+ trigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
trigger.setProcessor(noFirstRunProcessor);
trigger.run();
@@ -290,8 +298,8 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
trigger.run(); // this run should detect the lost node
trigger.close(); // close the old trigger
- try (NodeLostTrigger newTrigger = new NodeLostTrigger("some_different_name", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeLostTrigger newTrigger = new NodeLostTrigger("some_different_name")) {
+ newTrigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
try {
newTrigger.restoreState(trigger);
fail("Trigger should only be able to restore state from an old trigger of the same name");
@@ -300,8 +308,8 @@ public class NodeLostTriggerTest extends SolrCloudTestCase {
}
}
- try (NodeLostTrigger newTrigger = new NodeLostTrigger("node_lost_trigger", props, container.getResourceLoader(),
- container.getZkController().getSolrCloudManager())) {
+ try (NodeLostTrigger newTrigger = new NodeLostTrigger("node_lost_trigger")) {
+ newTrigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), props);
AtomicBoolean fired = new AtomicBoolean(false);
AtomicReference<TriggerEvent> eventRef = new AtomicReference<>();
newTrigger.setProcessor(event -> {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledTriggerTest.java
index 6fedd95..012dd94 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/ScheduledTriggerTest.java
@@ -81,8 +81,8 @@ public class ScheduledTriggerTest extends SolrCloudTestCase {
Map<String, Object> properties = createTriggerProperties(new Date(threeDaysAgo).toInstant().toString(),
TimeZone.getDefault().getID(),
"+2DAYS", "+1HOUR");
- try (ScheduledTrigger scheduledTrigger = new ScheduledTrigger("sched1", properties,
- container.getResourceLoader(), container.getZkController().getSolrCloudManager())) {
+ try (ScheduledTrigger scheduledTrigger = new ScheduledTrigger("sched1")) {
+ scheduledTrigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), properties);
scheduledTrigger.init();
AtomicReference<TriggerEvent> eventRef = new AtomicReference<>();
scheduledTrigger.setProcessor(event -> {
@@ -94,9 +94,9 @@ public class ScheduledTriggerTest extends SolrCloudTestCase {
}
}
- private void scheduledTriggerTest(CoreContainer container, Map<String, Object> properties) throws IOException, InterruptedException {
- try (ScheduledTrigger scheduledTrigger = new ScheduledTrigger("sched1", properties,
- container.getResourceLoader(), container.getZkController().getSolrCloudManager())) {
+ private void scheduledTriggerTest(CoreContainer container, Map<String, Object> properties) throws Exception {
+ try (ScheduledTrigger scheduledTrigger = new ScheduledTrigger("sched1")) {
+ scheduledTrigger.configure(container.getResourceLoader(), container.getZkController().getSolrCloudManager(), properties);
scheduledTrigger.init();
scheduledTrigger.setProcessor(noFirstRunProcessor);
scheduledTrigger.run();
@@ -119,7 +119,7 @@ public class ScheduledTriggerTest extends SolrCloudTestCase {
private Map<String, Object> createTriggerProperties(String startTime, String timeZone, String every, String graceTime) {
Map<String, Object> properties = new HashMap<>();
- properties.put("graceTime", graceTime);
+ properties.put("graceDuration", graceTime);
properties.put("startTime", startTime);
properties.put("timeZone", timeZone);
properties.put("every", every);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerTest.java
index 081cd90..1c72649 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/SearchRateTriggerTest.java
@@ -83,7 +83,9 @@ public class SearchRateTriggerTest extends SolrCloudTestCase {
final List<TriggerEvent> events = new ArrayList<>();
CloudSolrClient solrClient = cluster.getSolrClient();
- try (SearchRateTrigger trigger = new SearchRateTrigger("search_rate_trigger", props, loader, cloudManager)) {
+ try (SearchRateTrigger trigger = new SearchRateTrigger("search_rate_trigger")) {
+ trigger.configure(loader, cloudManager, props);
+ trigger.init();
trigger.setProcessor(noFirstRunProcessor);
trigger.run();
trigger.setProcessor(event -> events.add(event));
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java
index f29280b..5f97a50 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/TriggerIntegrationTest.java
@@ -663,10 +663,10 @@ public class TriggerIntegrationTest extends SolrCloudTestCase {
}
@Override
- public void init(Map<String, String> args) {
+ public void init() throws Exception {
log.info("TestTriggerAction init");
actionInitCalled.countDown();
- super.init(args);
+ super.init();
}
}
@@ -692,10 +692,10 @@ public class TriggerIntegrationTest extends SolrCloudTestCase {
}
@Override
- public void init(Map<String, String> args) {
- log.debug("TestTriggerAction init");
+ public void init() throws Exception {
+ log.info("TestEventQueueAction init");
actionInitCalled.countDown();
- super.init(args);
+ super.init();
}
}
@@ -871,10 +871,10 @@ public class TriggerIntegrationTest extends SolrCloudTestCase {
}
@Override
- public void init(Map<String, String> args) {
+ public void init() throws Exception {
log.info("TestEventMarkerAction init");
actionInitCalled.countDown();
- super.init(args);
+ super.init();
}
}
@@ -1295,7 +1295,7 @@ public class TriggerIntegrationTest extends SolrCloudTestCase {
try (ScheduledTriggers scheduledTriggers = new ScheduledTriggers(resourceLoader, solrCloudManager)) {
AutoScalingConfig config = new AutoScalingConfig(Collections.emptyMap());
scheduledTriggers.setAutoScalingConfig(config);
- scheduledTriggers.add(new TriggerBase(TriggerEventType.NODELOST, "x", Collections.emptyMap(), resourceLoader, solrCloudManager) {
+ AutoScaling.Trigger t = new TriggerBase(TriggerEventType.NODELOST, "x") {
@Override
protected Map<String, Object> getState() {
return Collections.singletonMap("x","y");
@@ -1318,7 +1318,10 @@ public class TriggerIntegrationTest extends SolrCloudTestCase {
diff.set(timeSource.getTimeNs() - l);
getTriggerFiredLatch().countDown();
}
- });
+ };
+ t.configure(runner.getCoreContainer().getResourceLoader(), runner.getCoreContainer().getZkController().getSolrCloudManager(), Collections.emptyMap());
+ scheduledTriggers.add(t);
+
assertTrue(getTriggerFiredLatch().await(4, TimeUnit.SECONDS));
assertTrue(diff.get() - TimeUnit.SECONDS.toNanos(ScheduledTriggers.DEFAULT_SCHEDULED_TRIGGER_DELAY_SECONDS) >= 0);
@@ -1340,7 +1343,7 @@ public class TriggerIntegrationTest extends SolrCloudTestCase {
final Set<String> triggerNames = Collections.synchronizedSet(new HashSet<>());
triggerFiredLatch = new CountDownLatch(8);
for (int i = 0; i < 8; i++) {
- triggerList.add(new MockTrigger(TriggerEventType.NODELOST, "x" + i, Collections.emptyMap(), resourceLoader, solrCloudManager) {
+ AutoScaling.Trigger trigger = new MockTrigger(TriggerEventType.NODELOST, "x" + i) {
@Override
public void run() {
try {
@@ -1355,7 +1358,9 @@ public class TriggerIntegrationTest extends SolrCloudTestCase {
threadNames.add(Thread.currentThread().getName());
}
}
- });
+ };
+ trigger.configure(resourceLoader, solrCloudManager, Collections.emptyMap());
+ triggerList.add(trigger);
scheduledTriggers.add(triggerList.get(i));
}
assertTrue("Timed out waiting for latch to fire", getTriggerFiredLatch().await(20, TimeUnit.SECONDS));
@@ -1383,8 +1388,8 @@ public class TriggerIntegrationTest extends SolrCloudTestCase {
public static class MockTrigger extends TriggerBase {
- public MockTrigger(TriggerEventType eventType, String name, Map<String, Object> properties, SolrResourceLoader loader, SolrCloudManager cloudManager) {
- super(eventType, name, properties, loader, cloudManager);
+ public MockTrigger(TriggerEventType eventType, String name) {
+ super(eventType, name);
}
@Override
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestComputePlanAction.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestComputePlanAction.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestComputePlanAction.java
index 4dde7b6..cdc4173 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestComputePlanAction.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestComputePlanAction.java
@@ -30,6 +30,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrResponse;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventType;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.cloud.CloudTestUtils;
@@ -38,6 +39,7 @@ import org.apache.solr.cloud.autoscaling.ComputePlanAction;
import org.apache.solr.cloud.autoscaling.ScheduledTriggers;
import org.apache.solr.cloud.autoscaling.TriggerAction;
import org.apache.solr.cloud.autoscaling.TriggerEvent;
+import org.apache.solr.cloud.autoscaling.TriggerValidationException;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
@@ -46,6 +48,7 @@ import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.TimeSource;
import org.apache.solr.common.util.Utils;
+import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.util.LogLevel;
import org.junit.After;
import org.junit.Before;
@@ -319,6 +322,16 @@ public class TestComputePlanAction extends SimSolrCloudTestCase {
static String expectedNode;
@Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+
+ }
+
+ @Override
+ public void init() {
+
+ }
+
+ @Override
public String getName() {
return null;
}
@@ -340,10 +353,5 @@ public class TestComputePlanAction extends SimSolrCloudTestCase {
public void close() throws IOException {
}
-
- @Override
- public void init(Map<String, String> args) {
-
- }
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestExecutePlanAction.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestExecutePlanAction.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestExecutePlanAction.java
index a030d8a..9117dcd 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestExecutePlanAction.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestExecutePlanAction.java
@@ -103,7 +103,7 @@ public class TestExecutePlanAction extends SimSolrCloudTestCase {
String survivor = otherNodes.get(0);
try (ExecutePlanAction action = new ExecutePlanAction()) {
- action.init(Collections.singletonMap("name", "execute_plan"));
+ action.configure(cluster.getLoader(), cluster, Collections.singletonMap("name", "execute_plan"));
// used to signal if we found that ExecutePlanAction did in fact create the right znode before executing the operation
AtomicBoolean znodeCreated = new AtomicBoolean(false);
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/059f495e/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeAddedTrigger.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeAddedTrigger.java b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeAddedTrigger.java
index eafc300..fd816ca 100644
--- a/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeAddedTrigger.java
+++ b/solr/core/src/test/org/apache/solr/cloud/autoscaling/sim/TestNodeAddedTrigger.java
@@ -27,12 +27,15 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
+import org.apache.solr.client.solrj.cloud.SolrCloudManager;
import org.apache.solr.cloud.autoscaling.ActionContext;
import org.apache.solr.cloud.autoscaling.AutoScaling;
import org.apache.solr.cloud.autoscaling.NodeAddedTrigger;
import org.apache.solr.cloud.autoscaling.TriggerAction;
import org.apache.solr.cloud.autoscaling.TriggerEvent;
+import org.apache.solr.cloud.autoscaling.TriggerValidationException;
import org.apache.solr.common.util.TimeSource;
+import org.apache.solr.core.SolrResourceLoader;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -75,7 +78,8 @@ public class TestNodeAddedTrigger extends SimSolrCloudTestCase {
long waitForSeconds = 1 + random().nextInt(5);
Map<String, Object> props = createTriggerProps(waitForSeconds);
- try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
+ trigger.configure(cluster.getLoader(), cluster, props);
trigger.setProcessor(noFirstRunProcessor);
trigger.run();
@@ -115,7 +119,9 @@ public class TestNodeAddedTrigger extends SimSolrCloudTestCase {
// add a new node but remove it before the waitFor period expires
// and assert that the trigger doesn't fire at all
- try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
+ trigger.configure(cluster.getLoader(), cluster, props);
+ trigger.init();
final long waitTime = 2;
props.put("waitFor", waitTime);
trigger.setProcessor(noFirstRunProcessor);
@@ -159,7 +165,8 @@ public class TestNodeAddedTrigger extends SimSolrCloudTestCase {
action.put("name", "testActionInit");
action.put("class", TestNodeAddedTrigger.AssertInitTriggerAction.class.getName());
actions.add(action);
- try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
+ trigger.configure(cluster.getLoader(), cluster, props);
assertEquals(true, actionConstructorCalled.get());
assertEquals(false, actionInitCalled.get());
assertEquals(false, actionCloseCalled.get());
@@ -176,6 +183,16 @@ public class TestNodeAddedTrigger extends SimSolrCloudTestCase {
}
@Override
+ public void configure(SolrResourceLoader loader, SolrCloudManager cloudManager, Map<String, Object> properties) throws TriggerValidationException {
+
+ }
+
+ @Override
+ public void init() {
+ actionInitCalled.compareAndSet(false, true);
+ }
+
+ @Override
public String getName() {
return "";
}
@@ -189,17 +206,14 @@ public class TestNodeAddedTrigger extends SimSolrCloudTestCase {
public void close() throws IOException {
actionCloseCalled.compareAndSet(false, true);
}
-
- @Override
- public void init(Map<String, String> args) {
- actionInitCalled.compareAndSet(false, true);
- }
- }
+ }
@Test
public void testListenerAcceptance() throws Exception {
Map<String, Object> props = createTriggerProps(0);
- try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger")) {
+ trigger.configure(cluster.getLoader(), cluster, props);
+ trigger.init();
trigger.setProcessor(noFirstRunProcessor);
trigger.run(); // starts tracking live nodes
@@ -234,7 +248,8 @@ public class TestNodeAddedTrigger extends SimSolrCloudTestCase {
// add a new node but update the trigger before the waitFor period expires
// and assert that the new trigger still fires
- NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger", props, cluster.getLoader(), cluster);
+ NodeAddedTrigger trigger = new NodeAddedTrigger("node_added_trigger");
+ trigger.configure(cluster.getLoader(), cluster, props);
trigger.setProcessor(noFirstRunProcessor);
trigger.run();
@@ -242,7 +257,8 @@ public class TestNodeAddedTrigger extends SimSolrCloudTestCase {
trigger.run(); // this run should detect the new node
trigger.close(); // close the old trigger
- try (NodeAddedTrigger newTrigger = new NodeAddedTrigger("some_different_name", props, cluster.getLoader(), cluster)) {
+ try (NodeAddedTrigger newTrigger = new NodeAddedTrigger("some_different_name")) {
+ newTrigger.configure(cluster.getLoader(), cluster, props);
try {
newTrigger.restoreState(trigger);
fail("Trigger should only be able to restore state from an old trigger of the same name");
@@ -251,7 +267,8 @@ public class TestNodeAddedTrigger extends SimSolrCloudTestCase {
}
}
- try (NodeAddedTrigger newTrigger = new NodeAddedTrigger("node_added_trigger", props, cluster.getLoader(), cluster)) {
+ try (NodeAddedTrigger newTrigger = new NodeAddedTrigger("node_added_trigger")) {
+ newTrigger.configure(cluster.getLoader(), cluster, props);
AtomicBoolean fired = new AtomicBoolean(false);
AtomicReference<TriggerEvent> eventRef = new AtomicReference<>();
newTrigger.setProcessor(event -> {