From 5af74124d76d299235accdbc09f82a8cad63ce80 Mon Sep 17 00:00:00 2001 From: ashishk Date: Tue, 3 Feb 2026 16:43:42 +0530 Subject: [PATCH 1/3] HDDS-14551. Don't update container state when replica sequence doesn't match with container seq id. --- .../health/EmptyContainerHandler.java | 6 ++++ .../health/TestEmptyContainerHandler.java | 36 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/EmptyContainerHandler.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/EmptyContainerHandler.java index e955193e6834..b415ce6342e0 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/EmptyContainerHandler.java +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/EmptyContainerHandler.java @@ -63,6 +63,12 @@ public boolean handle(ContainerCheckRequest request) { // delete replicas if they are closed and empty deleteContainerReplicas(containerInfo, replicas); + if (containerInfo.getReplicationType() == HddsProtos.ReplicationType.RATIS) { + if (replicas.stream().noneMatch(r -> r.getSequenceId() == containerInfo.getSequenceId())) { + // don't update container state if replica seqid don't match with container seq id + return true; + } + } // Update the container's state replicationManager.updateContainerState( containerInfo.containerID(), HddsProtos.LifeCycleEvent.DELETE); diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestEmptyContainerHandler.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestEmptyContainerHandler.java index 92c0b0fde062..7cd1527c2254 100644 --- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestEmptyContainerHandler.java +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestEmptyContainerHandler.java @@ -247,6 +247,42 @@ public void testEmptyECContainerWithNonEmptyReplicaReturnsFalse() assertAndVerify(request, false, 0, 0); } + /** + * Tests that container state is NOT updated to DELETE when no replica + * has a matching sequence ID with the container. + */ + @Test + public void testNoUpdateContainerStateWhenReplicaSequenceIdDoesNotMatch() + throws IOException { + long keyCount = 0L; + long bytesUsed = 0L; + long containerSequenceId = 100L; + // Create container with specific sequence ID + ContainerInfo containerInfo = ReplicationTestUtil.createContainerInfo( + ratisReplicationConfig, 1, CLOSED, containerSequenceId); + // Create replicas - all with 0 sequence IDs (none matching container) + Set containerReplicas = ReplicationTestUtil + .createReplicas(containerInfo.containerID(), + ContainerReplicaProto.State.CLOSED, keyCount, bytesUsed, + 0, 0, 0); + ContainerCheckRequest request = new ContainerCheckRequest.Builder() + .setPendingOps(Collections.emptyList()) + .setReport(new ReplicationManagerReport(rmConf.getContainerSampleLimit())) + .setContainerInfo(containerInfo) + .setContainerReplicas(containerReplicas) + .build(); + // Handler should return true but NOT update container state + // because no replica has matching sequence ID + assertEquals(true, emptyContainerHandler.handle(request)); + verify(replicationManager, times(3)).sendDeleteCommand( + any(ContainerInfo.class), anyInt(), + any(DatanodeDetails.class), eq(false)); + // updateContainerState should NOT be called when sequence IDs don't match + verify(replicationManager, times(0)).updateContainerState( + any(ContainerID.class), + any(HddsProtos.LifeCycleEvent.class)); + } + /** * Asserts that handler returns the specified assertion and delete command * to replicas is sent the specified number of times. From 51bc1e4c99f9efad934a906bf376b3b489d0a14c Mon Sep 17 00:00:00 2001 From: ashishk Date: Wed, 4 Feb 2026 09:55:00 +0530 Subject: [PATCH 2/3] Fix pmd error --- .../replication/health/TestEmptyContainerHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestEmptyContainerHandler.java b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestEmptyContainerHandler.java index 7cd1527c2254..4811a9651c45 100644 --- a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestEmptyContainerHandler.java +++ b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/replication/health/TestEmptyContainerHandler.java @@ -20,6 +20,7 @@ import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.LifeCycleState.CLOSED; import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.LifeCycleState.CLOSING; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.eq; @@ -273,7 +274,7 @@ public void testNoUpdateContainerStateWhenReplicaSequenceIdDoesNotMatch() .build(); // Handler should return true but NOT update container state // because no replica has matching sequence ID - assertEquals(true, emptyContainerHandler.handle(request)); + assertTrue(emptyContainerHandler.handle(request)); verify(replicationManager, times(3)).sendDeleteCommand( any(ContainerInfo.class), anyInt(), any(DatanodeDetails.class), eq(false)); From ded9ce5b2eccf19d47d4e4a2ba7e17a0dcbdad8e Mon Sep 17 00:00:00 2001 From: ashishk Date: Wed, 4 Feb 2026 11:12:04 +0530 Subject: [PATCH 3/3] Handle null check --- .../container/replication/health/EmptyContainerHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/EmptyContainerHandler.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/EmptyContainerHandler.java index b415ce6342e0..8fa72cbc50fb 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/EmptyContainerHandler.java +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/container/replication/health/EmptyContainerHandler.java @@ -64,7 +64,8 @@ public boolean handle(ContainerCheckRequest request) { deleteContainerReplicas(containerInfo, replicas); if (containerInfo.getReplicationType() == HddsProtos.ReplicationType.RATIS) { - if (replicas.stream().noneMatch(r -> r.getSequenceId() == containerInfo.getSequenceId())) { + if (replicas.stream().filter(r -> r.getSequenceId() != null) + .noneMatch(r -> r.getSequenceId() == containerInfo.getSequenceId())) { // don't update container state if replica seqid don't match with container seq id return true; }