Skip to content

Commit fdc38b5

Browse files
authored
HDDS-7252. Polled source Datanodes are wrongly not re-considered for balancing in Container Balancer (#6305)
1 parent 72240fa commit fdc38b5

File tree

5 files changed

+100
-4
lines changed

5 files changed

+100
-4
lines changed

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerSelectionCriteria.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public class ContainerBalancerSelectionCriteria {
5454
private ContainerManager containerManager;
5555
private Set<ContainerID> selectedContainers;
5656
private Set<ContainerID> excludeContainers;
57+
private Set<ContainerID> excludeContainersDueToFailure;
5758
private FindSourceStrategy findSourceStrategy;
5859
private Map<DatanodeDetails, NavigableSet<ContainerID>> setMap;
5960

@@ -68,6 +69,7 @@ public ContainerBalancerSelectionCriteria(
6869
this.replicationManager = replicationManager;
6970
this.containerManager = containerManager;
7071
selectedContainers = new HashSet<>();
72+
excludeContainersDueToFailure = new HashSet<>();
7173
excludeContainers = balancerConfiguration.getExcludeContainers();
7274
this.findSourceStrategy = findSourceStrategy;
7375
this.setMap = new HashMap<>();
@@ -174,7 +176,8 @@ public boolean shouldBeExcluded(ContainerID containerID,
174176
"candidate container. Excluding it.", containerID);
175177
return true;
176178
}
177-
return excludeContainers.contains(containerID) || selectedContainers.contains(containerID) ||
179+
return excludeContainers.contains(containerID) || excludeContainersDueToFailure.contains(containerID) ||
180+
selectedContainers.contains(containerID) ||
178181
!isContainerClosed(container, node) || isECContainerAndLegacyRMEnabled(container) ||
179182
isContainerReplicatingOrDeleting(containerID) ||
180183
!findSourceStrategy.canSizeLeaveSource(node, container.getUsedBytes())
@@ -242,6 +245,10 @@ public void setSelectedContainers(
242245
this.selectedContainers = selectedContainers;
243246
}
244247

248+
public void addToExcludeDueToFailContainers(ContainerID container) {
249+
this.excludeContainersDueToFailure.add(container);
250+
}
251+
245252

246253
private NavigableSet<ContainerID> getCandidateContainers(DatanodeDetails node) {
247254
NavigableSet<ContainerID> newSet =
@@ -251,6 +258,9 @@ private NavigableSet<ContainerID> getCandidateContainers(DatanodeDetails node) {
251258
if (excludeContainers != null) {
252259
idSet.removeAll(excludeContainers);
253260
}
261+
if (excludeContainersDueToFailure != null) {
262+
idSet.removeAll(excludeContainersDueToFailure);
263+
}
254264
if (selectedContainers != null) {
255265
idSet.removeAll(selectedContainers);
256266
}

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerTask.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,10 @@ private boolean processMoveSelection(DatanodeDetails source,
553553
containerID,
554554
containerToSourceMap.get(containerID),
555555
containerToTargetMap.get(containerID));
556+
// add source back to queue as a different container can be selected in next run.
557+
findSourceStrategy.addBackSourceDataNode(source);
558+
// exclude the container which caused failure of move to avoid error in next run.
559+
selectionCriteria.addToExcludeDueToFailContainers(moveSelection.getContainerID());
556560
return false;
557561
}
558562

@@ -563,6 +567,10 @@ private boolean processMoveSelection(DatanodeDetails source,
563567
} catch (ContainerNotFoundException e) {
564568
LOG.warn("Could not get container {} from Container Manager before " +
565569
"starting a container move", containerID, e);
570+
// add source back to queue as a different container can be selected in next run.
571+
findSourceStrategy.addBackSourceDataNode(source);
572+
// exclude the container which caused failure of move to avoid error in next run.
573+
selectionCriteria.addToExcludeDueToFailContainers(moveSelection.getContainerID());
566574
return false;
567575
}
568576
LOG.info("ContainerBalancer is trying to move container {} with size " +
@@ -862,13 +870,23 @@ private boolean moveContainer(DatanodeDetails source,
862870
} catch (ContainerNotFoundException e) {
863871
LOG.warn("Could not find Container {} for container move",
864872
containerID, e);
873+
// add source back to queue as a different container can be selected in next run.
874+
findSourceStrategy.addBackSourceDataNode(source);
875+
// exclude the container which caused failure of move to avoid error in next run.
876+
selectionCriteria.addToExcludeDueToFailContainers(moveSelection.getContainerID());
865877
metrics.incrementNumContainerMovesFailedInLatestIteration(1);
866878
return false;
867-
} catch (NodeNotFoundException | TimeoutException |
868-
ContainerReplicaNotFoundException e) {
879+
} catch (NodeNotFoundException | TimeoutException e) {
869880
LOG.warn("Container move failed for container {}", containerID, e);
870881
metrics.incrementNumContainerMovesFailedInLatestIteration(1);
871882
return false;
883+
} catch (ContainerReplicaNotFoundException e) {
884+
LOG.warn("Container move failed for container {}", containerID, e);
885+
metrics.incrementNumContainerMovesFailedInLatestIteration(1);
886+
// add source back to queue for replica not found only
887+
// the container is not excluded as it is a replica related failure
888+
findSourceStrategy.addBackSourceDataNode(source);
889+
return false;
872890
}
873891

874892
/*
@@ -881,6 +899,16 @@ private boolean moveContainer(DatanodeDetails source,
881899
} else {
882900
MoveManager.MoveResult result = future.join();
883901
moveSelectionToFutureMap.put(moveSelection, future);
902+
if (result == MoveManager.MoveResult.REPLICATION_FAIL_NOT_EXIST_IN_SOURCE ||
903+
result == MoveManager.MoveResult.REPLICATION_FAIL_EXIST_IN_TARGET ||
904+
result == MoveManager.MoveResult.REPLICATION_FAIL_CONTAINER_NOT_CLOSED ||
905+
result == MoveManager.MoveResult.REPLICATION_FAIL_INFLIGHT_DELETION ||
906+
result == MoveManager.MoveResult.REPLICATION_FAIL_INFLIGHT_REPLICATION) {
907+
// add source back to queue as a different container can be selected in next run.
908+
// the container which caused failure of move is not excluded
909+
// as it is an intermittent failure or a replica related failure
910+
findSourceStrategy.addBackSourceDataNode(source);
911+
}
884912
return result == MoveManager.MoveResult.COMPLETED;
885913
}
886914
} else {
@@ -1098,6 +1126,11 @@ Set<DatanodeDetails> getSelectedTargets() {
10981126
return selectedTargets;
10991127
}
11001128

1129+
@VisibleForTesting
1130+
Set<DatanodeDetails> getSelectedSources() {
1131+
return selectedSources;
1132+
}
1133+
11011134
@VisibleForTesting
11021135
int getCountDatanodesInvolvedPerIteration() {
11031136
return countDatanodesInvolvedPerIteration;

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceGreedy.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public void increaseSizeLeaving(DatanodeDetails dui, long size) {
107107
if (currentSize != null) {
108108
sizeLeavingNode.put(dui, currentSize + size);
109109
//reorder according to the latest sizeLeavingNode
110-
potentialSources.add(nodeManager.getUsageInfo(dui));
110+
addBackSourceDataNode(dui);
111111
return;
112112
}
113113
LOG.warn("Cannot find datanode {} in candidate source datanodes",
@@ -138,6 +138,12 @@ public void removeCandidateSourceDataNode(DatanodeDetails dui) {
138138
potentialSources.removeIf(a -> a.getDatanodeDetails().equals(dui));
139139
}
140140

141+
@Override
142+
public void addBackSourceDataNode(DatanodeDetails dn) {
143+
DatanodeUsageInfo dui = nodeManager.getUsageInfo(dn);
144+
potentialSources.add(dui);
145+
}
146+
141147
/**
142148
* Checks if specified size can leave a specified target datanode
143149
* according to {@link ContainerBalancerConfiguration}

hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceStrategy.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,16 @@ public interface FindSourceStrategy {
4545
*/
4646
void removeCandidateSourceDataNode(DatanodeDetails dui);
4747

48+
/**
49+
* add the specified data node to the candidate source
50+
* data nodes.
51+
* This method does not check whether the specified Datanode is already present in the Collection.
52+
* Callers must take the responsibility of checking and removing the Datanode before adding, if required.
53+
*
54+
* @param dn datanode to be added to potentialSources
55+
*/
56+
void addBackSourceDataNode(DatanodeDetails dn);
57+
4858
/**
4959
* increase the Leaving size of a candidate source data node.
5060
*/

hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/balancer/TestContainerBalancerTask.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,43 @@ public void balancerShouldExcludeECContainersWhenLegacyRmIsEnabled()
11201120
}
11211121

11221122
/**
1123+
* Tests if balancer is adding the polled source datanode back to potentialSources queue
1124+
* if a move has failed due to a container related failure, like REPLICATION_FAIL_NOT_EXIST_IN_SOURCE.
1125+
*/
1126+
@Test
1127+
public void testSourceDatanodeAddedBack()
1128+
throws NodeNotFoundException, IOException, IllegalContainerBalancerStateException,
1129+
InvalidContainerBalancerConfigurationException, TimeoutException, InterruptedException {
1130+
1131+
when(moveManager.move(any(ContainerID.class),
1132+
any(DatanodeDetails.class),
1133+
any(DatanodeDetails.class)))
1134+
.thenReturn(CompletableFuture.completedFuture(MoveManager.MoveResult.REPLICATION_FAIL_NOT_EXIST_IN_SOURCE))
1135+
.thenReturn(CompletableFuture.completedFuture(MoveManager.MoveResult.COMPLETED));
1136+
balancerConfiguration.setThreshold(10);
1137+
balancerConfiguration.setIterations(1);
1138+
balancerConfiguration.setMaxSizeEnteringTarget(10 * STORAGE_UNIT);
1139+
balancerConfiguration.setMaxSizeToMovePerIteration(100 * STORAGE_UNIT);
1140+
balancerConfiguration.setMaxDatanodesPercentageToInvolvePerIteration(100);
1141+
String includeNodes = nodesInCluster.get(0).getDatanodeDetails().getHostName() + "," +
1142+
nodesInCluster.get(nodesInCluster.size() - 1).getDatanodeDetails().getHostName();
1143+
balancerConfiguration.setIncludeNodes(includeNodes);
1144+
1145+
startBalancer(balancerConfiguration);
1146+
GenericTestUtils.waitFor(() -> ContainerBalancerTask.IterationResult.ITERATION_COMPLETED ==
1147+
containerBalancerTask.getIterationResult(), 10, 50);
1148+
1149+
assertEquals(2, containerBalancerTask.getCountDatanodesInvolvedPerIteration());
1150+
assertTrue(containerBalancerTask.getMetrics().getNumContainerMovesCompletedInLatestIteration() >= 1);
1151+
assertThat(containerBalancerTask.getMetrics().getNumContainerMovesFailed()).isEqualTo(1);
1152+
assertTrue(containerBalancerTask.getSelectedTargets().contains(nodesInCluster.get(0)
1153+
.getDatanodeDetails()));
1154+
assertTrue(containerBalancerTask.getSelectedSources().contains(nodesInCluster.get(nodesInCluster.size() - 1)
1155+
.getDatanodeDetails()));
1156+
stopBalancer();
1157+
}
1158+
1159+
/**
11231160
* Test to check if balancer picks up only positive size
11241161
* containers to move from source to destination.
11251162
*/

0 commit comments

Comments
 (0)