Skip to content
Open
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 number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class ContainerBalancerSelectionCriteria {
private Map<ContainerID, DatanodeDetails> containerToSourceMap;
private Set<ContainerID> excludeContainers;
private Set<ContainerID> includeContainers;
private Set<ContainerID> excludeContainersDueToFailure;
private final Set<ContainerID> excludeContainersDueToFailure;
private FindSourceStrategy findSourceStrategy;
private Map<DatanodeDetails, NavigableSet<ContainerID>> setMap;

Expand All @@ -66,12 +66,24 @@ public ContainerBalancerSelectionCriteria(
ContainerManager containerManager,
FindSourceStrategy findSourceStrategy,
Map<ContainerID, DatanodeDetails> containerToSourceMap) {
this(balancerConfiguration, nodeManager, replicationManager, containerManager,
findSourceStrategy, containerToSourceMap, new HashSet<>());
}

public ContainerBalancerSelectionCriteria(
ContainerBalancerConfiguration balancerConfiguration,
NodeManager nodeManager,
ReplicationManager replicationManager,
ContainerManager containerManager,
FindSourceStrategy findSourceStrategy,
Map<ContainerID, DatanodeDetails> containerToSourceMap,
Set<ContainerID> excludeContainersDueToFailure) {
this.balancerConfiguration = balancerConfiguration;
this.nodeManager = nodeManager;
this.replicationManager = replicationManager;
this.containerManager = containerManager;
this.containerToSourceMap = containerToSourceMap;
excludeContainersDueToFailure = new HashSet<>();
this.excludeContainersDueToFailure = excludeContainersDueToFailure;
excludeContainers = balancerConfiguration.getExcludeContainers();
includeContainers = balancerConfiguration.getIncludeContainers();
this.findSourceStrategy = findSourceStrategy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ public class ContainerBalancerTask implements Runnable {

private Set<DatanodeDetails> selectedTargets;
private Set<DatanodeDetails> selectedSources;
private final Set<ContainerID> excludeContainersDueToFailure = new HashSet<>();
private FindTargetStrategy findTargetStrategy;
private FindSourceStrategy findSourceStrategy;
private Map<ContainerMoveSelection, CompletableFuture<MoveManager.MoveResult>>
Expand Down Expand Up @@ -635,7 +636,7 @@ private boolean initializeIteration() {

selectionCriteria = new ContainerBalancerSelectionCriteria(config,
nodeManager, replicationManager, containerManager, findSourceStrategy,
containerToSourceMap);
containerToSourceMap, excludeContainersDueToFailure);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

REPLICATION_NOT_HEALTHY_AFTER_MOVE may be temporary or target-specific. Would it make sense to persist only the ContainerNotFoundException exclusions across iterations, and keep the transient ones iteration-scoped?

return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,42 @@ public void testConcurrentMoveCallbacksAccumulateMovedBytesAtomically() throws E
moveCompletionExecutor.shutdownNow();
}
}


@Test
public void testExcludeContainersDueToFailurePersistsAcrossIterations() throws Exception {
when(moveManager.move(any(ContainerID.class), any(DatanodeDetails.class),
any(DatanodeDetails.class)))
.thenReturn(CompletableFuture.completedFuture(
MoveManager.MoveResult.REPLICATION_NOT_HEALTHY_AFTER_MOVE))
.thenReturn(CompletableFuture.completedFuture(MoveManager.MoveResult.COMPLETED));

balancerConfiguration.setThreshold(10);
balancerConfiguration.setIterations(2);
balancerConfiguration.setBalancingInterval(0);
balancerConfiguration.setMaxSizeEnteringTarget(10 * STORAGE_UNIT);
balancerConfiguration.setMaxSizeToMovePerIteration(100 * STORAGE_UNIT);
balancerConfiguration.setMaxDatanodesPercentageToInvolvePerIteration(100);
String includeNodes = nodesInCluster.get(0).getDatanodeDetails().getHostName() + "," +
nodesInCluster.get(nodesInCluster.size() - 1).getDatanodeDetails().getHostName();
balancerConfiguration.setIncludeNodes(includeNodes);

startBalancer(balancerConfiguration);

ArgumentCaptor<ContainerID> containerCaptor = ArgumentCaptor.forClass(ContainerID.class);
verify(moveManager, atLeast(1)).move(containerCaptor.capture(),
any(DatanodeDetails.class), any(DatanodeDetails.class));
ContainerID failedContainerId = containerCaptor.getAllValues().get(0);

assertTrue(containerBalancerTask.getSelectionCriteria()
.getExcludeDueToFailContainers().contains(failedContainerId));

long failedContainerMoveAttempts = containerCaptor.getAllValues().stream()
.filter(id -> id.equals(failedContainerId))
.count();
assertEquals(1, failedContainerMoveAttempts,
"Permanently failed container should not be retried in later iterations");
}

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