You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by da...@apache.org on 2018/10/23 00:05:59 UTC

[38/52] [abbrv] [partial] lucene-solr:jira/gradle: Add gradle support for Solr

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0ae21ad0/solr/core/src/java/org/apache/solr/cloud/api/collections/TimeRoutedAlias.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/TimeRoutedAlias.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/TimeRoutedAlias.java
deleted file mode 100644
index 1fb3d9e..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/TimeRoutedAlias.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * 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.api.collections;
-
-import java.text.ParseException;
-import java.time.Instant;
-import java.time.ZoneOffset;
-import java.time.format.DateTimeFormatter;
-import java.time.format.DateTimeFormatterBuilder;
-import java.time.temporal.ChronoField;
-import java.util.AbstractMap;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Predicate;
-import java.util.function.Supplier;
-
-import com.google.common.base.Objects;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.cloud.Aliases;
-import org.apache.solr.common.params.CommonParams;
-import org.apache.solr.common.params.MapSolrParams;
-import org.apache.solr.common.params.RequiredSolrParams;
-import org.apache.solr.util.DateMathParser;
-import org.apache.solr.util.TimeZoneUtils;
-
-import static org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST;
-import static org.apache.solr.common.params.CommonParams.TZ;
-
-/**
- * Holds configuration for a routed alias, and some common code and constants.
- *
- * @see CreateAliasCmd
- * @see MaintainRoutedAliasCmd
- * @see org.apache.solr.update.processor.TimeRoutedAliasUpdateProcessor
- */
-public class TimeRoutedAlias {
-
-  // These are parameter names to routed alias creation, AND are stored as metadata with the alias.
-  public static final String ROUTER_PREFIX = "router.";
-  public static final String ROUTER_TYPE_NAME = ROUTER_PREFIX + "name";
-  public static final String ROUTER_FIELD = ROUTER_PREFIX + "field";
-  public static final String ROUTER_START = ROUTER_PREFIX + "start";
-  public static final String ROUTER_INTERVAL = ROUTER_PREFIX + "interval";
-  public static final String ROUTER_MAX_FUTURE = ROUTER_PREFIX + "maxFutureMs";
-  public static final String ROUTER_PREEMPTIVE_CREATE_MATH = ROUTER_PREFIX + "preemptiveCreateMath";
-  public static final String ROUTER_AUTO_DELETE_AGE = ROUTER_PREFIX + "autoDeleteAge";
-  public static final String CREATE_COLLECTION_PREFIX = "create-collection.";
-  // plus TZ and NAME
-
-  /**
-   * Parameters required for creating a routed alias
-   */
-  public static final List<String> REQUIRED_ROUTER_PARAMS = Collections.unmodifiableList(Arrays.asList(
-      CommonParams.NAME,
-      ROUTER_TYPE_NAME,
-      ROUTER_FIELD,
-      ROUTER_START,
-      ROUTER_INTERVAL));
-
-  /**
-   * Optional parameters for creating a routed alias excluding parameters for collection creation.
-   */
-  //TODO lets find a way to remove this as it's harder to maintain than required list
-  public static final List<String> OPTIONAL_ROUTER_PARAMS = Collections.unmodifiableList(Arrays.asList(
-      ROUTER_MAX_FUTURE,
-      ROUTER_AUTO_DELETE_AGE,
-      ROUTER_PREEMPTIVE_CREATE_MATH,
-      TZ)); // kinda special
-
-  static Predicate<String> PARAM_IS_PROP =
-      key -> key.equals(TZ) ||
-          (key.startsWith(ROUTER_PREFIX) && !key.equals(ROUTER_START)) || //TODO reconsider START special case
-          key.startsWith(CREATE_COLLECTION_PREFIX);
-
-  public static final String ROUTED_ALIAS_NAME_CORE_PROP = "routedAliasName"; // core prop
-
-  // This format must be compatible with collection name limitations
-  private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
-      .append(DateTimeFormatter.ISO_LOCAL_DATE).appendPattern("[_HH[_mm[_ss]]]") //brackets mean optional
-      .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
-      .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
-      .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
-      .toFormatter(Locale.ROOT).withZone(ZoneOffset.UTC); // deliberate -- collection names disregard TZ
-
-  public static Instant parseInstantFromCollectionName(String aliasName, String collection) {
-    final String dateTimePart = collection.substring(aliasName.length() + 1);
-    return DATE_TIME_FORMATTER.parse(dateTimePart, Instant::from);
-  }
-
-  public static String formatCollectionNameFromInstant(String aliasName, Instant timestamp) {
-    String nextCollName = DATE_TIME_FORMATTER.format(timestamp);
-    for (int i = 0; i < 3; i++) { // chop off seconds, minutes, hours
-      if (nextCollName.endsWith("_00")) {
-        nextCollName = nextCollName.substring(0, nextCollName.length()-3);
-      }
-    }
-    assert DATE_TIME_FORMATTER.parse(nextCollName, Instant::from).equals(timestamp);
-    return aliasName + "_" + nextCollName;
-  }
-
-
-  //
-  // Instance data and methods
-  //
-
-  private final String aliasName;
-  private final String routeField;
-  private final String intervalMath; // ex: +1DAY
-  private final long maxFutureMs;
-  private final String preemptiveCreateMath;
-  private final String autoDeleteAgeMath; // ex: /DAY-30DAYS  *optional*
-  private final TimeZone timeZone;
-
-  public TimeRoutedAlias(String aliasName, Map<String, String> aliasMetadata) {
-    this.aliasName = aliasName;
-    final MapSolrParams params = new MapSolrParams(aliasMetadata); // for convenience
-    final RequiredSolrParams required = params.required();
-    if (!"time".equals(required.get(ROUTER_TYPE_NAME))) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Only 'time' routed aliases is supported right now.");
-    }
-    routeField = required.get(ROUTER_FIELD);
-    intervalMath = required.get(ROUTER_INTERVAL);
-
-    //optional:
-    maxFutureMs = params.getLong(ROUTER_MAX_FUTURE, TimeUnit.MINUTES.toMillis(10));
-    // the date math configured is an interval to be subtracted from the most recent collection's time stamp
-    String pcmTmp = params.get(ROUTER_PREEMPTIVE_CREATE_MATH);
-    preemptiveCreateMath = pcmTmp != null ? (pcmTmp.startsWith("-") ? pcmTmp : "-" + pcmTmp) : null;
-    autoDeleteAgeMath = params.get(ROUTER_AUTO_DELETE_AGE); // no default
-    timeZone = TimeZoneUtils.parseTimezone(aliasMetadata.get(CommonParams.TZ));
-
-    // More validation:
-
-    // check that the date math is valid
-    final Date now = new Date();
-    try {
-      final Date after = new DateMathParser(now, timeZone).parseMath(intervalMath);
-      if (!after.after(now)) {
-        throw new SolrException(BAD_REQUEST, "duration must add to produce a time in the future");
-      }
-    } catch (Exception e) {
-      throw new SolrException(BAD_REQUEST, "bad " + TimeRoutedAlias.ROUTER_INTERVAL + ", " + e, e);
-    }
-
-    if (autoDeleteAgeMath != null) {
-      try {
-        final Date before =  new DateMathParser(now, timeZone).parseMath(autoDeleteAgeMath);
-        if (now.before(before)) {
-          throw new SolrException(BAD_REQUEST, "duration must round or subtract to produce a time in the past");
-        }
-      } catch (Exception e) {
-        throw new SolrException(BAD_REQUEST, "bad " + TimeRoutedAlias.ROUTER_AUTO_DELETE_AGE + ", " + e, e);
-      }
-    }
-    if (preemptiveCreateMath != null) {
-      try {
-        new DateMathParser().parseMath(preemptiveCreateMath);
-      } catch (ParseException e) {
-        throw new SolrException(BAD_REQUEST, "Invalid date math for preemptiveCreateMath:" + preemptiveCreateMath);
-      }
-    }
-
-    if (maxFutureMs < 0) {
-      throw new SolrException(BAD_REQUEST, ROUTER_MAX_FUTURE + " must be >= 0");
-    }
-  }
-
-  public String getAliasName() {
-    return aliasName;
-  }
-
-  public String getRouteField() {
-    return routeField;
-  }
-
-  public String getIntervalMath() {
-    return intervalMath;
-  }
-
-  public long getMaxFutureMs() {
-    return maxFutureMs;
-  }
-
-  public String getPreemptiveCreateWindow() {
-    return preemptiveCreateMath;
-  }
-
-  public String getAutoDeleteAgeMath() {
-    return autoDeleteAgeMath;
-  }
-
-  public TimeZone getTimeZone() {
-    return timeZone;
-  }
-
-  @Override
-  public String toString() {
-    return Objects.toStringHelper(this)
-        .add("aliasName", aliasName)
-        .add("routeField", routeField)
-        .add("intervalMath", intervalMath)
-        .add("maxFutureMs", maxFutureMs)
-        .add("preemptiveCreateMath", preemptiveCreateMath)
-        .add("autoDeleteAgeMath", autoDeleteAgeMath)
-        .add("timeZone", timeZone)
-        .toString();
-  }
-
-  /** Parses the timestamp from the collection list and returns them in reverse sorted order (most recent 1st) */
-  public List<Map.Entry<Instant,String>> parseCollections(Aliases aliases, Supplier<SolrException> aliasNotExist) {
-    final List<String> collections = aliases.getCollectionAliasListMap().get(aliasName);
-    if (collections == null) {
-      throw aliasNotExist.get();
-    }
-    // note: I considered TreeMap but didn't like the log(N) just to grab the most recent when we use it later
-    List<Map.Entry<Instant,String>> result = new ArrayList<>(collections.size());
-    for (String collection : collections) {
-      Instant colStartTime = parseInstantFromCollectionName(aliasName, collection);
-      result.add(new AbstractMap.SimpleImmutableEntry<>(colStartTime, collection));
-    }
-    result.sort((e1, e2) -> e2.getKey().compareTo(e1.getKey())); // reverse sort by key
-    return result;
-  }
-
-  /** Computes the timestamp of the next collection given the timestamp of the one before. */
-  public Instant computeNextCollTimestamp(Instant fromTimestamp) {
-    final Instant nextCollTimestamp =
-        DateMathParser.parseMath(Date.from(fromTimestamp), "NOW" + intervalMath, timeZone).toInstant();
-    assert nextCollTimestamp.isAfter(fromTimestamp);
-    return nextCollTimestamp;
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0ae21ad0/solr/core/src/java/org/apache/solr/cloud/api/collections/UtilizeNodeCmd.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/UtilizeNodeCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/UtilizeNodeCmd.java
deleted file mode 100644
index 818b16f..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/UtilizeNodeCmd.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * 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.api.collections;
-
-import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-import org.apache.solr.client.solrj.SolrRequest;
-import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
-import org.apache.solr.client.solrj.cloud.autoscaling.Policy;
-import org.apache.solr.client.solrj.cloud.autoscaling.PolicyHelper;
-import org.apache.solr.client.solrj.cloud.autoscaling.Suggester;
-import org.apache.solr.client.solrj.request.V2Request;
-import org.apache.solr.common.cloud.ClusterState;
-import org.apache.solr.common.cloud.ZkNodeProps;
-import org.apache.solr.common.params.CollectionParams;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.StrUtils;
-import org.apache.solr.common.util.Utils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.apache.solr.common.cloud.ZkStateReader.COLLECTION_PROP;
-import static org.apache.solr.common.cloud.ZkStateReader.REPLICA_PROP;
-import static org.apache.solr.common.params.AutoScalingParams.NODE;
-import static org.apache.solr.common.params.CollectionParams.CollectionAction.MOVEREPLICA;
-import static org.apache.solr.common.params.CommonAdminParams.ASYNC;
-
-public class UtilizeNodeCmd implements OverseerCollectionMessageHandler.Cmd {
-  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-  private final OverseerCollectionMessageHandler ocmh;
-
-  public UtilizeNodeCmd(OverseerCollectionMessageHandler ocmh) {
-    this.ocmh = ocmh;
-  }
-
-  @Override
-  public void call(ClusterState state, ZkNodeProps message, NamedList results) throws Exception {
-    ocmh.checkRequired(message, NODE);
-    String nodeName = message.getStr(NODE);
-    String async = message.getStr(ASYNC);
-    AutoScalingConfig autoScalingConfig = ocmh.overseer.getSolrCloudManager().getDistribStateManager().getAutoScalingConfig();
-
-    //first look for any violation that may use this replica
-    List<ZkNodeProps> requests = new ArrayList<>();
-    //first look for suggestions if any
-    List<Suggester.SuggestionInfo> suggestions = PolicyHelper.getSuggestions(autoScalingConfig, ocmh.overseer.getSolrCloudManager());
-    for (Suggester.SuggestionInfo suggestionInfo : suggestions) {
-      log.info("op: " + suggestionInfo.getOperation());
-      String coll = null;
-      List<String> pieces = StrUtils.splitSmart(suggestionInfo.getOperation().getPath(), '/');
-      if (pieces.size() > 1) {
-        coll = pieces.get(2);
-      } else {
-        continue;
-      }
-      log.info("coll: " + coll);
-      if (suggestionInfo.getOperation() instanceof V2Request) {
-        String targetNode = (String) Utils.getObjectByPath(suggestionInfo.getOperation(), true, "command/move-replica/targetNode");
-        if (Objects.equals(targetNode, nodeName)) {
-          String replica = (String) Utils.getObjectByPath(suggestionInfo.getOperation(), true, "command/move-replica/replica");
-          requests.add(new ZkNodeProps(COLLECTION_PROP, coll,
-              CollectionParams.TARGET_NODE, targetNode,
-              ASYNC, async,
-              REPLICA_PROP, replica));
-        }
-      }
-    }
-    executeAll(requests);
-    PolicyHelper.SessionWrapper sessionWrapper = PolicyHelper.getSession(ocmh.overseer.getSolrCloudManager());
-    Policy.Session session = sessionWrapper.get();
-    Suggester initialsuggester = session.getSuggester(MOVEREPLICA)
-        .hint(Suggester.Hint.TARGET_NODE, nodeName);
-    Suggester suggester = null;
-    for (; ; ) {
-      suggester = session.getSuggester(MOVEREPLICA)
-          .hint(Suggester.Hint.TARGET_NODE, nodeName);
-      SolrRequest request = suggester.getSuggestion();
-      if (requests.size() > 10) {
-        log.info("too_many_suggestions");
-        PolicyHelper.logState(ocmh.overseer.getSolrCloudManager(), initialsuggester);
-        break;
-      }
-      log.info("SUGGESTION: {}", request);
-      if (request == null) break;
-      session = suggester.getSession();
-      requests.add(new ZkNodeProps(COLLECTION_PROP, request.getParams().get(COLLECTION_PROP),
-          CollectionParams.TARGET_NODE, request.getParams().get(CollectionParams.TARGET_NODE),
-          REPLICA_PROP, request.getParams().get(REPLICA_PROP),
-          ASYNC, request.getParams().get(ASYNC)));
-    }
-    log.info("total_suggestions: {}", requests.size());
-    if (requests.size() == 0) {
-      PolicyHelper.logState(ocmh.overseer.getSolrCloudManager(), initialsuggester);
-    }
-    sessionWrapper.returnSession(session);
-    try {
-      executeAll(requests);
-    } finally {
-      sessionWrapper.release();
-    }
-  }
-
-  private void executeAll(List<ZkNodeProps> requests) throws Exception {
-    if (requests.isEmpty()) return;
-    for (ZkNodeProps props : requests) {
-      NamedList result = new NamedList();
-      ocmh.commandMap.get(MOVEREPLICA)
-          .call(ocmh.overseer.getSolrCloudManager().getClusterStateProvider().getClusterState(),
-              props,
-              result);
-    }
-    requests.clear();
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0ae21ad0/solr/core/src/java/org/apache/solr/cloud/api/collections/package-info.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/package-info.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/package-info.java
deleted file mode 100644
index 651d4fe..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/package-info.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * 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 related to internal implementations of the SolrCloud collections api
- */
-package org.apache.solr.cloud.api.collections;
-
-

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0ae21ad0/solr/core/src/java/org/apache/solr/cloud/autoscaling/ActionContext.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ActionContext.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/ActionContext.java
deleted file mode 100644
index 8487d3d..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ActionContext.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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.io.IOException;
-import java.util.Map;
-
-import org.apache.solr.client.solrj.cloud.SolrCloudManager;
-import org.apache.solr.common.MapWriter;
-
-/**
- * Provides additional context for the TriggerAction such as the trigger instance on
- * which the action is being executed as well as helper methods to pass computed information along
- * to the next action
- */
-public class ActionContext implements MapWriter {
-
-  private final SolrCloudManager cloudManager;
-  private final AutoScaling.Trigger source;
-  private final Map<String, Object> properties;
-
-  public ActionContext(SolrCloudManager cloudManager, AutoScaling.Trigger source, Map<String, Object> properties) {
-    this.cloudManager = cloudManager;
-    this.source = source;
-    this.properties = properties;
-  }
-
-  public SolrCloudManager getCloudManager() {
-    return cloudManager;
-  }
-
-  public AutoScaling.Trigger getSource() {
-    return source;
-  }
-
-  public Map<String, Object> getProperties()  {
-    return properties;
-  }
-
-  public Object getProperty(String name)  {
-    return properties != null ? properties.get(name) : null;
-  }
-
-  @Override
-  public void writeMap(EntryWriter ew) throws IOException {
-    ew.put("source", source.getName());
-    if (properties != null) {
-      for (Map.Entry<String, Object> entry : properties.entrySet()) {
-        ew.put("properties." + entry.getKey(), entry.getValue());
-      }
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0ae21ad0/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoAddReplicasPlanAction.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoAddReplicasPlanAction.java b/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoAddReplicasPlanAction.java
deleted file mode 100644
index fdd3474..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoAddReplicasPlanAction.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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.io.IOException;
-
-import org.apache.solr.client.solrj.cloud.autoscaling.NoneSuggester;
-import org.apache.solr.client.solrj.cloud.autoscaling.Policy;
-import org.apache.solr.client.solrj.cloud.SolrCloudManager;
-import org.apache.solr.client.solrj.cloud.autoscaling.Suggester;
-import org.apache.solr.client.solrj.impl.ClusterStateProvider;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.cloud.ClusterState;
-import org.apache.solr.common.cloud.DocCollection;
-import org.apache.solr.common.cloud.ZkStateReader;
-
-public class AutoAddReplicasPlanAction extends ComputePlanAction {
-
-  @Override
-  protected Suggester getSuggester(Policy.Session session, TriggerEvent event, ActionContext context, SolrCloudManager cloudManager) throws IOException {
-    // for backward compatibility
-    ClusterStateProvider stateProvider = cloudManager.getClusterStateProvider();
-    String autoAddReplicas = stateProvider.getClusterProperty(ZkStateReader.AUTO_ADD_REPLICAS, (String) null);
-    if (autoAddReplicas != null && autoAddReplicas.equals("false")) {
-      return NoneSuggester.get(session);
-    }
-
-    Suggester suggester = super.getSuggester(session, event, context, cloudManager);
-    ClusterState clusterState;
-    try {
-      clusterState = stateProvider.getClusterState();
-    } catch (IOException e) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Exception getting cluster state", e);
-    }
-
-    boolean anyCollections = false;
-    for (DocCollection collection: clusterState.getCollectionsMap().values()) {
-      if (collection.getAutoAddReplicas()) {
-        anyCollections = true;
-        suggester.hint(Suggester.Hint.COLL, collection.getName());
-      }
-    }
-
-    if (!anyCollections) return NoneSuggester.get(session);
-    return suggester;
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0ae21ad0/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
deleted file mode 100644
index 93f449a..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScaling.java
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * 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.io.Closeable;
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import org.apache.lucene.store.AlreadyClosedException;
-import org.apache.solr.client.solrj.cloud.SolrCloudManager;
-import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventType;
-import org.apache.solr.common.util.Utils;
-import org.apache.solr.core.SolrResourceLoader;
-
-public class AutoScaling {
-
-  /**
-   * Implementation of this interface is used for processing events generated by a trigger.
-   */
-  public interface TriggerEventProcessor {
-
-    /**
-     * This method is executed for events produced by {@link Trigger#run()}.
-     *
-     * @param event a subclass of {@link TriggerEvent}
-     * @return true if the processor was ready to perform actions on the event, false
-     * otherwise. If false was returned then callers should assume the event was discarded.
-     */
-    boolean process(TriggerEvent event);
-  }
-
-  /**
-   * Interface for a Solr trigger. Each trigger implements Runnable and Closeable interface. A trigger
-   * is scheduled using a {@link java.util.concurrent.ScheduledExecutorService} so it is executed as
-   * per a configured schedule to check whether the trigger is ready to fire. The {@link AutoScaling.Trigger#setProcessor(AutoScaling.TriggerEventProcessor)}
-   * method should be used to set a processor which is used by implementation of this class whenever
-   * ready.
-   * <p>
-   * As per the guarantees made by the {@link java.util.concurrent.ScheduledExecutorService} a trigger
-   * implementation is only ever called sequentially and therefore need not be thread safe. However, it
-   * is encouraged that implementations be immutable with the exception of the associated listener
-   * which can be get/set by a different thread than the one executing the trigger. Therefore, implementations
-   * should use appropriate synchronization around the listener.
-   * <p>
-   * When a trigger is ready to fire, it calls the {@link TriggerEventProcessor#process(TriggerEvent)} event
-   * with the proper trigger event object. If that method returns false then it should be interpreted to mean
-   * that Solr is not ready to process this trigger event and therefore we should retain the state and fire
-   * at the next invocation of the run() method.
-   */
-  public interface Trigger extends Closeable, Runnable {
-    /**
-     * Trigger name.
-     */
-    String getName();
-
-    /**
-     * Event type generated by this trigger.
-     */
-    TriggerEventType getEventType();
-
-    /** Returns true if this trigger is enabled. */
-    boolean isEnabled();
-
-    /** Trigger properties. */
-    Map<String, Object> getProperties();
-
-    /** Number of seconds to wait between fired events ("waitFor" property). */
-    int getWaitForSecond();
-
-    /** Actions to execute when event is fired. */
-    List<TriggerAction> getActions();
-
-    /** Set event processor to call when event is fired. */
-    void setProcessor(TriggerEventProcessor processor);
-
-    /** Get event processor. */
-    TriggerEventProcessor getProcessor();
-
-    /** Return true when this trigger is closed and cannot be used. */
-    boolean isClosed();
-
-    /** Set internal state of this trigger from another instance. */
-    void restoreState(Trigger old);
-
-    /** Save internal state of this trigger in ZooKeeper. */
-    void saveState();
-
-    /** Restore internal state of this trigger from ZooKeeper. */
-    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() throws Exception;
-  }
-
-  /**
-   * Factory to produce instances of {@link Trigger}.
-   */
-  public static abstract class TriggerFactory implements Closeable {
-    protected boolean isClosed = false;
-
-    public abstract Trigger create(TriggerEventType type, String name, Map<String, Object> props) throws TriggerValidationException;
-
-    @Override
-    public void close() throws IOException {
-      synchronized (this) {
-        isClosed = true;
-      }
-    }
-  }
-
-  /**
-   * Default implementation of {@link TriggerFactory}.
-   */
-  public static class TriggerFactoryImpl extends TriggerFactory {
-
-    private final SolrCloudManager cloudManager;
-    private final SolrResourceLoader loader;
-
-    public TriggerFactoryImpl(SolrResourceLoader loader, SolrCloudManager cloudManager) {
-      Objects.requireNonNull(cloudManager);
-      Objects.requireNonNull(loader);
-      this.cloudManager = cloudManager;
-      this.loader = loader;
-    }
-
-    @Override
-    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:
-          t = new NodeAddedTrigger(name);
-          break;
-        case NODELOST:
-          t = new NodeLostTrigger(name);
-        break;
-        case SEARCHRATE:
-          t = new SearchRateTrigger(name);
-        break;
-        case METRIC:
-          t = new MetricTrigger(name);
-        break;
-        case SCHEDULED:
-          t = new ScheduledTrigger(name);
-        break;
-        case INDEXSIZE:
-          t = new IndexSizeTrigger(name);
-          break;
-        default:
-          throw new IllegalArgumentException("Unknown event type: " + type + " in trigger: " + name);
-      }
-      t.configure(loader, cloudManager, props);
-      return t;
-    }
-
-  }
-
-  public static final String AUTO_ADD_REPLICAS_TRIGGER_NAME = ".auto_add_replicas";
-
-  public static final String AUTO_ADD_REPLICAS_TRIGGER_DSL =
-      "    {" +
-      "        'name' : '" + AUTO_ADD_REPLICAS_TRIGGER_NAME + "'," +
-      "        'event' : 'nodeLost'," +
-      "        'waitFor' : -1," +
-      "        'enabled' : true," +
-      "        'actions' : [" +
-      "            {" +
-      "                'name':'auto_add_replicas_plan'," +
-      "                'class':'solr.AutoAddReplicasPlanAction'" +
-      "            }," +
-      "            {" +
-      "                'name':'execute_plan'," +
-      "                'class':'solr.ExecutePlanAction'" +
-      "            }" +
-      "        ]" +
-      "    }";
-
-  public static final Map<String, Object> AUTO_ADD_REPLICAS_TRIGGER_PROPS = (Map) Utils.fromJSONString(AUTO_ADD_REPLICAS_TRIGGER_DSL);
-
-  public static final String SCHEDULED_MAINTENANCE_TRIGGER_NAME = ".scheduled_maintenance";
-
-  public static final String SCHEDULED_MAINTENANCE_TRIGGER_DSL =
-          "    {" +
-          "        'name' : '" + SCHEDULED_MAINTENANCE_TRIGGER_NAME + "'," +
-          "        'event' : 'scheduled'," +
-          "        'startTime' : 'NOW'," +
-          "        'every' : '+1DAY'," +
-          "        'enabled' : true," +
-          "        'actions' : [" +
-          "            {" +
-          "                'name':'inactive_shard_plan'," +
-          "                'class':'solr.InactiveShardPlanAction'" +
-          "            }," +
-          "            {" +
-          "                'name':'execute_plan'," +
-          "                'class':'solr.ExecutePlanAction'" +
-          "            }" +
-          "        ]" +
-          "    }";
-
-  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/0ae21ad0/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
deleted file mode 100644
index 899c5cd..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/AutoScalingHandler.java
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- * 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.io.IOException;
-import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.EnumSet;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.apache.solr.api.Api;
-import org.apache.solr.api.ApiBag;
-import org.apache.solr.client.solrj.cloud.SolrCloudManager;
-import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
-import org.apache.solr.client.solrj.cloud.autoscaling.BadVersionException;
-import org.apache.solr.client.solrj.cloud.autoscaling.Clause;
-import org.apache.solr.client.solrj.cloud.autoscaling.Policy;
-import org.apache.solr.client.solrj.cloud.autoscaling.PolicyHelper;
-import org.apache.solr.client.solrj.cloud.autoscaling.Preference;
-import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventProcessorStage;
-import org.apache.solr.client.solrj.cloud.autoscaling.TriggerEventType;
-import org.apache.solr.common.MapWriter;
-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.TimeSource;
-import org.apache.solr.common.util.Utils;
-import org.apache.solr.core.SolrResourceLoader;
-import org.apache.solr.handler.RequestHandlerBase;
-import org.apache.solr.handler.RequestHandlerUtils;
-import org.apache.solr.request.SolrQueryRequest;
-import org.apache.solr.request.SolrRequestHandler;
-import org.apache.solr.response.SolrQueryResponse;
-import org.apache.solr.security.AuthorizationContext;
-import org.apache.solr.security.PermissionNameProvider;
-import org.apache.zookeeper.KeeperException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static java.util.stream.Collectors.collectingAndThen;
-import static java.util.stream.Collectors.toSet;
-import static org.apache.solr.common.cloud.ZkStateReader.SOLR_AUTOSCALING_CONF_PATH;
-import static org.apache.solr.common.params.AutoScalingParams.*;
-import static org.apache.solr.common.params.CommonParams.JSON;
-
-/**
- * Handler for /cluster/autoscaling
- */
-public class AutoScalingHandler extends RequestHandlerBase implements PermissionNameProvider {
-  public static final String HANDLER_PATH = "/admin/autoscaling";
-  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));
-
-  private final TimeSource timeSource;
-
-  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");
-    map.put(CLASS, "solr.ComputePlanAction");
-    DEFAULT_ACTIONS.add(map);
-    map = new HashMap<>(2);
-    map.put(NAME, "execute_plan");
-    map.put(CLASS, "solr.ExecutePlanAction");
-    DEFAULT_ACTIONS.add(map);
-  }
-
-  @Override
-  public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws Exception {
-    try {
-      String httpMethod = (String) req.getContext().get("httpMethod");
-      RequestHandlerUtils.setWt(req, JSON);
-
-      if ("GET".equals(httpMethod)) {
-        String path = (String) req.getContext().get("path");
-        if (path == null) path = "/cluster/autoscaling";
-        List<String> parts = StrUtils.splitSmart(path, '/');
-        if (parts.get(0).isEmpty()) parts.remove(0);
-
-        if (parts.size() < 2 || parts.size() > 3) {
-          // invalid
-          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unknown path: " + path);
-        }
-
-        AutoScalingConfig autoScalingConf = cloudManager.getDistribStateManager().getAutoScalingConfig();
-        if (parts.size() == 2)  {
-          autoScalingConf.writeMap(new MapWriter.EntryWriter() {
-
-            @Override
-            public MapWriter.EntryWriter put(String k, Object v) throws IOException {
-              rsp.getValues().add(k, v);
-              return this;
-            }
-          });
-        } else if (parts.size() == 3) {
-          if (DIAGNOSTICS.equals(parts.get(2))) {
-            handleDiagnostics(rsp, autoScalingConf);
-          } else if (SUGGESTIONS.equals(parts.get(2))) {
-            handleSuggestions(rsp, autoScalingConf);
-          }
-        }
-      } else {
-        if (req.getContentStreams() == null) {
-          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No commands specified for autoscaling");
-        }
-        List<CommandOperation> ops = CommandOperation.readCommands(req.getContentStreams(), rsp.getValues(), singletonCommands);
-        if (ops == null) {
-          // errors have already been added to the response so there's nothing left to do
-          return;
-        }
-        processOps(req, rsp, ops);
-      }
-    } catch (Exception e) {
-      rsp.getValues().add("result", "failure");
-      throw e;
-    } finally {
-      RequestHandlerUtils.addExperimentalFormatWarning(rsp);
-    }
-  }
-
-
-  private void handleSuggestions(SolrQueryResponse rsp, AutoScalingConfig autoScalingConf) throws IOException {
-    rsp.getValues().add("suggestions",
-        PolicyHelper.getSuggestions(autoScalingConf, cloudManager));
-  }
-
-  public void processOps(SolrQueryRequest req, SolrQueryResponse rsp, List<CommandOperation> ops)
-      throws KeeperException, InterruptedException, IOException {
-    while (true) {
-      AutoScalingConfig initialConfig = cloudManager.getDistribStateManager().getAutoScalingConfig();
-      AutoScalingConfig currentConfig = initialConfig;
-      for (CommandOperation op : ops) {
-        switch (op.name) {
-          case CMD_SET_TRIGGER:
-            currentConfig = handleSetTrigger(req, rsp, op, currentConfig);
-            break;
-          case CMD_REMOVE_TRIGGER:
-            currentConfig = handleRemoveTrigger(req, rsp, op, currentConfig);
-            break;
-          case CMD_SET_LISTENER:
-            currentConfig = handleSetListener(req, rsp, op, currentConfig);
-            break;
-          case CMD_REMOVE_LISTENER:
-            currentConfig = handleRemoveListener(req, rsp, op, currentConfig);
-            break;
-          case CMD_SUSPEND_TRIGGER:
-            currentConfig = handleSuspendTrigger(req, rsp, op, currentConfig);
-            break;
-          case CMD_RESUME_TRIGGER:
-            currentConfig = handleResumeTrigger(req, rsp, op, currentConfig);
-            break;
-          case CMD_SET_POLICY:
-            currentConfig = handleSetPolicies(req, rsp, op, currentConfig);
-            break;
-          case CMD_REMOVE_POLICY:
-            currentConfig = handleRemovePolicy(req, rsp, op, currentConfig);
-            break;
-          case CMD_SET_CLUSTER_PREFERENCES:
-            currentConfig = handleSetClusterPreferences(req, rsp, op, currentConfig);
-            break;
-          case CMD_SET_CLUSTER_POLICY:
-            currentConfig = handleSetClusterPolicy(req, rsp, op, currentConfig);
-            break;
-          case CMD_SET_PROPERTIES:
-            currentConfig = handleSetProperties(req, rsp, op, currentConfig);
-            break;
-          default:
-            op.addError("Unknown command: " + op.name);
-        }
-      }
-      List errs = CommandOperation.captureErrors(ops);
-      if (!errs.isEmpty()) {
-        throw new ApiBag.ExceptionWithErrObject(SolrException.ErrorCode.BAD_REQUEST, "Error in command payload", errs);
-      }
-
-      if (!currentConfig.equals(initialConfig)) {
-        // update in ZK
-        if (setAutoScalingConfig(currentConfig)) {
-          break;
-        } else {
-          // someone else updated the config, get the latest one and re-apply our ops
-          rsp.getValues().add("retry", "initialVersion=" + initialConfig.getZkVersion());
-          continue;
-        }
-      } else {
-        // no changes
-        break;
-      }
-    }
-    rsp.getValues().add("result", "success");
-  }
-
-  private AutoScalingConfig handleSetProperties(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op, AutoScalingConfig currentConfig) {
-    Map<String, Object> map = op.getDataMap() == null ? Collections.emptyMap() : op.getDataMap();
-    Map<String, Object> configProps = new HashMap<>(currentConfig.getProperties());
-    configProps.putAll(map);
-    // remove a key which is set to null
-    map.forEach((k, v) -> {
-      if (v == null)  configProps.remove(k);
-    });
-    return currentConfig.withProperties(configProps);
-  }
-
-  private void handleDiagnostics(SolrQueryResponse rsp, AutoScalingConfig autoScalingConf) throws IOException {
-    Policy policy = autoScalingConf.getPolicy();
-    rsp.getValues().add("diagnostics", PolicyHelper.getDiagnostics(policy, cloudManager));
-  }
-
-  private AutoScalingConfig handleSetClusterPolicy(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                                   AutoScalingConfig currentConfig) throws KeeperException, InterruptedException, IOException {
-    List<Map<String, Object>> clusterPolicy = (List<Map<String, Object>>) op.getCommandData();
-    if (clusterPolicy == null || !(clusterPolicy instanceof List)) {
-      op.addError("set-cluster-policy expects an array of objects");
-      return currentConfig;
-    }
-    List<Clause> cp = null;
-    try {
-      cp = clusterPolicy.stream().map(Clause::create).collect(Collectors.toList());
-    } catch (Exception e) {
-      op.addError(e.getMessage());
-      return currentConfig;
-    }
-    Policy p = currentConfig.getPolicy().withClusterPolicy(cp);
-    currentConfig = currentConfig.withPolicy(p);
-    return currentConfig;
-  }
-
-  private AutoScalingConfig handleSetClusterPreferences(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                                        AutoScalingConfig currentConfig) throws KeeperException, InterruptedException, IOException {
-    List<Map<String, Object>> preferences = (List<Map<String, Object>>) op.getCommandData();
-    if (preferences == null || !(preferences instanceof List)) {
-      op.addError("A list of cluster preferences not found");
-      return currentConfig;
-    }
-    List<Preference> prefs = null;
-    try {
-      prefs = preferences.stream().map(Preference::new).collect(Collectors.toList());
-    } catch (Exception e) {
-      op.addError(e.getMessage());
-      return currentConfig;
-    }
-    Policy p = currentConfig.getPolicy().withClusterPreferences(prefs);
-    currentConfig = currentConfig.withPolicy(p);
-    return currentConfig;
-  }
-
-  private AutoScalingConfig handleRemovePolicy(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                               AutoScalingConfig currentConfig) throws KeeperException, InterruptedException, IOException {
-    String policyName = (String) op.getVal("");
-
-    if (op.hasError()) return currentConfig;
-
-    Map<String, List<Clause>> policies = currentConfig.getPolicy().getPolicies();
-    if (policies == null || !policies.containsKey(policyName)) {
-      op.addError("No policy exists with name: " + policyName);
-      return currentConfig;
-    }
-
-    cloudManager.getClusterStateProvider().getClusterState().forEachCollection(coll -> {
-      if (policyName.equals(coll.getPolicyName()))
-        op.addError(StrUtils.formatString("policy : {0} is being used by collection {1}", policyName, coll.getName()));
-    });
-    if (op.hasError()) return currentConfig;
-    policies = new HashMap<>(policies);
-    policies.remove(policyName);
-    Policy p = currentConfig.getPolicy().withPolicies(policies);
-    currentConfig = currentConfig.withPolicy(p);
-    return currentConfig;
-  }
-
-  private AutoScalingConfig handleSetPolicies(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                              AutoScalingConfig currentConfig) throws KeeperException, InterruptedException, IOException {
-    Map<String, Object> policiesMap = op.getDataMap();
-    for (Map.Entry<String, Object> policy : policiesMap.entrySet()) {
-      String policyName = policy.getKey();
-      if (policyName == null || policyName.trim().length() == 0) {
-        op.addError("The policy name cannot be null or empty");
-        return currentConfig;
-      }
-    }
-    Map<String, List<Clause>> currentClauses = new HashMap<>(currentConfig.getPolicy().getPolicies());
-    Map<String, List<Clause>> newClauses = null;
-    try {
-      newClauses = Policy.clausesFromMap((Map<String, List<Map<String, Object>>>) op.getCommandData(),
-          new ArrayList<>() );
-    } catch (Exception e) {
-      op.addError(e.getMessage());
-      return currentConfig;
-    }
-    currentClauses.putAll(newClauses);
-    Policy p = currentConfig.getPolicy().withPolicies(currentClauses);
-    currentConfig = currentConfig.withPolicy(p);
-    return currentConfig;
-  }
-
-  private AutoScalingConfig handleResumeTrigger(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                                AutoScalingConfig currentConfig) throws KeeperException, InterruptedException {
-    String triggerName = op.getStr(NAME);
-    if (op.hasError()) return currentConfig;
-    Map<String, AutoScalingConfig.TriggerConfig> triggers = currentConfig.getTriggerConfigs();
-    Set<String> changed = new HashSet<>();
-    if (!Policy.EACH.equals(triggerName) && !triggers.containsKey(triggerName)) {
-      op.addError("No trigger exists with name: " + triggerName);
-      return currentConfig;
-    }
-    Map<String, AutoScalingConfig.TriggerConfig> newTriggers = new HashMap<>();
-    for (Map.Entry<String, AutoScalingConfig.TriggerConfig> entry : triggers.entrySet()) {
-      if (Policy.EACH.equals(triggerName) || triggerName.equals(entry.getKey())) {
-        AutoScalingConfig.TriggerConfig trigger = entry.getValue();
-        if (!trigger.enabled) {
-          trigger = trigger.withEnabled(true);
-          newTriggers.put(entry.getKey(), trigger);
-          changed.add(entry.getKey());
-        } else {
-          newTriggers.put(entry.getKey(), entry.getValue());
-        }
-      } else {
-        newTriggers.put(entry.getKey(), entry.getValue());
-      }
-    }
-    rsp.getValues().add("changed", changed);
-    if (!changed.isEmpty()) {
-      currentConfig = currentConfig.withTriggerConfigs(newTriggers);
-    }
-    return currentConfig;
-  }
-
-  private AutoScalingConfig handleSuspendTrigger(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                                 AutoScalingConfig currentConfig) throws KeeperException, InterruptedException {
-    String triggerName = op.getStr(NAME);
-    if (op.hasError()) return currentConfig;
-    String timeout = op.getStr(TIMEOUT, null);
-    Date resumeTime = null;
-    if (timeout != null) {
-      try {
-        int timeoutSeconds = parseHumanTime(timeout);
-        resumeTime = new Date(TimeUnit.MILLISECONDS.convert(timeSource.getTimeNs(), TimeUnit.NANOSECONDS)
-            + TimeUnit.MILLISECONDS.convert(timeoutSeconds, TimeUnit.SECONDS));
-      } catch (IllegalArgumentException e) {
-        op.addError("Invalid 'timeout' value for suspend trigger: " + triggerName);
-        return currentConfig;
-      }
-    }
-
-    Map<String, AutoScalingConfig.TriggerConfig> triggers = currentConfig.getTriggerConfigs();
-    Set<String> changed = new HashSet<>();
-
-    if (!Policy.EACH.equals(triggerName) && !triggers.containsKey(triggerName)) {
-      op.addError("No trigger exists with name: " + triggerName);
-      return currentConfig;
-    }
-    Map<String, AutoScalingConfig.TriggerConfig> newTriggers = new HashMap<>();
-    for (Map.Entry<String, AutoScalingConfig.TriggerConfig> entry : triggers.entrySet()) {
-      if (Policy.EACH.equals(triggerName) || triggerName.equals(entry.getKey())) {
-        AutoScalingConfig.TriggerConfig trigger = entry.getValue();
-        if (trigger.enabled) {
-          trigger = trigger.withEnabled(false);
-          if (resumeTime != null) {
-            trigger = trigger.withProperty(RESUME_AT, resumeTime.getTime());
-          }
-          newTriggers.put(entry.getKey(), trigger);
-          changed.add(trigger.name);
-        } else {
-          newTriggers.put(entry.getKey(), entry.getValue());
-        }
-      } else {
-        newTriggers.put(entry.getKey(), entry.getValue());
-      }
-    }
-    rsp.getValues().add("changed", changed);
-    if (!changed.isEmpty()) {
-      currentConfig = currentConfig.withTriggerConfigs(newTriggers);
-    }
-    return currentConfig;
-  }
-
-  private AutoScalingConfig handleRemoveListener(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                    AutoScalingConfig currentConfig) throws KeeperException, InterruptedException {
-    String listenerName = op.getStr(NAME);
-
-    if (op.hasError()) return currentConfig;
-    Map<String, AutoScalingConfig.TriggerListenerConfig> listeners = currentConfig.getTriggerListenerConfigs();
-    if (listeners == null || !listeners.containsKey(listenerName)) {
-      op.addError("No listener exists with name: " + listenerName);
-      return currentConfig;
-    }
-    currentConfig = currentConfig.withoutTriggerListenerConfig(listenerName);
-    return currentConfig;
-  }
-
-  private AutoScalingConfig handleSetListener(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                 AutoScalingConfig currentConfig) throws KeeperException, InterruptedException {
-    String listenerName = op.getStr(NAME);
-    String triggerName = op.getStr(TRIGGER);
-    List<String> stageNames = op.getStrs(STAGE, Collections.emptyList());
-    String listenerClass = op.getStr(CLASS);
-    List<String> beforeActions = op.getStrs(BEFORE_ACTION, Collections.emptyList());
-    List<String> afterActions = op.getStrs(AFTER_ACTION, Collections.emptyList());
-
-    if (op.hasError()) return currentConfig;
-
-    Map<String, AutoScalingConfig.TriggerConfig> triggers = currentConfig.getTriggerConfigs();
-    if (triggers == null || !triggers.containsKey(triggerName)) {
-      op.addError("A trigger with the name " + triggerName + " does not exist");
-      return currentConfig;
-    }
-    AutoScalingConfig.TriggerConfig triggerConfig = triggers.get(triggerName);
-
-    if (stageNames.isEmpty() && beforeActions.isEmpty() && afterActions.isEmpty()) {
-      op.addError("Either 'stage' or 'beforeAction' or 'afterAction' must be specified");
-      return currentConfig;
-    }
-
-    for (String stage : stageNames) {
-      try {
-        TriggerEventProcessorStage.valueOf(stage);
-      } catch (IllegalArgumentException e) {
-        op.addError("Invalid stage name: " + stage);
-      }
-    }
-    if (op.hasError()) return currentConfig;
-
-    AutoScalingConfig.TriggerListenerConfig listenerConfig = new AutoScalingConfig.TriggerListenerConfig(listenerName, op.getValuesExcluding("name"));
-
-    // validate that we can load the listener class
-    // todo allow creation from blobstore
-    TriggerListener listener = null;
-    try {
-      listener = loader.newInstance(listenerClass, TriggerListener.class);
-      listener.configure(loader, cloudManager, listenerConfig);
-    } catch (TriggerValidationException e) {
-      log.warn("invalid listener configuration", e);
-      op.addError("invalid listener configuration: " + e.toString());
-      return currentConfig;
-    } catch (Exception e) {
-      log.warn("error loading listener class ", e);
-      op.addError("Listener not found: " + listenerClass + ". error message:" + e.getMessage());
-      return currentConfig;
-    } finally {
-      if (listener != null) {
-        IOUtils.closeQuietly(listener);
-      }
-    }
-
-    Set<String> actionNames = new HashSet<>();
-    actionNames.addAll(beforeActions);
-    actionNames.addAll(afterActions);
-    for (AutoScalingConfig.ActionConfig action : triggerConfig.actions) {
-      actionNames.remove(action.name);
-    }
-    if (!actionNames.isEmpty()) {
-      op.addError("The trigger '" + triggerName + "' does not have actions named: " + actionNames);
-      return currentConfig;
-    }
-    // todo - handle races between competing set-trigger and set-listener invocations
-    currentConfig = currentConfig.withTriggerListenerConfig(listenerConfig);
-    return currentConfig;
-  }
-
-  private AutoScalingConfig handleSetTrigger(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                             AutoScalingConfig currentConfig) throws KeeperException, InterruptedException {
-    // we're going to modify the op - use a copy
-    String triggerName = op.getStr(NAME);
-    String eventTypeStr = op.getStr(EVENT);
-
-    if (op.hasError()) return currentConfig;
-    TriggerEventType eventType = TriggerEventType.valueOf(eventTypeStr.trim().toUpperCase(Locale.ROOT));
-
-    String waitForStr = op.getStr(WAIT_FOR, null);
-
-    CommandOperation opCopy = new CommandOperation(op.name, Utils.getDeepCopy((Map) op.getCommandData(), 10));
-
-    if (waitForStr != null) {
-      int seconds = 0;
-      try {
-        seconds = parseHumanTime(waitForStr);
-      } catch (IllegalArgumentException e) {
-        op.addError("Invalid 'waitFor' value '" + waitForStr + "' in trigger: " + triggerName);
-        return currentConfig;
-      }
-      opCopy.getDataMap().put(WAIT_FOR, seconds);
-    }
-
-    Integer lowerBound = op.getInt(LOWER_BOUND, null);
-    Integer upperBound = op.getInt(UPPER_BOUND, null);
-
-    List<Map<String, String>> actions = (List<Map<String, String>>) op.getVal(ACTIONS);
-    if (actions == null) {
-      actions = DEFAULT_ACTIONS;
-      opCopy.getDataMap().put(ACTIONS, actions);
-    }
-
-    // validate that we can load all the actions
-    // todo allow creation from blobstore
-    for (Map<String, String> action : actions) {
-      if (!action.containsKey(NAME) || !action.containsKey(CLASS)) {
-        op.addError("No 'name' or 'class' specified for action: " + action);
-        return currentConfig;
-      }
-      String klass = action.get(CLASS);
-      try {
-        loader.findClass(klass, TriggerAction.class);
-      } catch (Exception e) {
-        log.warn("Could not load class : ", e);
-        op.addError("Action not found: " + klass + " " + e.getMessage());
-        return currentConfig;
-      }
-    }
-    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 (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);
-  }
-
-  private static String fullName = SystemLogListener.class.getName();
-  private static String solrName = "solr." + SystemLogListener.class.getSimpleName();
-
-  static AutoScalingConfig withSystemLogListener(AutoScalingConfig autoScalingConfig, String triggerName) {
-    Map<String, AutoScalingConfig.TriggerListenerConfig> configs = autoScalingConfig.getTriggerListenerConfigs();
-    for (AutoScalingConfig.TriggerListenerConfig cfg : configs.values()) {
-      if (triggerName.equals(cfg.trigger)) {
-        // already has some listener config
-        return autoScalingConfig;
-      }
-    }
-    // need to add
-    Map<String, Object> properties = new HashMap<>();
-    properties.put(AutoScalingParams.CLASS, SystemLogListener.class.getName());
-    properties.put(AutoScalingParams.TRIGGER, triggerName);
-    properties.put(AutoScalingParams.STAGE, EnumSet.allOf(TriggerEventProcessorStage.class));
-    AutoScalingConfig.TriggerListenerConfig listener =
-        new AutoScalingConfig.TriggerListenerConfig(triggerName + CollectionAdminParams.SYSTEM_COLL, properties);
-    autoScalingConfig = autoScalingConfig.withTriggerListenerConfig(listener);
-    return autoScalingConfig;
-  }
-
-  private int parseHumanTime(String timeStr) {
-    char c = timeStr.charAt(timeStr.length() - 1);
-    long timeValue = Long.parseLong(timeStr.substring(0, timeStr.length() - 1));
-    int seconds;
-    switch (c) {
-      case 'h':
-        seconds = (int) TimeUnit.HOURS.toSeconds(timeValue);
-        break;
-      case 'm':
-        seconds = (int) TimeUnit.MINUTES.toSeconds(timeValue);
-        break;
-      case 's':
-        seconds = (int) timeValue;
-        break;
-      default:
-        throw new IllegalArgumentException("Invalid time value");
-    }
-    return seconds;
-  }
-
-  private AutoScalingConfig handleRemoveTrigger(SolrQueryRequest req, SolrQueryResponse rsp, CommandOperation op,
-                                   AutoScalingConfig currentConfig) throws KeeperException, InterruptedException {
-    String triggerName = op.getStr(NAME);
-    boolean removeListeners = op.getBoolean(REMOVE_LISTENERS, false);
-
-    if (op.hasError()) return currentConfig;
-    Map<String, AutoScalingConfig.TriggerConfig> triggerConfigs = currentConfig.getTriggerConfigs();
-    if (!triggerConfigs.containsKey(triggerName)) {
-      op.addError("No trigger exists with name: " + triggerName);
-      return currentConfig;
-    }
-    triggerConfigs = new HashMap<>(triggerConfigs);
-    Set<String> activeListeners = new HashSet<>();
-    Map<String, AutoScalingConfig.TriggerListenerConfig> listeners = currentConfig.getTriggerListenerConfigs();
-    for (AutoScalingConfig.TriggerListenerConfig listener : listeners.values()) {
-      if (triggerName.equals(listener.trigger)) {
-        activeListeners.add(listener.name);
-      }
-    }
-    if (!activeListeners.isEmpty()) {
-      boolean onlySystemLog = false;
-      if (activeListeners.size() == 1) {
-        AutoScalingConfig.TriggerListenerConfig cfg = listeners.get(activeListeners.iterator().next());
-        if (SystemLogListener.class.getName().equals(cfg.listenerClass) ||
-            ("solr." + SystemLogListener.class.getSimpleName()).equals(cfg.listenerClass)) {
-          onlySystemLog = true;
-        }
-      }
-      if (removeListeners || onlySystemLog) {
-        listeners = new HashMap<>(listeners);
-        listeners.keySet().removeAll(activeListeners);
-      } else {
-        op.addError("Cannot remove trigger: " + triggerName + " because it has active listeners: " + activeListeners);
-        return currentConfig;
-      }
-    }
-    triggerConfigs.remove(triggerName);
-    currentConfig = currentConfig.withTriggerConfigs(triggerConfigs).withTriggerListenerConfigs(listeners);
-    return currentConfig;
-  }
-
-
-  private boolean setAutoScalingConfig(AutoScalingConfig currentConfig) throws KeeperException, InterruptedException, IOException {
-    verifyAutoScalingConf(currentConfig);
-    try {
-      cloudManager.getDistribStateManager().setData(SOLR_AUTOSCALING_CONF_PATH, Utils.toJSON(currentConfig), currentConfig.getZkVersion());
-    } catch (BadVersionException bve) {
-      // somebody else has changed the configuration so we must retry
-      return false;
-    }
-    //log.debug("-- saved version " + currentConfig.getZkVersion() + ": " + currentConfig);
-    return true;
-  }
-
-  private void verifyAutoScalingConf(AutoScalingConfig autoScalingConf) throws IOException {
-    Policy.Session session = autoScalingConf.getPolicy()
-        .createSession(cloudManager);
-    log.debug("Verified autoscaling configuration");
-  }
-
-  @Override
-  public String getDescription() {
-    return "A handler for autoscaling configuration";
-  }
-
-  @Override
-  public Name getPermissionName(AuthorizationContext request) {
-    switch (request.getHttpMethod()) {
-      case "GET":
-        return Name.AUTOSCALING_READ_PERM;
-      case "POST":
-        return Name.AUTOSCALING_WRITE_PERM;
-      default:
-        return null;
-    }
-  }
-
-  @Override
-  public Collection<Api> getApis() {
-    return ApiBag.wrapRequestHandlers(this, "autoscaling.Commands");
-  }
-
-  @Override
-  public Boolean registerV2() {
-    return Boolean.TRUE;
-  }
-
-  @Override
-  public SolrRequestHandler getSubHandler(String path) {
-    if (path.equals("/diagnostics") || path.equals("/suggestions")) return this;
-    return null;
-  }
-}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/0ae21ad0/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
deleted file mode 100644
index 7103bf5..0000000
--- a/solr/core/src/java/org/apache/solr/cloud/autoscaling/ComputePlanAction.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * 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.io.IOException;
-import java.lang.invoke.MethodHandles;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.solr.client.solrj.SolrRequest;
-import org.apache.solr.client.solrj.cloud.SolrCloudManager;
-import org.apache.solr.client.solrj.cloud.autoscaling.AutoScalingConfig;
-import org.apache.solr.client.solrj.cloud.autoscaling.NoneSuggester;
-import org.apache.solr.client.solrj.cloud.autoscaling.Policy;
-import org.apache.solr.client.solrj.cloud.autoscaling.PolicyHelper;
-import org.apache.solr.client.solrj.cloud.autoscaling.Suggester;
-import org.apache.solr.client.solrj.cloud.autoscaling.UnsupportedSuggester;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.cloud.ClusterState;
-import org.apache.solr.common.cloud.DocCollection;
-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.Pair;
-import org.apache.solr.common.util.StrUtils;
-import org.apache.solr.core.SolrResourceLoader;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import static org.apache.solr.cloud.autoscaling.TriggerEvent.NODE_NAMES;
-
-/**
- * This class is responsible for using the configured policy and preferences
- * with the hints provided by the trigger event to compute the required cluster operations.
- * <p>
- * The cluster operations computed here are put into the {@link ActionContext}'s properties
- * with the key name "operations". The value is a List of SolrRequest objects.
- */
-public class ComputePlanAction extends TriggerActionBase {
-  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
-  Set<String> collections = new HashSet<>();
-
-  public ComputePlanAction() {
-    super();
-    TriggerUtils.validProperties(validProperties, "collections");
-  }
-
-
-  @Override
-  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, ','));
-    }
-  }
-
-  @Override
-  public void process(TriggerEvent event, ActionContext context) throws Exception {
-    log.debug("-- processing event: {} with context properties: {}", event, context.getProperties());
-    SolrCloudManager cloudManager = context.getCloudManager();
-    try {
-      AutoScalingConfig autoScalingConf = cloudManager.getDistribStateManager().getAutoScalingConfig();
-      if (autoScalingConf.isEmpty()) {
-        throw new Exception("Action: " + getName() + " executed but no policy is configured");
-      }
-      PolicyHelper.SessionWrapper sessionWrapper = PolicyHelper.getSession(cloudManager);
-      Policy.Session session = sessionWrapper.get();
-      ClusterState clusterState = cloudManager.getClusterStateProvider().getClusterState();
-      if (log.isTraceEnabled()) {
-        log.trace("-- session: {}", session);
-        log.trace("-- state: {}", clusterState);
-      }
-      try {
-        Suggester suggester = getSuggester(session, event, context, cloudManager);
-        int maxOperations = getMaxNumOps(event, autoScalingConf, clusterState);
-        int requestedOperations = getRequestedNumOps(event);
-        if (requestedOperations > maxOperations) {
-          log.warn("Requested number of operations {} higher than maximum {}, adjusting...",
-              requestedOperations, maxOperations);
-        }
-        int opCount = 0;
-        int opLimit = maxOperations;
-        if (requestedOperations > 0) {
-          opLimit = requestedOperations;
-        }
-        do {
-          // computing changes in large clusters may take a long time
-          if (Thread.currentThread().isInterrupted()) {
-            throw new InterruptedException("stopping - thread was interrupted");
-          }
-          SolrRequest operation = suggester.getSuggestion();
-          opCount++;
-          // prepare suggester for the next iteration
-          if (suggester.getSession() != null) {
-            session = suggester.getSession();
-          }
-          suggester = getSuggester(session, event, context, cloudManager);
-
-          // break on first null op
-          // unless a specific number of ops was requested
-          // uncomment the following to log too many operations
-          /*if (opCount > 10) {
-            PolicyHelper.logState(cloudManager, initialSuggester);
-          }*/
-
-          if (operation == null) {
-            if (requestedOperations < 0) {
-              //uncomment the following to log zero operations
-//              PolicyHelper.logState(cloudManager, initialSuggester);
-              break;
-            } else {
-              log.info("Computed plan empty, remained " + (opCount - opLimit) + " requested ops to try.");
-              continue;
-            }
-          }
-          log.debug("Computed Plan: {}", operation.getParams());
-          if (!collections.isEmpty()) {
-            String coll = operation.getParams().get(CoreAdminParams.COLLECTION);
-            if (coll != null && !collections.contains(coll)) {
-              // discard an op that doesn't affect our collections
-              log.debug("-- discarding due to collection={} not in {}", coll, collections);
-              continue;
-            }
-          }
-          Map<String, Object> props = context.getProperties();
-          props.compute("operations", (k, v) -> {
-            List<SolrRequest> operations = (List<SolrRequest>) v;
-            if (operations == null) operations = new ArrayList<>();
-            operations.add(operation);
-            return operations;
-          });
-        } while (opCount < opLimit);
-      } finally {
-        releasePolicySession(sessionWrapper, session);
-      }
-    } catch (Exception e) {
-      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
-          "Unexpected exception while processing event: " + event, e);
-    }
-  }
-
-  private void releasePolicySession(PolicyHelper.SessionWrapper sessionWrapper, Policy.Session session) {
-    sessionWrapper.returnSession(session);
-    sessionWrapper.release();
-
-  }
-
-  protected int getMaxNumOps(TriggerEvent event, AutoScalingConfig autoScalingConfig, ClusterState clusterState) {
-    // estimate a maximum default limit that should be sufficient for most purposes:
-    // number of nodes * total number of replicas * 3
-    AtomicInteger totalRF = new AtomicInteger();
-    clusterState.forEachCollection(coll -> {
-      Integer rf = coll.getReplicationFactor();
-      if (rf == null) {
-        if (coll.getSlices().isEmpty()) {
-          rf = 1; // ???
-        } else {
-          rf = coll.getReplicas().size() / coll.getSlices().size();
-        }
-      }
-      totalRF.addAndGet(rf * coll.getSlices().size());
-    });
-    int totalMax = clusterState.getLiveNodes().size() * totalRF.get() * 3;
-    int maxOp = (Integer) autoScalingConfig.getProperties().getOrDefault(AutoScalingParams.MAX_COMPUTE_OPERATIONS, totalMax);
-    Object o = event.getProperty(AutoScalingParams.MAX_COMPUTE_OPERATIONS, maxOp);
-    try {
-      return Integer.parseInt(String.valueOf(o));
-    } catch (Exception e) {
-      log.warn("Invalid '" + AutoScalingParams.MAX_COMPUTE_OPERATIONS + "' event property: " + o + ", using default " + maxOp);
-      return maxOp;
-    }
-  }
-
-  protected int getRequestedNumOps(TriggerEvent event) {
-    Collection<TriggerEvent.Op> ops = (Collection<TriggerEvent.Op>) event.getProperty(TriggerEvent.REQUESTED_OPS, Collections.emptyList());
-    if (ops.isEmpty()) {
-      return -1;
-    } else {
-      return ops.size();
-    }
-  }
-
-  private static final String START = "__start__";
-
-  protected Suggester getSuggester(Policy.Session session, TriggerEvent event, ActionContext context, SolrCloudManager cloudManager) throws IOException {
-    Suggester suggester;
-    switch (event.getEventType()) {
-      case NODEADDED:
-        suggester = getNodeAddedSuggester(cloudManager, session, event);
-        break;
-      case NODELOST:
-        String preferredOp = (String) event.getProperty(AutoScalingParams.PREFERRED_OP, CollectionParams.CollectionAction.MOVEREPLICA.toLower());
-        CollectionParams.CollectionAction action = CollectionParams.CollectionAction.get(preferredOp);
-        switch (action) {
-          case MOVEREPLICA:
-            suggester = session.getSuggester(action)
-                .hint(Suggester.Hint.SRC_NODE, event.getProperty(NODE_NAMES));
-            break;
-          case DELETENODE:
-            int start = (Integer)event.getProperty(START, 0);
-            List<String> srcNodes = (List<String>) event.getProperty(NODE_NAMES);
-            if (srcNodes.isEmpty() || start >= srcNodes.size()) {
-              return NoneSuggester.get(session);
-            }
-            String sourceNode = srcNodes.get(start);
-            suggester = session.getSuggester(action)
-                .hint(Suggester.Hint.SRC_NODE, Collections.singletonList(sourceNode));
-            event.getProperties().put(START, ++start);
-            break;
-          case NONE:
-            return NoneSuggester.get(session);
-          default:
-            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unsupported preferredOperation: " + action.toLower() + " specified for node lost trigger");
-        }
-        break;
-      case SEARCHRATE:
-      case METRIC:
-      case INDEXSIZE:
-        List<TriggerEvent.Op> ops = (List<TriggerEvent.Op>)event.getProperty(TriggerEvent.REQUESTED_OPS, Collections.emptyList());
-        int start = (Integer)event.getProperty(START, 0);
-        if (ops.isEmpty() || start >= ops.size()) {
-          return NoneSuggester.get(session);
-        }
-        TriggerEvent.Op op = ops.get(start);
-        suggester = session.getSuggester(op.getAction());
-        if (suggester instanceof UnsupportedSuggester) {
-          List<TriggerEvent.Op> unsupportedOps = (List<TriggerEvent.Op>)context.getProperties().computeIfAbsent(TriggerEvent.UNSUPPORTED_OPS, k -> new ArrayList<TriggerEvent.Op>());
-          unsupportedOps.add(op);
-        }
-        for (Map.Entry<Suggester.Hint, Object> e : op.getHints().entrySet()) {
-          suggester = suggester.hint(e.getKey(), e.getValue());
-        }
-        suggester = suggester.forceOperation(true);
-        event.getProperties().put(START, ++start);
-        break;
-      case SCHEDULED:
-        preferredOp = (String) event.getProperty(AutoScalingParams.PREFERRED_OP, CollectionParams.CollectionAction.MOVEREPLICA.toLower());
-        action = CollectionParams.CollectionAction.get(preferredOp);
-        suggester = session.getSuggester(action);
-        break;
-      default:
-        throw new UnsupportedOperationException("No support for events other than nodeAdded, nodeLost, searchRate, metric, scheduled and indexSize. Received: " + event.getEventType());
-    }
-    return suggester;
-  }
-
-  private Suggester getNodeAddedSuggester(SolrCloudManager cloudManager, Policy.Session session, TriggerEvent event) throws IOException {
-    String preferredOp = (String) event.getProperty(AutoScalingParams.PREFERRED_OP, CollectionParams.CollectionAction.MOVEREPLICA.toLower());
-    CollectionParams.CollectionAction action = CollectionParams.CollectionAction.get(preferredOp);
-
-    Suggester suggester = session.getSuggester(action)
-        .hint(Suggester.Hint.TARGET_NODE, event.getProperty(NODE_NAMES));
-    switch (action) {
-      case ADDREPLICA:
-        // add all collection/shard pairs and let policy engine figure out which one
-        // to place on the target node
-        // todo in future we can prune ineligible collection/shard pairs
-        ClusterState clusterState = cloudManager.getClusterStateProvider().getClusterState();
-        Set<Pair<String, String>> collShards = new HashSet<>();
-        clusterState.getCollectionStates().forEach((collectionName, collectionRef) -> {
-          DocCollection docCollection = collectionRef.get();
-          if (docCollection != null)  {
-            docCollection.getActiveSlices().stream()
-                .map(slice -> new Pair<>(collectionName, slice.getName()))
-                .forEach(collShards::add);
-          }
-        });
-        suggester.hint(Suggester.Hint.COLL_SHARD, collShards);
-        break;
-      case MOVEREPLICA:
-      case NONE:
-        break;
-      default:
-        throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
-            "Unsupported preferredOperation=" + preferredOp + " for node added event");
-    }
-    return suggester;
-  }
-}