You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by lj...@apache.org on 2021/12/22 07:31:57 UTC
[ozone] branch master updated: HDDS-5602. make it configurable to choose the nearest one as the target in the candidates according to networkTopology (#2756)
This is an automated email from the ASF dual-hosted git repository.
ljain pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new e01b471 HDDS-5602. make it configurable to choose the nearest one as the target in the candidates according to networkTopology (#2756)
e01b471 is described below
commit e01b47184818365dcb7baf528fb2d874209b6b47
Author: Jackson Yao <ja...@tencent.com>
AuthorDate: Wed Dec 22 15:31:31 2021 +0800
HDDS-5602. make it configurable to choose the nearest one as the target in the candidates according to networkTopology (#2756)
---
...etGreedy.java => AbstractFindTargetGreedy.java} | 87 +++++----
.../scm/container/balancer/ContainerBalancer.java | 26 ++-
.../balancer/ContainerBalancerConfiguration.java | 27 ++-
.../FindTargetGreedyByNetworkTopology.java | 79 +++++++++
.../balancer/FindTargetGreedyByUsageInfo.java | 52 ++++++
.../hdds/scm/server/StorageContainerManager.java | 4 +-
.../container/balancer/TestContainerBalancer.java | 4 +-
.../container/balancer/TestFindTargetStrategy.java | 196 +++++++++++++++++++++
8 files changed, 428 insertions(+), 47 deletions(-)
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindTargetGreedy.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/AbstractFindTargetGreedy.java
similarity index 80%
rename from hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindTargetGreedy.java
rename to hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/AbstractFindTargetGreedy.java
index 5508943..a975f04 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindTargetGreedy.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/AbstractFindTargetGreedy.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.hdds.scm.container.balancer;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.scm.ContainerPlacementStatus;
import org.apache.hadoop.hdds.scm.PlacementPolicy;
@@ -29,32 +30,29 @@ import org.apache.hadoop.hdds.scm.container.ContainerReplica;
import org.apache.hadoop.hdds.scm.node.DatanodeUsageInfo;
import org.apache.hadoop.hdds.scm.node.NodeManager;
import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.TreeSet;
import java.util.UUID;
import java.util.stream.Collectors;
/**
- * Find a target giving preference to more under-utilized nodes.
+ * Find a target for a source datanode with greedy strategy.
*/
-public class FindTargetGreedy implements FindTargetStrategy {
- private static final Logger LOG =
- LoggerFactory.getLogger(FindTargetGreedy.class);
-
+public abstract class AbstractFindTargetGreedy implements FindTargetStrategy {
+ private Logger logger;
private ContainerManager containerManager;
private PlacementPolicy placementPolicy;
private Map<DatanodeDetails, Long> sizeEnteringNode;
private NodeManager nodeManager;
private ContainerBalancerConfiguration config;
private Double upperLimit;
- private TreeSet<DatanodeUsageInfo> potentialTargets;
+ private Collection<DatanodeUsageInfo> potentialTargets;
- public FindTargetGreedy(
+ protected AbstractFindTargetGreedy(
ContainerManager containerManager,
PlacementPolicy placementPolicy,
NodeManager nodeManager) {
@@ -62,37 +60,36 @@ public class FindTargetGreedy implements FindTargetStrategy {
this.containerManager = containerManager;
this.placementPolicy = placementPolicy;
this.nodeManager = nodeManager;
+ }
- potentialTargets = new TreeSet<>((a, b) -> {
- double currentUsageOfA = a.calculateUtilization(
- sizeEnteringNode.get(a.getDatanodeDetails()));
- double currentUsageOfB = b.calculateUtilization(
- sizeEnteringNode.get(b.getDatanodeDetails()));
- int ret = Double.compare(currentUsageOfA, currentUsageOfB);
- if (ret != 0) {
- return ret;
- }
- UUID uuidA = a.getDatanodeDetails().getUuid();
- UUID uuidB = b.getDatanodeDetails().getUuid();
- return uuidA.compareTo(uuidB);
- });
+ protected void setLogger(Logger log) {
+ logger = log;
+ }
+
+ protected void setPotentialTargets(Collection<DatanodeUsageInfo> pt) {
+ potentialTargets = pt;
}
private void setUpperLimit(Double upperLimit){
this.upperLimit = upperLimit;
}
- private void setPotentialTargets(
- List<DatanodeUsageInfo> potentialTargetDataNodes) {
- sizeEnteringNode.clear();
- potentialTargetDataNodes.forEach(
- p -> sizeEnteringNode.put(p.getDatanodeDetails(), 0L));
- potentialTargets.clear();
- potentialTargets.addAll(potentialTargetDataNodes);
+ protected int compareByUsage(DatanodeUsageInfo a, DatanodeUsageInfo b) {
+ double currentUsageOfA = a.calculateUtilization(
+ sizeEnteringNode.get(a.getDatanodeDetails()));
+ double currentUsageOfB = b.calculateUtilization(
+ sizeEnteringNode.get(b.getDatanodeDetails()));
+ int ret = Double.compare(currentUsageOfA, currentUsageOfB);
+ if (ret != 0) {
+ return ret;
+ }
+ UUID uuidA = a.getDatanodeDetails().getUuid();
+ UUID uuidB = b.getDatanodeDetails().getUuid();
+ return uuidA.compareTo(uuidB);
}
private void setConfiguration(ContainerBalancerConfiguration conf) {
- this.config = conf;
+ config = conf;
}
/**
@@ -109,6 +106,7 @@ public class FindTargetGreedy implements FindTargetStrategy {
@Override
public ContainerMoveSelection findTargetForContainerMove(
DatanodeDetails source, Set<ContainerID> candidateContainers) {
+ sortTargetForSource(source);
for (DatanodeUsageInfo targetInfo : potentialTargets) {
DatanodeDetails target = targetInfo.getDatanodeDetails();
for (ContainerID container : candidateContainers) {
@@ -118,7 +116,7 @@ public class FindTargetGreedy implements FindTargetStrategy {
replicas = containerManager.getContainerReplicas(container);
containerInfo = containerManager.getContainer(container);
} catch (ContainerNotFoundException e) {
- LOG.warn("Could not get Container {} from Container Manager for " +
+ logger.warn("Could not get Container {} from Container Manager for " +
"obtaining replicas in Container Balancer.", container, e);
continue;
}
@@ -132,8 +130,8 @@ public class FindTargetGreedy implements FindTargetStrategy {
}
}
}
- LOG.info("Container Balancer could not find a target for source datanode " +
- "{}", source.getUuidString());
+ logger.info("Container Balancer could not find a target for " +
+ "source datanode {}", source.getUuidString());
return null;
}
@@ -153,7 +151,7 @@ public class FindTargetGreedy implements FindTargetStrategy {
try {
containerInfo = containerManager.getContainer(containerID);
} catch (ContainerNotFoundException e) {
- LOG.warn("Could not get Container {} from Container Manager while " +
+ logger.warn("Could not get Container {} from Container Manager while " +
"checking if container move satisfies placement policy in " +
"Container Balancer.", containerID.toString(), e);
return false;
@@ -212,7 +210,7 @@ public class FindTargetGreedy implements FindTargetStrategy {
}
return;
}
- LOG.warn("Cannot find {} in the candidates target nodes",
+ logger.warn("Cannot find {} in the candidates target nodes",
target.getUuid());
}
@@ -225,6 +223,23 @@ public class FindTargetGreedy implements FindTargetStrategy {
Double upLimit) {
setConfiguration(conf);
setUpperLimit(upLimit);
- setPotentialTargets(potentialDataNodes);
+ sizeEnteringNode.clear();
+ potentialDataNodes.forEach(
+ p -> sizeEnteringNode.put(p.getDatanodeDetails(), 0L));
+ potentialTargets.clear();
+ potentialTargets.addAll(potentialDataNodes);
+ }
+
+ @VisibleForTesting
+ public Collection<DatanodeUsageInfo> getPotentialTargets() {
+ return potentialTargets;
}
+
+ /**
+ * sort potentialTargets for specified source datanode according to
+ * network topology if enabled.
+ * @param source the specified source datanode
+ */
+ @VisibleForTesting
+ public abstract void sortTargetForSource(DatanodeDetails source);
}
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancer.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancer.java
index 91dd1b2..5e31bee 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancer.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancer.java
@@ -30,6 +30,7 @@ import org.apache.hadoop.hdds.scm.container.ContainerManager;
import org.apache.hadoop.hdds.scm.container.ReplicationManager;
import org.apache.hadoop.hdds.scm.container.placement.metrics.SCMNodeStat;
import org.apache.hadoop.hdds.scm.ha.SCMContext;
+import org.apache.hadoop.hdds.scm.net.NetworkTopology;
import org.apache.hadoop.hdds.scm.node.DatanodeUsageInfo;
import org.apache.hadoop.hdds.scm.node.NodeManager;
import org.apache.hadoop.hdds.scm.node.states.NodeNotFoundException;
@@ -85,6 +86,8 @@ public class ContainerBalancer {
private long clusterUsed;
private long clusterRemaining;
private double clusterAvgUtilisation;
+ private PlacementPolicy placementPolicy;
+ private NetworkTopology networkTopology;
private double upperLimit;
private double lowerLimit;
private volatile boolean balancerRunning;
@@ -115,6 +118,7 @@ public class ContainerBalancer {
ReplicationManager replicationManager,
OzoneConfiguration ozoneConfiguration,
final SCMContext scmContext,
+ NetworkTopology networkTopology,
PlacementPolicy placementPolicy) {
this.nodeManager = nodeManager;
this.containerManager = containerManager;
@@ -129,10 +133,10 @@ public class ContainerBalancer {
this.underUtilizedNodes = new ArrayList<>();
this.withinThresholdUtilizedNodes = new ArrayList<>();
this.unBalancedNodes = new ArrayList<>();
+ this.placementPolicy = placementPolicy;
+ this.networkTopology = networkTopology;
this.lock = new ReentrantLock();
- findTargetStrategy = new FindTargetGreedy(
- containerManager, placementPolicy, nodeManager);
findSourceStrategy = new FindSourceGreedy(nodeManager);
}
@@ -179,6 +183,13 @@ public class ContainerBalancer {
this.maxDatanodesRatioToInvolvePerIteration =
config.getMaxDatanodesRatioToInvolvePerIteration();
this.maxSizeToMovePerIteration = config.getMaxSizeToMovePerIteration();
+ if (config.getNetworkTopologyEnable()) {
+ findTargetStrategy = new FindTargetGreedyByNetworkTopology(
+ containerManager, placementPolicy, nodeManager, networkTopology);
+ } else {
+ findTargetStrategy = new FindTargetGreedyByUsageInfo(containerManager,
+ placementPolicy, nodeManager);
+ }
for (int i = 0; i < idleIteration && balancerRunning; i++) {
// stop balancing if iteration is not initialized
if (!initializeIteration()) {
@@ -367,11 +378,6 @@ public class ContainerBalancer {
try {
// match each overUtilized node with a target
while (true) {
- DatanodeDetails source =
- findSourceStrategy.getNextCandidateSourceDataNode();
- if (source == null) {
- break;
- }
if (!isBalancerRunning()) {
return IterationResult.ITERATION_INTERRUPTED;
}
@@ -381,6 +387,12 @@ public class ContainerBalancer {
return result;
}
+ DatanodeDetails source =
+ findSourceStrategy.getNextCandidateSourceDataNode();
+ if (source == null) {
+ break;
+ }
+
ContainerMoveSelection moveSelection = matchSourceWithTarget(source);
if (moveSelection != null) {
isMoveGenerated = true;
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerConfiguration.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerConfiguration.java
index a0199e0..698b3b0 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerConfiguration.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerConfiguration.java
@@ -118,12 +118,19 @@ public final class ContainerBalancerConfiguration {
private String includeNodes = "";
@Config(key = "exclude.datanodes", type = ConfigType.STRING, defaultValue =
- "", tags = ConfigTag.BALANCER, description = "A list of Datanode " +
+ "", tags = {ConfigTag.BALANCER}, description = "A list of Datanode " +
"hostnames or ip addresses separated by commas. The Datanodes specified" +
" in this list are excluded from balancing. This configuration is empty" +
" by default.")
private String excludeNodes = "";
+ @Config(key = "move.networkTopology.enable", type = ConfigType.BOOLEAN,
+ defaultValue = "false", tags = {ConfigTag.BALANCER},
+ description = "whether to take network topology into account when " +
+ "selecting a target for a source. " +
+ "This configuration is false by default.")
+ private boolean networkTopologyEnable = false;
+
private DUFactory.Conf duConf;
/**
@@ -197,6 +204,24 @@ public final class ContainerBalancerConfiguration {
}
/**
+ * Get the NetworkTopologyEnable value for Container Balancer.
+ *
+ * @return the boolean value of networkTopologyEnable
+ */
+ public Boolean getNetworkTopologyEnable() {
+ return networkTopologyEnable;
+ }
+
+ /**
+ * Set the NetworkTopologyEnable value for Container Balancer.
+ *
+ * @param enable the boolean value to be set to networkTopologyEnable
+ */
+ public void setNetworkTopologyEnable(Boolean enable) {
+ networkTopologyEnable = enable;
+ }
+
+ /**
* Gets the ratio of maximum number of datanodes that will be involved in
* balancing by Container Balancer in one iteration to the total number of
* healthy, in-service nodes known to balancer.
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindTargetGreedyByNetworkTopology.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindTargetGreedyByNetworkTopology.java
new file mode 100644
index 0000000..ad1c8de
--- /dev/null
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindTargetGreedyByNetworkTopology.java
@@ -0,0 +1,79 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hdds.scm.container.balancer;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.scm.PlacementPolicy;
+import org.apache.hadoop.hdds.scm.container.ContainerManager;
+import org.apache.hadoop.hdds.scm.net.NetworkTopology;
+import org.apache.hadoop.hdds.scm.node.DatanodeUsageInfo;
+import org.apache.hadoop.hdds.scm.node.NodeManager;
+import org.slf4j.LoggerFactory;
+
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * an implementation of FindTargetGreedy, which will always select the
+ * target with the shortest distance according to network topology
+ * distance to the give source datanode.
+ */
+public class FindTargetGreedyByNetworkTopology
+ extends AbstractFindTargetGreedy {
+
+ private NetworkTopology networkTopology;
+ private List potentialTargets;
+
+ public FindTargetGreedyByNetworkTopology(
+ ContainerManager containerManager,
+ PlacementPolicy placementPolicy,
+ NodeManager nodeManager,
+ NetworkTopology networkTopology) {
+ super(containerManager, placementPolicy, nodeManager);
+ setLogger(LoggerFactory.getLogger(FindTargetGreedyByNetworkTopology.class));
+ potentialTargets = new LinkedList<>();
+ setPotentialTargets(potentialTargets);
+ this.networkTopology = networkTopology;
+ }
+
+ /**
+ * sort potentialTargets for specified source datanode according to
+ * network topology.
+ * @param source the specified source datanode
+ */
+ @VisibleForTesting
+ public void sortTargetForSource(DatanodeDetails source) {
+ Collections.sort(potentialTargets,
+ (DatanodeUsageInfo da, DatanodeUsageInfo db) -> {
+ DatanodeDetails a = da.getDatanodeDetails();
+ DatanodeDetails b = db.getDatanodeDetails();
+ // sort by network topology first
+ int distanceToA = networkTopology.getDistanceCost(source, a);
+ int distanceToB = networkTopology.getDistanceCost(source, b);
+ if (distanceToA != distanceToB) {
+ return distanceToA - distanceToB;
+ }
+ // if distance to source is equal , sort by usage
+ return compareByUsage(da, db);
+ });
+ }
+}
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindTargetGreedyByUsageInfo.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindTargetGreedyByUsageInfo.java
new file mode 100644
index 0000000..03cdc51
--- /dev/null
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindTargetGreedyByUsageInfo.java
@@ -0,0 +1,52 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hdds.scm.container.balancer;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.scm.PlacementPolicy;
+import org.apache.hadoop.hdds.scm.container.ContainerManager;
+import org.apache.hadoop.hdds.scm.node.NodeManager;
+import org.slf4j.LoggerFactory;
+
+import java.util.TreeSet;
+
+/**
+ * an implementation of FindTargetGreedy, which will always select the
+ * target with the lowest space usage.
+ */
+public class FindTargetGreedyByUsageInfo extends AbstractFindTargetGreedy {
+ public FindTargetGreedyByUsageInfo(
+ ContainerManager containerManager,
+ PlacementPolicy placementPolicy,
+ NodeManager nodeManager) {
+ super(containerManager, placementPolicy, nodeManager);
+ setLogger(LoggerFactory.getLogger(FindTargetGreedyByUsageInfo.class));
+ setPotentialTargets(new TreeSet<>((a, b) -> compareByUsage(a, b)));
+ }
+
+ /**
+ * do nothing , since TreeSet is ordered itself.
+ */
+ @VisibleForTesting
+ public void sortTargetForSource(DatanodeDetails source) {
+ //noop, Treeset is naturally sorted.
+ return;
+ }
+}
diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
index 0db807c..a3a1abb 100644
--- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
+++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/StorageContainerManager.java
@@ -380,8 +380,8 @@ public final class StorageContainerManager extends ServiceRuntimeInfoImpl
initializeEventHandlers();
- containerBalancer = new ContainerBalancer(scmNodeManager,
- containerManager, replicationManager, configuration, scmContext,
+ containerBalancer = new ContainerBalancer(scmNodeManager, containerManager,
+ replicationManager, configuration, scmContext, clusterMap,
ContainerPlacementPolicyFactory
.getPolicy(conf, scmNodeManager, clusterMap, true,
placementMetrics));
diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancer.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancer.java
index e260bb3..c2978b2 100644
--- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancer.java
+++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancer.java
@@ -37,6 +37,7 @@ import org.apache.hadoop.hdds.scm.container.placement.algorithms.SCMContainerPla
import org.apache.hadoop.hdds.scm.container.placement.metrics.SCMNodeStat;
import org.apache.hadoop.hdds.scm.exceptions.SCMException;
import org.apache.hadoop.hdds.scm.ha.SCMContext;
+import org.apache.hadoop.hdds.scm.net.NetworkTopologyImpl;
import org.apache.hadoop.hdds.scm.node.DatanodeUsageInfo;
import org.apache.hadoop.hdds.scm.node.NodeStatus;
import org.apache.hadoop.hdds.scm.node.states.NodeNotFoundException;
@@ -145,7 +146,8 @@ public class TestContainerBalancer {
.thenReturn(new ArrayList<>(cidToInfoMap.values()));
containerBalancer = new ContainerBalancer(mockNodeManager, containerManager,
- replicationManager, conf, SCMContext.emptyContext(), placementPolicy);
+ replicationManager, conf, SCMContext.emptyContext(),
+ new NetworkTopologyImpl(conf), placementPolicy);
}
@Test
diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestFindTargetStrategy.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestFindTargetStrategy.java
new file mode 100644
index 0000000..6d5a22d
--- /dev/null
+++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestFindTargetStrategy.java
@@ -0,0 +1,196 @@
+/*
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hdds.scm.container.balancer;
+
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
+import org.apache.hadoop.hdds.scm.container.placement.metrics.SCMNodeStat;
+import org.apache.hadoop.hdds.scm.net.NetworkTopology;
+import org.apache.hadoop.hdds.scm.net.NetworkTopologyImpl;
+import org.apache.hadoop.hdds.scm.net.NodeSchema;
+import org.apache.hadoop.hdds.scm.net.NodeSchemaManager;
+import org.apache.hadoop.hdds.scm.node.DatanodeUsageInfo;
+import org.junit.Test;
+import org.junit.Assert;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.apache.hadoop.hdds.scm.net.NetConstants.LEAF_SCHEMA;
+import static org.apache.hadoop.hdds.scm.net.NetConstants.NODEGROUP_SCHEMA;
+import static org.apache.hadoop.hdds.scm.net.NetConstants.RACK_SCHEMA;
+import static org.apache.hadoop.hdds.scm.net.NetConstants.ROOT_SCHEMA;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests for all the implementations of FindTargetStrategy.
+ */
+public class TestFindTargetStrategy {
+ /**
+ * Checks whether FindTargetGreedyByUsage always choose target
+ * for a given source by Usage.
+ */
+ @Test
+ public void testFindTargetGreedyByUsage() {
+ FindTargetGreedyByUsageInfo findTargetStrategyByUsageInfo =
+ new FindTargetGreedyByUsageInfo(null, null, null);
+ List<DatanodeUsageInfo> overUtilizedDatanodes = new ArrayList<>();
+
+ //create three datanodes with different usageinfo
+ DatanodeUsageInfo dui1 = new DatanodeUsageInfo(MockDatanodeDetails
+ .randomDatanodeDetails(), new SCMNodeStat(100, 0, 40));
+ DatanodeUsageInfo dui2 = new DatanodeUsageInfo(MockDatanodeDetails
+ .randomDatanodeDetails(), new SCMNodeStat(100, 0, 60));
+ DatanodeUsageInfo dui3 = new DatanodeUsageInfo(MockDatanodeDetails
+ .randomDatanodeDetails(), new SCMNodeStat(100, 0, 80));
+
+ //insert in ascending order
+ overUtilizedDatanodes.add(dui1);
+ overUtilizedDatanodes.add(dui2);
+ overUtilizedDatanodes.add(dui3);
+ findTargetStrategyByUsageInfo.reInitialize(
+ overUtilizedDatanodes, null, null);
+
+ //no need to set the datanode usage for source.
+ findTargetStrategyByUsageInfo.sortTargetForSource(
+ MockDatanodeDetails.randomDatanodeDetails());
+
+ Collection<DatanodeUsageInfo> potentialTargets =
+ findTargetStrategyByUsageInfo.getPotentialTargets();
+
+ Object[] sortedPotentialTargetArray = potentialTargets.toArray();
+
+ Assert.assertEquals(sortedPotentialTargetArray.length, 3);
+
+ //make sure after sorting target for source, the potentialTargets is
+ //sorted in descending order of usage
+ Assert.assertEquals(((DatanodeUsageInfo)sortedPotentialTargetArray[0])
+ .getDatanodeDetails(), dui3.getDatanodeDetails());
+ Assert.assertEquals(((DatanodeUsageInfo)sortedPotentialTargetArray[1])
+ .getDatanodeDetails(), dui2.getDatanodeDetails());
+ Assert.assertEquals(((DatanodeUsageInfo)sortedPotentialTargetArray[2])
+ .getDatanodeDetails(), dui1.getDatanodeDetails());
+
+ }
+
+ /**
+ * Checks whether FindTargetGreedyByNetworkTopology always choose target
+ * for a given source by network topology distance.
+ */
+ @Test
+ public void testFindTargetGreedyByNetworkTopology() {
+ // network topology with default cost
+ List<NodeSchema> schemas = new ArrayList<>();
+ schemas.add(ROOT_SCHEMA);
+ schemas.add(RACK_SCHEMA);
+ schemas.add(NODEGROUP_SCHEMA);
+ schemas.add(LEAF_SCHEMA);
+
+ NodeSchemaManager manager = NodeSchemaManager.getInstance();
+ manager.init(schemas.toArray(new NodeSchema[0]), true);
+ NetworkTopology newCluster =
+ new NetworkTopologyImpl(manager);
+
+ DatanodeDetails source =
+ MockDatanodeDetails.createDatanodeDetails("1.1.1.1", "/r1/ng1");
+ //create one target in the same rack and same node group
+ DatanodeDetails target1 =
+ MockDatanodeDetails.createDatanodeDetails("2.2.2.2", "/r1/ng1");
+ //create tree targets in the same rack but different node group
+ DatanodeDetails target2 =
+ MockDatanodeDetails.createDatanodeDetails("3.3.3.3", "/r1/ng2");
+ DatanodeDetails target3 =
+ MockDatanodeDetails.createDatanodeDetails("4.4.4.4", "/r1/ng2");
+ DatanodeDetails target4 =
+ MockDatanodeDetails.createDatanodeDetails("5.5.5.5", "/r1/ng2");
+ //create one target in different rack
+ DatanodeDetails target5 =
+ MockDatanodeDetails.createDatanodeDetails("6.6.6.6", "/r2/ng1");
+
+ //add all datanode to cluster map
+ newCluster.add(source);
+ newCluster.add(target1);
+ newCluster.add(target2);
+ newCluster.add(target3);
+ newCluster.add(target4);
+ newCluster.add(target5);
+
+ //make sure targets have different network topology distance to source
+ assertEquals(2, newCluster.getDistanceCost(source, target1));
+ assertEquals(4, newCluster.getDistanceCost(source, target2));
+ assertEquals(4, newCluster.getDistanceCost(source, target3));
+ assertEquals(4, newCluster.getDistanceCost(source, target4));
+ assertEquals(6, newCluster.getDistanceCost(source, target5));
+
+
+
+ //insert in ascending order of network topology distance
+ List<DatanodeUsageInfo> overUtilizedDatanodes = new ArrayList<>();
+ //set the farthest target with the lowest usage info
+ overUtilizedDatanodes.add(
+ new DatanodeUsageInfo(target5, new SCMNodeStat(100, 0, 90)));
+ //set the tree targets, which have the same network topology distance
+ //to source , with different usage info
+ overUtilizedDatanodes.add(
+ new DatanodeUsageInfo(target2, new SCMNodeStat(100, 0, 20)));
+ overUtilizedDatanodes.add(
+ new DatanodeUsageInfo(target3, new SCMNodeStat(100, 0, 40)));
+ overUtilizedDatanodes.add(
+ new DatanodeUsageInfo(target4, new SCMNodeStat(100, 0, 60)));
+ //set the nearest target with the highest usage info
+ overUtilizedDatanodes.add(
+ new DatanodeUsageInfo(target1, new SCMNodeStat(100, 0, 10)));
+
+
+ FindTargetGreedyByNetworkTopology findTargetGreedyByNetworkTopology =
+ new FindTargetGreedyByNetworkTopology(null, null, null, newCluster);
+
+ findTargetGreedyByNetworkTopology.reInitialize(
+ overUtilizedDatanodes, null, null);
+
+ findTargetGreedyByNetworkTopology.sortTargetForSource(source);
+
+ Collection<DatanodeUsageInfo> potentialTargets =
+ findTargetGreedyByNetworkTopology.getPotentialTargets();
+
+ Object[] sortedPotentialTargetArray = potentialTargets.toArray();
+ Assert.assertEquals(sortedPotentialTargetArray.length, 5);
+
+ // although target1 has the highest usage, it has the nearest network
+ // topology distance to source, so it should be at the head of the
+ // sorted PotentialTargetArray
+ Assert.assertEquals(((DatanodeUsageInfo)sortedPotentialTargetArray[0])
+ .getDatanodeDetails(), target1);
+
+ // these targets have same network topology distance to source,
+ // so they should be sorted by usage
+ Assert.assertEquals(((DatanodeUsageInfo)sortedPotentialTargetArray[1])
+ .getDatanodeDetails(), target4);
+ Assert.assertEquals(((DatanodeUsageInfo)sortedPotentialTargetArray[2])
+ .getDatanodeDetails(), target3);
+ Assert.assertEquals(((DatanodeUsageInfo)sortedPotentialTargetArray[3])
+ .getDatanodeDetails(), target2);
+
+ //target5 has the lowest usage , but it has the farthest distance to source
+ //so it should be at the tail of the sorted PotentialTargetArray
+ Assert.assertEquals(((DatanodeUsageInfo)sortedPotentialTargetArray[4])
+ .getDatanodeDetails(), target5);
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org