This is an automated email from the ASF dual-hosted git repository.

siddhant 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 fdc38b50fc HDDS-7252. Polled source Datanodes are wrongly not 
re-considered for balancing in Container Balancer (#6305)
fdc38b50fc is described below

commit fdc38b50fc6ee8495c011891dc70064d1c878fa5
Author: Tejaskriya <[email protected]>
AuthorDate: Wed Apr 17 14:05:16 2024 +0530

    HDDS-7252. Polled source Datanodes are wrongly not re-considered for 
balancing in Container Balancer (#6305)
---
 .../ContainerBalancerSelectionCriteria.java        | 12 ++++++-
 .../container/balancer/ContainerBalancerTask.java  | 37 ++++++++++++++++++++--
 .../scm/container/balancer/FindSourceGreedy.java   |  8 ++++-
 .../scm/container/balancer/FindSourceStrategy.java | 10 ++++++
 .../balancer/TestContainerBalancerTask.java        | 37 ++++++++++++++++++++++
 5 files changed, 100 insertions(+), 4 deletions(-)

diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerSelectionCriteria.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerSelectionCriteria.java
index d9102a8832..da1b8741cf 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerSelectionCriteria.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/ContainerBalancerSelectionCriteria.java
@@ -54,6 +54,7 @@ public class ContainerBalancerSelectionCriteria {
   private ContainerManager containerManager;
   private Set<ContainerID> selectedContainers;
   private Set<ContainerID> excludeContainers;
+  private Set<ContainerID> excludeContainersDueToFailure;
   private FindSourceStrategy findSourceStrategy;
   private Map<DatanodeDetails, NavigableSet<ContainerID>> setMap;
 
@@ -68,6 +69,7 @@ public class ContainerBalancerSelectionCriteria {
     this.replicationManager = replicationManager;
     this.containerManager = containerManager;
     selectedContainers = new HashSet<>();
+    excludeContainersDueToFailure = new HashSet<>();
     excludeContainers = balancerConfiguration.getExcludeContainers();
     this.findSourceStrategy = findSourceStrategy;
     this.setMap = new HashMap<>();
@@ -174,7 +176,8 @@ public class ContainerBalancerSelectionCriteria {
           "candidate container. Excluding it.", containerID);
       return true;
     }
-    return excludeContainers.contains(containerID) || 
selectedContainers.contains(containerID) ||
+    return excludeContainers.contains(containerID) || 
excludeContainersDueToFailure.contains(containerID) ||
+        selectedContainers.contains(containerID) ||
         !isContainerClosed(container, node) || 
isECContainerAndLegacyRMEnabled(container) ||
         isContainerReplicatingOrDeleting(containerID) ||
         !findSourceStrategy.canSizeLeaveSource(node, container.getUsedBytes())
@@ -242,6 +245,10 @@ public class ContainerBalancerSelectionCriteria {
     this.selectedContainers = selectedContainers;
   }
 
+  public void addToExcludeDueToFailContainers(ContainerID container) {
+    this.excludeContainersDueToFailure.add(container);
+  }
+
 
   private NavigableSet<ContainerID> getCandidateContainers(DatanodeDetails 
node) {
     NavigableSet<ContainerID> newSet =
@@ -251,6 +258,9 @@ public class ContainerBalancerSelectionCriteria {
       if (excludeContainers != null) {
         idSet.removeAll(excludeContainers);
       }
+      if (excludeContainersDueToFailure != null) {
+        idSet.removeAll(excludeContainersDueToFailure);
+      }
       if (selectedContainers != null) {
         idSet.removeAll(selectedContainers);
       }
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 94e8cfd04a..fe0c29e510 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
@@ -553,6 +553,10 @@ public class ContainerBalancerTask implements Runnable {
           containerID,
           containerToSourceMap.get(containerID),
           containerToTargetMap.get(containerID));
+      // add source back to queue as a different container can be selected in 
next run.
+      findSourceStrategy.addBackSourceDataNode(source);
+      // exclude the container which caused failure of move to avoid error in 
next run.
+      
selectionCriteria.addToExcludeDueToFailContainers(moveSelection.getContainerID());
       return false;
     }
 
@@ -563,6 +567,10 @@ public class ContainerBalancerTask implements Runnable {
     } catch (ContainerNotFoundException e) {
       LOG.warn("Could not get container {} from Container Manager before " +
           "starting a container move", containerID, e);
+      // add source back to queue as a different container can be selected in 
next run.
+      findSourceStrategy.addBackSourceDataNode(source);
+      // exclude the container which caused failure of move to avoid error in 
next run.
+      
selectionCriteria.addToExcludeDueToFailContainers(moveSelection.getContainerID());
       return false;
     }
     LOG.info("ContainerBalancer is trying to move container {} with size " +
@@ -862,13 +870,23 @@ public class ContainerBalancerTask implements Runnable {
     } catch (ContainerNotFoundException e) {
       LOG.warn("Could not find Container {} for container move",
           containerID, e);
+      // add source back to queue as a different container can be selected in 
next run.
+      findSourceStrategy.addBackSourceDataNode(source);
+      // exclude the container which caused failure of move to avoid error in 
next run.
+      
selectionCriteria.addToExcludeDueToFailContainers(moveSelection.getContainerID());
       metrics.incrementNumContainerMovesFailedInLatestIteration(1);
       return false;
-    } catch (NodeNotFoundException | TimeoutException |
-             ContainerReplicaNotFoundException e) {
+    } catch (NodeNotFoundException | TimeoutException e) {
       LOG.warn("Container move failed for container {}", containerID, e);
       metrics.incrementNumContainerMovesFailedInLatestIteration(1);
       return false;
+    } catch (ContainerReplicaNotFoundException e) {
+      LOG.warn("Container move failed for container {}", containerID, e);
+      metrics.incrementNumContainerMovesFailedInLatestIteration(1);
+      // add source back to queue for replica not found only
+      // the container is not excluded as it is a replica related failure
+      findSourceStrategy.addBackSourceDataNode(source);
+      return false;
     }
 
     /*
@@ -881,6 +899,16 @@ public class ContainerBalancerTask implements Runnable {
       } else {
         MoveManager.MoveResult result = future.join();
         moveSelectionToFutureMap.put(moveSelection, future);
+        if (result == 
MoveManager.MoveResult.REPLICATION_FAIL_NOT_EXIST_IN_SOURCE ||
+            result == MoveManager.MoveResult.REPLICATION_FAIL_EXIST_IN_TARGET 
||
+            result == 
MoveManager.MoveResult.REPLICATION_FAIL_CONTAINER_NOT_CLOSED ||
+            result == 
MoveManager.MoveResult.REPLICATION_FAIL_INFLIGHT_DELETION ||
+            result == 
MoveManager.MoveResult.REPLICATION_FAIL_INFLIGHT_REPLICATION) {
+          // add source back to queue as a different container can be selected 
in next run.
+          // the container which caused failure of move is not excluded
+          // as it is an intermittent failure or a replica related failure
+          findSourceStrategy.addBackSourceDataNode(source);
+        }
         return result == MoveManager.MoveResult.COMPLETED;
       }
     } else {
@@ -1098,6 +1126,11 @@ public class ContainerBalancerTask implements Runnable {
     return selectedTargets;
   }
 
+  @VisibleForTesting
+  Set<DatanodeDetails> getSelectedSources() {
+    return selectedSources;
+  }
+
   @VisibleForTesting
   int getCountDatanodesInvolvedPerIteration() {
     return countDatanodesInvolvedPerIteration;
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceGreedy.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceGreedy.java
index 684df784c2..8306d8e1e1 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceGreedy.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceGreedy.java
@@ -107,7 +107,7 @@ public class FindSourceGreedy implements FindSourceStrategy 
{
     if (currentSize != null) {
       sizeLeavingNode.put(dui, currentSize + size);
       //reorder according to the latest sizeLeavingNode
-      potentialSources.add(nodeManager.getUsageInfo(dui));
+      addBackSourceDataNode(dui);
       return;
     }
     LOG.warn("Cannot find datanode {} in candidate source datanodes",
@@ -138,6 +138,12 @@ public class FindSourceGreedy implements 
FindSourceStrategy {
     potentialSources.removeIf(a -> a.getDatanodeDetails().equals(dui));
   }
 
+  @Override
+  public void addBackSourceDataNode(DatanodeDetails dn) {
+    DatanodeUsageInfo dui = nodeManager.getUsageInfo(dn);
+    potentialSources.add(dui);
+  }
+
   /**
    * Checks if specified size can leave a specified target datanode
    * according to {@link ContainerBalancerConfiguration}
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceStrategy.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceStrategy.java
index 236bdfd98d..f9eb24bd3c 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceStrategy.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/balancer/FindSourceStrategy.java
@@ -45,6 +45,16 @@ public interface FindSourceStrategy {
    */
   void removeCandidateSourceDataNode(DatanodeDetails dui);
 
+  /**
+   * add the specified data node to the candidate source
+   * data nodes.
+   * This method does not check whether the specified Datanode is already 
present in the Collection.
+   * Callers must take the responsibility of checking and removing the 
Datanode before adding, if required.
+   *
+   * @param dn datanode to be added to potentialSources
+   */
+  void addBackSourceDataNode(DatanodeDetails dn);
+
   /**
    * increase the Leaving size of a candidate source data node.
    */
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 a4d7f37612..9f603d63ac 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
@@ -1120,6 +1120,43 @@ public class TestContainerBalancerTask {
   }
 
   /**
+   * Tests if balancer is adding the polled source datanode back to 
potentialSources queue
+   * if a move has failed due to a container related failure, like 
REPLICATION_FAIL_NOT_EXIST_IN_SOURCE.
+   */
+  @Test
+  public void testSourceDatanodeAddedBack()
+      throws NodeNotFoundException, IOException, 
IllegalContainerBalancerStateException,
+      InvalidContainerBalancerConfigurationException, TimeoutException, 
InterruptedException {
+
+    when(moveManager.move(any(ContainerID.class),
+        any(DatanodeDetails.class),
+        any(DatanodeDetails.class)))
+        
.thenReturn(CompletableFuture.completedFuture(MoveManager.MoveResult.REPLICATION_FAIL_NOT_EXIST_IN_SOURCE))
+        
.thenReturn(CompletableFuture.completedFuture(MoveManager.MoveResult.COMPLETED));
+    balancerConfiguration.setThreshold(10);
+    balancerConfiguration.setIterations(1);
+    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);
+    GenericTestUtils.waitFor(() -> 
ContainerBalancerTask.IterationResult.ITERATION_COMPLETED ==
+        containerBalancerTask.getIterationResult(), 10, 50);
+
+    assertEquals(2, 
containerBalancerTask.getCountDatanodesInvolvedPerIteration());
+    
assertTrue(containerBalancerTask.getMetrics().getNumContainerMovesCompletedInLatestIteration()
 >= 1);
+    
assertThat(containerBalancerTask.getMetrics().getNumContainerMovesFailed()).isEqualTo(1);
+    
assertTrue(containerBalancerTask.getSelectedTargets().contains(nodesInCluster.get(0)
+        .getDatanodeDetails()));
+    
assertTrue(containerBalancerTask.getSelectedSources().contains(nodesInCluster.get(nodesInCluster.size()
 - 1)
+        .getDatanodeDetails()));
+    stopBalancer();
+  }
+
+   /**
    * Test to check if balancer picks up only positive size
    * containers to move from source to destination.
    */


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to