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 16589ce3e2 HDDS-9976. Memory leak for DeleteBlocksCommand when queue 
is full (#5845)
16589ce3e2 is described below

commit 16589ce3e2b89478f7c9c123fe7afa31ce5e5a52
Author: XiChen <[email protected]>
AuthorDate: Tue Jan 2 19:12:55 2024 +0800

    HDDS-9976. Memory leak for DeleteBlocksCommand when queue is full (#5845)
---
 .../commandhandler/DeleteBlocksCommandHandler.java | 24 ++++++++--
 .../ozone/protocol/commands/CommandStatus.java     | 16 +++++--
 .../TestDeleteBlocksCommandHandler.java            | 54 +++++++++++++++++++++-
 3 files changed, 85 insertions(+), 9 deletions(-)

diff --git 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/DeleteBlocksCommandHandler.java
 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/DeleteBlocksCommandHandler.java
index bec6734768..a243b0c7da 100644
--- 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/DeleteBlocksCommandHandler.java
+++ 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/DeleteBlocksCommandHandler.java
@@ -135,12 +135,22 @@ public class DeleteBlocksCommandHandler implements 
CommandHandler {
           SCMCommandProto.Type.deleteBlocksCommand, command.getType());
       return;
     }
-
+    DeleteCmdInfo cmd = new DeleteCmdInfo((DeleteBlocksCommand) command,
+        container, context, connectionManager);
     try {
-      DeleteCmdInfo cmd = new DeleteCmdInfo((DeleteBlocksCommand) command,
-          container, context, connectionManager);
       deleteCommandQueues.add(cmd);
     } catch (IllegalStateException e) {
+      String dnId = context.getParent().getDatanodeDetails().getUuidString();
+      Consumer<CommandStatus> updateFailure = (cmdStatus) -> {
+        cmdStatus.markAsFailed();
+        ContainerBlocksDeletionACKProto emptyACK =
+            ContainerBlocksDeletionACKProto
+                .newBuilder()
+                .setDnId(dnId)
+                .build();
+        ((DeleteBlockCommandStatus)cmdStatus).setBlocksDeletionAck(emptyACK);
+      };
+      updateCommandStatus(cmd.getContext(), cmd.getCmd(), updateFailure, LOG);
       LOG.warn("Command is discarded because of the command queue is full");
     }
   }
@@ -382,9 +392,13 @@ public class DeleteBlocksCommandHandler implements 
CommandHandler {
     } finally {
       final ContainerBlocksDeletionACKProto deleteAck =
           blockDeletionACK;
-      final boolean status = cmdExecuted;
+      final boolean executedStatus = cmdExecuted;
       Consumer<CommandStatus> statusUpdater = (cmdStatus) -> {
-        cmdStatus.setStatus(status);
+        if (executedStatus) {
+          cmdStatus.markAsExecuted();
+        } else {
+          cmdStatus.markAsFailed();
+        }
         ((DeleteBlockCommandStatus)cmdStatus).setBlocksDeletionAck(deleteAck);
       };
       updateCommandStatus(cmd.getContext(), cmd.getCmd(), statusUpdater, LOG);
diff --git 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/protocol/commands/CommandStatus.java
 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/protocol/commands/CommandStatus.java
index 4b3ce840dc..08df150bd8 100644
--- 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/protocol/commands/CommandStatus.java
+++ 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/protocol/commands/CommandStatus.java
@@ -63,12 +63,22 @@ public class CommandStatus {
    *
    * @param status
    */
-  public void setStatus(Status status) {
+  private void setStatus(Status status) {
     this.status = status;
   }
 
-  public void setStatus(boolean cmdExecuted) {
-    setStatus(cmdExecuted ? Status.EXECUTED : Status.FAILED);
+  /**
+   * Marks the command status as executed.
+   */
+  public void markAsExecuted() {
+    setStatus(Status.EXECUTED);
+  }
+
+  /**
+   * Marks the command status as failed.
+   */
+  public void markAsFailed() {
+    setStatus(Status.FAILED);
   }
 
   /**
diff --git 
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/TestDeleteBlocksCommandHandler.java
 
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/TestDeleteBlocksCommandHandler.java
index 29b3fbe135..d336949a83 100644
--- 
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/TestDeleteBlocksCommandHandler.java
+++ 
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/statemachine/commandhandler/TestDeleteBlocksCommandHandler.java
@@ -16,23 +16,35 @@
  */
 package org.apache.hadoop.ozone.container.common.statemachine.commandhandler;
 
+import org.apache.hadoop.hdds.HddsConfigKeys;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
+import 
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.CommandStatus.Status;
 import 
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.DeletedBlocksTransaction;
 import org.apache.hadoop.ozone.container.ContainerTestHelper;
+import org.apache.hadoop.ozone.container.common.ContainerTestUtils;
 import 
org.apache.hadoop.ozone.container.common.helpers.BlockDeletingServiceMetrics;
 import org.apache.hadoop.ozone.container.common.impl.ContainerLayoutVersion;
 import org.apache.hadoop.ozone.container.common.impl.ContainerSet;
 import org.apache.hadoop.ozone.container.common.interfaces.Container;
 import 
org.apache.hadoop.ozone.container.common.statemachine.DatanodeConfiguration;
+import 
org.apache.hadoop.ozone.container.common.statemachine.DatanodeStateMachine;
+import 
org.apache.hadoop.ozone.container.common.statemachine.SCMConnectionManager;
+import org.apache.hadoop.ozone.container.common.statemachine.StateContext;
 import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
 import org.apache.hadoop.ozone.container.keyvalue.ContainerTestVersionInfo;
 import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer;
 import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
 import 
org.apache.hadoop.ozone.container.common.statemachine.commandhandler.DeleteBlocksCommandHandler.SchemaHandler;
 import org.apache.hadoop.ozone.container.ozoneimpl.OzoneContainer;
+import org.apache.hadoop.ozone.protocol.commands.CommandStatus;
+import org.apache.hadoop.ozone.protocol.commands.DeleteBlocksCommand;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Timeout;
+import org.junit.jupiter.api.io.TempDir;
 import org.mockito.Mockito;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -41,6 +53,7 @@ import org.apache.hadoop.hdds.protocol.proto
     .DeleteBlockTransactionResult;
 
 import java.io.IOException;
+import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -51,6 +64,7 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
+import static java.util.Collections.emptyList;
 import static org.assertj.core.api.Assertions.assertThat;
 import static 
org.apache.hadoop.ozone.container.common.statemachine.DatanodeConfiguration.BLOCK_DELETE_COMMAND_WORKER_INTERVAL;
 import static 
org.apache.hadoop.ozone.container.common.statemachine.DatanodeConfiguration.BLOCK_DELETE_COMMAND_WORKER_INTERVAL_DEFAULT;
@@ -70,7 +84,8 @@ import static org.mockito.Mockito.when;
  */
 @Timeout(300)
 public class TestDeleteBlocksCommandHandler {
-
+  @TempDir
+  private Path folder;
   private OzoneConfiguration conf;
   private ContainerLayoutVersion layout;
   private OzoneContainer ozoneContainer;
@@ -278,6 +293,43 @@ public class TestDeleteBlocksCommandHandler {
     Assertions.assertEquals(deleteCmdWorker.getInterval(), 4000);
   }
 
+  @Test
+  public void testDeleteBlockCommandHandleWhenDeleteCommandQueuesFull()
+      throws IOException {
+    int blockDeleteQueueLimit = 5;
+    // Setting up the test environment
+    OzoneConfiguration configuration = new OzoneConfiguration();
+    configuration.set(HddsConfigKeys.OZONE_METADATA_DIRS, folder.toString());
+    DatanodeDetails datanodeDetails = 
MockDatanodeDetails.randomDatanodeDetails();
+    DatanodeConfiguration dnConf =
+        configuration.getObject(DatanodeConfiguration.class);
+    OzoneContainer container = 
ContainerTestUtils.getOzoneContainer(datanodeDetails, configuration);
+    DatanodeStateMachine stateMachine = 
Mockito.mock(DatanodeStateMachine.class);
+    
Mockito.when(stateMachine.getDatanodeDetails()).thenReturn(datanodeDetails);
+    StateContext context = new StateContext(configuration,
+        Mockito.mock(DatanodeStateMachine.DatanodeStates.class),
+        stateMachine, "");
+
+    // Set Queue limit
+    dnConf.setBlockDeleteQueueLimit(blockDeleteQueueLimit);
+    handler = new DeleteBlocksCommandHandler(
+        container, configuration, dnConf, "");
+
+    // Check if the command status is as expected: PENDING when queue is not 
full, FAILED when queue is full
+    for (int i = 0; i < blockDeleteQueueLimit + 2; i++) {
+      DeleteBlocksCommand deleteBlocksCommand = new 
DeleteBlocksCommand(emptyList());
+      context.addCommand(deleteBlocksCommand);
+      handler.handle(deleteBlocksCommand, container, context, 
Mockito.mock(SCMConnectionManager.class));
+      CommandStatus cmdStatus = 
context.getCmdStatus(deleteBlocksCommand.getId());
+      if (i < blockDeleteQueueLimit) {
+        Assertions.assertEquals(cmdStatus.getStatus(), Status.PENDING);
+      } else {
+        Assertions.assertEquals(cmdStatus.getStatus(), Status.FAILED);
+        
Assertions.assertEquals(cmdStatus.getProtoBufMessage().getBlockDeletionAck().getResultsCount(),
 0);
+      }
+    }
+  }
+
   private DeletedBlocksTransaction createDeletedBlocksTransaction(long txID,
       long containerID) {
     return DeletedBlocksTransaction.newBuilder()


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

Reply via email to