Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line numberDiff line numberDiff line change
Expand Up@@ -89,8 +89,6 @@ public class ContainerBalancerTask implements Runnable {
private long maxSizeToMovePerIteration;
private int countDatanodesInvolvedPerIteration;
private long sizeScheduledForMoveInLatestIteration;
// count actual size moved in bytes
private long sizeActuallyMovedInLatestIteration;
private final List<DatanodeUsageInfo> overUtilizedNodes;
private final List<DatanodeUsageInfo> underUtilizedNodes;
private Set<String> excludeNodes;
Expand DownExpand Up@@ -338,29 +336,18 @@ private ContainerBalancerTaskIterationStatusInfo getIterationStatistic(Integer i
ContainerMoveInfo containerMoveInfo = new ContainerMoveInfo(metrics);

DataMoveInfo dataMoveInfo =
getDataMoveInfo(currentIterationResultName, sizeEnteringDataToNodes, sizeLeavingDataFromNodes);
getDataMoveInfo(sizeEnteringDataToNodes, sizeLeavingDataFromNodes);
return new ContainerBalancerTaskIterationStatusInfo(iterationInfo, containerMoveInfo, dataMoveInfo);
}

private DataMoveInfo getDataMoveInfo(String currentIterationResultName, Map<DatanodeID, Long> sizeEnteringDataToNodes,
private DataMoveInfo getDataMoveInfo(Map<DatanodeID, Long> sizeEnteringDataToNodes,
Map<DatanodeID, Long> sizeLeavingDataFromNodes) {
if (currentIterationResultName == null) {
// For unfinished iteration
return new DataMoveInfo(
getSizeScheduledForMoveInLatestIteration(),
sizeActuallyMovedInLatestIteration,
sizeEnteringDataToNodes,
sizeLeavingDataFromNodes
);
} else {
// For finished iteration
return new DataMoveInfo(
getSizeScheduledForMoveInLatestIteration(),
metrics.getDataSizeMovedInLatestIteration(),
sizeEnteringDataToNodes,
sizeLeavingDataFromNodes
);
}
return new DataMoveInfo(
getSizeScheduledForMoveInLatestIteration(),
metrics.getDataSizeMovedInLatestIteration(),
sizeEnteringDataToNodes,
sizeLeavingDataFromNodes
);
}

private Map<DatanodeID, Long> convertToNodeIdToTrafficMap(Map<DatanodeDetails, Long> nodeTrafficMap) {
Expand DownExpand Up@@ -743,9 +730,8 @@ private void checkIterationMoveResults() {

metrics.incrementNumContainerMovesTimeout(metrics.getNumContainerMovesTimeoutInLatestIteration());

metrics.incrementDataSizeMovedGBInLatestIteration(sizeActuallyMovedInLatestIteration / OzoneConsts.GB);

metrics.incrementDataSizeMovedInLatestIteration(sizeActuallyMovedInLatestIteration);
long bytesMovedInLatestIteration = metrics.getDataSizeMovedInLatestIteration();
metrics.incrementDataSizeMovedGBInLatestIteration(bytesMovedInLatestIteration / OzoneConsts.GB);

metrics.incrementDataSizeMovedGB(metrics.getDataSizeMovedGBInLatestIteration());

Expand All@@ -754,8 +740,8 @@ private void checkIterationMoveResults() {
LOG.info("Iteration Summary. Number of Datanodes involved: {}. Size " +
"moved: {} ({} Bytes). Number of Container moves completed: {}.",
countDatanodesInvolvedPerIteration,
byteDesc(sizeActuallyMovedInLatestIteration),
sizeActuallyMovedInLatestIteration,
byteDesc(bytesMovedInLatestIteration),
bytesMovedInLatestIteration,
metrics.getNumContainerMovesCompletedInLatestIteration());
}

Expand DownExpand Up@@ -943,8 +929,7 @@ private boolean moveContainer(DatanodeDetails source,
metrics.incrementNumContainerMovesFailedInLatestIteration(1);
} else {
if (result == MoveManager.MoveResult.COMPLETED) {
sizeActuallyMovedInLatestIteration +=
containerInfo.getUsedBytes();
metrics.incrementDataSizeMovedInLatestIteration(containerInfo.getUsedBytes());
LOG.debug("Container move completed for container {} from " +
"source {} to target {}", containerID, source,
moveSelection.getTargetNode());
Expand DownExpand Up@@ -1156,7 +1141,6 @@ private void resetState() {
this.selectedTargets.clear();
this.countDatanodesInvolvedPerIteration = 0;
this.sizeScheduledForMoveInLatestIteration = 0;
this.sizeActuallyMovedInLatestIteration = 0;
metrics.resetDataSizeMovedGBInLatestIteration();
metrics.resetDataSizeMovedInLatestIteration();
metrics.resetNumContainerMovesScheduledInLatestIteration();
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -43,9 +43,13 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.hadoop.conf.StorageUnit;
import org.apache.hadoop.hdds.client.ECReplicationConfig;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
Expand DownExpand Up@@ -432,6 +436,60 @@ public void balancerShouldMoveOnlyPositiveSizeContainers()
assertFalse(zeroOrNegSizeContainerMoved);
}

@Test
public void testConcurrentMoveCallbacksAccumulateMovedBytesAtomically() throws Exception {
int concurrentParties = 10;
CyclicBarrier completionBarrier = new CyclicBarrier(concurrentParties);
AtomicInteger completionOrder = new AtomicInteger(0);
ExecutorService moveCompletionExecutor = Executors.newFixedThreadPool(concurrentParties);

try {
when(moveManager.move(any(ContainerID.class), any(DatanodeDetails.class),
any(DatanodeDetails.class)))
.thenAnswer(invocation -> {
CompletableFuture<MoveManager.MoveResult> future = new CompletableFuture<>();
int order = completionOrder.getAndIncrement();

moveCompletionExecutor.execute(() -> {
try {
//This forces 10 completion threads to release together
if (order < concurrentParties) {
completionBarrier.await(30, TimeUnit.SECONDS);
}
} catch (Exception e) {
future.completeExceptionally(e);
return;
}
future.complete(MoveManager.MoveResult.COMPLETED);
});
return future;
});

balancerConfiguration.setThreshold(10);
balancerConfiguration.setIterations(1);
balancerConfiguration.setMaxSizeEnteringTarget(500 * STORAGE_UNIT);
balancerConfiguration.setMaxSizeToMovePerIteration(500 * STORAGE_UNIT);
balancerConfiguration.setMaxDatanodesPercentageToInvolvePerIteration(100);

startBalancer(balancerConfiguration);

ContainerBalancerMetrics metrics = containerBalancerTask.getMetrics();
int completedMoves = (int) metrics.getNumContainerMovesCompletedInLatestIteration();

assertTrue(completedMoves >= concurrentParties,
"Expected at least " + concurrentParties + " completed moves");

long expectedBytesMoved = 0;
for (ContainerID containerID : containerBalancerTask.getContainerToSourceMap().keySet()) {
expectedBytesMoved += cidToInfoMap.get(containerID).getUsedBytes();
}

assertEquals(expectedBytesMoved, metrics.getDataSizeMovedInLatestIteration());
} finally {
moveCompletionExecutor.shutdownNow();
}
}

/**
* Generates a range of equally spaced utilization(that is, used / capacity)
* values from 0 to 1.
Expand Down