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

adoroszlai 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 82105bab836 HDDS-15305. `ozone admin container list --all` returns 
duplicate containers due to sort/pagination key mismatch (#10300)
82105bab836 is described below

commit 82105bab8360782cf801a149e2a3901bc6937103
Author: sreejasahithi <[email protected]>
AuthorDate: Tue May 19 22:05:16 2026 +0530

    HDDS-15305. `ozone admin container list --all` returns duplicate containers 
due to sort/pagination key mismatch (#10300)
---
 .../hdds/scm/server/SCMClientProtocolServer.java   |  3 +-
 .../scm/server/TestSCMClientProtocolServer.java    | 52 ++++++++++++++++++++++
 2 files changed, 54 insertions(+), 1 deletion(-)

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 156eed688d8..4a83e9543bc 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
@@ -40,6 +40,7 @@
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -512,7 +513,7 @@ private ContainerListResult listContainerInternal(long 
startContainerID, int cou
       
       List<ContainerInfo> containerInfos =
           containerStream.filter(info -> info.containerID().getId() >= 
startContainerID)
-              .sorted().collect(Collectors.toList());
+              
.sorted(Comparator.comparing(ContainerInfo::containerID)).collect(Collectors.toList());
       List<ContainerInfo> limitedContainers =
           containerInfos.stream().limit(count).collect(Collectors.toList());
       long totalCount = (long) containerInfos.size();
diff --git 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/TestSCMClientProtocolServer.java
 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/TestSCMClientProtocolServer.java
index 7d2f399d1fa..964fcb3b0d0 100644
--- 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/TestSCMClientProtocolServer.java
+++ 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/server/TestSCMClientProtocolServer.java
@@ -29,7 +29,12 @@
 import java.io.File;
 import java.io.IOException;
 import java.net.InetSocketAddress;
+import java.time.Clock;
+import java.time.Instant;
+import java.time.ZoneOffset;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import org.apache.hadoop.hdds.client.RatisReplicationConfig;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
@@ -155,12 +160,49 @@ public void testScmGetContainerCount() throws IOException 
{
       scmServer.stop();
     }
   }
+  
+  @Test
+  public void testListContainerPaginationHasNoDuplicates() throws Exception {
+    Instant base = Instant.parse("2026-01-01T00:00:00Z");
+    List<ContainerInfo> infos = new ArrayList<>();
+    infos.add(newContainerWithLastUsedTime(100, base));
+    infos.add(newContainerWithLastUsedTime(5, base.plusMillis(1)));
+    infos.add(newContainerWithLastUsedTime(10, base.plusMillis(2)));
+
+    SCMClientProtocolServer scmServer = new SCMClientProtocolServer(new 
OzoneConfiguration(),
+        mockStorageContainerManager(infos), 
mock(ReconfigurationHandler.class));
+    try {
+      List<Long> ids = new ArrayList<>();
+      long start = 0;
+      int batchSize = 2;
+      while (true) {
+        List<ContainerInfo> page =
+            scmServer.listContainer(start, batchSize, null, null, 
null).getContainerInfoList();
+        if (page.isEmpty()) {
+          break;
+        }
+        for (ContainerInfo c : page) {
+          ids.add(c.getContainerID());
+        }
+        start = page.get(page.size() - 1).getContainerID() + 1;
+      }
+      List<Long> expectedIds = Arrays.asList(5L, 10L, 100L);
+      assertEquals(ids.size(), new HashSet<>(ids).size());
+      assertEquals(expectedIds, ids);
+    } finally {
+      scmServer.stop();
+    }
+  }
 
   private StorageContainerManager mockStorageContainerManager() {
     List<ContainerInfo> infos = new ArrayList<>();
     for (int i = 0; i < 10; i++) {
       infos.add(newContainerInfoForTest());
     }
+    return mockStorageContainerManager(infos);
+  }
+
+  private StorageContainerManager 
mockStorageContainerManager(List<ContainerInfo> infos) {
     ContainerManagerImpl containerManager = mock(ContainerManagerImpl.class);
     when(containerManager.getContainers()).thenReturn(infos);
     
when(containerManager.getContainerStateCount(any(LifeCycleState.class))).thenReturn(infos.size());
@@ -174,6 +216,16 @@ private StorageContainerManager 
mockStorageContainerManager() {
     return storageContainerManager;
   }
 
+  private ContainerInfo newContainerWithLastUsedTime(long containerId,
+      Instant fixedLastUsedInstant) {
+    return new ContainerInfo.Builder()
+        .setContainerID(containerId)
+        .setClock(Clock.fixed(fixedLastUsedInstant, ZoneOffset.UTC))
+        .setPipelineID(PipelineID.randomId())
+        
.setReplicationConfig(RatisReplicationConfig.getInstance(HddsProtos.ReplicationFactor.THREE))
+        .build();
+  }
+
   private ContainerInfo newContainerInfoForTest() {
     return new ContainerInfo.Builder()
         .setContainerID(1)


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

Reply via email to