Sfoglia il codice sorgente

Makes allocator decision classes top-level classes (#21662)

This commit moves several allocation decider related inner classes
into their own top-level class, in order to use more easily in
the allocation explain API. This commit also renames some of those
decision related classes to more suitable names.

This is simply a cosmetic change - no functionality changes with this
commit whatsoever.

To summarize the changes:
 1. ShardAllocationDecision renamed to AllocateUnassignedDecision
 2. RelocationDecision moved to a top-level class
 3. MoveDecision moved to a top-level class
 4. RebalanceDecision moved to a top-level class
 5. ShardAllocationDecisionTests renamed to AllocateUnassignedDecisionTests
 6. NodeRebalanceResult moved to a top-level class
 7. ShardAllocationDecision#WeightedDecision moved to a top-level class and renamed to NodeAllocationResult.
Ali Beyad 9 anni fa
parent
commit
1d2a1540cc

+ 41 - 92
core/src/main/java/org/elasticsearch/cluster/routing/allocation/ShardAllocationDecision.java → core/src/main/java/org/elasticsearch/cluster/routing/allocation/AllocateUnassignedDecision.java

@@ -30,29 +30,29 @@ import java.util.Map;
 import java.util.Objects;
 
 /**
- * Represents the allocation decision by an allocator for a shard.
+ * Represents the allocation decision by an allocator for an unassigned shard.
  */
-public class ShardAllocationDecision {
+public class AllocateUnassignedDecision {
     /** a constant representing a shard decision where no decision was taken */
-    public static final ShardAllocationDecision DECISION_NOT_TAKEN =
-        new ShardAllocationDecision(null, null, null, null, null, null, null);
+    public static final AllocateUnassignedDecision NOT_TAKEN =
+        new AllocateUnassignedDecision(null, null, null, null, null, null, null);
     /**
      * a map of cached common no/throttle decisions that don't need explanations,
      * this helps prevent unnecessary object allocations for the non-explain API case
      */
-    private static final Map<AllocationStatus, ShardAllocationDecision> CACHED_DECISIONS;
+    private static final Map<AllocationStatus, AllocateUnassignedDecision> CACHED_DECISIONS;
     static {
-        Map<AllocationStatus, ShardAllocationDecision> cachedDecisions = new HashMap<>();
+        Map<AllocationStatus, AllocateUnassignedDecision> cachedDecisions = new HashMap<>();
         cachedDecisions.put(AllocationStatus.FETCHING_SHARD_DATA,
-            new ShardAllocationDecision(Type.NO, AllocationStatus.FETCHING_SHARD_DATA, null, null, null, null, null));
+            new AllocateUnassignedDecision(Type.NO, AllocationStatus.FETCHING_SHARD_DATA, null, null, null, null, null));
         cachedDecisions.put(AllocationStatus.NO_VALID_SHARD_COPY,
-            new ShardAllocationDecision(Type.NO, AllocationStatus.NO_VALID_SHARD_COPY, null, null, null, null, null));
+            new AllocateUnassignedDecision(Type.NO, AllocationStatus.NO_VALID_SHARD_COPY, null, null, null, null, null));
         cachedDecisions.put(AllocationStatus.DECIDERS_NO,
-            new ShardAllocationDecision(Type.NO, AllocationStatus.DECIDERS_NO, null, null, null, null, null));
+            new AllocateUnassignedDecision(Type.NO, AllocationStatus.DECIDERS_NO, null, null, null, null, null));
         cachedDecisions.put(AllocationStatus.DECIDERS_THROTTLED,
-            new ShardAllocationDecision(Type.THROTTLE, AllocationStatus.DECIDERS_THROTTLED, null, null, null, null, null));
+            new AllocateUnassignedDecision(Type.THROTTLE, AllocationStatus.DECIDERS_THROTTLED, null, null, null, null, null));
         cachedDecisions.put(AllocationStatus.DELAYED_ALLOCATION,
-            new ShardAllocationDecision(Type.NO, AllocationStatus.DELAYED_ALLOCATION, null, null, null, null, null));
+            new AllocateUnassignedDecision(Type.NO, AllocationStatus.DELAYED_ALLOCATION, null, null, null, null, null));
         CACHED_DECISIONS = Collections.unmodifiableMap(cachedDecisions);
     }
 
@@ -67,17 +67,17 @@ public class ShardAllocationDecision {
     @Nullable
     private final String allocationId;
     @Nullable
-    private final Map<String, WeightedDecision> nodeDecisions;
+    private final Map<String, NodeAllocationResult> nodeDecisions;
     @Nullable
     private final Decision shardDecision;
 
-    private ShardAllocationDecision(Type finalDecision,
-                                    AllocationStatus allocationStatus,
-                                    String finalExplanation,
-                                    String assignedNodeId,
-                                    String allocationId,
-                                    Map<String, WeightedDecision> nodeDecisions,
-                                    Decision shardDecision) {
+    private AllocateUnassignedDecision(Type finalDecision,
+                                       AllocationStatus allocationStatus,
+                                       String finalExplanation,
+                                       String assignedNodeId,
+                                       String allocationId,
+                                       Map<String, NodeAllocationResult> nodeDecisions,
+                                       Decision shardDecision) {
         assert assignedNodeId != null || finalDecision == null || finalDecision != Type.YES :
             "a yes decision must have a node to assign the shard to";
         assert allocationStatus != null || finalDecision == null || finalDecision == Type.YES :
@@ -96,9 +96,9 @@ public class ShardAllocationDecision {
     /**
      * Returns a NO decision with the given shard-level decision and explanation (if in explain mode).
      */
-    public static ShardAllocationDecision no(Decision shardDecision, @Nullable String explanation) {
+    public static AllocateUnassignedDecision no(Decision shardDecision, @Nullable String explanation) {
         if (explanation != null) {
-            return new ShardAllocationDecision(Type.NO, AllocationStatus.DECIDERS_NO, explanation, null, null, null, shardDecision);
+            return new AllocateUnassignedDecision(Type.NO, AllocationStatus.DECIDERS_NO, explanation, null, null, null, shardDecision);
         } else {
             return getCachedDecision(AllocationStatus.DECIDERS_NO);
         }
@@ -107,7 +107,7 @@ public class ShardAllocationDecision {
     /**
      * Returns a NO decision with the given {@link AllocationStatus} and explanation for the NO decision, if in explain mode.
      */
-    public static ShardAllocationDecision no(AllocationStatus allocationStatus, @Nullable String explanation) {
+    public static AllocateUnassignedDecision no(AllocationStatus allocationStatus, @Nullable String explanation) {
         return no(allocationStatus, explanation, null);
     }
 
@@ -115,11 +115,11 @@ public class ShardAllocationDecision {
      * Returns a NO decision with the given {@link AllocationStatus}, and the explanation for the NO decision
      * as well as the individual node-level decisions that comprised the final NO decision if in explain mode.
      */
-    public static ShardAllocationDecision no(AllocationStatus allocationStatus, @Nullable String explanation,
-                                             @Nullable Map<String, Decision> nodeDecisions) {
+    public static AllocateUnassignedDecision no(AllocationStatus allocationStatus, @Nullable String explanation,
+                                                @Nullable Map<String, Decision> nodeDecisions) {
         Objects.requireNonNull(allocationStatus, "allocationStatus must not be null");
         if (explanation != null) {
-            return new ShardAllocationDecision(Type.NO, allocationStatus, explanation, null, null, asExplanations(nodeDecisions), null);
+            return new AllocateUnassignedDecision(Type.NO, allocationStatus, explanation, null, null, asExplanations(nodeDecisions), null);
         } else {
             return getCachedDecision(allocationStatus);
         }
@@ -129,9 +129,9 @@ public class ShardAllocationDecision {
      * Returns a THROTTLE decision, with the given explanation and individual node-level decisions that
      * comprised the final THROTTLE decision if in explain mode.
      */
-    public static ShardAllocationDecision throttle(@Nullable String explanation, @Nullable Map<String, Decision> nodeDecisions) {
+    public static AllocateUnassignedDecision throttle(@Nullable String explanation, @Nullable Map<String, Decision> nodeDecisions) {
         if (explanation != null) {
-            return new ShardAllocationDecision(Type.THROTTLE, AllocationStatus.DECIDERS_THROTTLED, explanation, null, null,
+            return new AllocateUnassignedDecision(Type.THROTTLE, AllocationStatus.DECIDERS_THROTTLED, explanation, null, null,
                                                asExplanations(nodeDecisions), null);
         } else {
             return getCachedDecision(AllocationStatus.DECIDERS_THROTTLED);
@@ -143,17 +143,18 @@ public class ShardAllocationDecision {
      * comprised the final YES decision, along with the node id to which the shard is assigned and
      * the allocation id for the shard, if available.
      */
-    public static ShardAllocationDecision yes(String assignedNodeId, @Nullable String explanation, @Nullable String allocationId,
-                                              @Nullable Map<String, Decision> nodeDecisions) {
+    public static AllocateUnassignedDecision yes(String assignedNodeId, @Nullable String explanation, @Nullable String allocationId,
+                                                 @Nullable Map<String, Decision> nodeDecisions) {
         Objects.requireNonNull(assignedNodeId, "assignedNodeId must not be null");
-        return new ShardAllocationDecision(Type.YES, null, explanation, assignedNodeId, allocationId, asExplanations(nodeDecisions), null);
+        return new AllocateUnassignedDecision(Type.YES, null, explanation, assignedNodeId, allocationId,
+                                                 asExplanations(nodeDecisions), null);
     }
 
     /**
-     * Creates a {@link ShardAllocationDecision} from the given {@link Decision} and the assigned node, if any.
+     * Creates a {@link AllocateUnassignedDecision} from the given {@link Decision} and the assigned node, if any.
      */
-    public static ShardAllocationDecision fromDecision(Decision decision, @Nullable String assignedNodeId, boolean explain,
-                                                       @Nullable Map<String, WeightedDecision> nodeDecisions) {
+    public static AllocateUnassignedDecision fromDecision(Decision decision, @Nullable String assignedNodeId, boolean explain,
+                                                          @Nullable Map<String, NodeAllocationResult> nodeDecisions) {
         final Type decisionType = decision.type();
         AllocationStatus allocationStatus = decisionType != Type.YES ? AllocationStatus.fromDecision(decisionType) : null;
         String explanation = null;
@@ -168,19 +169,19 @@ public class ShardAllocationDecision {
                 explanation = "shard cannot be assigned to any node in the cluster";
             }
         }
-        return new ShardAllocationDecision(decisionType, allocationStatus, explanation, assignedNodeId, null, nodeDecisions, null);
+        return new AllocateUnassignedDecision(decisionType, allocationStatus, explanation, assignedNodeId, null, nodeDecisions, null);
     }
 
-    private static ShardAllocationDecision getCachedDecision(AllocationStatus allocationStatus) {
-        ShardAllocationDecision decision = CACHED_DECISIONS.get(allocationStatus);
+    private static AllocateUnassignedDecision getCachedDecision(AllocationStatus allocationStatus) {
+        AllocateUnassignedDecision decision = CACHED_DECISIONS.get(allocationStatus);
         return Objects.requireNonNull(decision, "precomputed decision not found for " + allocationStatus);
     }
 
-    private static Map<String, WeightedDecision> asExplanations(Map<String, Decision> decisionMap) {
+    private static Map<String, NodeAllocationResult> asExplanations(Map<String, Decision> decisionMap) {
         if (decisionMap != null) {
-            Map<String, WeightedDecision> explanationMap = new HashMap<>();
+            Map<String, NodeAllocationResult> explanationMap = new HashMap<>();
             for (Map.Entry<String, Decision> entry : decisionMap.entrySet()) {
-                explanationMap.put(entry.getKey(), new WeightedDecision(entry.getValue(), Float.POSITIVE_INFINITY));
+                explanationMap.put(entry.getKey(), new NodeAllocationResult(entry.getValue(), Float.POSITIVE_INFINITY));
             }
             return explanationMap;
         }
@@ -259,7 +260,7 @@ public class ShardAllocationDecision {
      * as the decision for the given node.
      */
     @Nullable
-    public Map<String, WeightedDecision> getNodeDecisions() {
+    public Map<String, NodeAllocationResult> getNodeDecisions() {
         return nodeDecisions;
     }
 
@@ -273,56 +274,4 @@ public class ShardAllocationDecision {
         return shardDecision;
     }
 
-    /**
-     * This class represents the shard allocation decision for a single node,
-     * including the {@link Decision} whether to allocate to the node and the
-     * weight assigned to the node for the shard in question.
-     */
-    public static final class WeightedDecision {
-
-        private final Decision decision;
-        private final float weight;
-
-        public WeightedDecision(Decision decision) {
-            this.decision = Objects.requireNonNull(decision);
-            this.weight = Float.POSITIVE_INFINITY;
-        }
-
-        public WeightedDecision(Decision decision, float weight) {
-            this.decision = Objects.requireNonNull(decision);
-            this.weight = Objects.requireNonNull(weight);
-        }
-
-        /**
-         * The decision for allocating to the node.
-         */
-        public Decision getDecision() {
-            return decision;
-        }
-
-        /**
-         * The calculated weight for allocating a shard to the node.  A value of {@link Float#POSITIVE_INFINITY}
-         * means the weight was not calculated or factored into the decision.
-         */
-        public float getWeight() {
-            return weight;
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (this == other) {
-                return true;
-            }
-            if (other == null || getClass() != other.getClass()) {
-                return false;
-            }
-            WeightedDecision that = (WeightedDecision) other;
-            return decision.equals(that.decision) && Float.compare(weight, that.weight) == 0;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(decision, weight);
-        }
-    }
 }

+ 127 - 0
core/src/main/java/org/elasticsearch/cluster/routing/allocation/MoveDecision.java

@@ -0,0 +1,127 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.cluster.routing.allocation;
+
+import org.elasticsearch.cluster.routing.allocation.decider.Decision;
+import org.elasticsearch.common.Nullable;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * Represents a decision to move a started shard because it is no longer allowed to remain on its current node.
+ */
+public final class MoveDecision extends RelocationDecision {
+    /** a constant representing no decision taken */
+    public static final MoveDecision NOT_TAKEN = new MoveDecision(null, null, null, null, null);
+    /** cached decisions so we don't have to recreate objects for common decisions when not in explain mode. */
+    private static final MoveDecision CACHED_STAY_DECISION = new MoveDecision(Decision.YES, Decision.Type.NO, null, null, null);
+    private static final MoveDecision CACHED_CANNOT_MOVE_DECISION = new MoveDecision(Decision.NO, Decision.Type.NO, null, null, null);
+
+    @Nullable
+    private final Decision canRemainDecision;
+    @Nullable
+    private final Map<String, NodeAllocationResult> nodeDecisions;
+
+    private MoveDecision(Decision canRemainDecision, Decision.Type finalDecision, String finalExplanation,
+                         String assignedNodeId, Map<String, NodeAllocationResult> nodeDecisions) {
+        super(finalDecision, finalExplanation, assignedNodeId);
+        this.canRemainDecision = canRemainDecision;
+        this.nodeDecisions = nodeDecisions != null ? Collections.unmodifiableMap(nodeDecisions) : null;
+    }
+
+    /**
+     * Creates a move decision for the shard being able to remain on its current node, so not moving.
+     */
+    public static MoveDecision stay(Decision canRemainDecision, boolean explain) {
+        assert canRemainDecision.type() != Decision.Type.NO;
+        if (explain) {
+            final String explanation;
+            if (explain) {
+                explanation = "shard is allowed to remain on its current node, so no reason to move";
+            } else {
+                explanation = null;
+            }
+            return new MoveDecision(Objects.requireNonNull(canRemainDecision), Decision.Type.NO, explanation, null, null);
+        } else {
+            return CACHED_STAY_DECISION;
+        }
+    }
+
+    /**
+     * Creates a move decision for the shard not being able to remain on its current node.
+     *
+     * @param canRemainDecision the decision for whether the shard is allowed to remain on its current node
+     * @param finalDecision the decision of whether to move the shard to another node
+     * @param explain true if in explain mode
+     * @param currentNodeId the current node id where the shard is assigned
+     * @param assignedNodeId the node id for where the shard can move to
+     * @param nodeDecisions the node-level decisions that comprised the final decision, non-null iff explain is true
+     * @return the {@link MoveDecision} for moving the shard to another node
+     */
+    public static MoveDecision decision(Decision canRemainDecision, Decision.Type finalDecision, boolean explain, String currentNodeId,
+                                        String assignedNodeId, Map<String, NodeAllocationResult> nodeDecisions) {
+        assert canRemainDecision != null;
+        assert canRemainDecision.type() != Decision.Type.YES : "create decision with MoveDecision#stay instead";
+        String finalExplanation = null;
+        if (explain) {
+            assert currentNodeId != null;
+            if (finalDecision == Decision.Type.YES) {
+                assert assignedNodeId != null;
+                finalExplanation = "shard cannot remain on node [" + currentNodeId + "], moving to node [" + assignedNodeId + "]";
+            } else if (finalDecision == Decision.Type.THROTTLE) {
+                finalExplanation = "shard cannot remain on node [" + currentNodeId + "], throttled on moving to another node";
+            } else {
+                finalExplanation = "shard cannot remain on node [" + currentNodeId + "], but cannot be assigned to any other node";
+            }
+        }
+        if (finalExplanation == null && finalDecision == Decision.Type.NO) {
+            // the final decision is NO (no node to move the shard to) and we are not in explain mode, return a cached version
+            return CACHED_CANNOT_MOVE_DECISION;
+        } else {
+            assert ((assignedNodeId == null) == (finalDecision != Decision.Type.YES));
+            return new MoveDecision(canRemainDecision, finalDecision, finalExplanation, assignedNodeId, nodeDecisions);
+        }
+    }
+
+    /**
+     * Returns {@code true} if the shard cannot remain on its current node and can be moved, returns {@code false} otherwise.
+     */
+    public boolean move() {
+        return cannotRemain() && getFinalDecisionType() == Decision.Type.YES;
+    }
+
+    /**
+     * Returns {@code true} if the shard cannot remain on its current node.
+     */
+    public boolean cannotRemain() {
+        return isDecisionTaken() && canRemainDecision.type() == Decision.Type.NO;
+    }
+
+    /**
+     * Gets the individual node-level decisions that went into making the final decision as represented by
+     * {@link #getFinalDecisionType()}.  The map that is returned has the node id as the key and a {@link NodeAllocationResult}.
+     */
+    @Nullable
+    public Map<String, NodeAllocationResult> getNodeDecisions() {
+        return nodeDecisions;
+    }
+}

+ 77 - 0
core/src/main/java/org/elasticsearch/cluster/routing/allocation/NodeAllocationResult.java

@@ -0,0 +1,77 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.cluster.routing.allocation;
+
+import org.elasticsearch.cluster.routing.allocation.decider.Decision;
+
+import java.util.Objects;
+
+/**
+ * This class represents the shard allocation decision for a single node,
+ * including the {@link Decision} whether to allocate to the node and other
+ * information related to obtaining the decision for the node.
+ */
+public final class NodeAllocationResult {
+
+    private final Decision decision;
+    private final float weight;
+
+    public NodeAllocationResult(Decision decision) {
+        this.decision = Objects.requireNonNull(decision);
+        this.weight = Float.POSITIVE_INFINITY;
+    }
+
+    public NodeAllocationResult(Decision decision, float weight) {
+        this.decision = Objects.requireNonNull(decision);
+        this.weight = Objects.requireNonNull(weight);
+    }
+
+    /**
+     * The decision for allocating to the node.
+     */
+    public Decision getDecision() {
+        return decision;
+    }
+
+    /**
+     * The calculated weight for allocating a shard to the node.  A value of {@link Float#POSITIVE_INFINITY}
+     * means the weight was not calculated or factored into the decision.
+     */
+    public float getWeight() {
+        return weight;
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (other == null || getClass() != other.getClass()) {
+            return false;
+        }
+        NodeAllocationResult that = (NodeAllocationResult) other;
+        return decision.equals(that.decision) && Float.compare(weight, that.weight) == 0;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(decision, weight);
+    }
+}

+ 88 - 0
core/src/main/java/org/elasticsearch/cluster/routing/allocation/NodeRebalanceResult.java

@@ -0,0 +1,88 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.cluster.routing.allocation;
+
+import org.elasticsearch.cluster.routing.allocation.decider.Decision;
+
+import java.util.Objects;
+
+/**
+ * A node-level explanation for the decision to rebalance a shard.
+ */
+public final class NodeRebalanceResult {
+    private final Decision.Type nodeDecisionType;
+    private final Decision canAllocate;
+    private final boolean betterWeightThanCurrent;
+    private final boolean deltaAboveThreshold;
+    private final float currentWeight;
+    private final float weightWithShardAdded;
+
+    public NodeRebalanceResult(Decision.Type nodeDecisionType, Decision canAllocate, boolean betterWeightThanCurrent,
+                               boolean deltaAboveThreshold, float currentWeight, float weightWithShardAdded) {
+        this.nodeDecisionType = Objects.requireNonNull(nodeDecisionType);
+        this.canAllocate = Objects.requireNonNull(canAllocate);
+        this.betterWeightThanCurrent = betterWeightThanCurrent;
+        this.deltaAboveThreshold = deltaAboveThreshold;
+        this.currentWeight = currentWeight;
+        this.weightWithShardAdded = weightWithShardAdded;
+    }
+
+    /**
+     * Returns the decision to rebalance to the node.
+     */
+    public Decision.Type getNodeDecisionType() {
+        return nodeDecisionType;
+    }
+
+    /**
+     * Returns whether the shard is allowed to be allocated to the node.
+     */
+    public Decision getCanAllocateDecision() {
+        return canAllocate;
+    }
+
+    /**
+     * Returns whether the weight of the node is better than the weight of the node where the shard currently resides.
+     */
+    public boolean isBetterWeightThanCurrent() {
+        return betterWeightThanCurrent;
+    }
+
+    /**
+     * Returns if the weight delta by assigning to this node was above the threshold to warrant a rebalance.
+     */
+    public boolean isDeltaAboveThreshold() {
+        return deltaAboveThreshold;
+    }
+
+    /**
+     * Returns the current weight of the node if the shard is not added to the node.
+     */
+    public float getCurrentWeight() {
+        return currentWeight;
+    }
+
+    /**
+     * Returns the weight of the node if the shard is added to the node.
+     */
+    public float getWeightWithShardAdded() {
+        return weightWithShardAdded;
+    }
+}

+ 95 - 0
core/src/main/java/org/elasticsearch/cluster/routing/allocation/RebalanceDecision.java

@@ -0,0 +1,95 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.cluster.routing.allocation;
+
+import org.elasticsearch.cluster.routing.allocation.decider.Decision;
+import org.elasticsearch.cluster.routing.allocation.decider.Decision.Type;
+import org.elasticsearch.common.Nullable;
+
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Represents a decision to move a started shard to form a more optimally balanced cluster.
+ */
+public final class RebalanceDecision extends RelocationDecision {
+    /** a constant representing no decision taken */
+    public static final RebalanceDecision NOT_TAKEN = new RebalanceDecision(null, null, null, null, null, Float.POSITIVE_INFINITY);
+
+    @Nullable
+    private final Decision canRebalanceDecision;
+    @Nullable
+    private final Map<String, NodeRebalanceResult> nodeDecisions;
+    private float currentWeight;
+
+    public RebalanceDecision(Decision canRebalanceDecision, Type finalDecision, String finalExplanation) {
+        this(canRebalanceDecision, finalDecision, finalExplanation, null, null, Float.POSITIVE_INFINITY);
+    }
+
+    public RebalanceDecision(Decision canRebalanceDecision, Type finalDecision, String finalExplanation,
+                             String assignedNodeId, Map<String, NodeRebalanceResult> nodeDecisions, float currentWeight) {
+        super(finalDecision, finalExplanation, assignedNodeId);
+        this.canRebalanceDecision = canRebalanceDecision;
+        this.nodeDecisions = nodeDecisions != null ? Collections.unmodifiableMap(nodeDecisions) : null;
+        this.currentWeight = currentWeight;
+    }
+
+    /**
+     * Creates a new {@link RebalanceDecision}, computing the explanation based on the decision parameters.
+     */
+    public static RebalanceDecision decision(Decision canRebalanceDecision, Type finalDecision, String assignedNodeId,
+                                             Map<String, NodeRebalanceResult> nodeDecisions, float currentWeight, float threshold) {
+        final String explanation = produceFinalExplanation(finalDecision, assignedNodeId, threshold);
+        return new RebalanceDecision(canRebalanceDecision, finalDecision, explanation, assignedNodeId, nodeDecisions, currentWeight);
+    }
+
+    /**
+     * Returns the decision for being allowed to rebalance the shard.
+     */
+    @Nullable
+    public Decision getCanRebalanceDecision() {
+        return canRebalanceDecision;
+    }
+
+    /**
+     * Gets the individual node-level decisions that went into making the final decision as represented by
+     * {@link #getFinalDecisionType()}.  The map that is returned has the node id as the key and a {@link NodeRebalanceResult}.
+     */
+    @Nullable
+    public Map<String, NodeRebalanceResult> getNodeDecisions() {
+        return nodeDecisions;
+    }
+
+    private static String produceFinalExplanation(final Type finalDecisionType, final String assignedNodeId, final float threshold) {
+        final String finalExplanation;
+        if (assignedNodeId != null) {
+            if (finalDecisionType == Type.THROTTLE) {
+                finalExplanation = "throttle moving shard to node [" + assignedNodeId + "], as it is " +
+                                       "currently busy with other shard relocations";
+            } else {
+                finalExplanation = "moving shard to node [" + assignedNodeId + "] to form a more balanced cluster";
+            }
+        } else {
+            finalExplanation = "cannot rebalance shard, no other node exists that would form a more balanced " +
+                                   "cluster within the defined threshold [" + threshold + "]";
+        }
+        return finalExplanation;
+    }
+}

+ 74 - 0
core/src/main/java/org/elasticsearch/cluster/routing/allocation/RelocationDecision.java

@@ -0,0 +1,74 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch 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.elasticsearch.cluster.routing.allocation;
+
+import org.elasticsearch.cluster.routing.allocation.decider.Decision;
+import org.elasticsearch.common.Nullable;
+
+/**
+ * Represents a decision to relocate a started shard from its current node.
+ */
+public abstract class RelocationDecision {
+    @Nullable
+    private final Decision.Type finalDecision;
+    @Nullable
+    private final String finalExplanation;
+    @Nullable
+    private final String assignedNodeId;
+
+    protected RelocationDecision(Decision.Type finalDecision, String finalExplanation, String assignedNodeId) {
+        this.finalDecision = finalDecision;
+        this.finalExplanation = finalExplanation;
+        this.assignedNodeId = assignedNodeId;
+    }
+
+    /**
+     * Returns {@code true} if a decision was taken by the allocator, {@code false} otherwise.
+     * If no decision was taken, then the rest of the fields in this object are meaningless and return {@code null}.
+     */
+    public boolean isDecisionTaken() {
+        return finalDecision != null;
+    }
+
+    /**
+     * Returns the final decision made by the allocator on whether to assign the shard, and
+     * {@code null} if no decision was taken.
+     */
+    public Decision.Type getFinalDecisionType() {
+        return finalDecision;
+    }
+
+    /**
+     * Returns the free-text explanation for the reason behind the decision taken in {@link #getFinalDecisionType()}.
+     */
+    @Nullable
+    public String getFinalExplanation() {
+        return finalExplanation;
+    }
+
+    /**
+     * Get the node id that the allocator will assign the shard to, unless {@link #getFinalDecisionType()} returns
+     * a value other than {@link Decision.Type#YES}, in which case this returns {@code null}.
+     */
+    @Nullable
+    public String getAssignedNodeId() {
+        return assignedNodeId;
+    }
+}

+ 17 - 299
core/src/main/java/org/elasticsearch/cluster/routing/allocation/allocator/BalancedShardsAllocator.java

@@ -30,14 +30,16 @@ import org.elasticsearch.cluster.routing.RoutingNodes;
 import org.elasticsearch.cluster.routing.ShardRouting;
 import org.elasticsearch.cluster.routing.ShardRoutingState;
 import org.elasticsearch.cluster.routing.UnassignedInfo;
+import org.elasticsearch.cluster.routing.allocation.AllocateUnassignedDecision;
+import org.elasticsearch.cluster.routing.allocation.MoveDecision;
+import org.elasticsearch.cluster.routing.allocation.NodeRebalanceResult;
+import org.elasticsearch.cluster.routing.allocation.RebalanceDecision;
 import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
-import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision;
-import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision.WeightedDecision;
+import org.elasticsearch.cluster.routing.allocation.NodeAllocationResult;
 import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision.Type;
 import org.elasticsearch.cluster.routing.allocation.decider.DiskThresholdDecider;
-import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.collect.Tuple;
 import org.elasticsearch.common.component.AbstractComponent;
 import org.elasticsearch.common.inject.Inject;
@@ -54,7 +56,6 @@ import java.util.HashSet;
 import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.Map;
-import java.util.Objects;
 import java.util.Set;
 
 import static org.elasticsearch.cluster.routing.ShardRoutingState.RELOCATING;
@@ -368,7 +369,7 @@ public class BalancedShardsAllocator extends AbstractComponent implements Shards
             final float currentWeight = sorter.weight(currentNode);
             final AllocationDeciders deciders = allocation.deciders();
             final String idxName = shard.getIndexName();
-            Map<String, NodeRebalanceDecision> nodeDecisions = new HashMap<>(modelNodes.length - 1);
+            Map<String, NodeRebalanceResult> nodeDecisions = new HashMap<>(modelNodes.length - 1);
             Type rebalanceDecisionType = Type.NO;
             String assignedNodeId = null;
             for (ModelNode node : modelNodes) {
@@ -412,7 +413,7 @@ public class BalancedShardsAllocator extends AbstractComponent implements Shards
                         assignedNodeId = node.getNodeId();
                     }
                 }
-                nodeDecisions.put(node.getNodeId(), new NodeRebalanceDecision(
+                nodeDecisions.put(node.getNodeId(), new NodeRebalanceResult(
                     rebalanceConditionsMet ? canAllocate.type() : Type.NO,
                     canAllocate,
                     betterWeightThanCurrent,
@@ -683,14 +684,14 @@ public class BalancedShardsAllocator extends AbstractComponent implements Shards
              */
             Type bestDecision = Type.NO;
             RoutingNode targetNode = null;
-            final Map<String, WeightedDecision> nodeExplanationMap = explain ? new HashMap<>() : null;
+            final Map<String, NodeAllocationResult> nodeExplanationMap = explain ? new HashMap<>() : null;
             for (ModelNode currentNode : sorter.modelNodes) {
                 if (currentNode != sourceNode) {
                     RoutingNode target = currentNode.getRoutingNode();
                     // don't use canRebalance as we want hard filtering rules to apply. See #17698
                     Decision allocationDecision = allocation.deciders().canAllocate(shardRouting, target, allocation);
                     if (explain) {
-                        nodeExplanationMap.put(currentNode.getNodeId(), new WeightedDecision(allocationDecision, sorter.weight(currentNode)));
+                        nodeExplanationMap.put(currentNode.getNodeId(), new NodeAllocationResult(allocationDecision, sorter.weight(currentNode)));
                     }
                     // TODO maybe we can respect throttling here too?
                     if (allocationDecision.type().higherThan(bestDecision)) {
@@ -791,7 +792,7 @@ public class BalancedShardsAllocator extends AbstractComponent implements Shards
             do {
                 for (int i = 0; i < primaryLength; i++) {
                     ShardRouting shard = primary[i];
-                    ShardAllocationDecision allocationDecision = decideAllocateUnassigned(shard, throttledNodes);
+                    AllocateUnassignedDecision allocationDecision = decideAllocateUnassigned(shard, throttledNodes);
                     final Type decisionType = allocationDecision.getFinalDecisionType();
                     final String assignedNodeId = allocationDecision.getAssignedNodeId();
                     final ModelNode minNode = assignedNodeId != null ? nodes.get(assignedNodeId) : null;
@@ -864,16 +865,16 @@ public class BalancedShardsAllocator extends AbstractComponent implements Shards
          * {@link ModelNode} representing the node that the shard should be assigned to.  If the decision returned
          * is of type {@link Type#NO}, then the assigned node will be null.
          */
-        private ShardAllocationDecision decideAllocateUnassigned(final ShardRouting shard, final Set<ModelNode> throttledNodes) {
+        private AllocateUnassignedDecision decideAllocateUnassigned(final ShardRouting shard, final Set<ModelNode> throttledNodes) {
             if (shard.assignedToNode()) {
                 // we only make decisions for unassigned shards here
-                return ShardAllocationDecision.DECISION_NOT_TAKEN;
+                return AllocateUnassignedDecision.NOT_TAKEN;
             }
 
             Decision shardLevelDecision = allocation.deciders().canAllocate(shard, allocation);
             if (shardLevelDecision.type() == Type.NO) {
                 // NO decision for allocating the shard, irrespective of any particular node, so exit early
-                return ShardAllocationDecision.no(shardLevelDecision, explain("cannot allocate shard in its current state"));
+                return AllocateUnassignedDecision.no(shardLevelDecision, explain("cannot allocate shard in its current state"));
             }
 
             /* find an node with minimal weight we can allocate on*/
@@ -884,11 +885,11 @@ public class BalancedShardsAllocator extends AbstractComponent implements Shards
             if (throttledNodes.size() >= nodes.size() && explain == false) {
                 // all nodes are throttled, so we know we won't be able to allocate this round,
                 // so if we are not in explain mode, short circuit
-                return ShardAllocationDecision.no(UnassignedInfo.AllocationStatus.DECIDERS_NO, null);
+                return AllocateUnassignedDecision.no(UnassignedInfo.AllocationStatus.DECIDERS_NO, null);
             }
             /* Don't iterate over an identity hashset here the
              * iteration order is different for each run and makes testing hard */
-            Map<String, WeightedDecision> nodeExplanationMap = explain ? new HashMap<>() : null;
+            Map<String, NodeAllocationResult> nodeExplanationMap = explain ? new HashMap<>() : null;
             for (ModelNode node : nodes.values()) {
                 if ((throttledNodes.contains(node) || node.containsShard(shard)) && explain == false) {
                     // decision is NO without needing to check anything further, so short circuit
@@ -904,7 +905,7 @@ public class BalancedShardsAllocator extends AbstractComponent implements Shards
 
                 Decision currentDecision = allocation.deciders().canAllocate(shard, node.getRoutingNode(), allocation);
                 if (explain) {
-                    nodeExplanationMap.put(node.getNodeId(), new WeightedDecision(currentDecision, currentWeight));
+                    nodeExplanationMap.put(node.getNodeId(), new NodeAllocationResult(currentDecision, currentWeight));
                 }
                 if (currentDecision.type() == Type.YES || currentDecision.type() == Type.THROTTLE) {
                     final boolean updateMinNode;
@@ -945,7 +946,7 @@ public class BalancedShardsAllocator extends AbstractComponent implements Shards
                 // decision was not set and a node was not assigned, so treat it as a NO decision
                 decision = Decision.NO;
             }
-            return ShardAllocationDecision.fromDecision(
+            return AllocateUnassignedDecision.fromDecision(
                 decision,
                 minNode != null ? minNode.getNodeId() : null,
                 explain,
@@ -1223,287 +1224,4 @@ public class BalancedShardsAllocator extends AbstractComponent implements Shards
         }
     }
 
-    /**
-     * Represents a decision to relocate a started shard from its current node.
-     */
-    public abstract static class RelocationDecision {
-        @Nullable
-        private final Type finalDecision;
-        @Nullable
-        private final String finalExplanation;
-        @Nullable
-        private final String assignedNodeId;
-
-        protected RelocationDecision(Type finalDecision, String finalExplanation, String assignedNodeId) {
-            this.finalDecision = finalDecision;
-            this.finalExplanation = finalExplanation;
-            this.assignedNodeId = assignedNodeId;
-        }
-
-        /**
-         * Returns {@code true} if a decision was taken by the allocator, {@code false} otherwise.
-         * If no decision was taken, then the rest of the fields in this object are meaningless and return {@code null}.
-         */
-        public boolean isDecisionTaken() {
-            return finalDecision != null;
-        }
-
-        /**
-         * Returns the final decision made by the allocator on whether to assign the shard, and
-         * {@code null} if no decision was taken.
-         */
-        public Type getFinalDecisionType() {
-            return finalDecision;
-        }
-
-        /**
-         * Returns the free-text explanation for the reason behind the decision taken in {@link #getFinalDecisionType()}.
-         */
-        @Nullable
-        public String getFinalExplanation() {
-            return finalExplanation;
-        }
-
-        /**
-         * Get the node id that the allocator will assign the shard to, unless {@link #getFinalDecisionType()} returns
-         * a value other than {@link Decision.Type#YES}, in which case this returns {@code null}.
-         */
-        @Nullable
-        public String getAssignedNodeId() {
-            return assignedNodeId;
-        }
-    }
-
-    /**
-     * Represents a decision to move a started shard because it is no longer allowed to remain on its current node.
-     */
-    public static final class MoveDecision extends RelocationDecision {
-        /** a constant representing no decision taken */
-        public static final MoveDecision NOT_TAKEN = new MoveDecision(null, null, null, null, null);
-        /** cached decisions so we don't have to recreate objects for common decisions when not in explain mode. */
-        private static final MoveDecision CACHED_STAY_DECISION = new MoveDecision(Decision.YES, Type.NO, null, null, null);
-        private static final MoveDecision CACHED_CANNOT_MOVE_DECISION = new MoveDecision(Decision.NO, Type.NO, null, null, null);
-
-        @Nullable
-        private final Decision canRemainDecision;
-        @Nullable
-        private final Map<String, WeightedDecision> nodeDecisions;
-
-        private MoveDecision(Decision canRemainDecision, Type finalDecision, String finalExplanation,
-                             String assignedNodeId, Map<String, WeightedDecision> nodeDecisions) {
-            super(finalDecision, finalExplanation, assignedNodeId);
-            this.canRemainDecision = canRemainDecision;
-            this.nodeDecisions = nodeDecisions != null ? Collections.unmodifiableMap(nodeDecisions) : null;
-        }
-
-        /**
-         * Creates a move decision for the shard being able to remain on its current node, so not moving.
-         */
-        public static MoveDecision stay(Decision canRemainDecision, boolean explain) {
-            assert canRemainDecision.type() != Type.NO;
-            if (explain) {
-                final String explanation;
-                if (explain) {
-                    explanation = "shard is allowed to remain on its current node, so no reason to move";
-                } else {
-                    explanation = null;
-                }
-                return new MoveDecision(Objects.requireNonNull(canRemainDecision), Type.NO, explanation, null, null);
-            } else {
-                return CACHED_STAY_DECISION;
-            }
-        }
-
-        /**
-         * Creates a move decision for the shard not being able to remain on its current node.
-         *
-         * @param canRemainDecision the decision for whether the shard is allowed to remain on its current node
-         * @param finalDecision the decision of whether to move the shard to another node
-         * @param explain true if in explain mode
-         * @param currentNodeId the current node id where the shard is assigned
-         * @param assignedNodeId the node id for where the shard can move to
-         * @param nodeDecisions the node-level decisions that comprised the final decision, non-null iff explain is true
-         * @return the {@link MoveDecision} for moving the shard to another node
-         */
-        public static MoveDecision decision(Decision canRemainDecision, Type finalDecision, boolean explain, String currentNodeId,
-                                            String assignedNodeId, Map<String, WeightedDecision> nodeDecisions) {
-            assert canRemainDecision != null;
-            assert canRemainDecision.type() != Type.YES : "create decision with MoveDecision#stay instead";
-            String finalExplanation = null;
-            if (explain) {
-                assert currentNodeId != null;
-                if (finalDecision == Type.YES) {
-                    assert assignedNodeId != null;
-                    finalExplanation = "shard cannot remain on node [" + currentNodeId + "], moving to node [" + assignedNodeId + "]";
-                } else if (finalDecision == Type.THROTTLE) {
-                    finalExplanation = "shard cannot remain on node [" + currentNodeId + "], throttled on moving to another node";
-                } else {
-                    finalExplanation = "shard cannot remain on node [" + currentNodeId + "], but cannot be assigned to any other node";
-                }
-            }
-            if (finalExplanation == null && finalDecision == Type.NO) {
-                // the final decision is NO (no node to move the shard to) and we are not in explain mode, return a cached version
-                return CACHED_CANNOT_MOVE_DECISION;
-            } else {
-                assert ((assignedNodeId == null) == (finalDecision != Type.YES));
-                return new MoveDecision(canRemainDecision, finalDecision, finalExplanation, assignedNodeId, nodeDecisions);
-            }
-        }
-
-        /**
-         * Returns {@code true} if the shard cannot remain on its current node and can be moved, returns {@code false} otherwise.
-         */
-        public boolean move() {
-            return cannotRemain() && getFinalDecisionType() == Type.YES;
-        }
-
-        /**
-         * Returns {@code true} if the shard cannot remain on its current node.
-         */
-        public boolean cannotRemain() {
-            return isDecisionTaken() && canRemainDecision.type() == Type.NO;
-        }
-
-        /**
-         * Gets the individual node-level decisions that went into making the final decision as represented by
-         * {@link #getFinalDecisionType()}.  The map that is returned has the node id as the key and a {@link WeightedDecision}.
-         */
-        @Nullable
-        public Map<String, WeightedDecision> getNodeDecisions() {
-            return nodeDecisions;
-        }
-    }
-
-    /**
-     * Represents a decision to move a started shard to form a more optimally balanced cluster.
-     */
-    public static final class RebalanceDecision extends RelocationDecision {
-        /** a constant representing no decision taken */
-        public static final RebalanceDecision NOT_TAKEN = new RebalanceDecision(null, null, null, null, null, Float.POSITIVE_INFINITY);
-
-        @Nullable
-        private final Decision canRebalanceDecision;
-        @Nullable
-        private final Map<String, NodeRebalanceDecision> nodeDecisions;
-        private float currentWeight;
-
-        protected RebalanceDecision(Decision canRebalanceDecision, Type finalDecision, String finalExplanation) {
-            this(canRebalanceDecision, finalDecision, finalExplanation, null, null, Float.POSITIVE_INFINITY);
-        }
-
-        protected RebalanceDecision(Decision canRebalanceDecision, Type finalDecision, String finalExplanation,
-                                    String assignedNodeId, Map<String, NodeRebalanceDecision> nodeDecisions, float currentWeight) {
-            super(finalDecision, finalExplanation, assignedNodeId);
-            this.canRebalanceDecision = canRebalanceDecision;
-            this.nodeDecisions = nodeDecisions != null ? Collections.unmodifiableMap(nodeDecisions) : null;
-            this.currentWeight = currentWeight;
-        }
-
-        /**
-         * Creates a new {@link RebalanceDecision}, computing the explanation based on the decision parameters.
-         */
-        public static RebalanceDecision decision(Decision canRebalanceDecision, Type finalDecision, String assignedNodeId,
-                                                 Map<String, NodeRebalanceDecision> nodeDecisions, float currentWeight, float threshold) {
-            final String explanation = produceFinalExplanation(finalDecision, assignedNodeId, threshold);
-            return new RebalanceDecision(canRebalanceDecision, finalDecision, explanation, assignedNodeId, nodeDecisions, currentWeight);
-        }
-
-        /**
-         * Returns the decision for being allowed to rebalance the shard.
-         */
-        @Nullable
-        public Decision getCanRebalanceDecision() {
-            return canRebalanceDecision;
-        }
-
-        /**
-         * Gets the individual node-level decisions that went into making the final decision as represented by
-         * {@link #getFinalDecisionType()}.  The map that is returned has the node id as the key and a {@link NodeRebalanceDecision}.
-         */
-        @Nullable
-        public Map<String, NodeRebalanceDecision> getNodeDecisions() {
-            return nodeDecisions;
-        }
-
-        private static String produceFinalExplanation(final Type finalDecisionType, final String assignedNodeId, final float threshold) {
-            final String finalExplanation;
-            if (assignedNodeId != null) {
-                if (finalDecisionType == Type.THROTTLE) {
-                    finalExplanation = "throttle moving shard to node [" + assignedNodeId + "], as it is " +
-                                           "currently busy with other shard relocations";
-                } else {
-                    finalExplanation = "moving shard to node [" + assignedNodeId + "] to form a more balanced cluster";
-                }
-            } else {
-                finalExplanation = "cannot rebalance shard, no other node exists that would form a more balanced " +
-                                       "cluster within the defined threshold [" + threshold + "]";
-            }
-            return finalExplanation;
-        }
-    }
-
-    /**
-     * A node-level explanation for the decision to rebalance a shard.
-     */
-    public static final class NodeRebalanceDecision {
-        private final Type nodeDecisionType;
-        private final Decision canAllocate;
-        private final boolean betterWeightThanCurrent;
-        private final boolean deltaAboveThreshold;
-        private final float currentWeight;
-        private final float weightWithShardAdded;
-
-        NodeRebalanceDecision(Type nodeDecisionType, Decision canAllocate, boolean betterWeightThanCurrent,
-                              boolean deltaAboveThreshold, float currentWeight, float weightWithShardAdded) {
-            this.nodeDecisionType = Objects.requireNonNull(nodeDecisionType);
-            this.canAllocate = Objects.requireNonNull(canAllocate);
-            this.betterWeightThanCurrent = betterWeightThanCurrent;
-            this.deltaAboveThreshold = deltaAboveThreshold;
-            this.currentWeight = currentWeight;
-            this.weightWithShardAdded = weightWithShardAdded;
-        }
-
-        /**
-         * Returns the decision to rebalance to the node.
-         */
-        public Type getNodeDecisionType() {
-            return nodeDecisionType;
-        }
-
-        /**
-         * Returns whether the shard is allowed to be allocated to the node.
-         */
-        public Decision getCanAllocateDecision() {
-            return canAllocate;
-        }
-
-        /**
-         * Returns whether the weight of the node is better than the weight of the node where the shard currently resides.
-         */
-        public boolean isBetterWeightThanCurrent() {
-            return betterWeightThanCurrent;
-        }
-
-        /**
-         * Returns if the weight delta by assigning to this node was above the threshold to warrant a rebalance.
-         */
-        public boolean isDeltaAboveThreshold() {
-            return deltaAboveThreshold;
-        }
-
-        /**
-         * Returns the current weight of the node if the shard is not added to the node.
-         */
-        public float getCurrentWeight() {
-            return currentWeight;
-        }
-
-        /**
-         * Returns the weight of the node if the shard is added to the node.
-         */
-        public float getWeightWithShardAdded() {
-            return weightWithShardAdded;
-        }
-    }
-
 }

+ 11 - 11
core/src/main/java/org/elasticsearch/gateway/BaseGatewayShardAllocator.java

@@ -22,8 +22,8 @@ package org.elasticsearch.gateway;
 import org.apache.logging.log4j.Logger;
 import org.elasticsearch.cluster.routing.RoutingNodes;
 import org.elasticsearch.cluster.routing.ShardRouting;
+import org.elasticsearch.cluster.routing.allocation.AllocateUnassignedDecision;
 import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
-import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision;
 import org.elasticsearch.common.component.AbstractComponent;
 import org.elasticsearch.common.settings.Settings;
@@ -53,21 +53,21 @@ public abstract class BaseGatewayShardAllocator extends AbstractComponent {
         final RoutingNodes.UnassignedShards.UnassignedIterator unassignedIterator = routingNodes.unassigned().iterator();
         while (unassignedIterator.hasNext()) {
             final ShardRouting shard = unassignedIterator.next();
-            final ShardAllocationDecision shardAllocationDecision = makeAllocationDecision(shard, allocation, logger);
+            final AllocateUnassignedDecision allocateUnassignedDecision = makeAllocationDecision(shard, allocation, logger);
 
-            if (shardAllocationDecision.isDecisionTaken() == false) {
+            if (allocateUnassignedDecision.isDecisionTaken() == false) {
                 // no decision was taken by this allocator
                 continue;
             }
 
-            if (shardAllocationDecision.getFinalDecisionSafe() == Decision.Type.YES) {
-                unassignedIterator.initialize(shardAllocationDecision.getAssignedNodeId(),
-                    shardAllocationDecision.getAllocationId(),
+            if (allocateUnassignedDecision.getFinalDecisionSafe() == Decision.Type.YES) {
+                unassignedIterator.initialize(allocateUnassignedDecision.getAssignedNodeId(),
+                    allocateUnassignedDecision.getAllocationId(),
                     shard.primary() ? ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE :
                                       allocation.clusterInfo().getShardSize(shard, ShardRouting.UNAVAILABLE_EXPECTED_SHARD_SIZE),
                     allocation.changes());
             } else {
-                unassignedIterator.removeAndIgnore(shardAllocationDecision.getAllocationStatus(), allocation.changes());
+                unassignedIterator.removeAndIgnore(allocateUnassignedDecision.getAllocationStatus(), allocation.changes());
             }
         }
     }
@@ -80,9 +80,9 @@ public abstract class BaseGatewayShardAllocator extends AbstractComponent {
      * @param unassignedShard  the unassigned shard to allocate
      * @param allocation       the current routing state
      * @param logger           the logger
-     * @return an {@link ShardAllocationDecision} with the final decision of whether to allocate and details of the decision
+     * @return an {@link AllocateUnassignedDecision} with the final decision of whether to allocate and details of the decision
      */
-    public abstract ShardAllocationDecision makeAllocationDecision(ShardRouting unassignedShard,
-                                                                   RoutingAllocation allocation,
-                                                                   Logger logger);
+    public abstract AllocateUnassignedDecision makeAllocationDecision(ShardRouting unassignedShard,
+                                                                      RoutingAllocation allocation,
+                                                                      Logger logger);
 }

+ 14 - 14
core/src/main/java/org/elasticsearch/gateway/PrimaryShardAllocator.java

@@ -31,8 +31,8 @@ import org.elasticsearch.cluster.routing.RoutingNode;
 import org.elasticsearch.cluster.routing.RoutingNodes;
 import org.elasticsearch.cluster.routing.ShardRouting;
 import org.elasticsearch.cluster.routing.UnassignedInfo.AllocationStatus;
+import org.elasticsearch.cluster.routing.allocation.AllocateUnassignedDecision;
 import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
-import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision.Type;
 import org.elasticsearch.common.settings.Setting;
@@ -110,19 +110,19 @@ public abstract class PrimaryShardAllocator extends BaseGatewayShardAllocator {
     }
 
     @Override
-    public ShardAllocationDecision makeAllocationDecision(final ShardRouting unassignedShard,
-                                                          final RoutingAllocation allocation,
-                                                          final Logger logger) {
+    public AllocateUnassignedDecision makeAllocationDecision(final ShardRouting unassignedShard,
+                                                             final RoutingAllocation allocation,
+                                                             final Logger logger) {
         if (isResponsibleFor(unassignedShard) == false) {
             // this allocator is not responsible for allocating this shard
-            return ShardAllocationDecision.DECISION_NOT_TAKEN;
+            return AllocateUnassignedDecision.NOT_TAKEN;
         }
 
         final boolean explain = allocation.debugDecision();
         final FetchResult<NodeGatewayStartedShards> shardState = fetchData(unassignedShard, allocation);
         if (shardState.hasData() == false) {
             allocation.setHasPendingAsyncFetch();
-            return ShardAllocationDecision.no(AllocationStatus.FETCHING_SHARD_DATA,
+            return AllocateUnassignedDecision.no(AllocationStatus.FETCHING_SHARD_DATA,
                 explain ? "still fetching shard state from the nodes in the cluster" : null);
         }
 
@@ -167,18 +167,18 @@ public abstract class PrimaryShardAllocator extends BaseGatewayShardAllocator {
                 // let BalancedShardsAllocator take care of allocating this shard
                 logger.debug("[{}][{}]: missing local data, will restore from [{}]",
                              unassignedShard.index(), unassignedShard.id(), unassignedShard.recoverySource());
-                return ShardAllocationDecision.DECISION_NOT_TAKEN;
+                return AllocateUnassignedDecision.NOT_TAKEN;
             } else if (recoverOnAnyNode) {
                 // let BalancedShardsAllocator take care of allocating this shard
                 logger.debug("[{}][{}]: missing local data, recover from any node", unassignedShard.index(), unassignedShard.id());
-                return ShardAllocationDecision.DECISION_NOT_TAKEN;
+                return AllocateUnassignedDecision.NOT_TAKEN;
             } else {
                 // We have a shard that was previously allocated, but we could not find a valid shard copy to allocate the primary.
                 // We could just be waiting for the node that holds the primary to start back up, in which case the allocation for
                 // this shard will be picked up when the node joins and we do another allocation reroute
                 logger.debug("[{}][{}]: not allocating, number_of_allocated_shards_found [{}]",
                              unassignedShard.index(), unassignedShard.id(), nodeShardsResult.allocationsFound);
-                return ShardAllocationDecision.no(AllocationStatus.NO_VALID_SHARD_COPY,
+                return AllocateUnassignedDecision.no(AllocationStatus.NO_VALID_SHARD_COPY,
                     explain ? "shard was previously allocated, but no valid shard copy could be found amongst the nodes in the cluster" : null);
             }
         }
@@ -191,7 +191,7 @@ public abstract class PrimaryShardAllocator extends BaseGatewayShardAllocator {
             logger.debug("[{}][{}]: allocating [{}] to [{}] on primary allocation",
                          unassignedShard.index(), unassignedShard.id(), unassignedShard, decidedNode.nodeShardState.getNode());
             final String nodeId = decidedNode.nodeShardState.getNode().getId();
-            return ShardAllocationDecision.yes(nodeId,
+            return AllocateUnassignedDecision.yes(nodeId,
                 "the allocation deciders returned a YES decision to allocate to node [" + nodeId + "]",
                 decidedNode.nodeShardState.allocationId(),
                 buildNodeDecisions(nodesToAllocate, explain));
@@ -207,20 +207,20 @@ public abstract class PrimaryShardAllocator extends BaseGatewayShardAllocator {
                 logger.debug("[{}][{}]: allocating [{}] to [{}] on forced primary allocation",
                              unassignedShard.index(), unassignedShard.id(), unassignedShard, nodeShardState.getNode());
                 final String nodeId = nodeShardState.getNode().getId();
-                return ShardAllocationDecision.yes(nodeId,
+                return AllocateUnassignedDecision.yes(nodeId,
                     "allocating the primary shard to node [" + nodeId+ "], which has a complete copy of the shard data",
                     nodeShardState.allocationId(),
                     buildNodeDecisions(nodesToForceAllocate, explain));
             } else if (nodesToForceAllocate.throttleNodeShards.isEmpty() == false) {
                 logger.debug("[{}][{}]: throttling allocation [{}] to [{}] on forced primary allocation",
                              unassignedShard.index(), unassignedShard.id(), unassignedShard, nodesToForceAllocate.throttleNodeShards);
-                return ShardAllocationDecision.throttle(
+                return AllocateUnassignedDecision.throttle(
                     explain ? "allocation throttled as all nodes to which the shard may be force allocated are busy with other recoveries" : null,
                     buildNodeDecisions(nodesToForceAllocate, explain));
             } else {
                 logger.debug("[{}][{}]: forced primary allocation denied [{}]",
                              unassignedShard.index(), unassignedShard.id(), unassignedShard);
-                return ShardAllocationDecision.no(AllocationStatus.DECIDERS_NO,
+                return AllocateUnassignedDecision.no(AllocationStatus.DECIDERS_NO,
                     explain ? "all nodes that hold a valid shard copy returned a NO decision, and force allocation is not permitted" : null,
                     buildNodeDecisions(nodesToForceAllocate, explain));
             }
@@ -229,7 +229,7 @@ public abstract class PrimaryShardAllocator extends BaseGatewayShardAllocator {
             // taking place on the node currently, ignore it for now
             logger.debug("[{}][{}]: throttling allocation [{}] to [{}] on primary allocation",
                          unassignedShard.index(), unassignedShard.id(), unassignedShard, nodesToAllocate.throttleNodeShards);
-            return ShardAllocationDecision.throttle(
+            return AllocateUnassignedDecision.throttle(
                 explain ? "allocation throttled as all nodes to which the shard may be allocated are busy with other recoveries" : null,
                 buildNodeDecisions(nodesToAllocate, explain));
         }

+ 12 - 12
core/src/main/java/org/elasticsearch/gateway/ReplicaShardAllocator.java

@@ -31,8 +31,8 @@ import org.elasticsearch.cluster.routing.RoutingNodes;
 import org.elasticsearch.cluster.routing.ShardRouting;
 import org.elasticsearch.cluster.routing.UnassignedInfo;
 import org.elasticsearch.cluster.routing.UnassignedInfo.AllocationStatus;
+import org.elasticsearch.cluster.routing.allocation.AllocateUnassignedDecision;
 import org.elasticsearch.cluster.routing.allocation.RoutingAllocation;
-import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision;
 import org.elasticsearch.common.Nullable;
 import org.elasticsearch.common.collect.Tuple;
@@ -139,12 +139,12 @@ public abstract class ReplicaShardAllocator extends BaseGatewayShardAllocator {
     }
 
     @Override
-    public ShardAllocationDecision makeAllocationDecision(final ShardRouting unassignedShard,
-                                                          final RoutingAllocation allocation,
-                                                          final Logger logger) {
+    public AllocateUnassignedDecision makeAllocationDecision(final ShardRouting unassignedShard,
+                                                             final RoutingAllocation allocation,
+                                                             final Logger logger) {
         if (isResponsibleFor(unassignedShard) == false) {
             // this allocator is not responsible for deciding on this shard
-            return ShardAllocationDecision.DECISION_NOT_TAKEN;
+            return AllocateUnassignedDecision.NOT_TAKEN;
         }
 
         final RoutingNodes routingNodes = allocation.routingNodes();
@@ -153,7 +153,7 @@ public abstract class ReplicaShardAllocator extends BaseGatewayShardAllocator {
         Tuple<Decision, Map<String, Decision>> allocateDecision = canBeAllocatedToAtLeastOneNode(unassignedShard, allocation, explain);
         if (allocateDecision.v1().type() != Decision.Type.YES) {
             logger.trace("{}: ignoring allocation, can't be allocated on any node", unassignedShard);
-            return ShardAllocationDecision.no(UnassignedInfo.AllocationStatus.fromDecision(allocateDecision.v1().type()),
+            return AllocateUnassignedDecision.no(UnassignedInfo.AllocationStatus.fromDecision(allocateDecision.v1().type()),
                 explain ? "all nodes returned a " + allocateDecision.v1().type() + " decision for allocating the replica shard" : null,
                 allocateDecision.v2());
         }
@@ -162,7 +162,7 @@ public abstract class ReplicaShardAllocator extends BaseGatewayShardAllocator {
         if (shardStores.hasData() == false) {
             logger.trace("{}: ignoring allocation, still fetching shard stores", unassignedShard);
             allocation.setHasPendingAsyncFetch();
-            return ShardAllocationDecision.no(AllocationStatus.FETCHING_SHARD_DATA,
+            return AllocateUnassignedDecision.no(AllocationStatus.FETCHING_SHARD_DATA,
                 explain ? "still fetching shard state from the nodes in the cluster" : null);
         }
 
@@ -175,7 +175,7 @@ public abstract class ReplicaShardAllocator extends BaseGatewayShardAllocator {
             // will try and recover from
             // Note, this is the existing behavior, as exposed in running CorruptFileTest#testNoPrimaryData
             logger.trace("{}: no primary shard store found or allocated, letting actual allocation figure it out", unassignedShard);
-            return ShardAllocationDecision.DECISION_NOT_TAKEN;
+            return AllocateUnassignedDecision.NOT_TAKEN;
         }
 
         MatchingNodes matchingNodes = findMatchingNodes(unassignedShard, allocation, primaryStore, shardStores, explain);
@@ -189,14 +189,14 @@ public abstract class ReplicaShardAllocator extends BaseGatewayShardAllocator {
                 logger.debug("[{}][{}]: throttling allocation [{}] to [{}] in order to reuse its unallocated persistent store",
                     unassignedShard.index(), unassignedShard.id(), unassignedShard, nodeWithHighestMatch.node());
                 // we are throttling this, as we have enough other shards to allocate to this node, so ignore it for now
-                return ShardAllocationDecision.throttle(
+                return AllocateUnassignedDecision.throttle(
                     explain ? "returned a THROTTLE decision on each node that has an existing copy of the shard, so waiting to re-use one of those copies" : null,
                     matchingNodes.nodeDecisions);
             } else {
                 logger.debug("[{}][{}]: allocating [{}] to [{}] in order to reuse its unallocated persistent store",
                     unassignedShard.index(), unassignedShard.id(), unassignedShard, nodeWithHighestMatch.node());
                 // we found a match
-                return ShardAllocationDecision.yes(nodeWithHighestMatch.nodeId(),
+                return AllocateUnassignedDecision.yes(nodeWithHighestMatch.nodeId(),
                     "allocating to node [" + nodeWithHighestMatch.nodeId() + "] in order to re-use its unallocated persistent store",
                     null,
                     matchingNodes.nodeDecisions);
@@ -206,11 +206,11 @@ public abstract class ReplicaShardAllocator extends BaseGatewayShardAllocator {
             // unassigned due to a node leaving, so we delay allocation of this replica to see if the
             // node with the shard copy will rejoin so we can re-use the copy it has
             logger.debug("{}: allocation of [{}] is delayed", unassignedShard.shardId(), unassignedShard);
-            return ShardAllocationDecision.no(AllocationStatus.DELAYED_ALLOCATION,
+            return AllocateUnassignedDecision.no(AllocationStatus.DELAYED_ALLOCATION,
                 explain ? "not allocating this shard, no nodes contain data for the replica and allocation is delayed" : null);
         }
 
-        return ShardAllocationDecision.DECISION_NOT_TAKEN;
+        return AllocateUnassignedDecision.NOT_TAKEN;
     }
 
     /**

+ 36 - 37
core/src/test/java/org/elasticsearch/cluster/routing/allocation/ShardAllocationDecisionTests.java → core/src/test/java/org/elasticsearch/cluster/routing/allocation/AllocateUnassignedDecisionTests.java

@@ -20,7 +20,6 @@
 package org.elasticsearch.cluster.routing.allocation;
 
 import org.elasticsearch.cluster.routing.UnassignedInfo.AllocationStatus;
-import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision.WeightedDecision;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision;
 import org.elasticsearch.test.ESTestCase;
 
@@ -32,27 +31,27 @@ import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
- * Unit tests for the {@link ShardAllocationDecision} class.
+ * Unit tests for the {@link AllocateUnassignedDecision} class.
  */
-public class ShardAllocationDecisionTests extends ESTestCase {
+public class AllocateUnassignedDecisionTests extends ESTestCase {
 
     public void testDecisionNotTaken() {
-        ShardAllocationDecision shardAllocationDecision = ShardAllocationDecision.DECISION_NOT_TAKEN;
-        assertFalse(shardAllocationDecision.isDecisionTaken());
-        assertNull(shardAllocationDecision.getFinalDecisionType());
-        assertNull(shardAllocationDecision.getAllocationStatus());
-        assertNull(shardAllocationDecision.getAllocationId());
-        assertNull(shardAllocationDecision.getAssignedNodeId());
-        assertNull(shardAllocationDecision.getFinalExplanation());
-        assertNull(shardAllocationDecision.getNodeDecisions());
-        expectThrows(IllegalArgumentException.class, () -> shardAllocationDecision.getFinalDecisionSafe());
+        AllocateUnassignedDecision allocateUnassignedDecision = AllocateUnassignedDecision.NOT_TAKEN;
+        assertFalse(allocateUnassignedDecision.isDecisionTaken());
+        assertNull(allocateUnassignedDecision.getFinalDecisionType());
+        assertNull(allocateUnassignedDecision.getAllocationStatus());
+        assertNull(allocateUnassignedDecision.getAllocationId());
+        assertNull(allocateUnassignedDecision.getAssignedNodeId());
+        assertNull(allocateUnassignedDecision.getFinalExplanation());
+        assertNull(allocateUnassignedDecision.getNodeDecisions());
+        expectThrows(IllegalArgumentException.class, () -> allocateUnassignedDecision.getFinalDecisionSafe());
     }
 
     public void testNoDecision() {
         final AllocationStatus allocationStatus = randomFrom(
             AllocationStatus.DELAYED_ALLOCATION, AllocationStatus.NO_VALID_SHARD_COPY, AllocationStatus.FETCHING_SHARD_DATA
         );
-        ShardAllocationDecision noDecision = ShardAllocationDecision.no(allocationStatus, "something is wrong");
+        AllocateUnassignedDecision noDecision = AllocateUnassignedDecision.no(allocationStatus, "something is wrong");
         assertTrue(noDecision.isDecisionTaken());
         assertEquals(Decision.Type.NO, noDecision.getFinalDecisionType());
         assertEquals(allocationStatus, noDecision.getAllocationStatus());
@@ -61,10 +60,10 @@ public class ShardAllocationDecisionTests extends ESTestCase {
         assertNull(noDecision.getAssignedNodeId());
         assertNull(noDecision.getAllocationId());
 
-        Map<String, ShardAllocationDecision.WeightedDecision> nodeDecisions = new HashMap<>();
-        nodeDecisions.put("node1", new ShardAllocationDecision.WeightedDecision(Decision.NO));
-        nodeDecisions.put("node2", new ShardAllocationDecision.WeightedDecision(Decision.NO));
-        noDecision = ShardAllocationDecision.no(AllocationStatus.DECIDERS_NO, "something is wrong",
+        Map<String, NodeAllocationResult> nodeDecisions = new HashMap<>();
+        nodeDecisions.put("node1", new NodeAllocationResult(Decision.NO));
+        nodeDecisions.put("node2", new NodeAllocationResult(Decision.NO));
+        noDecision = AllocateUnassignedDecision.no(AllocationStatus.DECIDERS_NO, "something is wrong",
             nodeDecisions.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getDecision()))
         );
         assertTrue(noDecision.isDecisionTaken());
@@ -76,14 +75,14 @@ public class ShardAllocationDecisionTests extends ESTestCase {
         assertNull(noDecision.getAllocationId());
 
         // test bad values
-        expectThrows(NullPointerException.class, () -> ShardAllocationDecision.no((AllocationStatus)null, "a"));
+        expectThrows(NullPointerException.class, () -> AllocateUnassignedDecision.no((AllocationStatus)null, "a"));
     }
 
     public void testThrottleDecision() {
-        Map<String, WeightedDecision> nodeDecisions = new HashMap<>();
-        nodeDecisions.put("node1", new ShardAllocationDecision.WeightedDecision(Decision.NO));
-        nodeDecisions.put("node2", new ShardAllocationDecision.WeightedDecision(Decision.THROTTLE));
-        ShardAllocationDecision throttleDecision = ShardAllocationDecision.throttle("too much happening",
+        Map<String, NodeAllocationResult> nodeDecisions = new HashMap<>();
+        nodeDecisions.put("node1", new NodeAllocationResult(Decision.NO));
+        nodeDecisions.put("node2", new NodeAllocationResult(Decision.THROTTLE));
+        AllocateUnassignedDecision throttleDecision = AllocateUnassignedDecision.throttle("too much happening",
             nodeDecisions.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getDecision()))
         );
         assertTrue(throttleDecision.isDecisionTaken());
@@ -96,11 +95,11 @@ public class ShardAllocationDecisionTests extends ESTestCase {
     }
 
     public void testYesDecision() {
-        Map<String, ShardAllocationDecision.WeightedDecision> nodeDecisions = new HashMap<>();
-        nodeDecisions.put("node1", new ShardAllocationDecision.WeightedDecision(Decision.YES));
-        nodeDecisions.put("node2", new ShardAllocationDecision.WeightedDecision(Decision.NO));
+        Map<String, NodeAllocationResult> nodeDecisions = new HashMap<>();
+        nodeDecisions.put("node1", new NodeAllocationResult(Decision.YES));
+        nodeDecisions.put("node2", new NodeAllocationResult(Decision.NO));
         String allocId = randomBoolean() ? "allocId" : null;
-        ShardAllocationDecision yesDecision = ShardAllocationDecision.yes(
+        AllocateUnassignedDecision yesDecision = AllocateUnassignedDecision.yes(
             "node1", "node was very kind", allocId, nodeDecisions.entrySet().stream().collect(
                 Collectors.toMap(Map.Entry::getKey, e -> e.getValue().getDecision())
             )
@@ -119,27 +118,27 @@ public class ShardAllocationDecisionTests extends ESTestCase {
             AllocationStatus.NO_VALID_SHARD_COPY, AllocationStatus.FETCHING_SHARD_DATA, AllocationStatus.DELAYED_ALLOCATION);
         for (AllocationStatus allocationStatus : cachableStatuses) {
             if (allocationStatus == AllocationStatus.DECIDERS_THROTTLED) {
-                ShardAllocationDecision cached = ShardAllocationDecision.throttle(null, null);
-                ShardAllocationDecision another = ShardAllocationDecision.throttle(null, null);
+                AllocateUnassignedDecision cached = AllocateUnassignedDecision.throttle(null, null);
+                AllocateUnassignedDecision another = AllocateUnassignedDecision.throttle(null, null);
                 assertSame(cached, another);
-                ShardAllocationDecision notCached = ShardAllocationDecision.throttle("abc", null);
-                another = ShardAllocationDecision.throttle("abc", null);
+                AllocateUnassignedDecision notCached = AllocateUnassignedDecision.throttle("abc", null);
+                another = AllocateUnassignedDecision.throttle("abc", null);
                 assertNotSame(notCached, another);
             } else {
-                ShardAllocationDecision cached = ShardAllocationDecision.no(allocationStatus, null);
-                ShardAllocationDecision another = ShardAllocationDecision.no(allocationStatus, null);
+                AllocateUnassignedDecision cached = AllocateUnassignedDecision.no(allocationStatus, null);
+                AllocateUnassignedDecision another = AllocateUnassignedDecision.no(allocationStatus, null);
                 assertSame(cached, another);
-                ShardAllocationDecision notCached = ShardAllocationDecision.no(allocationStatus, "abc");
-                another = ShardAllocationDecision.no(allocationStatus, "abc");
+                AllocateUnassignedDecision notCached = AllocateUnassignedDecision.no(allocationStatus, "abc");
+                another = AllocateUnassignedDecision.no(allocationStatus, "abc");
                 assertNotSame(notCached, another);
             }
         }
 
         // yes decisions are not precomputed and cached
         Map<String, Decision> dummyMap = Collections.emptyMap();
-        ShardAllocationDecision first = ShardAllocationDecision.yes("node1", "abc", "alloc1", dummyMap);
-        ShardAllocationDecision second = ShardAllocationDecision.yes("node1", "abc", "alloc1", dummyMap);
-        // same fields for the ShardAllocationDecision, but should be different instances
+        AllocateUnassignedDecision first = AllocateUnassignedDecision.yes("node1", "abc", "alloc1", dummyMap);
+        AllocateUnassignedDecision second = AllocateUnassignedDecision.yes("node1", "abc", "alloc1", dummyMap);
+        // same fields for the AllocateUnassignedDecision, but should be different instances
         assertNotSame(first, second);
     }
 

+ 2 - 4
core/src/test/java/org/elasticsearch/cluster/routing/allocation/BalancedSingleShardTests.java

@@ -31,8 +31,6 @@ import org.elasticsearch.cluster.routing.ShardRouting;
 import org.elasticsearch.cluster.routing.ShardRoutingState;
 import org.elasticsearch.cluster.routing.allocation.allocator.BalancedShardsAllocator;
 import org.elasticsearch.cluster.routing.allocation.allocator.BalancedShardsAllocator.Balancer;
-import org.elasticsearch.cluster.routing.allocation.allocator.BalancedShardsAllocator.NodeRebalanceDecision;
-import org.elasticsearch.cluster.routing.allocation.allocator.BalancedShardsAllocator.RebalanceDecision;
 import org.elasticsearch.cluster.routing.allocation.decider.AllocationDecider;
 import org.elasticsearch.cluster.routing.allocation.decider.AllocationDeciders;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision;
@@ -222,8 +220,8 @@ public class BalancedSingleShardTests extends ESAllocationTestCase {
         assertEquals(shardToRebalance.relocatingNodeId(), rebalanceDecision.getAssignedNodeId());
         // make sure all excluded nodes returned a NO decision
         for (String exludedNode : excludeNodes) {
-            NodeRebalanceDecision nodeRebalanceDecision = rebalanceDecision.getNodeDecisions().get(exludedNode);
-            assertEquals(Type.NO, nodeRebalanceDecision.getCanAllocateDecision().type());
+            NodeRebalanceResult nodeRebalanceResult = rebalanceDecision.getNodeDecisions().get(exludedNode);
+            assertEquals(Type.NO, nodeRebalanceResult.getCanAllocateDecision().type());
         }
     }
 

+ 3 - 5
core/src/test/java/org/elasticsearch/cluster/routing/allocation/MoveDecisionTests.java

@@ -19,8 +19,6 @@
 
 package org.elasticsearch.cluster.routing.allocation;
 
-import org.elasticsearch.cluster.routing.allocation.ShardAllocationDecision.WeightedDecision;
-import org.elasticsearch.cluster.routing.allocation.allocator.BalancedShardsAllocator.MoveDecision;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision;
 import org.elasticsearch.cluster.routing.allocation.decider.Decision.Type;
 import org.elasticsearch.test.ESTestCase;
@@ -79,9 +77,9 @@ public class MoveDecisionTests extends ESTestCase {
     }
 
     public void testDecisionWithExplain() {
-        Map<String, WeightedDecision> nodeDecisions = new HashMap<>();
-        nodeDecisions.put("node1", new WeightedDecision(randomFrom(Decision.NO, Decision.THROTTLE, Decision.YES), randomFloat()));
-        nodeDecisions.put("node2", new WeightedDecision(randomFrom(Decision.NO, Decision.THROTTLE, Decision.YES), randomFloat()));
+        Map<String, NodeAllocationResult> nodeDecisions = new HashMap<>();
+        nodeDecisions.put("node1", new NodeAllocationResult(randomFrom(Decision.NO, Decision.THROTTLE, Decision.YES), randomFloat()));
+        nodeDecisions.put("node2", new NodeAllocationResult(randomFrom(Decision.NO, Decision.THROTTLE, Decision.YES), randomFloat()));
         MoveDecision decision = MoveDecision.decision(Decision.NO, Type.NO, true, "node1", null, nodeDecisions);
         assertNotNull(decision.getFinalDecisionType());
         assertNotNull(decision.getFinalExplanation());