This is an automated email from the ASF dual-hosted git repository.
adoroszlai 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 df5683fef7 HDDS-10699. Refactor ContainerBalancerTask and
TestContainerBalancerTask (#6537)
df5683fef7 is described below
commit df5683fef70dbfc79658501bdf579feac7b7ba03
Author: Andrei Mikhalev <[email protected]>
AuthorDate: Fri May 17 11:51:59 2024 +0300
HDDS-10699. Refactor ContainerBalancerTask and TestContainerBalancerTask
(#6537)
---
.../container/balancer/ContainerBalancerTask.java | 61 +++-----
.../hdds/scm/container/balancer/MockedSCM.java | 35 ++---
.../TestContainerBalancerDatanodeNodeLimit.java | 165 +++++++++++++++++++-
.../balancer/TestContainerBalancerTask.java | 167 +--------------------
.../scm/container/balancer/TestableCluster.java | 8 +-
5 files changed, 212 insertions(+), 224 deletions(-)
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerTask.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerTask.java
index fe0c29e510..0bfedd4396 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerTask.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerTask.java
@@ -75,7 +75,6 @@ public class ContainerBalancerTask implements Runnable {
private OzoneConfiguration ozoneConfiguration;
private ContainerBalancer containerBalancer;
private final SCMContext scmContext;
- private double threshold;
private int totalNodesInCluster;
private double maxDatanodesRatioToInvolvePerIteration;
private long maxSizeToMovePerIteration;
@@ -84,17 +83,13 @@ public class ContainerBalancerTask implements Runnable {
// count actual size moved in bytes
private long sizeActuallyMovedInLatestIteration;
private int iterations;
- private List<DatanodeUsageInfo> unBalancedNodes;
- private List<DatanodeUsageInfo> overUtilizedNodes;
- private List<DatanodeUsageInfo> underUtilizedNodes;
+ private final List<DatanodeUsageInfo> overUtilizedNodes;
+ private final List<DatanodeUsageInfo> underUtilizedNodes;
private List<DatanodeUsageInfo> withinThresholdUtilizedNodes;
private Set<String> excludeNodes;
private Set<String> includeNodes;
private ContainerBalancerConfiguration config;
private ContainerBalancerMetrics metrics;
- private long clusterCapacity;
- private long clusterRemaining;
- private double clusterAvgUtilisation;
private PlacementPolicyValidateProxy placementPolicyValidateProxy;
private NetworkTopology networkTopology;
private double upperLimit;
@@ -150,7 +145,6 @@ public class ContainerBalancerTask implements Runnable {
this.overUtilizedNodes = new ArrayList<>();
this.underUtilizedNodes = new ArrayList<>();
this.withinThresholdUtilizedNodes = new ArrayList<>();
- this.unBalancedNodes = new ArrayList<>();
this.placementPolicyValidateProxy = scm.getPlacementPolicyValidateProxy();
this.networkTopology = scm.getClusterMap();
this.nextIterationIndex = nextIterationIndex;
@@ -348,7 +342,6 @@ public class ContainerBalancerTask implements Runnable {
return false;
}
- this.threshold = config.getThresholdAsRatio();
this.maxDatanodesRatioToInvolvePerIteration =
config.getMaxDatanodesRatioToInvolvePerIteration();
this.maxSizeToMovePerIteration = config.getMaxSizeToMovePerIteration();
@@ -368,22 +361,19 @@ public class ContainerBalancerTask implements Runnable {
this.totalNodesInCluster = datanodeUsageInfos.size();
- clusterAvgUtilisation = calculateAvgUtilization(datanodeUsageInfos);
+ double clusterAvgUtilisation = calculateAvgUtilization(datanodeUsageInfos);
if (LOG.isDebugEnabled()) {
- LOG.debug("Average utilization of the cluster is {}",
- clusterAvgUtilisation);
+ LOG.debug("Average utilization of the cluster is {}",
clusterAvgUtilisation);
}
- // over utilized nodes have utilization(that is, used / capacity) greater
- // than upper limit
+ double threshold = config.getThresholdAsRatio();
+ // over utilized nodes have utilization(that is, used / capacity) greater
than upper limit
this.upperLimit = clusterAvgUtilisation + threshold;
- // under utilized nodes have utilization(that is, used / capacity) less
- // than lower limit
+ // under utilized nodes have utilization(that is, used / capacity) less
than lower limit
this.lowerLimit = clusterAvgUtilisation - threshold;
if (LOG.isDebugEnabled()) {
- LOG.debug("Lower limit for utilization is {} and Upper limit for " +
- "utilization is {}", lowerLimit, upperLimit);
+ LOG.debug("Lower limit for utilization is {} and Upper limit for
utilization is {}", lowerLimit, upperLimit);
}
long totalOverUtilizedBytes = 0L, totalUnderUtilizedBytes = 0L;
@@ -433,12 +423,7 @@ public class ContainerBalancerTask implements Runnable {
OzoneConsts.GB);
Collections.reverse(underUtilizedNodes);
- unBalancedNodes = new ArrayList<>(
- overUtilizedNodes.size() + underUtilizedNodes.size());
- unBalancedNodes.addAll(overUtilizedNodes);
- unBalancedNodes.addAll(underUtilizedNodes);
-
- if (unBalancedNodes.isEmpty()) {
+ if (overUtilizedNodes.isEmpty() && underUtilizedNodes.isEmpty()) {
LOG.info("Did not find any unbalanced Datanodes.");
return false;
}
@@ -487,7 +472,7 @@ public class ContainerBalancerTask implements Runnable {
findTargetStrategy.reInitialize(potentialTargets, config, upperLimit);
findSourceStrategy.reInitialize(getPotentialSources(), config, lowerLimit);
- moveSelectionToFutureMap = new HashMap<>(unBalancedNodes.size());
+ moveSelectionToFutureMap = new HashMap<>(underUtilizedNodes.size() +
overUtilizedNodes.size());
boolean isMoveGeneratedInThisIteration = false;
iterationResult = IterationResult.ITERATION_COMPLETED;
boolean canAdaptWhenNearingLimits = true;
@@ -965,8 +950,8 @@ public class ContainerBalancerTask implements Runnable {
* @return Average utilization value
*/
@VisibleForTesting
- double calculateAvgUtilization(List<DatanodeUsageInfo> nodes) {
- if (nodes.size() == 0) {
+ public static double calculateAvgUtilization(List<DatanodeUsageInfo> nodes) {
+ if (nodes.isEmpty()) {
LOG.warn("No nodes to calculate average utilization for in " +
"ContainerBalancer.");
return 0;
@@ -976,8 +961,8 @@ public class ContainerBalancerTask implements Runnable {
for (DatanodeUsageInfo node : nodes) {
aggregatedStats.add(node.getScmNodeStat());
}
- clusterCapacity = aggregatedStats.getCapacity().get();
- clusterRemaining = aggregatedStats.getRemaining().get();
+ long clusterCapacity = aggregatedStats.getCapacity().get();
+ long clusterRemaining = aggregatedStats.getRemaining().get();
return (clusterCapacity - clusterRemaining) / (double) clusterCapacity;
}
@@ -1060,11 +1045,8 @@ public class ContainerBalancerTask implements Runnable {
*/
private void resetState() {
moveManager.resetState();
- this.clusterCapacity = 0L;
- this.clusterRemaining = 0L;
this.overUtilizedNodes.clear();
this.underUtilizedNodes.clear();
- this.unBalancedNodes.clear();
this.containerToSourceMap.clear();
this.containerToTargetMap.clear();
this.selectedSources.clear();
@@ -1090,15 +1072,14 @@ public class ContainerBalancerTask implements Runnable {
return taskStatus == Status.RUNNING;
}
- /**
- * Gets the list of unBalanced nodes, that is, the over and under utilized
- * nodes in the cluster.
- *
- * @return List of DatanodeUsageInfo containing unBalanced nodes.
- */
@VisibleForTesting
- List<DatanodeUsageInfo> getUnBalancedNodes() {
- return unBalancedNodes;
+ public List<DatanodeUsageInfo> getOverUtilizedNodes() {
+ return overUtilizedNodes;
+ }
+
+ @VisibleForTesting
+ public List<DatanodeUsageInfo> getUnderUtilizedNodes() {
+ return underUtilizedNodes;
}
/**
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/MockedSCM.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/MockedSCM.java
index b290b95044..a3ec55d586 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/MockedSCM.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/MockedSCM.java
@@ -6,9 +6,9 @@
* 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>
+ *
+ * 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.
@@ -66,28 +66,32 @@ public final class MockedSCM {
private final StorageContainerManager scm;
private final TestableCluster cluster;
private final MockNodeManager mockNodeManager;
- private MockedReplicationManager mockedReplicaManager;
- private MoveManager moveManager;
- private ContainerManager containerManager;
-
+ private final MockedReplicationManager mockedReplicaManager;
+ private final MoveManager moveManager;
+ private final ContainerManager containerManager;
private MockedPlacementPolicies mockedPlacementPolicies;
public MockedSCM(@Nonnull TestableCluster testableCluster) {
scm = mock(StorageContainerManager.class);
cluster = testableCluster;
mockNodeManager = new
MockNodeManager(cluster.getDatanodeToContainersMap());
+ try {
+ moveManager = mockMoveManager();
+ containerManager = mockContainerManager(cluster);
+ mockedReplicaManager = MockedReplicationManager.doMock();
+ } catch (NodeNotFoundException | ContainerReplicaNotFoundException |
ContainerNotFoundException |
+ TimeoutException e
+ ) {
+ throw new RuntimeException("Can't create MockedSCM instance: ", e);
+ }
}
- public void init(@Nonnull ContainerBalancerConfiguration balancerConfig) {
- init(balancerConfig, new OzoneConfiguration());
- }
-
- public void init(@Nonnull ContainerBalancerConfiguration balancerConfig,
@Nonnull OzoneConfiguration ozoneCfg) {
+ private void init(@Nonnull ContainerBalancerConfiguration balancerConfig,
@Nonnull OzoneConfiguration ozoneCfg) {
ozoneCfg.setFromObject(balancerConfig);
try {
doMock(balancerConfig, ozoneCfg);
} catch (IOException | NodeNotFoundException | TimeoutException e) {
- throw new RuntimeException("Can't initialize TestOzoneHDDS: ", e);
+ throw new RuntimeException("Can't create MockedSCM instance: ", e);
}
}
@@ -96,9 +100,6 @@ public final class MockedSCM {
*/
private void doMock(@Nonnull ContainerBalancerConfiguration cfg, @Nonnull
OzoneConfiguration ozoneCfg)
throws IOException, NodeNotFoundException, TimeoutException {
- containerManager = mockContainerManager(cluster);
- mockedReplicaManager = MockedReplicationManager.doMock();
- moveManager = mockMoveManager();
StatefulServiceStateManager stateManager =
MockedServiceStateManager.doMock();
SCMServiceManager scmServiceManager = mockSCMServiceManger();
@@ -137,7 +138,7 @@ public final class MockedSCM {
}
public @Nonnull ContainerBalancerTask startBalancerTask(@Nonnull
ContainerBalancerConfiguration config) {
- init(config);
+ init(config, new OzoneConfiguration());
return startBalancerTask(new ContainerBalancer(scm), config);
}
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancerDatanodeNodeLimit.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancerDatanodeNodeLimit.java
index 8f1db615df..35804795cc 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancerDatanodeNodeLimit.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancerDatanodeNodeLimit.java
@@ -20,6 +20,10 @@ package org.apache.hadoop.hdds.scm.container.balancer;
import jakarta.annotation.Nonnull;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.scm.container.ContainerID;
+import org.apache.hadoop.hdds.scm.node.DatanodeUsageInfo;
+import org.apache.hadoop.hdds.scm.node.states.NodeNotFoundException;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.ozone.test.GenericTestUtils;
import org.junit.jupiter.api.BeforeAll;
@@ -28,13 +32,26 @@ import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.slf4j.event.Level;
+import java.io.IOException;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;
+import static
org.apache.hadoop.hdds.scm.container.balancer.TestableCluster.RANDOM;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
-import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
/**
* Tests for {@link ContainerBalancerTask} moved from {@link
TestContainerBalancerTask} to run them on clusters
@@ -170,8 +187,152 @@ public class TestContainerBalancerDatanodeNodeLimit {
assertNotEquals(0, task.getSizeScheduledForMoveInLatestIteration());
}
+ /**
+ * Checks whether ContainerBalancer is correctly updating the list of
+ * unBalanced nodes with varying values of Threshold.
+ */
+ @ParameterizedTest(name = "MockedSCM #{index}: {0}")
+ @MethodSource("createMockedSCMs")
+ public void
initializeIterationShouldUpdateUnBalancedNodesWhenThresholdChanges(@Nonnull
MockedSCM mockedSCM) {
+ ContainerBalancerConfiguration config = new
OzoneConfiguration().getObject(ContainerBalancerConfiguration.class);
+ int nodeCount = mockedSCM.getCluster().getNodeCount();
+ if (nodeCount < DATANODE_COUNT_LIMIT_FOR_SMALL_CLUSTER) {
+ config.setMaxDatanodesPercentageToInvolvePerIteration(100);
+ }
+ config.setThreshold(10);
+ config.setIterations(1);
+ config.setMaxSizeToMovePerIteration(50 * STORAGE_UNIT);
+ config.setMaxSizeEnteringTarget(50 * STORAGE_UNIT);
+
+ // check for random threshold values
+ for (int i = 0; i < 50; i++) {
+ double randomThreshold = RANDOM.nextDouble() * 100;
+ List<DatanodeUsageInfo> expectedUnBalancedNodes =
mockedSCM.getCluster().getUnBalancedNodes(randomThreshold);
+ config.setThreshold(randomThreshold);
+
+ ContainerBalancerTask task = mockedSCM.startBalancerTask(config);
+ List<DatanodeUsageInfo> unBalancedNodesAccordingToBalancer =
getUnBalancedNodes(task);
+
+ assertEquals(expectedUnBalancedNodes.size(),
unBalancedNodesAccordingToBalancer.size());
+
+ for (int j = 0; j < expectedUnBalancedNodes.size(); j++) {
+ assertEquals(expectedUnBalancedNodes.get(j).getDatanodeDetails(),
+ unBalancedNodesAccordingToBalancer.get(j).getDatanodeDetails());
+ }
+ }
+ }
+
+ @ParameterizedTest(name = "MockedSCM #{index}: {0}")
+ @MethodSource("createMockedSCMs")
+ public void testCalculationOfUtilization(@Nonnull MockedSCM mockedSCM) {
+ TestableCluster cluster = mockedSCM.getCluster();
+ DatanodeUsageInfo[] nodesInCluster = cluster.getNodesInCluster();
+ double[] nodeUtilizations = cluster.getNodeUtilizationList();
+ assertEquals(nodesInCluster.length, nodeUtilizations.length);
+ for (int i = 0; i < nodesInCluster.length; i++) {
+ assertEquals(nodeUtilizations[i],
nodesInCluster[i].calculateUtilization(), 0.0001);
+ }
+
+ // should be equal to average utilization of the cluster
+ assertEquals(cluster.getAverageUtilization(),
+
ContainerBalancerTask.calculateAvgUtilization(Arrays.asList(nodesInCluster)),
0.0001);
+ }
+
+ @ParameterizedTest(name = "MockedSCM #{index}: {0}")
+ @MethodSource("createMockedSCMs")
+ public void testBalancerWithMoveManager(@Nonnull MockedSCM mockedSCM)
+ throws IOException, NodeNotFoundException, TimeoutException {
+ ContainerBalancerConfiguration config = new
OzoneConfiguration().getObject(ContainerBalancerConfiguration.class);
+ int nodeCount = mockedSCM.getCluster().getNodeCount();
+ if (nodeCount < DATANODE_COUNT_LIMIT_FOR_SMALL_CLUSTER) {
+ config.setMaxDatanodesPercentageToInvolvePerIteration(100);
+ }
+ config.setThreshold(10);
+ config.setIterations(1);
+ config.setMaxSizeToMovePerIteration(50 * STORAGE_UNIT);
+ config.setMaxSizeEnteringTarget(50 * STORAGE_UNIT);
+
+ mockedSCM.disableLegacyReplicationManager();
+ mockedSCM.startBalancerTask(config);
+
+ verify(mockedSCM.getMoveManager(), atLeastOnce())
+ .move(any(ContainerID.class),
+ any(DatanodeDetails.class),
+ any(DatanodeDetails.class));
+
+ verify(mockedSCM.getReplicationManager(), times(0))
+ .move(any(ContainerID.class), any(
+ DatanodeDetails.class), any(DatanodeDetails.class));
+ }
+
+ @ParameterizedTest(name = "MockedSCM #{index}: {0}")
+ @MethodSource("createMockedSCMs")
+ public void unBalancedNodesListShouldBeEmptyWhenClusterIsBalanced(@Nonnull
MockedSCM mockedSCM) {
+ ContainerBalancerConfiguration config = new
OzoneConfiguration().getObject(ContainerBalancerConfiguration.class);
+ int nodeCount = mockedSCM.getCluster().getNodeCount();
+ if (nodeCount < DATANODE_COUNT_LIMIT_FOR_SMALL_CLUSTER) {
+ config.setMaxDatanodesPercentageToInvolvePerIteration(100);
+ }
+ config.setThreshold(10);
+ config.setIterations(1);
+ config.setMaxSizeToMovePerIteration(50 * STORAGE_UNIT);
+ config.setMaxSizeEnteringTarget(50 * STORAGE_UNIT);
+ config.setThreshold(99.99);
+
+ ContainerBalancerTask task = mockedSCM.startBalancerTask(config);
+ ContainerBalancerMetrics metrics = task.getMetrics();
+ assertEquals(0, getUnBalancedNodes(task).size());
+ assertEquals(0, metrics.getNumDatanodesUnbalanced());
+ }
+
+ @ParameterizedTest(name = "MockedSCM #{index}: {0}")
+ @MethodSource("createMockedSCMs")
+ public void testMetrics(@Nonnull MockedSCM mockedSCM) throws IOException,
NodeNotFoundException {
+ OzoneConfiguration ozoneConfig = new OzoneConfiguration();
+ ozoneConfig.set("hdds.datanode.du.refresh.period", "1ms");
+ ContainerBalancerConfiguration config =
balancerConfigByOzoneConfig(ozoneConfig);
+ int nodeCount = mockedSCM.getCluster().getNodeCount();
+ if (nodeCount < DATANODE_COUNT_LIMIT_FOR_SMALL_CLUSTER) {
+ config.setMaxDatanodesPercentageToInvolvePerIteration(100);
+ }
+ config.setBalancingInterval(Duration.ofMillis(2));
+ config.setThreshold(10);
+ config.setIterations(1);
+ config.setMaxSizeEnteringTarget(6 * STORAGE_UNIT);
+ // deliberately set max size per iteration to a low value, 6 GB
+ config.setMaxSizeToMovePerIteration(6 * STORAGE_UNIT);
+
+ when(mockedSCM.getMoveManager().move(any(), any(), any()))
+
.thenReturn(CompletableFuture.completedFuture(MoveManager.MoveResult.REPLICATION_FAIL_NODE_UNHEALTHY))
+
.thenReturn(CompletableFuture.completedFuture(MoveManager.MoveResult.COMPLETED));
+ ContainerBalancerTask task = mockedSCM.startBalancerTask(config);
+
+ ContainerBalancerMetrics metrics = task.getMetrics();
+
assertEquals(mockedSCM.getCluster().getUnBalancedNodes(config.getThreshold()).size(),
+ metrics.getNumDatanodesUnbalanced());
+
assertThat(metrics.getDataSizeMovedGBInLatestIteration()).isLessThanOrEqualTo(6);
+ assertThat(metrics.getDataSizeMovedGB()).isGreaterThan(0);
+ assertEquals(1, metrics.getNumIterations());
+
assertThat(metrics.getNumContainerMovesScheduledInLatestIteration()).isGreaterThan(0);
+ assertEquals(metrics.getNumContainerMovesScheduled(),
metrics.getNumContainerMovesScheduledInLatestIteration());
+ assertEquals(metrics.getNumContainerMovesScheduled(),
+ metrics.getNumContainerMovesCompleted() +
+ metrics.getNumContainerMovesFailed() +
+ metrics.getNumContainerMovesTimeout());
+ assertEquals(0, metrics.getNumContainerMovesTimeout());
+ assertEquals(1, metrics.getNumContainerMovesFailed());
+ }
+
+
+ public static List<DatanodeUsageInfo> getUnBalancedNodes(@Nonnull
ContainerBalancerTask task) {
+ ArrayList<DatanodeUsageInfo> result = new ArrayList<>();
+ result.addAll(task.getOverUtilizedNodes());
+ result.addAll(task.getUnderUtilizedNodes());
+ return result;
+ }
+
private static boolean stillHaveUnbalancedNodes(@Nonnull
ContainerBalancerTask task) {
- return !task.getUnBalancedNodes().isEmpty();
+ return !getUnBalancedNodes(task).isEmpty();
}
public static @Nonnull MockedSCM getMockedSCM(int datanodeCount) {
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancerTask.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancerTask.java
index 3518e45237..0f4551b45c 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancerTask.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancerTask.java
@@ -88,7 +88,6 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
@@ -115,7 +114,6 @@ public class TestContainerBalancerTask {
private ContainerBalancerConfiguration balancerConfiguration;
private List<DatanodeUsageInfo> nodesInCluster;
private List<Double> nodeUtilizations;
- private double averageUtilization;
private int numberOfNodes;
private Map<ContainerID, Set<ContainerReplica>> cidToReplicasMap =
new HashMap<>();
@@ -168,7 +166,7 @@ public class TestContainerBalancerTask {
.filter(method ->
method.getName().equals("balancerShouldMoveOnlyPositiveSizeContainers"))
.map(method -> new int[]{0, 0, 0, 0, 0, 1, 2, 3, 4, 5})
.orElse(null);
- averageUtilization = createCluster(sizeArray);
+ createCluster(sizeArray);
mockNodeManager = new MockNodeManager(datanodeToContainersMap);
NetworkTopology clusterMap =
mockNodeManager.getClusterNetworkTopologyMap();
@@ -250,88 +248,6 @@ public class TestContainerBalancerTask {
sb.getMetrics(), balancerConfiguration, false);
}
- @Test
- public void testCalculationOfUtilization() {
- assertEquals(nodesInCluster.size(), nodeUtilizations.size());
- for (int i = 0; i < nodesInCluster.size(); i++) {
- assertEquals(nodeUtilizations.get(i),
- nodesInCluster.get(i).calculateUtilization(), 0.0001);
- }
-
- // should be equal to average utilization of the cluster
- assertEquals(averageUtilization,
containerBalancerTask.calculateAvgUtilization(nodesInCluster), 0.0001);
- }
-
- /**
- * Checks whether ContainerBalancer is correctly updating the list of
- * unBalanced nodes with varying values of Threshold.
- */
- @Test
- public void
- initializeIterationShouldUpdateUnBalancedNodesWhenThresholdChanges() {
- List<DatanodeUsageInfo> expectedUnBalancedNodes;
- List<DatanodeUsageInfo> unBalancedNodesAccordingToBalancer;
-
- // check for random threshold values
- ContainerBalancer sb = new ContainerBalancer(scm);
- for (int i = 0; i < 50; i++) {
- double randomThreshold = RANDOM.nextDouble() * 100;
-
- expectedUnBalancedNodes =
- determineExpectedUnBalancedNodes(randomThreshold);
-
- balancerConfiguration.setThreshold(randomThreshold);
- containerBalancerTask = new ContainerBalancerTask(scm, 0, sb,
- sb.getMetrics(), balancerConfiguration, false);
- containerBalancerTask.run();
-
- unBalancedNodesAccordingToBalancer =
- containerBalancerTask.getUnBalancedNodes();
-
- assertEquals(expectedUnBalancedNodes.size(),
unBalancedNodesAccordingToBalancer.size());
-
- for (int j = 0; j < expectedUnBalancedNodes.size(); j++) {
- assertEquals(expectedUnBalancedNodes.get(j).getDatanodeDetails(),
- unBalancedNodesAccordingToBalancer.get(j).getDatanodeDetails());
- }
- }
- }
-
- @Test
- public void testBalancerWithMoveManager()
- throws IllegalContainerBalancerStateException, IOException,
- InvalidContainerBalancerConfigurationException, TimeoutException,
- NodeNotFoundException {
- rmConf.setEnableLegacy(false);
- startBalancer(balancerConfiguration);
- verify(moveManager, atLeastOnce())
- .move(any(ContainerID.class),
- any(DatanodeDetails.class),
- any(DatanodeDetails.class));
-
- verify(replicationManager, times(0))
- .move(any(ContainerID.class), any(
- DatanodeDetails.class), any(DatanodeDetails.class));
- }
-
- /**
- * Checks whether the list of unBalanced nodes is empty when the cluster is
- * balanced.
- */
- @Test
- public void unBalancedNodesListShouldBeEmptyWhenClusterIsBalanced()
- throws IllegalContainerBalancerStateException, IOException,
- InvalidContainerBalancerConfigurationException, TimeoutException {
- balancerConfiguration.setThreshold(99.99);
- startBalancer(balancerConfiguration);
-
-
- stopBalancer();
- ContainerBalancerMetrics metrics = containerBalancerTask.getMetrics();
- assertEquals(0, containerBalancerTask.getUnBalancedNodes().size());
- assertEquals(0, metrics.getNumDatanodesUnbalanced());
- }
-
@Test
public void containerBalancerShouldSelectOnlyClosedContainers()
throws IllegalContainerBalancerStateException, IOException,
@@ -345,8 +261,7 @@ public class TestContainerBalancerTask {
stopBalancer();
// balancer should have identified unbalanced nodes
- assertFalse(containerBalancerTask.getUnBalancedNodes()
- .isEmpty());
+
assertFalse(TestContainerBalancerDatanodeNodeLimit.getUnBalancedNodes(containerBalancerTask).isEmpty());
// no container should have been selected
assertTrue(containerBalancerTask.getContainerToSourceMap()
.isEmpty());
@@ -407,8 +322,7 @@ public class TestContainerBalancerTask {
stopBalancer();
// balancer should have identified unbalanced nodes
- assertFalse(containerBalancerTask.getUnBalancedNodes()
- .isEmpty());
+
assertFalse(TestContainerBalancerDatanodeNodeLimit.getUnBalancedNodes(containerBalancerTask).isEmpty());
// no container should have moved because all replicas are CLOSING
assertTrue(
containerBalancerTask.getContainerToSourceMap().isEmpty());
@@ -587,46 +501,6 @@ public class TestContainerBalancerTask {
}
}
- @Test
- public void testMetrics()
- throws IllegalContainerBalancerStateException, IOException,
- InvalidContainerBalancerConfigurationException, TimeoutException,
- NodeNotFoundException {
- conf.set("hdds.datanode.du.refresh.period", "1ms");
- balancerConfiguration.setBalancingInterval(Duration.ofMillis(2));
- balancerConfiguration.setThreshold(10);
- balancerConfiguration.setIterations(1);
- balancerConfiguration.setMaxSizeEnteringTarget(6 * STORAGE_UNIT);
- // deliberately set max size per iteration to a low value, 6 GB
- balancerConfiguration.setMaxSizeToMovePerIteration(6 * STORAGE_UNIT);
- balancerConfiguration.setMaxDatanodesPercentageToInvolvePerIteration(100);
- when(moveManager.move(any(), any(), any()))
- .thenReturn(CompletableFuture.completedFuture(
- MoveManager.MoveResult.REPLICATION_FAIL_NODE_UNHEALTHY))
- .thenReturn(CompletableFuture.completedFuture(
- MoveManager.MoveResult.COMPLETED));
-
- startBalancer(balancerConfiguration);
- stopBalancer();
-
- ContainerBalancerMetrics metrics = containerBalancerTask.getMetrics();
- assertEquals(determineExpectedUnBalancedNodes(
- balancerConfiguration.getThreshold()).size(),
- metrics.getNumDatanodesUnbalanced());
-
assertThat(metrics.getDataSizeMovedGBInLatestIteration()).isLessThanOrEqualTo(6);
- assertThat(metrics.getDataSizeMovedGB()).isGreaterThan(0);
- assertEquals(1, metrics.getNumIterations());
-
assertThat(metrics.getNumContainerMovesScheduledInLatestIteration()).isGreaterThan(0);
- assertEquals(metrics.getNumContainerMovesScheduled(),
- metrics.getNumContainerMovesScheduledInLatestIteration());
- assertEquals(metrics.getNumContainerMovesScheduled(),
- metrics.getNumContainerMovesCompleted() +
- metrics.getNumContainerMovesFailed() +
- metrics.getNumContainerMovesTimeout());
- assertEquals(0, metrics.getNumContainerMovesTimeout());
- assertEquals(1, metrics.getNumContainerMovesFailed());
- }
-
/**
* Tests if {@link ContainerBalancer} follows the includeNodes and
* excludeNodes configurations in {@link ContainerBalancerConfiguration}.
@@ -1077,35 +951,6 @@ public class TestContainerBalancerTask {
assertFalse(zeroOrNegSizeContainerMoved);
}
- /**
- * Determines unBalanced nodes, that is, over and under utilized nodes,
- * according to the generated utilization values for nodes and the threshold.
- *
- * @param threshold A percentage in the range 0 to 100
- * @return List of DatanodeUsageInfo containing the expected(correct)
- * unBalanced nodes.
- */
- private List<DatanodeUsageInfo> determineExpectedUnBalancedNodes(
- double threshold) {
- threshold /= 100;
- double lowerLimit = averageUtilization - threshold;
- double upperLimit = averageUtilization + threshold;
-
- // use node utilizations to determine over and under utilized nodes
- List<DatanodeUsageInfo> expectedUnBalancedNodes = new ArrayList<>();
- for (int i = 0; i < numberOfNodes; i++) {
- if (nodeUtilizations.get(numberOfNodes - i - 1) > upperLimit) {
- expectedUnBalancedNodes.add(nodesInCluster.get(numberOfNodes - i - 1));
- }
- }
- for (int i = 0; i < numberOfNodes; i++) {
- if (nodeUtilizations.get(i) < lowerLimit) {
- expectedUnBalancedNodes.add(nodesInCluster.get(i));
- }
- }
- return expectedUnBalancedNodes;
- }
-
/**
* Generates a range of equally spaced utilization(that is, used / capacity)
* values from 0 to 1.
@@ -1132,10 +977,9 @@ public class TestContainerBalancerTask {
* cluster have utilization values determined by generateUtilizations method.
* @return average utilization (used space / capacity) of the cluster
*/
- private double createCluster(int[] sizeArray) {
+ private void createCluster(int[] sizeArray) {
generateData(sizeArray);
createReplicasForContainers();
- long clusterCapacity = 0, clusterUsedSpace = 0;
// for each node utilization, calculate that datanode's used space and
// capacity
@@ -1158,10 +1002,7 @@ public class TestContainerBalancerTask {
datanodeCapacity - datanodeUsedSpace, 0,
datanodeCapacity - datanodeUsedSpace - 1);
nodesInCluster.get(i).setScmNodeStat(stat);
- clusterUsedSpace += datanodeUsedSpace;
- clusterCapacity += datanodeCapacity;
}
- return (double) clusterUsedSpace / clusterCapacity;
}
/**
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestableCluster.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestableCluster.java
index 60ee45535f..a565fac0e3 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestableCluster.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestableCluster.java
@@ -138,8 +138,12 @@ public final class TestableCluster {
// Use node utilization to determine over and under utilized nodes.
List<DatanodeUsageInfo> expectedUnBalancedNodes = new ArrayList<>();
for (int i = 0; i < nodeCount; i++) {
- double nodeUtilization = nodeUtilizationList[i];
- if (nodeUtilization < lowerLimit || nodeUtilization > upperLimit) {
+ if (nodeUtilizationList[nodeCount - i - 1] > upperLimit) {
+ expectedUnBalancedNodes.add(nodesInCluster[nodeCount - i - 1]);
+ }
+ }
+ for (int i = 0; i < nodeCount; i++) {
+ if (nodeUtilizationList[i] < lowerLimit) {
expectedUnBalancedNodes.add(nodesInCluster[i]);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]