You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ozone.apache.org by av...@apache.org on 2021/01/08 11:17:37 UTC

[ozone] branch HDDS-3698-upgrade updated: HDDS-4612. Create OMCancelPrepareRequest and Response to cancel the prepared state of an OM. (#1765)

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

avijayan pushed a commit to branch HDDS-3698-upgrade
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/HDDS-3698-upgrade by this push:
     new 72c215c  HDDS-4612. Create OMCancelPrepareRequest and Response to cancel the prepared state of an OM. (#1765)
72c215c is described below

commit 72c215cd07ba90fcfcf0e8aecbfe41d99a11f2a9
Author: Ethan Rose <33...@users.noreply.github.com>
AuthorDate: Fri Jan 8 06:17:21 2021 -0500

    HDDS-4612. Create OMCancelPrepareRequest and Response to cancel the prepared state of an OM. (#1765)
---
 .../main/java/org/apache/hadoop/ozone/OmUtils.java |   1 +
 .../ozone/om/protocol/OzoneManagerProtocol.java    |  10 ++
 ...OzoneManagerProtocolClientSideTranslatorPB.java |  11 +++
 .../hadoop/ozone/om/TestOzoneManagerPrepare.java   |  76 ++++++++++++--
 .../src/main/proto/OmClientProtocol.proto          |  14 ++-
 .../hadoop/ozone/om/OzoneManagerPrepareState.java  |   4 +-
 .../om/request/upgrade/OMCancelPrepareRequest.java |  88 +++++++++++++++++
 .../response/upgrade/OMCancelPrepareResponse.java  |  44 +++++++++
 .../ozone/om/request/key/TestOMKeyRequest.java     |   8 ++
 .../upgrade/TestOMCancelPrepareRequest.java        | 110 +++++++++++++++++++++
 .../ozone/om/response/TestCleanupTableInfo.java    |   8 +-
 .../om/upgrade/TestOzoneManagerPrepareState.java   |   3 +-
 12 files changed, 358 insertions(+), 19 deletions(-)

diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
index c0235dc..b4fd90b 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
@@ -296,6 +296,7 @@ public final class OmUtils {
     case RecoverTrash:
     case FinalizeUpgrade:
     case Prepare:
+    case CancelPrepare:
     case DeleteOpenKeys:
       return false;
     default:
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
index 07e8044..374a567 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java
@@ -51,6 +51,7 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse.PrepareStatus;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CancelPrepareResponse;
 import org.apache.hadoop.ozone.security.OzoneDelegationTokenSelector;
 import org.apache.hadoop.ozone.security.acl.OzoneObj;
 import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer.StatusAndMessages;
@@ -618,4 +619,13 @@ public interface OzoneManagerProtocol
         .setStatus(PrepareStatus.PREPARE_NOT_STARTED)
         .build();
   }
+
+  /**
+   * Cancel the prepare state of the Ozone Manager. If ozone manager is not
+   * prepared, has no effect.
+   * @throws IOException on exception.
+   */
+  default CancelPrepareResponse cancelOzoneManagerPrepare() throws IOException {
+    return CancelPrepareResponse.newBuilder().build();
+  }
 }
diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
index 222883b..a26c436 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java
@@ -1587,6 +1587,17 @@ public final class OzoneManagerProtocolClientSideTranslatorPB
     return prepareStatusResponse;
   }
 
+  @Override
+  public CancelPrepareResponse cancelOzoneManagerPrepare() throws IOException {
+    CancelPrepareRequest cancelPrepareRequest =
+        CancelPrepareRequest.newBuilder().build();
+
+    OMRequest omRequest = createOMRequest(Type.CancelPrepare)
+        .setCancelPrepareRequest(cancelPrepareRequest).build();
+
+    return handleError(submitRequest(omRequest)).getCancelPrepareResponse();
+  }
+
   @VisibleForTesting
   public OmTransport getTransport() {
     return transport;
diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerPrepare.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerPrepare.java
index 9fe873a..b25d160 100644
--- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerPrepare.java
+++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerPrepare.java
@@ -18,7 +18,6 @@
 package org.apache.hadoop.ozone.om;
 
 import static java.nio.charset.StandardCharsets.UTF_8;
-import static org.apache.hadoop.ozone.OzoneConsts.TRANSACTION_INFO_KEY;
 
 import java.io.File;
 import java.nio.file.Paths;
@@ -44,7 +43,7 @@ import org.apache.hadoop.ozone.container.ContainerTestHelper;
 import org.apache.hadoop.ozone.container.TestHelper;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
 import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
-import org.apache.hadoop.ozone.om.ratis.OMTransactionInfo;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse.PrepareStatus;
 import org.apache.hadoop.test.LambdaTestUtils;
 import org.junit.Assert;
 import org.junit.Test;
@@ -70,6 +69,10 @@ public class TestOzoneManagerPrepare extends TestOzoneManagerHA {
     cluster = getCluster();
     store = getObjectStore();
     clientProtocol = store.getClientProxy();
+
+    store.createVolume(VOLUME);
+    OzoneVolume volume = store.getVolume(VOLUME);
+    volume.createBucket(BUCKET);
   }
 
   /**
@@ -227,6 +230,36 @@ public class TestOzoneManagerPrepare extends TestOzoneManagerHA {
     executorService.shutdown();
   }
 
+  @Test
+  public void testCancelPrepare() throws Exception {
+    setup();
+    Set<String> writtenKeys = writeKeysAndWaitForLogs(10);
+    long prepareIndex = submitPrepareRequest();
+
+    // Make sure all OMs are prepared and all OMs still have their data.
+    assertClusterPrepared(prepareIndex);
+    assertRatisLogsCleared();
+    assertKeysWritten(writtenKeys);
+
+    // Cancel prepare and check that data is still present.
+    submitCancelPrepareRequest();
+    assertClusterNotPrepared();
+    assertKeysWritten(writtenKeys);
+
+    // Cancelling prepare again should have no effect.
+    submitCancelPrepareRequest();
+    assertClusterNotPrepared();
+
+    // Write more data after cancelling prepare.
+    writtenKeys.addAll(writeKeysAndWaitForLogs(10));
+
+    // Cancelling prepare again should have no effect and new data should be
+    // preserved.
+    submitCancelPrepareRequest();
+    assertClusterNotPrepared();
+    assertKeysWritten(writtenKeys);
+  }
+
   private boolean logFilesPresentInRatisPeer(OzoneManager om) {
     String ratisDir = om.getOmRatisServer().getServer().getProperties()
         .get("raft.server.storage.dir");
@@ -251,10 +284,6 @@ public class TestOzoneManagerPrepare extends TestOzoneManagerHA {
   private Set<String> writeKeysAndWaitForLogs(int numKeys,
       List<OzoneManager> ozoneManagers) throws Exception {
 
-    store.createVolume(VOLUME);
-    OzoneVolume volume = store.getVolume(VOLUME);
-    volume.createBucket(BUCKET);
-
     Set<String> writtenKeys = new HashSet<>();
     for (int i = 1; i <= numKeys; i++) {
       String keyName = KEY_PREFIX + i;
@@ -308,6 +337,10 @@ public class TestOzoneManagerPrepare extends TestOzoneManagerHA {
             PREPARE_FLUSH_INTERVAL_SECONDS);
   }
 
+  private void submitCancelPrepareRequest() throws Exception {
+    clientProtocol.getOzoneManagerClient().cancelOzoneManagerPrepare();
+  }
+
   private void assertClusterPrepared(long preparedIndex) throws Exception {
     assertClusterPrepared(preparedIndex, cluster.getOzoneManagersList());
   }
@@ -323,9 +356,8 @@ public class TestOzoneManagerPrepare extends TestOzoneManagerHA {
           if (!om.isRunning()) {
             return false;
           } else {
-            OMTransactionInfo txnInfo = om.getMetadataManager()
-                .getTransactionInfoTable().get(TRANSACTION_INFO_KEY);
-            return txnInfo.getTransactionIndex() == preparedIndex;
+            return om.getPrepareState().getState().getStatus() ==
+                PrepareStatus.PREPARE_COMPLETED;
           }
         });
     }
@@ -344,6 +376,32 @@ public class TestOzoneManagerPrepare extends TestOzoneManagerHA {
     }
   }
 
+  private void assertClusterNotPrepared() throws Exception {
+    assertClusterNotPrepared(cluster.getOzoneManagersList());
+  }
+
+  private void assertClusterNotPrepared(List<OzoneManager> ozoneManagers)
+      throws Exception {
+    for (OzoneManager om : ozoneManagers) {
+      LambdaTestUtils.await(WAIT_TIMEOUT_MILLIS,
+          1000, () -> {
+            if (!om.isRunning()) {
+              return false;
+            } else {
+              return om.getPrepareState().getState().getStatus() ==
+                  PrepareStatus.PREPARE_NOT_STARTED;
+            }
+          });
+    }
+
+    // Submitting a read request should pass.
+    clientProtocol.listVolumes(VOLUME, "", 100);
+
+    // Submitting write request should also pass.
+    clientProtocol.createVolume("vol");
+    clientProtocol.deleteVolume("vol");
+  }
+
   private void assertRatisLogsCleared() throws Exception {
     assertRatisLogsCleared(cluster.getOzoneManagersList());
   }
diff --git a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index d18354f..490e228 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -76,6 +76,7 @@ enum Type {
   FinalizeUpgradeProgress = 55;
   Prepare = 56;
   PrepareStatus = 57;
+  CancelPrepare = 58;
 
   GetDelegationToken = 61;
   RenewDelegationToken = 62;
@@ -149,6 +150,7 @@ message OMRequest {
   optional FinalizeUpgradeProgressRequest   finalizeUpgradeProgressRequest = 55;
   optional PrepareRequest                   prepareRequest                 = 56;
   optional PrepareStatusRequest             prepareStatusRequest           = 57;
+  optional CancelPrepareRequest             cancelPrepareRequest           = 58;
 
   optional hadoop.common.GetDelegationTokenRequestProto getDelegationTokenRequest = 61;
   optional hadoop.common.RenewDelegationTokenRequestProto renewDelegationTokenRequest= 62;
@@ -226,6 +228,7 @@ message OMResponse {
   optional FinalizeUpgradeProgressResponse finalizeUpgradeProgressResponse = 55;
   optional PrepareResponse                 prepareResponse                 = 56;
   optional PrepareStatusResponse           prepareStatusResponse           = 57;
+  optional CancelPrepareResponse           cancelPrepareResponse           = 58;
 
   optional GetDelegationTokenResponseProto getDelegationTokenResponse = 61;
   optional RenewDelegationTokenResponseProto renewDelegationTokenResponse = 62;
@@ -1088,9 +1091,6 @@ message PrepareStatusRequest {
 
 message PrepareStatusResponse {
     enum PrepareStatus {
-        // TODO
-        // HDDS-4569 may introduce new states here, like marker file found
-        // but with different txn id. We can add them as make sense.
         PREPARE_NOT_STARTED = 1;
         PREPARE_IN_PROGRESS = 2;
         PREPARE_COMPLETED = 3;
@@ -1099,6 +1099,14 @@ message PrepareStatusResponse {
     optional uint64 currentTxnIndex = 2;
 }
 
+message CancelPrepareRequest {
+
+}
+
+message CancelPrepareResponse {
+
+}
+
 message ServicePort {
     enum Type {
         RPC = 1;
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManagerPrepareState.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManagerPrepareState.java
index a79531f..71eb8c6 100644
--- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManagerPrepareState.java
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManagerPrepareState.java
@@ -199,8 +199,8 @@ public final class OzoneManagerPrepareState {
     boolean requestAllowed = true;
 
     if (prepareGateEnabled) {
-      // TODO: Also return true for cancel prepare when it is implemented.
-      requestAllowed = (requestType == Type.Prepare);
+      requestAllowed =
+          (requestType == Type.Prepare) || (requestType == Type.CancelPrepare);
     }
 
     return requestAllowed;
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMCancelPrepareRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMCancelPrepareRequest.java
new file mode 100644
index 0000000..86cc402
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/upgrade/OMCancelPrepareRequest.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership.  The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package org.apache.hadoop.ozone.om.request.upgrade;
+
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
+import org.apache.hadoop.ozone.om.request.OMClientRequest;
+import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.om.response.upgrade.OMCancelPrepareResponse;
+import org.apache.hadoop.ozone.om.response.upgrade.OMPrepareResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CancelPrepareResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+
+import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public class OMCancelPrepareRequest extends OMClientRequest {
+  private static final Logger LOG =
+      LoggerFactory.getLogger(OMCancelPrepareRequest.class);
+
+  public OMCancelPrepareRequest(OMRequest omRequest) {
+    super(omRequest);
+  }
+
+  @Override
+  public OMClientResponse validateAndUpdateCache(
+      OzoneManager ozoneManager, long transactionLogIndex,
+      OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper) {
+
+    LOG.info("OM {} Received cancel request with log index {}",
+        ozoneManager.getOMNodeId(), transactionLogIndex);
+
+    OMRequest omRequest = getOmRequest();
+    OMResponse.Builder responseBuilder =
+        OmResponseUtil.getOMResponseBuilder(omRequest);
+    responseBuilder.setCmdType(Type.CancelPrepare);
+    OMClientResponse response = null;
+
+    try {
+      // Create response.
+      CancelPrepareResponse omResponse = CancelPrepareResponse.newBuilder()
+          .build();
+      responseBuilder.setCancelPrepareResponse(omResponse);
+      response = new OMCancelPrepareResponse(responseBuilder.build());
+
+      // Deletes on disk marker file, does not update DB and therefore does
+      // not update cache.
+      ozoneManager.getPrepareState().cancelPrepare();
+      ozoneManagerDoubleBufferHelper.add(response, transactionLogIndex);
+
+      LOG.info("OM {} prepare state cancelled at log index {}. Returning " +
+              "response {}",
+          ozoneManager.getOMNodeId(), transactionLogIndex, omResponse);
+    } catch (IOException e) {
+      LOG.error("Cancel Prepare Request apply failed in {}. ",
+          ozoneManager.getOMNodeId(), e);
+      response = new OMPrepareResponse(
+          createErrorOMResponse(responseBuilder, e));
+    }
+
+    return response;
+  }
+
+  public static String getRequestType() {
+    return Type.CancelPrepare.name();
+  }
+}
diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/upgrade/OMCancelPrepareResponse.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/upgrade/OMCancelPrepareResponse.java
new file mode 100644
index 0000000..0ce30ea
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/upgrade/OMCancelPrepareResponse.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership.  The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.hadoop.ozone.om.response.upgrade;
+
+import org.apache.hadoop.hdds.utils.db.BatchOperation;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.response.CleanupTableInfo;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+
+import java.io.IOException;
+
+/**
+ * Response for cancel prepare.
+ */
+@CleanupTableInfo()
+public class OMCancelPrepareResponse extends OMClientResponse {
+  public OMCancelPrepareResponse(
+      OzoneManagerProtocolProtos.OMResponse omResponse) {
+    super(omResponse);
+  }
+
+  @Override
+  protected void addToDBBatch(OMMetadataManager omMetadataManager,
+      BatchOperation batchOperation) throws IOException {
+    // The cancel prepare request will delete the prepare marker file and
+    // update in memory state, so this response does not need to perform  DB
+    // update.
+  }
+}
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyRequest.java
index 4c1425e..9c2ad92 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyRequest.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyRequest.java
@@ -23,6 +23,8 @@ import java.util.List;
 import java.util.UUID;
 
 import org.apache.commons.lang3.tuple.Pair;
+import org.apache.hadoop.ozone.OzoneConfigKeys;
+import org.apache.hadoop.ozone.om.OzoneManagerPrepareState;
 import org.apache.hadoop.ozone.om.ResolvedBucket;
 import org.apache.hadoop.ozone.om.KeyManager;
 import org.apache.hadoop.ozone.om.KeyManagerImpl;
@@ -75,6 +77,7 @@ public class TestOMKeyRequest {
   protected OMMetrics omMetrics;
   protected OMMetadataManager omMetadataManager;
   protected AuditLogger auditLogger;
+  protected OzoneManagerPrepareState prepareState;
 
   protected ScmClient scmClient;
   protected OzoneBlockTokenSecretManager ozoneBlockTokenSecretManager;
@@ -106,6 +109,8 @@ public class TestOMKeyRequest {
     OzoneConfiguration ozoneConfiguration = new OzoneConfiguration();
     ozoneConfiguration.set(OMConfigKeys.OZONE_OM_DB_DIRS,
         folder.newFolder().getAbsolutePath());
+    ozoneConfiguration.set(OzoneConfigKeys.OZONE_METADATA_DIRS,
+        folder.newFolder().getAbsolutePath());
     omMetadataManager = new OmMetadataManagerImpl(ozoneConfiguration);
     when(ozoneManager.getMetrics()).thenReturn(omMetrics);
     when(ozoneManager.getMetadataManager()).thenReturn(omMetadataManager);
@@ -134,6 +139,9 @@ public class TestOMKeyRequest {
     when(scmClient.getBlockClient()).thenReturn(scmBlockLocationProtocol);
     when(ozoneManager.getKeyManager()).thenReturn(keyManager);
 
+    prepareState = new OzoneManagerPrepareState(ozoneConfiguration);
+    when(ozoneManager.getPrepareState()).thenReturn(prepareState);
+
     Pipeline pipeline = Pipeline.newBuilder()
         .setState(Pipeline.PipelineState.OPEN)
         .setId(PipelineID.randomId())
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMCancelPrepareRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMCancelPrepareRequest.java
new file mode 100644
index 0000000..9fcc1c9
--- /dev/null
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/upgrade/TestOMCancelPrepareRequest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with this
+ * work for additional information regarding copyright ownership.  The ASF
+ * licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.apache.hadoop.ozone.om.request.upgrade;
+
+import org.apache.hadoop.ozone.om.OzoneManagerPrepareState;
+import org.apache.hadoop.ozone.om.request.key.TestOMKeyRequest;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.om.response.key.OMOpenKeysDeleteRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse.PrepareStatus;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.UUID;
+
+/**
+ * Unit testing of cancel prepare request. Cancel prepare response does not
+ * perform an action, so it has no unit testing.
+ */
+public class TestOMCancelPrepareRequest extends TestOMKeyRequest {
+  private static final long LOG_INDEX = 1;
+
+  @Test
+  public void testCancelPrepare() throws Exception {
+    assertNotPrepared();
+    ozoneManager.getPrepareState().finishPrepare(LOG_INDEX);
+    assertPrepared(LOG_INDEX);
+    submitCancelPrepareRequest();
+    assertNotPrepared();
+
+    // Another cancel prepare should be able to be submitted without error.
+    submitCancelPrepareRequest();
+    assertNotPrepared();
+  }
+
+  private void assertPrepared(long logIndex) {
+    OzoneManagerPrepareState prepareState = ozoneManager.getPrepareState();
+    OzoneManagerPrepareState.State state = prepareState.getState();
+
+    Assert.assertEquals(state.getStatus(), PrepareStatus.PREPARE_COMPLETED);
+    Assert.assertEquals(state.getIndex(), logIndex);
+    Assert.assertTrue(prepareState.getPrepareMarkerFile().exists());
+    Assert.assertFalse(prepareState.requestAllowed(Type.CreateVolume));
+  }
+
+  private void assertNotPrepared() {
+    OzoneManagerPrepareState prepareState = ozoneManager.getPrepareState();
+    OzoneManagerPrepareState.State state = prepareState.getState();
+
+    Assert.assertEquals(state.getStatus(), PrepareStatus.PREPARE_NOT_STARTED);
+    Assert.assertEquals(state.getIndex(),
+        OzoneManagerPrepareState.NO_PREPARE_INDEX);
+    Assert.assertFalse(prepareState.getPrepareMarkerFile().exists());
+    Assert.assertTrue(prepareState.requestAllowed(Type.CreateVolume));
+  }
+
+  private void submitCancelPrepareRequest() throws Exception {
+    OMRequest omRequest =
+        doPreExecute(createCancelPrepareRequest());
+
+    OMCancelPrepareRequest cancelPrepareRequest =
+        new OMCancelPrepareRequest(omRequest);
+
+    OMClientResponse omClientResponse =
+        cancelPrepareRequest.validateAndUpdateCache(ozoneManager,
+            LOG_INDEX, ozoneManagerDoubleBufferHelper);
+
+    Assert.assertEquals(OzoneManagerProtocolProtos.Status.OK,
+        omClientResponse.getOMResponse().getStatus());
+  }
+
+  private OMRequest doPreExecute(OMRequest originalOmRequest) throws Exception {
+    OMOpenKeysDeleteRequest omOpenKeysDeleteRequest =
+        new OMOpenKeysDeleteRequest(originalOmRequest);
+
+    OMRequest modifiedOmRequest =
+        omOpenKeysDeleteRequest.preExecute(ozoneManager);
+
+    // Will not be equal, as UserInfo will be set.
+    Assert.assertNotEquals(originalOmRequest, modifiedOmRequest);
+
+    return modifiedOmRequest;
+  }
+
+  private OMRequest createCancelPrepareRequest() {
+    OzoneManagerProtocolProtos.CancelPrepareRequest cancelPrepareRequest =
+        OzoneManagerProtocolProtos.CancelPrepareRequest.newBuilder().build();
+
+    return OMRequest.newBuilder()
+        .setCancelPrepareRequest(cancelPrepareRequest)
+        .setCmdType(OzoneManagerProtocolProtos.Type.CancelPrepare)
+        .setClientId(UUID.randomUUID().toString()).build();
+  }
+}
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/TestCleanupTableInfo.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/TestCleanupTableInfo.java
index 99944ce..23ab5fc 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/TestCleanupTableInfo.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/TestCleanupTableInfo.java
@@ -43,6 +43,7 @@ import org.apache.hadoop.ozone.om.request.file.OMFileCreateRequest;
 import org.apache.hadoop.ozone.om.request.key.OMKeyCreateRequest;
 import org.apache.hadoop.ozone.om.response.file.OMFileCreateResponse;
 import org.apache.hadoop.ozone.om.response.key.OMKeyCreateResponse;
+import org.apache.hadoop.ozone.om.response.upgrade.OMCancelPrepareResponse;
 import org.apache.hadoop.ozone.om.response.upgrade.OMPrepareResponse;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateFileRequest;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateKeyRequest;
@@ -156,9 +157,10 @@ public class TestCleanupTableInfo {
         Assert.assertTrue(
             Arrays.stream(cleanupTables).allMatch(tables::contains)
         );
-      } else if (aClass != OMPrepareResponse.class) {
-        // Prepare response is allowed to have no cleanup tables, since it
-        // does not modify the DB.
+      } else if (aClass != OMPrepareResponse.class &&
+          aClass != OMCancelPrepareResponse.class) {
+        // Prepare and cancel responses are allowed to have no cleanup tables,
+        // since they do not modify the DB.
         Assert.assertTrue(cleanupAll);
       }
     });
diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/upgrade/TestOzoneManagerPrepareState.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/upgrade/TestOzoneManagerPrepareState.java
index 7dffe33..035b67a 100644
--- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/upgrade/TestOzoneManagerPrepareState.java
+++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/upgrade/TestOzoneManagerPrepareState.java
@@ -252,8 +252,7 @@ public class TestOzoneManagerPrepareState {
     // Once preparation has begun, only prepare and cancel prepare should be
     // allowed.
     for (Type cmdType: Type.values()) {
-      if (cmdType == Type.Prepare) {
-        // TODO: Add cancelPrepare to allowed request types when it is added.
+      if (cmdType == Type.Prepare || cmdType == Type.CancelPrepare) {
         Assert.assertTrue(prepareState.requestAllowed(cmdType));
       } else {
         Assert.assertFalse(prepareState.requestAllowed(cmdType));


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@ozone.apache.org
For additional commands, e-mail: commits-help@ozone.apache.org