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

szetszwo 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 575fe4f1cd7 HDDS-15837. Add health-aware container ID listing in SCM 
(#10736)
575fe4f1cd7 is described below

commit 575fe4f1cd7bdd9f6226051fcf7c260d4a24e1c8
Author: Sarveksha Yeshavantha Raju 
<[email protected]>
AuthorDate: Tue Jul 14 22:57:27 2026 +0530

    HDDS-15837. Add health-aware container ID listing in SCM (#10736)
---
 .../hdds/scm/container/ContainerManager.java       |   4 +-
 .../hdds/scm/container/ContainerManagerImpl.java   |   5 +-
 .../hdds/scm/container/ContainerStateManager.java  |   5 +-
 .../scm/container/ContainerStateManagerImpl.java   |   5 +-
 .../scm/container/states/ContainerStateMap.java    |  49 ++++++++--
 .../ha/invoker/ContainerStateManagerInvoker.java   |  83 +++++++++--------
 .../hdds/scm/server/SCMClientProtocolServer.java   |   2 +-
 .../scm/container/TestContainerStateManager.java   |   2 +-
 .../container/states/TestContainerStateMap.java    | 102 ++++++++++++++++-----
 9 files changed, 181 insertions(+), 76 deletions(-)

diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerManager.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerManager.java
index 5481d0dd859..e7d2070d8fa 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerManager.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerManager.java
@@ -66,10 +66,12 @@ default List<ContainerInfo> getContainers() {
    *              Usually the count will be replaced with a very big
    *              value instead of being unlimited in case the db is very big.
    * @param state container state
+   * @param healthState container health state              
    *
    * @return a list of container IDs.
    */
-  List<ContainerID> getContainerIDs(ContainerID startID, int count, 
LifeCycleState state);
+  List<ContainerID> getContainerIDs(ContainerID startID, int count, 
LifeCycleState state, 
+      ContainerHealthState healthState);
 
   /**
    * Returns containers under certain conditions.
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerManagerImpl.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerManagerImpl.java
index 83a07f4df2e..3dc87a40ef1 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerManagerImpl.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerManagerImpl.java
@@ -134,9 +134,10 @@ public List<ContainerInfo> getContainers(ReplicationType 
type) {
   @Override
   public List<ContainerID> getContainerIDs(final ContainerID startID,
                                            final int count,
-                                           final LifeCycleState state) {
+                                           final LifeCycleState state,
+                                           final ContainerHealthState 
healthState) {
     scmContainerManagerMetrics.incNumListContainersOps();
-    return containerStateManager.getContainerIDs(state, startID, count);
+    return containerStateManager.getContainerIDs(state, healthState, startID, 
count);
   }
 
   @Override
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManager.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManager.java
index 3f0e12fda98..913e1ce84a4 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManager.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManager.java
@@ -104,13 +104,14 @@ public interface ContainerStateManager extends SCMHandler 
{
   boolean contains(ContainerID containerID);
 
   /**
-   * Get {@link ContainerID}s for the given state.
+   * Get {@link ContainerID}s for the given optional lifeCycleState and 
healthState.
    *
    * @param start the start {@link ContainerID} (inclusive)
    * @param count the size limit
    * @return a list of {@link ContainerID};
    */
-  List<ContainerID> getContainerIDs(LifeCycleState state, ContainerID start, 
int count);
+  List<ContainerID> getContainerIDs(LifeCycleState state, ContainerHealthState 
healthState, 
+       ContainerID start, int count);
 
   /**
    * Get {@link ContainerInfo}s.
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManagerImpl.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManagerImpl.java
index 65e3964557f..65060c0a171 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManagerImpl.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/ContainerStateManagerImpl.java
@@ -281,9 +281,10 @@ private void initialize() throws IOException {
   }
 
   @Override
-  public List<ContainerID> getContainerIDs(LifeCycleState state, ContainerID 
start, int count) {
+  public List<ContainerID> getContainerIDs(LifeCycleState state, 
ContainerHealthState healthState,
+      ContainerID start, int count) {
     try (AutoCloseableLock ignored = readLock()) {
-      return containers.getContainerIDs(state, start, count);
+      return containers.getContainerIDs(state, healthState, start, count);
     }
   }
 
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerStateMap.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerStateMap.java
index 48336ef56de..c9bae225520 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerStateMap.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/states/ContainerStateMap.java
@@ -17,6 +17,8 @@
 
 package org.apache.hadoop.hdds.scm.container.states;
 
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.NavigableMap;
 import java.util.Objects;
@@ -26,6 +28,7 @@
 import org.apache.hadoop.hdds.protocol.DatanodeID;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.LifeCycleState;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationType;
+import org.apache.hadoop.hdds.scm.container.ContainerHealthState;
 import org.apache.hadoop.hdds.scm.container.ContainerID;
 import org.apache.hadoop.hdds.scm.container.ContainerInfo;
 import org.apache.hadoop.hdds.scm.container.ContainerReplica;
@@ -118,6 +121,23 @@ List<ContainerInfo> getInfos(ContainerID start, int count) 
{
           .collect(Collectors.toList());
     }
 
+    List<ContainerID> getContainerIDs(ContainerID start, int count, 
ContainerHealthState healthState) {
+      Objects.requireNonNull(start, "start == null");
+      Preconditions.assertTrue(count >= 0, "count < 0");
+
+      final List<ContainerID> result = new ArrayList<>(1024);
+      for (ContainerEntry entry : map.tailMap(start).values()) {
+        ContainerInfo info = entry.getInfo();
+        if (healthState == null || info.getHealthState() == healthState) {
+          result.add(info.containerID());
+          if (result.size() >= count) {
+            break;
+          }
+        }
+      }
+      return result;
+    }
+
     Set<ContainerReplica> getReplicas(ContainerID id) {
       Objects.requireNonNull(id, "id == null");
       final ContainerEntry entry = map.get(id);
@@ -261,17 +281,34 @@ public void updateState(ContainerID containerID, 
LifeCycleState currentState,
   }
 
   /**
+   * Returns container IDs matching given optional lifeCycleState and 
healthState,
+   * in ascending {@link ContainerID} order starting from {@code start} 
(inclusive).
    *
-   * @param state the state of the containers
    * @param start the start id
    * @param count the maximum size of the returned list
    * @return a list of sorted {@link ContainerID}s
    */
-  public List<ContainerID> getContainerIDs(LifeCycleState state, ContainerID 
start, int count) {
-    Preconditions.assertTrue(count >= 0, "count < 0");
-    return lifeCycleStateMap.tailMap(state, start).keySet().stream()
-        .limit(count)
-        .collect(Collectors.toList());
+  public List<ContainerID> getContainerIDs(LifeCycleState lifeCycleState,
+      ContainerHealthState healthState, ContainerID start, int count) {
+    if (count == 0) {
+      return Collections.emptyList();
+    }
+    Preconditions.assertTrue(count > 0, "count < 0");
+
+    if (lifeCycleState == null) {
+      return containerMap.getContainerIDs(start, count, healthState);
+    }
+
+    final List<ContainerID> result = new ArrayList<>(Math.min(count, 1024));
+    for (ContainerInfo info : lifeCycleStateMap.tailMap(lifeCycleState, 
start).values()) {
+      if (healthState == null || info.getHealthState() == healthState) {
+        result.add(info.containerID());
+        if (result.size() >= count) {
+          break;
+        }
+      }
+    }
+    return result;
   }
 
   public List<ContainerInfo> getContainerInfos(ContainerID start, int count) {
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java
index 3e0b8115732..d5c7be1c8fe 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/invoker/ContainerStateManagerInvoker.java
@@ -26,6 +26,7 @@
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.LifeCycleEvent;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.LifeCycleState;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationType;
+import org.apache.hadoop.hdds.scm.container.ContainerHealthState;
 import org.apache.hadoop.hdds.scm.container.ContainerID;
 import org.apache.hadoop.hdds.scm.container.ContainerInfo;
 import org.apache.hadoop.hdds.scm.container.ContainerReplica;
@@ -109,8 +110,9 @@ public int getContainerCount(LifeCycleState arg0) {
       }
 
       @Override
-      public List<ContainerID> getContainerIDs(LifeCycleState arg0, 
ContainerID arg1, int arg2) {
-        return invoker.getImpl().getContainerIDs(arg0, arg1, arg2);
+      public List<ContainerID> getContainerIDs(LifeCycleState arg0, 
ContainerHealthState arg1, ContainerID arg2, int
+          arg3) {
+        return invoker.getImpl().getContainerIDs(arg0, arg1, arg2, arg3);
       }
 
       @Override
@@ -217,94 +219,95 @@ public Message invokeLocal(String methodName, Object[] p) 
throws Exception {
 
     case "getContainerIDs":
       final LifeCycleState arg4 = p.length > 0 ? (LifeCycleState) p[0] : null;
-      final ContainerID arg5 = p.length > 1 ? (ContainerID) p[1] : null;
-      final int arg6 = p.length > 2 ? (int) p[2] : 0;
+      final ContainerHealthState arg5 = p.length > 1 ? (ContainerHealthState) 
p[1] : null;
+      final ContainerID arg6 = p.length > 2 ? (ContainerID) p[2] : null;
+      final int arg7 = p.length > 3 ? (int) p[3] : 0;
       returnType = List.class;
-      returnValue = getImpl().getContainerIDs(arg4, arg5, arg6);
+      returnValue = getImpl().getContainerIDs(arg4, arg5, arg6, arg7);
       break;
 
     case "getContainerInfos":
       if (p.length == 1 && (p[0] == null || 
LifeCycleState.class.isInstance(p[0]))) {
-        final LifeCycleState arg7 = (LifeCycleState) p[0];
+        final LifeCycleState arg8 = (LifeCycleState) p[0];
         returnType = List.class;
-        returnValue = getImpl().getContainerInfos(arg7);
+        returnValue = getImpl().getContainerInfos(arg8);
         break;
       }
       if (p.length == 1 && (p[0] == null || 
ReplicationType.class.isInstance(p[0]))) {
-        final ReplicationType arg8 = (ReplicationType) p[0];
+        final ReplicationType arg9 = (ReplicationType) p[0];
         returnType = List.class;
-        returnValue = getImpl().getContainerInfos(arg8);
+        returnValue = getImpl().getContainerInfos(arg9);
         break;
       }
       if (p.length == 2 && (p[0] == null || 
ContainerID.class.isInstance(p[0])) && p[1] instanceof Integer) {
-        final ContainerID arg9 = (ContainerID) p[0];
-        final int arg10 = (int) p[1];
+        final ContainerID arg10 = (ContainerID) p[0];
+        final int arg11 = (int) p[1];
         returnType = List.class;
-        returnValue = getImpl().getContainerInfos(arg9, arg10);
+        returnValue = getImpl().getContainerInfos(arg10, arg11);
         break;
       }
       if (p.length == 3 && (p[0] == null || 
LifeCycleState.class.isInstance(p[0])) && (p[1] == null ||
           ContainerID.class.isInstance(p[1])) && p[2] instanceof Integer) {
-        final LifeCycleState arg11 = (LifeCycleState) p[0];
-        final ContainerID arg12 = (ContainerID) p[1];
-        final int arg13 = (int) p[2];
+        final LifeCycleState arg12 = (LifeCycleState) p[0];
+        final ContainerID arg13 = (ContainerID) p[1];
+        final int arg14 = (int) p[2];
         returnType = List.class;
-        returnValue = getImpl().getContainerInfos(arg11, arg12, arg13);
+        returnValue = getImpl().getContainerInfos(arg12, arg13, arg14);
         break;
       }
       throw new IllegalArgumentException("Method not found: " + methodName + " 
in ContainerStateManager");
 
     case "getContainerReplicas":
-      final ContainerID arg14 = p.length > 0 ? (ContainerID) p[0] : null;
+      final ContainerID arg15 = p.length > 0 ? (ContainerID) p[0] : null;
       returnType = Set.class;
-      returnValue = getImpl().getContainerReplicas(arg14);
+      returnValue = getImpl().getContainerReplicas(arg15);
       break;
 
     case "getMatchingContainer":
-      final long arg15 = p.length > 0 ? (long) p[0] : 0L;
-      final String arg16 = p.length > 1 ? (String) p[1] : null;
-      final PipelineID arg17 = p.length > 2 ? (PipelineID) p[2] : null;
-      final NavigableSet arg18 = p.length > 3 ? (NavigableSet) p[3] : null;
+      final long arg16 = p.length > 0 ? (long) p[0] : 0L;
+      final String arg17 = p.length > 1 ? (String) p[1] : null;
+      final PipelineID arg18 = p.length > 2 ? (PipelineID) p[2] : null;
+      final NavigableSet arg19 = p.length > 3 ? (NavigableSet) p[3] : null;
       returnType = ContainerInfo.class;
-      returnValue = getImpl().getMatchingContainer(arg15, arg16, arg17, arg18);
+      returnValue = getImpl().getMatchingContainer(arg16, arg17, arg18, arg19);
       break;
 
     case "reinitialize":
-      final Table arg19 = p.length > 0 ? (Table) p[0] : null;
-      getImpl().reinitialize(arg19);
+      final Table arg20 = p.length > 0 ? (Table) p[0] : null;
+      getImpl().reinitialize(arg20);
       return Message.EMPTY;
 
     case "removeContainer":
-      final HddsProtos.ContainerID arg20 = p.length > 0 ? 
(HddsProtos.ContainerID) p[0] : null;
-      getImpl().removeContainer(arg20);
+      final HddsProtos.ContainerID arg21 = p.length > 0 ? 
(HddsProtos.ContainerID) p[0] : null;
+      getImpl().removeContainer(arg21);
       return Message.EMPTY;
 
     case "removeContainerReplica":
-      final ContainerReplica arg21 = p.length > 0 ? (ContainerReplica) p[0] : 
null;
-      getImpl().removeContainerReplica(arg21);
+      final ContainerReplica arg22 = p.length > 0 ? (ContainerReplica) p[0] : 
null;
+      getImpl().removeContainerReplica(arg22);
       return Message.EMPTY;
 
     case "transitionDeletingOrDeletedToTargetState":
-      final HddsProtos.ContainerID arg22 = p.length > 0 ? 
(HddsProtos.ContainerID) p[0] : null;
-      final LifeCycleState arg23 = p.length > 1 ? (LifeCycleState) p[1] : null;
-      getImpl().transitionDeletingOrDeletedToTargetState(arg22, arg23);
+      final HddsProtos.ContainerID arg23 = p.length > 0 ? 
(HddsProtos.ContainerID) p[0] : null;
+      final LifeCycleState arg24 = p.length > 1 ? (LifeCycleState) p[1] : null;
+      getImpl().transitionDeletingOrDeletedToTargetState(arg23, arg24);
       return Message.EMPTY;
 
     case "updateContainerInfo":
-      final ContainerInfoProto arg24 = p.length > 0 ? (ContainerInfoProto) 
p[0] : null;
-      getImpl().updateContainerInfo(arg24);
+      final ContainerInfoProto arg25 = p.length > 0 ? (ContainerInfoProto) 
p[0] : null;
+      getImpl().updateContainerInfo(arg25);
       return Message.EMPTY;
 
     case "updateContainerReplica":
-      final ContainerReplica arg25 = p.length > 0 ? (ContainerReplica) p[0] : 
null;
-      getImpl().updateContainerReplica(arg25);
+      final ContainerReplica arg26 = p.length > 0 ? (ContainerReplica) p[0] : 
null;
+      getImpl().updateContainerReplica(arg26);
       return Message.EMPTY;
 
     case "updateContainerStateWithSequenceId":
-      final HddsProtos.ContainerID arg26 = p.length > 0 ? 
(HddsProtos.ContainerID) p[0] : null;
-      final LifeCycleEvent arg27 = p.length > 1 ? (LifeCycleEvent) p[1] : null;
-      final Long arg28 = p.length > 2 ? (Long) p[2] : null;
-      getImpl().updateContainerStateWithSequenceId(arg26, arg27, arg28);
+      final HddsProtos.ContainerID arg27 = p.length > 0 ? 
(HddsProtos.ContainerID) p[0] : null;
+      final LifeCycleEvent arg28 = p.length > 1 ? (LifeCycleEvent) p[1] : null;
+      final Long arg29 = p.length > 2 ? (Long) p[2] : null;
+      getImpl().updateContainerStateWithSequenceId(arg27, arg28, arg29);
       return Message.EMPTY;
 
     default:
diff --git 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMClientProtocolServer.java
 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMClientProtocolServer.java
index 6883cee0127..27f9d124401 100644
--- 
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMClientProtocolServer.java
+++ 
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/server/SCMClientProtocolServer.java
@@ -1569,7 +1569,7 @@ public List<ContainerID> getListOfContainerIDs(
     auditMap.put("state", String.valueOf(state));
     try {
       List<ContainerID> results = scm.getContainerManager().getContainerIDs(
-          startContainerID, count, state);
+          startContainerID, count, state, null);
       AUDIT.logReadSuccess(buildAuditMessageForSuccess(
           SCMAction.LIST_CONTAINER_IDS, auditMap));
       return results;
diff --git 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerStateManager.java
 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerStateManager.java
index 3d3f57268ce..6b1a2cca0b2 100644
--- 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerStateManager.java
+++ 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerStateManager.java
@@ -405,7 +405,7 @@ public void testGetContainerIDs() throws IOException {
     containerStateManager.addContainer(closedContainerInfo.getProtobuf());
 
     assertEquals(1, containerStateManager.getContainerIDs(
-        HddsProtos.LifeCycleState.CLOSED, ContainerID.MIN, 10).size());
+        HddsProtos.LifeCycleState.CLOSED, ContainerHealthState.HEALTHY, 
ContainerID.MIN, 10).size());
   }
 
   @Test
diff --git 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/states/TestContainerStateMap.java
 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/states/TestContainerStateMap.java
index c38c3c211bd..1c3a4883055 100644
--- 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/states/TestContainerStateMap.java
+++ 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/states/TestContainerStateMap.java
@@ -22,54 +22,114 @@
 import static 
org.apache.hadoop.hdds.protocol.proto.HddsProtos.LifeCycleState.OPEN;
 import static 
org.apache.hadoop.hdds.protocol.proto.HddsProtos.LifeCycleState.QUASI_CLOSED;
 import static 
org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.THREE;
+import static 
org.apache.hadoop.hdds.scm.container.ContainerHealthState.HEALTHY;
+import static 
org.apache.hadoop.hdds.scm.container.ContainerHealthState.MISSING;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.scm.container.ContainerHealthState;
 import org.apache.hadoop.hdds.scm.container.ContainerID;
 import org.apache.hadoop.hdds.scm.container.ContainerInfo;
+import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
 
 class TestContainerStateMap {
 
+  private static ContainerStateMap map;
+
+  @BeforeAll
+  public static void setup() {
+    map = new ContainerStateMap();
+    containerInfos().forEach(map::addContainer);
+  }
+
   @Test
   void testGetContainerIDs() {
-    ContainerStateMap map = new ContainerStateMap();
+    assertEquals(4, map.getContainerIDs(OPEN, null, ContainerID.MIN, 
10).size());
+    assertEquals(4, map.getContainerIDs(CLOSED, null, ContainerID.MIN, 
10).size());
 
-    List<ContainerInfo> containerInfos = containerInfos();
+    // verify pagination
+    assertEquals(3, map.getContainerIDs(CLOSED, null, ContainerID.MIN, 
3).size());
+    assertEquals(3, map.getContainerIDs(CLOSED, null, ContainerID.valueOf(7), 
3).size());
+  }
 
-    // initialize map
-    containerInfos.forEach(map::addContainer);
+  /**
+   * {@code getContainerIDs(lifecycle, health, start, count)} with {@code 
healthState == null}
+   * uses the lifecycle index.
+   */
+  @Test
+  void testGetContainerIDsForLifecycleState() {
+    List<ContainerID> closed = map.getContainerIDs(CLOSED, null, 
ContainerID.MIN, 10);
+    assertEquals(Arrays.asList(2L, 7L, 8L, 9L), toIds(closed));
+  }
 
-    assertEquals(4, map.getContainerIDs(OPEN, ContainerID.MIN, 
containerInfos.size()).size());
-    assertEquals(4, map.getContainerIDs(CLOSED, ContainerID.MIN, 
containerInfos.size()).size());
+  /**
+   * {@code getContainerIDs(lifecycle, health, start, count)} with both 
lifeCycleState and
+   * healthState set uses the lifecycle index.
+   */
+  @Test
+  void testGetContainerIDsWithLifeCycleStateAndHealthState() {
+    List<ContainerID> missingClosed = map.getContainerIDs(CLOSED, MISSING, 
ContainerID.MIN, 10);
+    assertEquals(Arrays.asList(2L, 8L), toIds(missingClosed));
+  }
 
-    // verify pagination
-    assertEquals(3, map.getContainerIDs(CLOSED, ContainerID.MIN, 3).size());
-    assertEquals(3, map.getContainerIDs(CLOSED, ContainerID.valueOf(7), 
3).size());
+  /**
+   * {@code getContainerIDs(lifecycle, health, start, count)} with {@code 
lifeCycleState == null}
+   * scans the full container map (no lifecycle index).
+   */
+  @Test
+  void testGetContainerIDsFullMapScanPath() {
+    List<ContainerID> missing = map.getContainerIDs(null, MISSING, 
ContainerID.MIN, 10);
+    assertEquals(Arrays.asList(1L, 2L, 4L, 8L), toIds(missing));
+  }
+
+  @Test
+  void testPaginationAcrossPages() {
+    List<ContainerID> page1 = map.getContainerIDs(CLOSED, null, 
ContainerID.MIN, 2);
+    assertEquals(Arrays.asList(2L, 7L), toIds(page1));
+
+    List<ContainerID> page2 = map.getContainerIDs(CLOSED, null, 
ContainerID.valueOf(8), 2);
+    assertEquals(Arrays.asList(8L, 9L), toIds(page2));
+
+    assertTrue(map.getContainerIDs(CLOSED, null, ContainerID.valueOf(10), 
2).isEmpty());
+  }
+
+  @Test
+  void testZeroCountReturnsEmptyList() {
+    assertTrue(map.getContainerIDs(CLOSED, null, ContainerID.MIN, 
0).isEmpty());
+    assertTrue(map.getContainerIDs(null, MISSING, ContainerID.MIN, 
0).isEmpty());
+  }
+
+  private static List<Long> toIds(List<ContainerID> ids) {
+    return ids.stream().map(id -> 
id.getProtobuf().getId()).collect(Collectors.toList());
   }
 
-  private List<ContainerInfo> containerInfos() {
+  private static List<ContainerInfo> containerInfos() {
     return Arrays.asList(
-        buildContainerInfo(1, OPEN),
-        buildContainerInfo(2, CLOSED),
-        buildContainerInfo(3, QUASI_CLOSED),
-        buildContainerInfo(4, DELETED),
-        buildContainerInfo(5, OPEN),
-        buildContainerInfo(6, OPEN),
-        buildContainerInfo(7, CLOSED),
-        buildContainerInfo(8, CLOSED),
-        buildContainerInfo(9, CLOSED),
-        buildContainerInfo(10, OPEN)
+        buildContainerInfo(1, OPEN, MISSING),
+        buildContainerInfo(2, CLOSED, MISSING),
+        buildContainerInfo(3, QUASI_CLOSED, HEALTHY),
+        buildContainerInfo(4, DELETED, MISSING),
+        buildContainerInfo(5, OPEN, HEALTHY),
+        buildContainerInfo(6, OPEN, HEALTHY),
+        buildContainerInfo(7, CLOSED, HEALTHY),
+        buildContainerInfo(8, CLOSED, MISSING),
+        buildContainerInfo(9, CLOSED, HEALTHY),
+        buildContainerInfo(10, OPEN, HEALTHY)
     );
   }
 
-  private ContainerInfo buildContainerInfo(long containerID, 
HddsProtos.LifeCycleState state) {
+  private static ContainerInfo buildContainerInfo(long containerID, 
HddsProtos.LifeCycleState state,
+      ContainerHealthState healthState) {
     return new ContainerInfo.Builder()
         .setContainerID(containerID)
         .setState(state)
+        .setHealthState(healthState)
         .setReplicationConfig(StandaloneReplicationConfig.getInstance(THREE))
         .build();
   }


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

Reply via email to