From adea638a436e69730b157bd1c309e4298869de49 Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Mon, 26 Aug 2019 17:40:43 -0700 Subject: [PATCH 1/7] Implement POC hard constraints --- .../constraints/FaultZoneAwareConstraint.java | 39 +++++++++++++++ .../constraints/NodeActivateConstraint.java | 46 +++++++++++++++++ .../constraints/NodeCapacityConstraint.java | 49 +++++++++++++++++++ .../NodeMaxPartitionLimitConstraint.java | 40 +++++++++++++++ .../constraints/NodeValidTagConstraint.java | 38 ++++++++++++++ .../ReplicaAntiAffinityConstraint.java | 31 ++++++++++++ .../waged/model/AssignableNode.java | 11 +++++ 7 files changed, 254 insertions(+) create mode 100644 helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java create mode 100644 helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeActivateConstraint.java create mode 100644 helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java create mode 100644 helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java create mode 100644 helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeValidTagConstraint.java create mode 100644 helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java new file mode 100644 index 0000000000..1ececfd785 --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java @@ -0,0 +1,39 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; + +public class FaultZoneAwareConstraint extends HardConstraint { + + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { + return node.getFaultZone() == null || !clusterContext + .getPartitionsForResourceAndFaultZone(node.getFaultZone(), replica.getResourceName()) + .contains(replica.getPartitionName()); + } + + @Override + String getDescription() { + return "A fault zone cannot contain more than 1 replicas of same partition"; + } +} diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeActivateConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeActivateConstraint.java new file mode 100644 index 0000000000..7e950e78bf --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeActivateConstraint.java @@ -0,0 +1,46 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.List; + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; + +public class NodeActivateConstraint extends HardConstraint { + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { + if (!node.isEnabled() || !node.isAlive()) { + return false; + } + List disabledPartitions = node.getDisabledPartitionsMap().get(replica.getResourceName()); + if (disabledPartitions == null) { + return true; + } + + return !disabledPartitions.contains(replica.getPartitionName()); + } + + @Override + String getDescription() { + return "Cannot assign a deactivated node"; + } +} diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java new file mode 100644 index 0000000000..1fb412418a --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java @@ -0,0 +1,49 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import java.util.Map; + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; + +public class NodeCapacityConstraint extends HardConstraint { + + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { + Map nodeCurrentCapacity = node.getCurrentCapacity(); + Map repCurrentCapacity = replica.getCapacity(); + + for (String key : repCurrentCapacity.keySet()) { + if (nodeCurrentCapacity.containsKey(key)) { + if (nodeCurrentCapacity.get(key) < repCurrentCapacity.get(key)) { + return false; + } + } + } + return true; + } + + @Override + String getDescription() { + return "Node has insufficient capacity"; + } +} diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java new file mode 100644 index 0000000000..c108cc1588 --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java @@ -0,0 +1,40 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; + +public class NodeMaxPartitionLimitConstraint extends HardConstraint { + + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, + ClusterContext clusterContext) { + return node.getCurrentAssignmentCount() < node.getMaxPartition() + && node.getCurrentAssignmentsByResource(replica.getResourceName()).size() < replica + .getResourceMaxPartitionsPerInstance(); + } + + @Override + String getDescription() { + return "Cannot exceed max partitions on node"; + } +} diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeValidTagConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeValidTagConstraint.java new file mode 100644 index 0000000000..25f91ecea8 --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeValidTagConstraint.java @@ -0,0 +1,38 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; + +public class NodeValidTagConstraint extends HardConstraint { + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, + ClusterContext clusterContext) { + return replica.getResourceInstanceGroupTag() == null + || node.getInstanceTags().contains(replica.getResourceInstanceGroupTag()); + } + + @Override + String getDescription() { + return "Node has no or invalid tag"; + } +} diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java new file mode 100644 index 0000000000..fce5bb9d0d --- /dev/null +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java @@ -0,0 +1,31 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; + +public class ReplicaAntiAffinityConstraint extends HardConstraint { + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { + return !node.getCurrentAssignmentsByResource(replica.getResourceName()).contains(replica.getPartitionName()); + } +} diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java index 4141d20d31..b4b5f77389 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java @@ -51,6 +51,9 @@ public class AssignableNode implements Comparable { private Map> _disabledPartitionsMap; private Map _maxCapacity; private int _maxPartition; // maximum number of the partitions that can be assigned to the node. + //TODO: fill the information runtime status in constructor + private boolean _isEnabled; + private boolean _isAlive; // A map of > that tracks the replicas assigned to the node. private Map> _currentAssignedReplicaMap; @@ -77,6 +80,14 @@ private void reset() { _highestCapacityUtilization = 0; } + public boolean isEnabled() { + return _isEnabled; + } + + public boolean isAlive() { + return _isAlive; + } + /** * Update the node with a ClusterDataCache. This resets the current assignment and recalculates currentCapacity. * NOTE: While this is required to be used in the constructor, this can also be used when the clusterCache needs to be From 0a26e2334c9412a0b43ffdce0c04cf681469ae1c Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Mon, 26 Aug 2019 19:11:30 -0700 Subject: [PATCH 2/7] address comments --- .../constraints/FaultZoneAwareConstraint.java | 6 +- .../NodeMaxPartitionLimitConstraint.java | 2 +- ...nt.java => ReplicaActivateConstraint.java} | 13 +-- .../ReplicaAntiAffinityConstraint.java | 10 ++- ...a => ValidInstanceGroupTagConstraint.java} | 11 ++- .../waged/model/AssignableNode.java | 84 +++++++++---------- .../waged/model/AssignableReplica.java | 4 + 7 files changed, 67 insertions(+), 63 deletions(-) rename helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/{NodeActivateConstraint.java => ReplicaActivateConstraint.java} (80%) rename helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/{NodeValidTagConstraint.java => ValidInstanceGroupTagConstraint.java} (80%) diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java index 1ececfd785..bea2e5d3bd 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java @@ -27,8 +27,10 @@ public class FaultZoneAwareConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - return node.getFaultZone() == null || !clusterContext - .getPartitionsForResourceAndFaultZone(node.getFaultZone(), replica.getResourceName()) + if (!node.hasFaultZone()) { + return true; + } + return !clusterContext.getPartitionsForResourceAndFaultZone(replica.getResourceName(), node.getFaultZone()) .contains(replica.getPartitionName()); } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java index c108cc1588..d8afa5f758 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java @@ -35,6 +35,6 @@ boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, @Override String getDescription() { - return "Cannot exceed max partitions on node"; + return "Cannot exceed maximum number of partitions on node"; } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeActivateConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java similarity index 80% rename from helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeActivateConstraint.java rename to helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java index 7e950e78bf..051eb161d5 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeActivateConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java @@ -25,22 +25,15 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -public class NodeActivateConstraint extends HardConstraint { +public class ReplicaActivateConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - if (!node.isEnabled() || !node.isAlive()) { - return false; - } List disabledPartitions = node.getDisabledPartitionsMap().get(replica.getResourceName()); - if (disabledPartitions == null) { - return true; - } - - return !disabledPartitions.contains(replica.getPartitionName()); + return disabledPartitions == null || !disabledPartitions.contains(replica.getPartitionName()); } @Override String getDescription() { - return "Cannot assign a deactivated node"; + return "Cannot assign the inactive replica"; } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java index fce5bb9d0d..2bba80a055 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java @@ -24,8 +24,10 @@ import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; public class ReplicaAntiAffinityConstraint extends HardConstraint { - @Override - boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - return !node.getCurrentAssignmentsByResource(replica.getResourceName()).contains(replica.getPartitionName()); - } + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, + ClusterContext clusterContext) { + return !node.getCurrentAssignmentsByResource(replica.getResourceName()) + .contains(replica.getPartitionName()); + } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeValidTagConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidInstanceGroupTagConstraint.java similarity index 80% rename from helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeValidTagConstraint.java rename to helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidInstanceGroupTagConstraint.java index 25f91ecea8..2c7b4cc6fc 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeValidTagConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidInstanceGroupTagConstraint.java @@ -23,16 +23,19 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -public class NodeValidTagConstraint extends HardConstraint { +public class ValidInstanceGroupTagConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - return replica.getResourceInstanceGroupTag() == null - || node.getInstanceTags().contains(replica.getResourceInstanceGroupTag()); + if (replica.hasResourceInstanceGroupTag()) { + return true; + } + + return node.getInstanceTags().contains(replica.getResourceInstanceGroupTag()); } @Override String getDescription() { - return "Node has no or invalid tag"; + return "Checks whether the tags on the node and replica match or that the node doesn't have any tags."; } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java index b4b5f77389..8ffc333d97 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java @@ -19,6 +19,8 @@ * under the License. */ +import static java.lang.Math.max; + import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -35,8 +37,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static java.lang.Math.max; - /** * This class represents a possible allocation of the replication. * Note that any usage updates to the AssignableNode are not thread safe. @@ -51,11 +51,9 @@ public class AssignableNode implements Comparable { private Map> _disabledPartitionsMap; private Map _maxCapacity; private int _maxPartition; // maximum number of the partitions that can be assigned to the node. - //TODO: fill the information runtime status in constructor - private boolean _isEnabled; - private boolean _isAlive; - // A map of > that tracks the replicas assigned to the node. + // A map of > that tracks the replicas assigned to the + // node. private Map> _currentAssignedReplicaMap; // A map of that tracks the current available node capacity private Map _currentCapacityMap; @@ -80,22 +78,16 @@ private void reset() { _highestCapacityUtilization = 0; } - public boolean isEnabled() { - return _isEnabled; - } - - public boolean isAlive() { - return _isAlive; - } - /** - * Update the node with a ClusterDataCache. This resets the current assignment and recalculates currentCapacity. - * NOTE: While this is required to be used in the constructor, this can also be used when the clusterCache needs to be - * refreshed. This is under the assumption that the capacity mappings of InstanceConfig and ResourceConfig could + * Update the node with a ClusterDataCache. This resets the current assignment and recalculates + * currentCapacity. + * NOTE: While this is required to be used in the constructor, this can also be used when the + * clusterCache needs to be + * refreshed. This is under the assumption that the capacity mappings of InstanceConfig and + * ResourceConfig could * subject to change. If the assumption is no longer true, this function should become private. - * - * @param clusterConfig - the Cluster Config of the cluster where the node is located - * @param instanceConfig - the Instance Config of the node + * @param clusterConfig - the Cluster Config of the cluster where the node is located + * @param instanceConfig - the Instance Config of the node * @param existingAssignment - all the existing replicas that are current assigned to the node */ private void refresh(ClusterConfig clusterConfig, InstanceConfig instanceConfig, @@ -115,7 +107,6 @@ private void refresh(ClusterConfig clusterConfig, InstanceConfig instanceConfig, /** * Assign a replica to the node. - * * @param assignableReplica - the replica to be assigned */ void assign(AssignableReplica assignableReplica) { @@ -127,7 +118,6 @@ void assign(AssignableReplica assignableReplica) { /** * Release a replica from the node. * If the replication is not on this node, the assignable node is not updated. - * * @param replica - the replica to be released */ void release(AssignableReplica replica) throws IllegalArgumentException { @@ -142,8 +132,8 @@ void release(AssignableReplica replica) throws IllegalArgumentException { } Map partitionMap = _currentAssignedReplicaMap.get(resourceName); - if (!partitionMap.containsKey(partitionName) || !partitionMap.get(partitionName) - .equals(replica)) { + if (!partitionMap.containsKey(partitionName) + || !partitionMap.get(partitionName).equals(replica)) { LOG.warn("Replica {} is not assigned to node {}. Ignore the release call.", replica.toString(), getInstanceName()); return; @@ -185,7 +175,8 @@ public Set getAssignedPartitionsByResource(String resource) { /** * @param resource Resource name - * @return A set of the current assigned replicas' partition names with the top state in the specified resource. + * @return A set of the current assigned replicas' partition names with the top state in the + * specified resource. */ public Set getAssignedTopStatePartitionsByResource(String resource) { return _currentAssignedReplicaMap.getOrDefault(resource, Collections.emptyMap()).entrySet() @@ -218,7 +209,8 @@ public Map getCurrentCapacity() { /** * Return the most concerning capacity utilization number for evenly partition assignment. - * The method dynamically returns the highest utilization number among all the capacity categories. + * The method dynamically returns the highest utilization number among all the capacity + * categories. * For example, if the current node usage is {CPU: 0.9, MEM: 0.4, DISK: 0.6}. Then this call shall * return 0.9. * @@ -240,15 +232,21 @@ public String getFaultZone() { return _faultZone; } + public boolean hasFaultZone() { + return _faultZone != null; + } + /** - * @return A map of contains all the partitions that are disabled on the node. + * @return A map of contains all the partitions that are + * disabled on the node. */ public Map> getDisabledPartitionsMap() { return _disabledPartitionsMap; } /** - * @return A map of that describes the max capacity of the node. + * @return A map of that describes the max capacity of the + * node. */ public Map getMaxCapacity() { return _maxCapacity; @@ -262,8 +260,10 @@ public int getMaxPartition() { } /** - * Computes the fault zone id based on the domain and fault zone type when topology is enabled. For example, when - * the domain is "zone=2, instance=testInstance" and the fault zone type is "zone", this function returns "2". + * Computes the fault zone id based on the domain and fault zone type when topology is enabled. + * For example, when + * the domain is "zone=2, instance=testInstance" and the fault zone type is "zone", this function + * returns "2". * If cannot find the fault zone id, this function leaves the fault zone id as the instance name. * TODO merge this logic with Topology.java tree building logic. * For now, the WAGED rebalancer has a more strict topology def requirement. @@ -278,8 +278,8 @@ private String computeFaultZone(ClusterConfig clusterConfig, InstanceConfig inst } String[] topologyDef = topologyStr.trim().split("/"); - if (topologyDef.length == 0 || Arrays.stream(topologyDef) - .noneMatch(type -> type.equals(faultZoneType))) { + if (topologyDef.length == 0 + || Arrays.stream(topologyDef).noneMatch(type -> type.equals(faultZoneType))) { throw new HelixException( "The configured topology definition is empty or does not contain the fault zone type."); } @@ -315,7 +315,8 @@ private String computeFaultZone(ClusterConfig clusterConfig, InstanceConfig inst } /** - * This function should only be used to assign a set of new partitions that are not allocated on this node. + * This function should only be used to assign a set of new partitions that are not allocated on + * this node. * Using this function avoids the overhead of updating capacity repeatedly. */ private void assignNewBatch(Collection replicas) { @@ -325,9 +326,8 @@ private void assignNewBatch(Collection replicas) { // increment the capacity requirement according to partition's capacity configuration. for (Map.Entry capacity : replica.getCapacity().entrySet()) { totalPartitionCapacity.compute(capacity.getKey(), - (key, totalValue) -> (totalValue == null) ? - capacity.getValue() : - totalValue + capacity.getValue()); + (key, totalValue) -> (totalValue == null) ? capacity.getValue() + : totalValue + capacity.getValue()); } } @@ -343,12 +343,12 @@ private void assignNewBatch(Collection replicas) { private void addToAssignmentRecord(AssignableReplica replica) { String resourceName = replica.getResourceName(); String partitionName = replica.getPartitionName(); - if (_currentAssignedReplicaMap.containsKey(resourceName) && _currentAssignedReplicaMap - .get(resourceName).containsKey(partitionName)) { - throw new HelixException(String - .format("Resource %s already has a replica with state %s from partition %s on node %s", - replica.getResourceName(), replica.getReplicaState(), replica.getPartitionName(), - getInstanceName())); + if (_currentAssignedReplicaMap.containsKey(resourceName) + && _currentAssignedReplicaMap.get(resourceName).containsKey(partitionName)) { + throw new HelixException(String.format( + "Resource %s already has a replica with state %s from partition %s on node %s", + replica.getResourceName(), replica.getReplicaState(), replica.getPartitionName(), + getInstanceName())); } else { _currentAssignedReplicaMap.computeIfAbsent(resourceName, key -> new HashMap<>()) .put(partitionName, replica); diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableReplica.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableReplica.java index 537bf70477..3714efd48a 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableReplica.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableReplica.java @@ -87,6 +87,10 @@ public String getResourceInstanceGroupTag() { return _resourceInstanceGroupTag; } + public boolean hasResourceInstanceGroupTag() { + return _resourceInstanceGroupTag != null; + } + public int getResourceMaxPartitionsPerInstance() { return _resourceMaxPartitionsPerInstance; } From e13759f57c5a10394f5a732501ff0d5f2aeb619a Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Wed, 28 Aug 2019 15:54:26 -0700 Subject: [PATCH 3/7] Add unit tests --- .../constraints/FaultZoneAwareConstraint.java | 26 +++--- .../constraints/NodeCapacityConstraint.java | 33 ++++---- .../NodeMaxPartitionLimitConstraint.java | 2 +- .../ReplicaActivateConstraint.java | 20 ++--- ...aint.java => ValidGroupTagConstraint.java} | 6 +- .../TestFaultZoneAwareConstraint.java | 79 ++++++++++++++++++ .../TestNodeActivateConstraint.java | 81 +++++++++++++++++++ .../TestNodeCapacityConstraint.java | 54 +++++++++++++ .../TestNodeMaxPartitionLimitConstraint.java | 56 +++++++++++++ .../TestNodeValidTagConstraint.java | 66 +++++++++++++++ .../TestReplicaAntiAffinityConstraint.java | 59 ++++++++++++++ 11 files changed, 441 insertions(+), 41 deletions(-) rename helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/{ValidInstanceGroupTagConstraint.java => ValidGroupTagConstraint.java} (85%) create mode 100644 helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestFaultZoneAwareConstraint.java create mode 100644 helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeActivateConstraint.java create mode 100644 helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeCapacityConstraint.java create mode 100644 helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeMaxPartitionLimitConstraint.java create mode 100644 helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeValidTagConstraint.java create mode 100644 helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java index bea2e5d3bd..c33419e38b 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/FaultZoneAwareConstraint.java @@ -23,19 +23,21 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -public class FaultZoneAwareConstraint extends HardConstraint { +class FaultZoneAwareConstraint extends HardConstraint { - @Override - boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - if (!node.hasFaultZone()) { - return true; - } - return !clusterContext.getPartitionsForResourceAndFaultZone(replica.getResourceName(), node.getFaultZone()) - .contains(replica.getPartitionName()); + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, + ClusterContext clusterContext) { + if (!node.hasFaultZone()) { + return true; } + return !clusterContext + .getPartitionsForResourceAndFaultZone(replica.getResourceName(), node.getFaultZone()) + .contains(replica.getPartitionName()); + } - @Override - String getDescription() { - return "A fault zone cannot contain more than 1 replicas of same partition"; - } + @Override + String getDescription() { + return "A fault zone cannot contain more than 1 replica of same partition"; + } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java index 1fb412418a..a0bdfe6ac3 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java @@ -25,25 +25,26 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -public class NodeCapacityConstraint extends HardConstraint { +class NodeCapacityConstraint extends HardConstraint { - @Override - boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - Map nodeCurrentCapacity = node.getCurrentCapacity(); - Map repCurrentCapacity = replica.getCapacity(); + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, + ClusterContext clusterContext) { + Map nodeCurrentCapacity = node.getCurrentCapacity(); + Map repCurrentCapacity = replica.getCapacity(); - for (String key : repCurrentCapacity.keySet()) { - if (nodeCurrentCapacity.containsKey(key)) { - if (nodeCurrentCapacity.get(key) < repCurrentCapacity.get(key)) { - return false; - } - } + for (String key : repCurrentCapacity.keySet()) { + if (nodeCurrentCapacity.containsKey(key)) { + if (nodeCurrentCapacity.get(key) < repCurrentCapacity.get(key)) { + return false; } - return true; + } } + return true; + } - @Override - String getDescription() { - return "Node has insufficient capacity"; - } + @Override + String getDescription() { + return "Node has insufficient capacity"; + } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java index d8afa5f758..ce8ce1aaa4 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java @@ -23,7 +23,7 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -public class NodeMaxPartitionLimitConstraint extends HardConstraint { +class NodeMaxPartitionLimitConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java index 051eb161d5..74eef2449f 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java @@ -26,14 +26,16 @@ import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; public class ReplicaActivateConstraint extends HardConstraint { - @Override - boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - List disabledPartitions = node.getDisabledPartitionsMap().get(replica.getResourceName()); - return disabledPartitions == null || !disabledPartitions.contains(replica.getPartitionName()); - } + @Override + boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, + ClusterContext clusterContext) { + List disabledPartitions = + node.getDisabledPartitionsMap().get(replica.getResourceName()); + return disabledPartitions == null || !disabledPartitions.contains(replica.getPartitionName()); + } - @Override - String getDescription() { - return "Cannot assign the inactive replica"; - } + @Override + String getDescription() { + return "Cannot assign the inactive replica"; + } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidInstanceGroupTagConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java similarity index 85% rename from helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidInstanceGroupTagConstraint.java rename to helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java index 2c7b4cc6fc..00d6dc0010 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidInstanceGroupTagConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java @@ -23,11 +23,11 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -public class ValidInstanceGroupTagConstraint extends HardConstraint { +public class ValidGroupTagConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - if (replica.hasResourceInstanceGroupTag()) { + if (!replica.hasResourceInstanceGroupTag()) { return true; } @@ -36,6 +36,6 @@ boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, @Override String getDescription() { - return "Checks whether the tags on the node and replica match or that the node doesn't have any tags."; + return "Checks whether the tags on the node and replica match or that the node doesn't have any tags."; } } diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestFaultZoneAwareConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestFaultZoneAwareConstraint.java new file mode 100644 index 0000000000..9d2cb14e70 --- /dev/null +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestFaultZoneAwareConstraint.java @@ -0,0 +1,79 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import static org.mockito.Mockito.when; + +import java.util.Collections; + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +public class TestFaultZoneAwareConstraint { + private static final String TEST_PARTITION = "testPartition"; + private static final String TEST_ZONE = "testZone"; + private static final String TEST_RESOURCE = "testResource"; + private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); + private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); + private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); + + private final HardConstraint _faultZoneAwareConstraint = new FaultZoneAwareConstraint(); + + @BeforeMethod + public void init() { + when(_testReplica.getResourceName()).thenReturn(TEST_RESOURCE); + when(_testReplica.getPartitionName()).thenReturn(TEST_PARTITION); + when(_testNode.getFaultZone()).thenReturn(TEST_ZONE); + } + + @Test + public void inValidWhenFaultZoneAlreadyAssigned() { + when(_testNode.hasFaultZone()).thenReturn(true); + when(_clusterContext.getPartitionsForResourceAndFaultZone(TEST_RESOURCE, TEST_ZONE)).thenReturn( + ImmutableSet.of(TEST_PARTITION)); + + Assert.assertFalse( + _faultZoneAwareConstraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } + + @Test + public void validWhenEmptyAssignment() { + when(_testNode.hasFaultZone()).thenReturn(true); + when(_clusterContext.getPartitionsForResourceAndFaultZone(TEST_RESOURCE, TEST_ZONE)).thenReturn(Collections.emptySet()); + + Assert.assertTrue( + _faultZoneAwareConstraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } + + @Test + public void validWhenNoFaultZone() { + when(_testNode.hasFaultZone()).thenReturn(false); + + Assert.assertTrue( + _faultZoneAwareConstraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } +} diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeActivateConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeActivateConstraint.java new file mode 100644 index 0000000000..16f1087408 --- /dev/null +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeActivateConstraint.java @@ -0,0 +1,81 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import static org.mockito.Mockito.when; + +import java.util.Collections; + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class TestNodeActivateConstraint { + private static final String TEST_PARTITION = "TestPartition"; + private static final String TEST_RESOURCE = "TestResource"; + private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); + private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); + private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); + private final HardConstraint _constraint = new NodeActivateConstraint(); + + @Test + public void testConstraintValid() { + when(_testNode.isEnabled()).thenReturn(true); + when(_testNode.isLive()).thenReturn(true); + when(_testReplica.getResourceName()).thenReturn(TEST_RESOURCE); + when(_testReplica.getPartitionName()).thenReturn(TEST_PARTITION); + when(_testNode.getDisabledPartitionsMap()) + .thenReturn(ImmutableMap.of(TEST_PARTITION, Collections.emptyList())); + Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + when(_testNode.getDisabledPartitionsMap()) + .thenReturn(ImmutableMap.of(TEST_PARTITION, ImmutableList.of("dummy"))); + Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } + + @Test + public void testConstraintInValidWhenNodeInactive() { + when(_testNode.isEnabled()).thenReturn(false); + when(_testNode.isLive()).thenReturn(true); + Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + when(_testNode.isEnabled()).thenReturn(false); + when(_testNode.isLive()).thenReturn(false); + Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + when(_testNode.isEnabled()).thenReturn(true); + when(_testNode.isLive()).thenReturn(false); + Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } + + @Test + public void testConstraintInvalidWhenReplicaIsDisabled() { + when(_testNode.isEnabled()).thenReturn(true); + when(_testNode.isLive()).thenReturn(true); + when(_testReplica.getResourceName()).thenReturn(TEST_RESOURCE); + when(_testReplica.getPartitionName()).thenReturn(TEST_PARTITION); + when(_testNode.getDisabledPartitionsMap()) + .thenReturn(ImmutableMap.of(TEST_PARTITION, ImmutableList.of(TEST_PARTITION))); + Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } +} diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeCapacityConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeCapacityConstraint.java new file mode 100644 index 0000000000..511f881b3f --- /dev/null +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeCapacityConstraint.java @@ -0,0 +1,54 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import static org.mockito.Mockito.when; + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableMap; + +public class TestNodeCapacityConstraint { + private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); + private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); + private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); + private final HardConstraint _constraint = new NodeCapacityConstraint(); + + @Test + public void testConstraintValidWhenNodeHasEnoughSpace() { + String key = "testKey"; + when(_testNode.getCurrentCapacity()).thenReturn(ImmutableMap.of(key, 10)); + when(_testReplica.getCapacity()).thenReturn(ImmutableMap.of(key, 5)); + Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } + + @Test + public void testConstraintInValidWhenNodeHasInsufficientSpace() { + String key = "testKey"; + when(_testNode.getCurrentCapacity()).thenReturn(ImmutableMap.of(key, 1)); + when(_testReplica.getCapacity()).thenReturn(ImmutableMap.of(key, 5)); + Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } +} diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeMaxPartitionLimitConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeMaxPartitionLimitConstraint.java new file mode 100644 index 0000000000..1c5e55613f --- /dev/null +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeMaxPartitionLimitConstraint.java @@ -0,0 +1,56 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import static org.mockito.Mockito.when; + +import java.util.Collections; + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.Test; + +public class TestNodeMaxPartitionLimitConstraint { + private static final String TEST_RESOURCE = "TestResource"; + private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); + private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); + private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); + private final HardConstraint _constraint = new NodeMaxPartitionLimitConstraint(); + + @Test + public void testConstraintValid() { + when(_testNode.getCurrentAssignmentCount()).thenReturn(0); + when(_testNode.getMaxPartition()).thenReturn(10); + when(_testNode.getCurrentAssignmentsByResource(TEST_RESOURCE)) + .thenReturn(Collections.emptySet()); + when(_testReplica.getResourceMaxPartitionsPerInstance()).thenReturn(5); + Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } + + @Test + public void testConstraintInvalid() { + when(_testNode.getCurrentAssignmentCount()).thenReturn(10); + when(_testNode.getMaxPartition()).thenReturn(5); + Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } +} diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeValidTagConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeValidTagConstraint.java new file mode 100644 index 0000000000..a6e4737c5c --- /dev/null +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeValidTagConstraint.java @@ -0,0 +1,66 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import static org.mockito.Mockito.when; + +import java.util.Collections; + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +public class TestNodeValidTagConstraint { + private static final String TEST_TAG = "testTag"; + private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); + private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); + private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); + private final HardConstraint _constraint = new NodeValidTagConstraint(); + + @Test + public void testConstraintValid() { + when(_testReplica.hasResourceInstanceGroupTag()).thenReturn(true); + when(_testReplica.getResourceInstanceGroupTag()).thenReturn(TEST_TAG); + when(_testNode.getInstanceTags()).thenReturn(ImmutableSet.of(TEST_TAG)); + + Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } + + @Test + public void testConstraintInValid() { + when(_testReplica.hasResourceInstanceGroupTag()).thenReturn(true); + when(_testReplica.getResourceInstanceGroupTag()).thenReturn(TEST_TAG); + when(_testNode.getInstanceTags()).thenReturn(Collections.emptySet()); + + Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } + + @Test + public void testConstraintWhenReplicaHasNoTag() { + when(_testReplica.hasResourceInstanceGroupTag()).thenReturn(false); + + Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } +} diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java new file mode 100644 index 0000000000..6946216834 --- /dev/null +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java @@ -0,0 +1,59 @@ +package org.apache.helix.controller.rebalancer.waged.constraints; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import static org.mockito.Mockito.when; + +import org.apache.helix.controller.rebalancer.waged.model.AssignableNode; +import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; +import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; +import org.mockito.Mockito; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.google.common.collect.ImmutableSet; + +public class TestReplicaAntiAffinityConstraint { + private static final String TEST_RESOURCE = "TestResource"; + private static final String TEST_PARTITIOIN = TEST_RESOURCE + "0"; + private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); + private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); + private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); + private final HardConstraint _constraint = new ReplicaAntiAffinityConstraint(); + + @Test + public void testConstraintValid() { + when(_testNode.getCurrentAssignmentsByResource(TEST_RESOURCE)) + .thenReturn(ImmutableSet.of("dummy")); + when(_testReplica.getResourceName()).thenReturn(TEST_RESOURCE); + when(_testReplica.getPartitionName()).thenReturn(TEST_PARTITIOIN); + + Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } + + @Test + public void testConstraintInValid() { + when(_testNode.getCurrentAssignmentsByResource(TEST_RESOURCE)) + .thenReturn(ImmutableSet.of(TEST_PARTITIOIN)); + when(_testReplica.getResourceName()).thenReturn(TEST_RESOURCE); + when(_testReplica.getPartitionName()).thenReturn(TEST_PARTITIOIN); + Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); + } +} From c0fd6d096bb7af4b06edca98d1278a8eededed52 Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Wed, 28 Aug 2019 17:45:29 -0700 Subject: [PATCH 4/7] Address more comments --- .../constraints/NodeCapacityConstraint.java | 10 ++++----- .../NodeMaxPartitionLimitConstraint.java | 6 +++--- .../ReplicaAntiAffinityConstraint.java | 2 +- .../waged/model/AssignableReplica.java | 2 +- ...a => TestPartitionActivateConstraint.java} | 21 ++----------------- 5 files changed, 12 insertions(+), 29 deletions(-) rename helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/{TestNodeActivateConstraint.java => TestPartitionActivateConstraint.java} (74%) diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java index a0bdfe6ac3..5fc2faffd5 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeCapacityConstraint.java @@ -30,12 +30,12 @@ class NodeCapacityConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - Map nodeCurrentCapacity = node.getCurrentCapacity(); - Map repCurrentCapacity = replica.getCapacity(); + Map nodeCapacity = node.getCurrentCapacity(); + Map replicaCapacity = replica.getCapacity(); - for (String key : repCurrentCapacity.keySet()) { - if (nodeCurrentCapacity.containsKey(key)) { - if (nodeCurrentCapacity.get(key) < repCurrentCapacity.get(key)) { + for (String key : replicaCapacity.keySet()) { + if (nodeCapacity.containsKey(key)) { + if (nodeCapacity.get(key) < replicaCapacity.get(key)) { return false; } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java index ce8ce1aaa4..6c8c3dce20 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java @@ -28,13 +28,13 @@ class NodeMaxPartitionLimitConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - return node.getCurrentAssignmentCount() < node.getMaxPartition() - && node.getCurrentAssignmentsByResource(replica.getResourceName()).size() < replica + return node.getCurrentAssignmentCount() <= node.getMaxPartition() + && node.getCurrentAssignmentsByResource(replica.getResourceName()).size() <= replica .getResourceMaxPartitionsPerInstance(); } @Override String getDescription() { - return "Cannot exceed maximum number of partitions on node"; + return "Cannot exceed the maximum number of partitions limitation on node"; } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java index 2bba80a055..fa0ebc46c5 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java @@ -23,7 +23,7 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -public class ReplicaAntiAffinityConstraint extends HardConstraint { +class ReplicaAntiAffinityConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableReplica.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableReplica.java index 3714efd48a..66bd7b774e 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableReplica.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableReplica.java @@ -88,7 +88,7 @@ public String getResourceInstanceGroupTag() { } public boolean hasResourceInstanceGroupTag() { - return _resourceInstanceGroupTag != null; + return _resourceInstanceGroupTag != null && !_resourceInstanceGroupTag.isEmpty(); } public int getResourceMaxPartitionsPerInstance() { diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeActivateConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestPartitionActivateConstraint.java similarity index 74% rename from helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeActivateConstraint.java rename to helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestPartitionActivateConstraint.java index 16f1087408..18823c8c03 100644 --- a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeActivateConstraint.java +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestPartitionActivateConstraint.java @@ -33,18 +33,16 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; -public class TestNodeActivateConstraint { +public class TestPartitionActivateConstraint { private static final String TEST_PARTITION = "TestPartition"; private static final String TEST_RESOURCE = "TestResource"; private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); - private final HardConstraint _constraint = new NodeActivateConstraint(); + private final HardConstraint _constraint = new PartitionActivateConstraint(); @Test public void testConstraintValid() { - when(_testNode.isEnabled()).thenReturn(true); - when(_testNode.isLive()).thenReturn(true); when(_testReplica.getResourceName()).thenReturn(TEST_RESOURCE); when(_testReplica.getPartitionName()).thenReturn(TEST_PARTITION); when(_testNode.getDisabledPartitionsMap()) @@ -55,23 +53,8 @@ public void testConstraintValid() { Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); } - @Test - public void testConstraintInValidWhenNodeInactive() { - when(_testNode.isEnabled()).thenReturn(false); - when(_testNode.isLive()).thenReturn(true); - Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); - when(_testNode.isEnabled()).thenReturn(false); - when(_testNode.isLive()).thenReturn(false); - Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); - when(_testNode.isEnabled()).thenReturn(true); - when(_testNode.isLive()).thenReturn(false); - Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); - } - @Test public void testConstraintInvalidWhenReplicaIsDisabled() { - when(_testNode.isEnabled()).thenReturn(true); - when(_testNode.isLive()).thenReturn(true); when(_testReplica.getResourceName()).thenReturn(TEST_RESOURCE); when(_testReplica.getPartitionName()).thenReturn(TEST_PARTITION); when(_testNode.getDisabledPartitionsMap()) From e69704a65ac31d3a23208d10a415e4a343e781dd Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Wed, 4 Sep 2019 16:53:17 -0700 Subject: [PATCH 5/7] Address comments, fix style and description --- .../constraints/NodeMaxPartitionLimitConstraint.java | 4 ++-- ...nstraint.java => SameReplicaOnInstanceConstraint.java} | 8 +++++++- .../waged/constraints/ValidGroupTagConstraint.java | 2 +- .../constraints/TestReplicaAntiAffinityConstraint.java | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) rename helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/{ReplicaAntiAffinityConstraint.java => SameReplicaOnInstanceConstraint.java} (87%) diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java index 6c8c3dce20..83d4577ed0 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java @@ -28,8 +28,8 @@ class NodeMaxPartitionLimitConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - return node.getCurrentAssignmentCount() <= node.getMaxPartition() - && node.getCurrentAssignmentsByResource(replica.getResourceName()).size() <= replica + return node.getCurrentAssignmentCount() < node.getMaxPartition() + && node.getCurrentAssignmentsByResource(replica.getResourceName()).size() < replica .getResourceMaxPartitionsPerInstance(); } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java similarity index 87% rename from helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java rename to helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java index fa0ebc46c5..56f448a0ca 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaAntiAffinityConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java @@ -23,11 +23,17 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -class ReplicaAntiAffinityConstraint extends HardConstraint { +class SameReplicaOnInstanceConstraint extends HardConstraint { + @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { return !node.getCurrentAssignmentsByResource(replica.getResourceName()) .contains(replica.getPartitionName()); } + + @Override + String getDescription() { + return "Same partition of different states cannot co-exist in one instance"; + } } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java index 00d6dc0010..85fd8174f3 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java @@ -36,6 +36,6 @@ boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, @Override String getDescription() { - return "Checks whether the tags on the node and replica match or that the node doesn't have any tags."; + return "Instance doesn't have the tag of the replica"; } } diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java index 6946216834..ba989d7670 100644 --- a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java @@ -36,7 +36,7 @@ public class TestReplicaAntiAffinityConstraint { private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); - private final HardConstraint _constraint = new ReplicaAntiAffinityConstraint(); + private final HardConstraint _constraint = new SameReplicaOnInstanceConstraint(); @Test public void testConstraintValid() { From f4c4880519e0512b4fa500a2844088037541b617 Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Wed, 4 Sep 2019 17:06:15 -0700 Subject: [PATCH 6/7] Merge with the latest change --- .../waged/constraints/NodeMaxPartitionLimitConstraint.java | 4 ++-- .../waged/constraints/ReplicaActivateConstraint.java | 2 +- .../waged/constraints/SameReplicaOnInstanceConstraint.java | 2 +- .../waged/constraints/ValidGroupTagConstraint.java | 2 +- .../controller/rebalancer/waged/model/AssignableNode.java | 2 +- .../constraints/TestNodeMaxPartitionLimitConstraint.java | 6 +++--- .../waged/constraints/TestPartitionActivateConstraint.java | 2 +- ...traint.java => TestSameReplicaOnInstanceConstraint.java} | 6 +++--- ...dTagConstraint.java => TestValidGroupTagConstraint.java} | 4 ++-- 9 files changed, 15 insertions(+), 15 deletions(-) rename helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/{TestReplicaAntiAffinityConstraint.java => TestSameReplicaOnInstanceConstraint.java} (93%) rename helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/{TestNodeValidTagConstraint.java => TestValidGroupTagConstraint.java} (95%) diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java index 83d4577ed0..9d0752be6c 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/NodeMaxPartitionLimitConstraint.java @@ -28,8 +28,8 @@ class NodeMaxPartitionLimitConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - return node.getCurrentAssignmentCount() < node.getMaxPartition() - && node.getCurrentAssignmentsByResource(replica.getResourceName()).size() < replica + return node.getAssignedReplicaCount() < node.getMaxPartition() + && node.getAssignedPartitionsByResource(replica.getResourceName()).size() < replica .getResourceMaxPartitionsPerInstance(); } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java index 74eef2449f..9152efef85 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ReplicaActivateConstraint.java @@ -25,7 +25,7 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -public class ReplicaActivateConstraint extends HardConstraint { +class ReplicaActivateConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java index 56f448a0ca..de4d305a95 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java @@ -28,7 +28,7 @@ class SameReplicaOnInstanceConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { - return !node.getCurrentAssignmentsByResource(replica.getResourceName()) + return !node.getAssignedPartitionsByResource(replica.getResourceName()) .contains(replica.getPartitionName()); } diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java index 85fd8174f3..e31864fde1 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/ValidGroupTagConstraint.java @@ -23,7 +23,7 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -public class ValidGroupTagConstraint extends HardConstraint { +class ValidGroupTagConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, ClusterContext clusterContext) { diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java index 8ffc333d97..f25c2894fb 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/model/AssignableNode.java @@ -196,7 +196,7 @@ public long getAssignedTopStatePartitionsCount() { /** * @return The total count of assigned replicas. */ - public long getAssignedReplicaCount() { + public int getAssignedReplicaCount() { return _currentAssignedReplicaMap.values().stream().mapToInt(Map::size).sum(); } diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeMaxPartitionLimitConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeMaxPartitionLimitConstraint.java index 1c5e55613f..4cb7466283 100644 --- a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeMaxPartitionLimitConstraint.java +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeMaxPartitionLimitConstraint.java @@ -39,9 +39,9 @@ public class TestNodeMaxPartitionLimitConstraint { @Test public void testConstraintValid() { - when(_testNode.getCurrentAssignmentCount()).thenReturn(0); + when(_testNode.getAssignedReplicaCount()).thenReturn(0); when(_testNode.getMaxPartition()).thenReturn(10); - when(_testNode.getCurrentAssignmentsByResource(TEST_RESOURCE)) + when(_testNode.getAssignedPartitionsByResource(TEST_RESOURCE)) .thenReturn(Collections.emptySet()); when(_testReplica.getResourceMaxPartitionsPerInstance()).thenReturn(5); Assert.assertTrue(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); @@ -49,7 +49,7 @@ public void testConstraintValid() { @Test public void testConstraintInvalid() { - when(_testNode.getCurrentAssignmentCount()).thenReturn(10); + when(_testNode.getAssignedReplicaCount()).thenReturn(10); when(_testNode.getMaxPartition()).thenReturn(5); Assert.assertFalse(_constraint.isAssignmentValid(_testNode, _testReplica, _clusterContext)); } diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestPartitionActivateConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestPartitionActivateConstraint.java index 18823c8c03..ecfdaa2029 100644 --- a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestPartitionActivateConstraint.java +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestPartitionActivateConstraint.java @@ -39,7 +39,7 @@ public class TestPartitionActivateConstraint { private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); - private final HardConstraint _constraint = new PartitionActivateConstraint(); + private final HardConstraint _constraint = new ReplicaActivateConstraint(); @Test public void testConstraintValid() { diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestSameReplicaOnInstanceConstraint.java similarity index 93% rename from helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java rename to helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestSameReplicaOnInstanceConstraint.java index ba989d7670..d7d497de84 100644 --- a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestReplicaAntiAffinityConstraint.java +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestSameReplicaOnInstanceConstraint.java @@ -30,7 +30,7 @@ import com.google.common.collect.ImmutableSet; -public class TestReplicaAntiAffinityConstraint { +public class TestSameReplicaOnInstanceConstraint { private static final String TEST_RESOURCE = "TestResource"; private static final String TEST_PARTITIOIN = TEST_RESOURCE + "0"; private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); @@ -40,7 +40,7 @@ public class TestReplicaAntiAffinityConstraint { @Test public void testConstraintValid() { - when(_testNode.getCurrentAssignmentsByResource(TEST_RESOURCE)) + when(_testNode.getAssignedPartitionsByResource(TEST_RESOURCE)) .thenReturn(ImmutableSet.of("dummy")); when(_testReplica.getResourceName()).thenReturn(TEST_RESOURCE); when(_testReplica.getPartitionName()).thenReturn(TEST_PARTITIOIN); @@ -50,7 +50,7 @@ public void testConstraintValid() { @Test public void testConstraintInValid() { - when(_testNode.getCurrentAssignmentsByResource(TEST_RESOURCE)) + when(_testNode.getAssignedPartitionsByResource(TEST_RESOURCE)) .thenReturn(ImmutableSet.of(TEST_PARTITIOIN)); when(_testReplica.getResourceName()).thenReturn(TEST_RESOURCE); when(_testReplica.getPartitionName()).thenReturn(TEST_PARTITIOIN); diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeValidTagConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestValidGroupTagConstraint.java similarity index 95% rename from helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeValidTagConstraint.java rename to helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestValidGroupTagConstraint.java index a6e4737c5c..8d02b3d801 100644 --- a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestNodeValidTagConstraint.java +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestValidGroupTagConstraint.java @@ -32,12 +32,12 @@ import com.google.common.collect.ImmutableSet; -public class TestNodeValidTagConstraint { +public class TestValidGroupTagConstraint { private static final String TEST_TAG = "testTag"; private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); - private final HardConstraint _constraint = new NodeValidTagConstraint(); + private final HardConstraint _constraint = new ValidGroupTagConstraint(); @Test public void testConstraintValid() { From df5906de4170a8011a1a47ad694cbe2853c2bbc3 Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Mon, 9 Sep 2019 11:29:57 -0700 Subject: [PATCH 7/7] Implement all of basic Hard Constraints 1. Partitions count cannot exceed instance's upper limit 2. Fault zone aware (no same partitions on the same zone) 3. Partitions weight cannot exceed instance's capacity 4. Cannot assign inactived partitions 5. Same partition of different states cannot co-exist in one instance 6. Instance doesn't have the tag of the replica --- ...Constraint.java => SamePartitionOnInstanceConstraint.java} | 2 +- ...traint.java => TestSamePartitionOnInstanceConstraint.java} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/{SameReplicaOnInstanceConstraint.java => SamePartitionOnInstanceConstraint.java} (95%) rename helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/{TestSameReplicaOnInstanceConstraint.java => TestSamePartitionOnInstanceConstraint.java} (94%) diff --git a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SamePartitionOnInstanceConstraint.java similarity index 95% rename from helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java rename to helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SamePartitionOnInstanceConstraint.java index de4d305a95..202e49af24 100644 --- a/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SameReplicaOnInstanceConstraint.java +++ b/helix-core/src/main/java/org/apache/helix/controller/rebalancer/waged/constraints/SamePartitionOnInstanceConstraint.java @@ -23,7 +23,7 @@ import org.apache.helix.controller.rebalancer.waged.model.AssignableReplica; import org.apache.helix.controller.rebalancer.waged.model.ClusterContext; -class SameReplicaOnInstanceConstraint extends HardConstraint { +class SamePartitionOnInstanceConstraint extends HardConstraint { @Override boolean isAssignmentValid(AssignableNode node, AssignableReplica replica, diff --git a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestSameReplicaOnInstanceConstraint.java b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestSamePartitionOnInstanceConstraint.java similarity index 94% rename from helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestSameReplicaOnInstanceConstraint.java rename to helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestSamePartitionOnInstanceConstraint.java index d7d497de84..50b0c037be 100644 --- a/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestSameReplicaOnInstanceConstraint.java +++ b/helix-core/src/test/java/org/apache/helix/controller/rebalancer/waged/constraints/TestSamePartitionOnInstanceConstraint.java @@ -30,13 +30,13 @@ import com.google.common.collect.ImmutableSet; -public class TestSameReplicaOnInstanceConstraint { +public class TestSamePartitionOnInstanceConstraint { private static final String TEST_RESOURCE = "TestResource"; private static final String TEST_PARTITIOIN = TEST_RESOURCE + "0"; private final AssignableReplica _testReplica = Mockito.mock(AssignableReplica.class); private final AssignableNode _testNode = Mockito.mock(AssignableNode.class); private final ClusterContext _clusterContext = Mockito.mock(ClusterContext.class); - private final HardConstraint _constraint = new SameReplicaOnInstanceConstraint(); + private final HardConstraint _constraint = new SamePartitionOnInstanceConstraint(); @Test public void testConstraintValid() {