@Inject
  public DiskThresholdDecider(
      Settings settings,
      NodeSettingsService nodeSettingsService,
      ClusterInfoService infoService,
      Client client) {
    super(settings);
    String lowWatermark = settings.get(CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK, "85%");
    String highWatermark = settings.get(CLUSTER_ROUTING_ALLOCATION_HIGH_DISK_WATERMARK, "90%");

    if (!validWatermarkSetting(lowWatermark, CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK)) {
      throw new ElasticsearchParseException("unable to parse low watermark [{}]", lowWatermark);
    }
    if (!validWatermarkSetting(highWatermark, CLUSTER_ROUTING_ALLOCATION_HIGH_DISK_WATERMARK)) {
      throw new ElasticsearchParseException("unable to parse high watermark [{}]", highWatermark);
    }
    // Watermark is expressed in terms of used data, but we need "free" data watermark
    this.freeDiskThresholdLow = 100.0 - thresholdPercentageFromWatermark(lowWatermark);
    this.freeDiskThresholdHigh = 100.0 - thresholdPercentageFromWatermark(highWatermark);

    this.freeBytesThresholdLow =
        thresholdBytesFromWatermark(lowWatermark, CLUSTER_ROUTING_ALLOCATION_LOW_DISK_WATERMARK);
    this.freeBytesThresholdHigh =
        thresholdBytesFromWatermark(highWatermark, CLUSTER_ROUTING_ALLOCATION_HIGH_DISK_WATERMARK);
    this.includeRelocations =
        settings.getAsBoolean(CLUSTER_ROUTING_ALLOCATION_INCLUDE_RELOCATIONS, true);
    this.rerouteInterval =
        settings.getAsTime(
            CLUSTER_ROUTING_ALLOCATION_REROUTE_INTERVAL, TimeValue.timeValueSeconds(60));

    this.enabled = settings.getAsBoolean(CLUSTER_ROUTING_ALLOCATION_DISK_THRESHOLD_ENABLED, true);
    nodeSettingsService.addListener(new ApplySettings());
    infoService.addListener(new DiskListener(client));
  }
 public RoutingAllocation.Result applyStartedShards(
     ClusterState clusterState, List<? extends ShardRouting> startedShards, boolean withReroute) {
   RoutingNodes routingNodes = clusterState.routingNodes();
   // shuffle the unassigned nodes, just so we won't have things like poison failed shards
   routingNodes.unassigned().shuffle();
   StartedRerouteAllocation allocation =
       new StartedRerouteAllocation(
           allocationDeciders,
           routingNodes,
           clusterState.nodes(),
           startedShards,
           clusterInfoService.getClusterInfo());
   boolean changed = applyStartedShards(routingNodes, startedShards);
   if (!changed) {
     return new RoutingAllocation.Result(false, clusterState.routingTable());
   }
   shardsAllocators.applyStartedShards(allocation);
   if (withReroute) {
     reroute(allocation);
   }
   return new RoutingAllocation.Result(
       true,
       new RoutingTable.Builder()
           .updateNodes(routingNodes)
           .build()
           .validateRaiseException(clusterState.metaData()));
 }
  /**
   * Only handles reroute but *without* any reassignment of unassigned shards or rebalancing. Does
   * make sure to handle removed nodes, but only moved the shards to UNASSIGNED, does not reassign
   * them.
   */
  public RoutingAllocation.Result rerouteWithNoReassign(ClusterState clusterState, boolean debug) {
    RoutingNodes routingNodes = clusterState.routingNodes();
    // shuffle the unassigned nodes, just so we won't have things like poison failed shards
    routingNodes.unassigned().shuffle();
    RoutingAllocation allocation =
        new RoutingAllocation(
            allocationDeciders,
            routingNodes,
            clusterState.nodes(),
            clusterInfoService.getClusterInfo());
    allocation.debugDecision(debug);
    boolean changed = false;
    // first, clear from the shards any node id they used to belong to that is now dead
    changed |= deassociateDeadNodes(allocation);

    // create a sorted list of from nodes with least number of shards to the maximum ones
    applyNewNodes(allocation);

    // elect primaries *before* allocating unassigned, so backups of primaries that failed
    // will be moved to primary state and not wait for primaries to be allocated and recovered
    // (*from gateway*)
    changed |= electPrimariesAndUnassignedDanglingReplicas(allocation);

    if (!changed) {
      return new RoutingAllocation.Result(false, clusterState.routingTable());
    }
    return new RoutingAllocation.Result(
        true,
        new RoutingTable.Builder()
            .updateNodes(routingNodes)
            .build()
            .validateRaiseException(clusterState.metaData()));
  }
 public RoutingAllocation.Result reroute(
     ClusterState clusterState, AllocationCommands commands, boolean explain)
     throws ElasticsearchException {
   RoutingNodes routingNodes = clusterState.routingNodes();
   // we don't shuffle the unassigned shards here, to try and get as close as possible to
   // a consistent result of the effect the commands have on the routing
   // this allows systems to dry run the commands, see the resulting cluster state, and act on it
   RoutingAllocation allocation =
       new RoutingAllocation(
           allocationDeciders,
           routingNodes,
           clusterState.nodes(),
           clusterInfoService.getClusterInfo());
   // don't short circuit deciders, we want a full explanation
   allocation.debugDecision(true);
   // we ignore disable allocation, because commands are explicit
   allocation.ignoreDisable(true);
   RoutingExplanations explanations = commands.execute(allocation, explain);
   // we revert the ignore disable flag, since when rerouting, we want the original setting to take
   // place
   allocation.ignoreDisable(false);
   // the assumption is that commands will move / act on shards (or fail through exceptions)
   // so, there will always be shard "movements", so no need to check on reroute
   reroute(allocation);
   return new RoutingAllocation.Result(
       true,
       new RoutingTable.Builder()
           .updateNodes(routingNodes)
           .build()
           .validateRaiseException(clusterState.metaData()),
       explanations);
 }
 /**
  * Applies the failed shards. Note, shards can be called several times within this method.
  *
  * <p>
  *
  * <p>If the same instance of the routing table is returned, then no change has been made.
  */
 public RoutingAllocation.Result applyFailedShards(
     ClusterState clusterState, List<ShardRouting> failedShards) {
   RoutingNodes routingNodes = clusterState.routingNodes();
   // shuffle the unassigned nodes, just so we won't have things like poison failed shards
   routingNodes.unassigned().shuffle();
   FailedRerouteAllocation allocation =
       new FailedRerouteAllocation(
           allocationDeciders,
           routingNodes,
           clusterState.nodes(),
           failedShards,
           clusterInfoService.getClusterInfo());
   boolean changed = false;
   for (ShardRouting failedShard : failedShards) {
     changed |= applyFailedShard(allocation, failedShard, true);
   }
   if (!changed) {
     return new RoutingAllocation.Result(false, clusterState.routingTable());
   }
   shardsAllocators.applyFailedShards(allocation);
   reroute(allocation);
   return new RoutingAllocation.Result(
       true,
       new RoutingTable.Builder()
           .updateNodes(routingNodes)
           .build()
           .validateRaiseException(clusterState.metaData()));
 }
 /**
  * Reroutes the routing table based on the live nodes.
  *
  * <p>
  *
  * <p>If the same instance of the routing table is returned, then no change has been made.
  */
 public RoutingAllocation.Result reroute(ClusterState clusterState, boolean debug) {
   RoutingNodes routingNodes = clusterState.routingNodes();
   // shuffle the unassigned nodes, just so we won't have things like poison failed shards
   routingNodes.unassigned().shuffle();
   RoutingAllocation allocation =
       new RoutingAllocation(
           allocationDeciders,
           routingNodes,
           clusterState.nodes(),
           clusterInfoService.getClusterInfo());
   allocation.debugDecision(debug);
   if (!reroute(allocation)) {
     return new RoutingAllocation.Result(false, clusterState.routingTable());
   }
   return new RoutingAllocation.Result(
       true,
       new RoutingTable.Builder()
           .updateNodes(routingNodes)
           .build()
           .validateRaiseException(clusterState.metaData()));
 }