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

ashishkr 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 b104f09ab25 HDDS-13846. Handle sequenceid synch during close container 
in SCM. (#9228)
b104f09ab25 is described below

commit b104f09ab25945692bab18e0a1de329bd86fb590
Author: Ashish Kumar <[email protected]>
AuthorDate: Mon Jan 5 13:12:13 2026 +0530

    HDDS-13846. Handle sequenceid synch during close container in SCM. (#9228)
---
 .../hdds/scm/container/ContainerManagerImpl.java   |  6 +++-
 .../hdds/scm/container/ContainerStateManager.java  |  9 +++--
 .../scm/container/ContainerStateManagerImpl.java   | 26 ++++++++++----
 .../scm/container/TestContainerReportHandler.java  |  4 +--
 .../scm/container/TestContainerStateManager.java   | 41 ++++++++++++++++++++++
 .../TestIncrementalContainerReportHandler.java     |  4 +--
 .../hdds/scm/storage/TestContainerCommandsEC.java  | 24 ++++++-------
 7 files changed, 87 insertions(+), 27 deletions(-)

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 d255bc9a672..c93383e40db 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
@@ -281,7 +281,11 @@ public void updateContainerState(final ContainerID cid,
     lock.lock();
     try {
       if (containerExist(cid)) {
-        containerStateManager.updateContainerState(protoId, event);
+        final ContainerInfo info = containerStateManager.getContainer(cid);
+        if (info != null) {
+          // Delegate to @Replicate method with current sequenceId
+          containerStateManager.updateContainerStateWithSequenceId(protoId, 
event, info.getSequenceId());
+        }
       } else {
         throw new ContainerNotFoundException(cid);
       }
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 0194e65fe00..f5a2334b7cd 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
@@ -160,11 +160,14 @@ void addContainer(ContainerInfoProto containerInfo)
       throws IOException;
 
   /**
-   *
+   * Updates container state with sequenceId synchronization for HA 
consistency.
+   * This method ensures that all SCM nodes have the same sequenceId when 
+   * state transitions occur.
    */
   @Replicate
-  void updateContainerState(HddsProtos.ContainerID id,
-                            HddsProtos.LifeCycleEvent event)
+  void updateContainerStateWithSequenceId(HddsProtos.ContainerID id,
+                                          HddsProtos.LifeCycleEvent event,
+                                          Long sequenceId)
       throws IOException, InvalidStateTransitionException;
 
 
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 4b4578894a6..d971b19c406 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
@@ -353,29 +353,41 @@ public boolean contains(ContainerID id) {
   }
 
   @Override
-  public void updateContainerState(final HddsProtos.ContainerID containerID,
-                                   final LifeCycleEvent event)
+  public void updateContainerStateWithSequenceId(final HddsProtos.ContainerID 
containerID,
+                                                  final LifeCycleEvent event,
+                                                  final Long sequenceId)
       throws IOException, InvalidStateTransitionException {
     // TODO: Remove the protobuf conversion after fixing ContainerStateMap.
     final ContainerID id = ContainerID.getFromProtobuf(containerID);
 
     try (AutoCloseableLock ignored = writeLock(id)) {
       if (containers.contains(id)) {
-        final ContainerInfo oldInfo = containers.getContainerInfo(id);
-        final LifeCycleState oldState = oldInfo.getState();
+        final ContainerInfo containerInfo = containers.getContainerInfo(id);
+        
+        // Synchronize sequenceId first
+        if (containerInfo.getSequenceId() < sequenceId) {
+          containerInfo.updateSequenceId(sequenceId);
+        } else if (containerInfo.getSequenceId() > sequenceId) {
+          LOG.warn("Container sequenceId is {} greater than the leader 
container sequenceId {}",
+              containerInfo.getSequenceId(), sequenceId);
+        }
+        
+        final LifeCycleState oldState = containerInfo.getState();
         final LifeCycleState newState = stateMachine.getNextState(
-            oldInfo.getState(), event);
+            oldState, event);
         if (newState.getNumber() > oldState.getNumber()) {
           ExecutionUtil.create(() -> {
             containers.updateState(id, oldState, newState);
             transactionBuffer.addToBuffer(containerStore, id,
                 containers.getContainerInfo(id));
           }).onException(() -> {
-            transactionBuffer.addToBuffer(containerStore, id, oldInfo);
             containers.updateState(id, newState, oldState);
+            ContainerInfo currentInfo = containers.getContainerInfo(id);
+            transactionBuffer.addToBuffer(containerStore, id, currentInfo);
+
           }).execute();
           containerStateChangeActions.getOrDefault(event, info -> { })
-              .accept(oldInfo);
+              .accept(containerInfo);
         }
       }
     }
diff --git 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerReportHandler.java
 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerReportHandler.java
index e4176e18b35..edd224fbdaa 100644
--- 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerReportHandler.java
+++ 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestContainerReportHandler.java
@@ -132,9 +132,9 @@ void setup() throws IOException, 
InvalidStateTransitionException {
 
     doAnswer(invocation -> {
       containerStateManager
-          .updateContainerState(((ContainerID)invocation
+          .updateContainerStateWithSequenceId(((ContainerID)invocation
                   .getArguments()[0]).getProtobuf(),
-              (HddsProtos.LifeCycleEvent)invocation.getArguments()[1]);
+              (HddsProtos.LifeCycleEvent)invocation.getArguments()[1], 0L);
       return null;
     }).when(containerManager).updateContainerState(
         any(ContainerID.class),
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 422b29f1b5b..799ea3fbcd5 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
@@ -32,6 +32,7 @@
 import java.util.Set;
 import java.util.concurrent.TimeoutException;
 import org.apache.hadoop.hdds.HddsConfigKeys;
+import org.apache.hadoop.hdds.client.RatisReplicationConfig;
 import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
 import org.apache.hadoop.hdds.protocol.DatanodeDetails;
@@ -196,6 +197,46 @@ public void 
testTransitionContainerToClosedStateAllowOnlyDeletingOrDeletedContai
     }
   }
 
+  @Test
+  public void testSequenceIdOnStateUpdate() throws Exception {
+    ContainerID containerID = ContainerID.valueOf(3L);
+    long sequenceId = 100L;
+
+    ContainerInfo containerInfo = new ContainerInfo.Builder()
+        .setContainerID(containerID.getId())
+        .setState(HddsProtos.LifeCycleState.OPEN)
+        .setSequenceId(sequenceId)
+        .setOwner("scm")
+        .setPipelineID(PipelineID.randomId())
+        .setReplicationConfig(
+            RatisReplicationConfig
+                .getInstance(ReplicationFactor.THREE))
+        .build();
+
+    containerStateManager.addContainer(containerInfo.getProtobuf());
+
+    // Try to update with a higher sequenceId
+    containerStateManager.updateContainerStateWithSequenceId(
+        containerID.getProtobuf(),
+        HddsProtos.LifeCycleEvent.FINALIZE,
+        sequenceId + 1);
+
+    ContainerInfo afterFirst = containerStateManager.getContainer(containerID);
+    long currentSequenceId = afterFirst.getSequenceId();
+    // Sequence id should be updated with latest sequence id
+    assertEquals(sequenceId + 1, currentSequenceId);
+
+    // Try updating with older sequenceId
+    containerStateManager.updateContainerStateWithSequenceId(
+        containerID.getProtobuf(),
+        HddsProtos.LifeCycleEvent.CLOSE,
+        sequenceId - 10); // Older sequenceId
+
+    // Assert - SequenceId should not change
+    ContainerInfo finalInfo = containerStateManager.getContainer(containerID);
+    assertEquals(finalInfo.getSequenceId(), currentSequenceId);
+  }
+
   private void addReplica(ContainerInfo cont, DatanodeDetails node) {
     ContainerReplica replica = ContainerReplica.newBuilder()
         .setContainerID(cont.containerID())
diff --git 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestIncrementalContainerReportHandler.java
 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestIncrementalContainerReportHandler.java
index a87fdaec980..8e87cc5d88d 100644
--- 
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestIncrementalContainerReportHandler.java
+++ 
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/TestIncrementalContainerReportHandler.java
@@ -165,9 +165,9 @@ public void setup() throws IOException, 
InvalidStateTransitionException,
 
     doAnswer(invocation -> {
       containerStateManager
-          .updateContainerState(((ContainerID)invocation
+          .updateContainerStateWithSequenceId(((ContainerID)invocation
                   .getArguments()[0]).getProtobuf(),
-              (HddsProtos.LifeCycleEvent)invocation.getArguments()[1]);
+              (HddsProtos.LifeCycleEvent)invocation.getArguments()[1], 0L);
       return null;
     }).when(containerManager).updateContainerState(
         any(ContainerID.class),
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java
index 7e604774470..7ce4f9319db 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/storage/TestContainerCommandsEC.java
@@ -465,11 +465,11 @@ public void testCreateRecoveryContainer() throws 
Exception {
         // To create the actual situation, container would have been in closed
         // state at SCM.
         scm.getContainerManager().getContainerStateManager()
-            .updateContainerState(container.containerID().getProtobuf(),
-                HddsProtos.LifeCycleEvent.FINALIZE);
+            
.updateContainerStateWithSequenceId(container.containerID().getProtobuf(),
+                HddsProtos.LifeCycleEvent.FINALIZE, 0L);
         scm.getContainerManager().getContainerStateManager()
-            .updateContainerState(container.containerID().getProtobuf(),
-                HddsProtos.LifeCycleEvent.CLOSE);
+            
.updateContainerStateWithSequenceId(container.containerID().getProtobuf(),
+                HddsProtos.LifeCycleEvent.CLOSE, 0L);
 
         //Create the recovering container in DN.
         String encodedToken = cToken.encodeToUrlString();
@@ -555,11 +555,11 @@ public void testCreateRecoveryContainerAfterDNRestart() 
throws Exception {
         // To create the actual situation, container would have been in closed
         // state at SCM.
         scm.getContainerManager().getContainerStateManager()
-            .updateContainerState(container.containerID().getProtobuf(),
-                HddsProtos.LifeCycleEvent.FINALIZE);
+            
.updateContainerStateWithSequenceId(container.containerID().getProtobuf(),
+                HddsProtos.LifeCycleEvent.FINALIZE, 0L);
         scm.getContainerManager().getContainerStateManager()
-            .updateContainerState(container.containerID().getProtobuf(),
-                HddsProtos.LifeCycleEvent.CLOSE);
+            
.updateContainerStateWithSequenceId(container.containerID().getProtobuf(),
+                HddsProtos.LifeCycleEvent.CLOSE, 0L);
 
         //Create the recovering container in target DN.
         String encodedToken = cToken.encodeToUrlString();
@@ -936,12 +936,12 @@ public void 
testECReconstructionCoordinatorShouldCleanupContainersOnFailure()
   private void closeContainer(long conID)
       throws IOException, InvalidStateTransitionException {
     //Close the container first.
-    scm.getContainerManager().getContainerStateManager().updateContainerState(
+    
scm.getContainerManager().getContainerStateManager().updateContainerStateWithSequenceId(
         HddsProtos.ContainerID.newBuilder().setId(conID).build(),
-        HddsProtos.LifeCycleEvent.FINALIZE);
-    scm.getContainerManager().getContainerStateManager().updateContainerState(
+        HddsProtos.LifeCycleEvent.FINALIZE, 0L);
+    
scm.getContainerManager().getContainerStateManager().updateContainerStateWithSequenceId(
         HddsProtos.ContainerID.newBuilder().setId(conID).build(),
-        HddsProtos.LifeCycleEvent.CLOSE);
+        HddsProtos.LifeCycleEvent.CLOSE, 0L);
   }
 
   private void checkBlockDataWithRetry(


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

Reply via email to