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

prashantpogde 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 1c785fdfde HDDS-8859. [Snapshot] Return failure message to client for 
a failed snapshot diff jobs (#4993)
1c785fdfde is described below

commit 1c785fdfde458678b4b86808a58e705f1609a4b5
Author: Hemant Kumar <[email protected]>
AuthorDate: Tue Jun 27 19:38:06 2023 -0700

    HDDS-8859. [Snapshot] Return failure message to client for a failed 
snapshot diff jobs (#4993)
---
 .../common/src/main/resources/ozone-default.xml    |   2 +-
 .../apache/hadoop/ozone/client/ObjectStore.java    |  26 +++-
 .../ozone/client/protocol/ClientProtocol.java      |  21 ++-
 .../apache/hadoop/ozone/client/rpc/RpcClient.java  |  24 ++-
 .../main/java/org/apache/hadoop/ozone/OmUtils.java |   1 +
 .../org/apache/hadoop/ozone/om/OMConfigKeys.java   |   2 +-
 .../hadoop/ozone/om/helpers/SnapshotDiffJob.java   |  43 ++++--
 .../ozone/om/protocol/OzoneManagerProtocol.java    |  24 ++-
 ...OzoneManagerProtocolClientSideTranslatorPB.java |  39 ++++-
 .../ozone/snapshot/CancelSnapshotDiffResponse.java |  67 +++++++++
 .../ozone/snapshot/SnapshotDiffResponse.java       |  79 ++++------
 .../org/apache/hadoop/ozone/om/TestOmSnapshot.java | 148 +++++++++----------
 .../ozone/om/TestOzoneManagerHASnapshot.java       |   8 +-
 .../src/main/proto/OmClientProtocol.proto          |  27 ++--
 .../apache/hadoop/ozone/om/OmSnapshotManager.java  |  16 +-
 .../org/apache/hadoop/ozone/om/OzoneManager.java   |  23 +--
 .../ozone/om/snapshot/SnapshotDiffManager.java     | 161 +++++++++++----------
 .../protocolPB/OzoneManagerRequestHandler.java     |  38 ++++-
 .../ozone/om/snapshot/TestSnapshotDiffManager.java |  45 +++---
 .../fs/ozone/BasicOzoneClientAdapterImpl.java      |   2 +-
 .../ozone/BasicRootedOzoneClientAdapterImpl.java   |   2 +-
 .../hadoop/ozone/client/ClientProtocolStub.java    |  15 +-
 .../ozone/shell/snapshot/SnapshotDiffHandler.java  |  23 ++-
 23 files changed, 533 insertions(+), 303 deletions(-)

diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml 
b/hadoop-hdds/common/src/main/resources/ozone-default.xml
index f835ed3128..a9a07371a1 100644
--- a/hadoop-hdds/common/src/main/resources/ozone-default.xml
+++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml
@@ -3991,7 +3991,7 @@
 
   <property>
     <name>ozone.om.snapshot.diff.cleanup.service.run.internal</name>
-    <value>60m</value>
+    <value>1m</value>
     <tag>OZONE, OM</tag>
     <description>
       Interval at which snapshot diff clean up service will run.
diff --git 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/ObjectStore.java
 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/ObjectStore.java
index d205dfdae2..27b1964ea0 100644
--- 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/ObjectStore.java
+++ 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/ObjectStore.java
@@ -45,6 +45,7 @@ import org.apache.hadoop.ozone.om.helpers.TenantUserInfoValue;
 import org.apache.hadoop.ozone.om.helpers.TenantUserList;
 import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
 import org.apache.hadoop.ozone.security.acl.OzoneObj;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
 import org.apache.hadoop.security.UserGroupInformation;
 
@@ -667,22 +668,37 @@ public class ObjectStore {
    * @param token to get the index to return diff report from.
    * @param pageSize maximum entries returned to the report.
    * @param forceFullDiff request to force full diff, skipping DAG optimization
-   * @param cancel request to cancel a running snapshot diff job.
    * @return the difference report between two snapshots
    * @throws IOException in case of any exception while generating snapshot 
diff
    */
-  @SuppressWarnings("parameternumber")
   public SnapshotDiffResponse snapshotDiff(String volumeName,
                                            String bucketName,
                                            String fromSnapshot,
                                            String toSnapshot,
                                            String token,
                                            int pageSize,
-                                           boolean forceFullDiff,
-                                           boolean cancel)
+                                           boolean forceFullDiff)
       throws IOException {
     return proxy.snapshotDiff(volumeName, bucketName, fromSnapshot, toSnapshot,
-        token, pageSize, forceFullDiff, cancel);
+        token, pageSize, forceFullDiff);
+  }
+
+  /**
+   * Cancel the snap diff jobs.
+   * @param volumeName Name of the volume to which the snapshot bucket belong
+   * @param bucketName Name of the bucket to which the snapshots belong
+   * @param fromSnapshot The name of the starting snapshot
+   * @param toSnapshot The name of the ending snapshot
+   * @return the success if cancel succeeds.
+   * @throws IOException in case of any exception while generating snapshot 
diff
+   */
+  public CancelSnapshotDiffResponse cancelSnapshotDiff(String volumeName,
+                                                       String bucketName,
+                                                       String fromSnapshot,
+                                                       String toSnapshot)
+      throws IOException {
+    return proxy.cancelSnapshotDiff(volumeName, bucketName, fromSnapshot,
+        toSnapshot);
   }
 
   /**
diff --git 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java
 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java
index 83e29be2b2..87c2290ad4 100644
--- 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java
+++ 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java
@@ -64,6 +64,7 @@ import org.apache.hadoop.ozone.om.protocol.S3Auth;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRoleInfo;
 import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
 import org.apache.hadoop.ozone.security.acl.OzoneObj;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
 import org.apache.hadoop.security.KerberosInfo;
 import org.apache.hadoop.security.token.Token;
@@ -1058,7 +1059,6 @@ public interface ClientProtocol {
       String volumeName, String bucketName, String snapshotPrefix,
       String prevSnapshot, int maxListResult) throws IOException;
 
-
   /**
    * Get the differences between two snapshots.
    * @param volumeName Name of the volume to which the snapshotted bucket 
belong
@@ -1068,15 +1068,28 @@ public interface ClientProtocol {
    * @param token to get the index to return diff report from.
    * @param pageSize maximum entries returned to the report.
    * @param forceFullDiff request to force full diff, skipping DAG optimization
-   * @param cancel request to cancel a running snapshot diff job.
    * @return the difference report between two snapshots
    * @throws IOException in case of any exception while generating snapshot 
diff
    */
-  @SuppressWarnings("parameternumber")
   SnapshotDiffResponse snapshotDiff(String volumeName, String bucketName,
                                     String fromSnapshot, String toSnapshot,
                                     String token, int pageSize,
-                                    boolean forceFullDiff, boolean cancel)
+                                    boolean forceFullDiff)
+      throws IOException;
+
+  /**
+   * Cancel snapshot diff job.
+   * @param volumeName Name of the volume to which the snapshotted bucket 
belong
+   * @param bucketName Name of the bucket to which the snapshots belong
+   * @param fromSnapshot The name of the starting snapshot
+   * @param toSnapshot The name of the ending snapshot
+   * @return the success if cancel succeeds.
+   * @throws IOException in case of any exception while cancelling snap diff 
job
+   */
+  CancelSnapshotDiffResponse cancelSnapshotDiff(String volumeName,
+                                                String bucketName,
+                                                String fromSnapshot,
+                                                String toSnapshot)
       throws IOException;
 
   /**
diff --git 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
index fcaa48bd77..b22ca66708 100644
--- 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
+++ 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java
@@ -151,6 +151,7 @@ import 
org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLIdentityType;
 import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer.ACLType;
 import org.apache.hadoop.ozone.security.acl.OzoneAclConfig;
 import org.apache.hadoop.ozone.security.acl.OzoneObj;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.security.token.Token;
@@ -986,15 +987,32 @@ public class RpcClient implements ClientProtocol {
                                            String toSnapshot,
                                            String token,
                                            int pageSize,
-                                           boolean forceFullDiff,
-                                           boolean cancel)
+                                           boolean forceFullDiff)
       throws IOException {
     Preconditions.checkArgument(StringUtils.isNotBlank(volumeName),
         "volume can't be null or empty.");
     Preconditions.checkArgument(StringUtils.isNotBlank(bucketName),
         "bucket can't be null or empty.");
     return ozoneManagerClient.snapshotDiff(volumeName, bucketName,
-        fromSnapshot, toSnapshot, token, pageSize, forceFullDiff, cancel);
+        fromSnapshot, toSnapshot, token, pageSize, forceFullDiff);
+  }
+
+  @Override
+  public CancelSnapshotDiffResponse cancelSnapshotDiff(String volumeName,
+                                                       String bucketName,
+                                                       String fromSnapshot,
+                                                       String toSnapshot)
+      throws IOException {
+    Preconditions.checkArgument(StringUtils.isNotBlank(volumeName),
+        "volume can't be null or empty.");
+    Preconditions.checkArgument(StringUtils.isNotBlank(bucketName),
+        "bucket can't be null or empty.");
+    Preconditions.checkArgument(StringUtils.isNotBlank(fromSnapshot),
+        "fromSnapshot can't be null or empty.");
+    Preconditions.checkArgument(StringUtils.isNotBlank(toSnapshot),
+        "toSnapshot can't be null or empty.");
+    return ozoneManagerClient.cancelSnapshotDiff(volumeName, bucketName,
+        fromSnapshot, toSnapshot);
   }
 
   @Override
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 1ff24bed16..7f40ab9485 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
@@ -266,6 +266,7 @@ public final class OmUtils {
       // operation SetRangerServiceVersion.
     case GetKeyInfo:
     case SnapshotDiff:
+    case CancelSnapshotDiff:
     case ListSnapshotDiffJobs:
     case TransferLeadership:
       return true;
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
index e8d29e13e3..c5c07e2857 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
@@ -527,7 +527,7 @@ public final class OMConfigKeys {
       = "ozone.om.snapshot.diff.cleanup.service.run.internal";
   public static final long
       OZONE_OM_SNAPSHOT_DIFF_CLEANUP_SERVICE_RUN_INTERVAL_DEFAULT
-      = TimeUnit.HOURS.toMillis(1);
+      = TimeUnit.MINUTES.toMillis(1);
 
   public static final String OZONE_OM_SNAPSHOT_DIFF_CLEANUP_SERVICE_TIMEOUT
       = "ozone.om.snapshot.diff.cleanup.service.timeout";
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/SnapshotDiffJob.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/SnapshotDiffJob.java
index 380483f15a..0465c4e1ae 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/SnapshotDiffJob.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/SnapshotDiffJob.java
@@ -22,6 +22,8 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
 import java.util.Objects;
+
+import org.apache.commons.lang3.StringUtils;
 import org.apache.hadoop.hdds.utils.db.Codec;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SnapshotDiffJobProto;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus;
@@ -48,6 +50,10 @@ public class SnapshotDiffJob {
   private boolean forceFullDiff;
   private long totalDiffEntries;
 
+  // Reason tells why the job was FAILED. It should be set only if job status
+  // is FAILED.
+  private String reason;
+
   // Default constructor for Jackson Serializer.
   public SnapshotDiffJob() {
 
@@ -72,6 +78,7 @@ public class SnapshotDiffJob {
     this.toSnapshot = toSnapshot;
     this.forceFullDiff = forceFullDiff;
     this.totalDiffEntries = totalDiffEntries;
+    this.reason = StringUtils.EMPTY;
   }
 
   public String getJobId() {
@@ -146,17 +153,30 @@ public class SnapshotDiffJob {
     this.totalDiffEntries = totalDiffEntries;
   }
 
+  public String getReason() {
+    return reason;
+  }
+
+  public void setReason(String reason) {
+    this.reason = reason;
+  }
+
   @Override
   public String toString() {
-    return "creationTime : " + creationTime +
-        ", jobId: " + jobId +
-        ", status: " + status +
-        ", volume: " + volume +
-        ", bucket: " + bucket +
-        ", fromSnapshot: " + fromSnapshot +
-        ", toSnapshot: " + toSnapshot +
-        ", forceFullDiff: " + forceFullDiff +
-        ", totalDiffEntries: " + totalDiffEntries;
+    StringBuilder sb = new StringBuilder("creationTime : 
").append(creationTime)
+        .append(", jobId: ").append(jobId)
+        .append(", status: ").append(status)
+        .append(", volume: ").append(volume)
+        .append(", bucket: ").append(bucket)
+        .append(", fromSnapshot: ").append(fromSnapshot)
+        .append(", toSnapshot: ").append(toSnapshot)
+        .append(", forceFullDiff: ").append(forceFullDiff)
+        .append(", totalDiffEntries: ").append(totalDiffEntries);
+
+    if (StringUtils.isNotEmpty(reason)) {
+      sb.append(", reason: ").append(reason);
+    }
+    return sb.toString();
   }
 
   @Override
@@ -175,7 +195,8 @@ public class SnapshotDiffJob {
           Objects.equals(this.fromSnapshot, otherJob.fromSnapshot) &&
           Objects.equals(this.toSnapshot, otherJob.toSnapshot) &&
           Objects.equals(this.forceFullDiff, otherJob.forceFullDiff) &&
-          Objects.equals(this.totalDiffEntries, otherJob.totalDiffEntries);
+          Objects.equals(this.totalDiffEntries, otherJob.totalDiffEntries) &&
+          Objects.equals(this.reason, otherJob.reason);
     }
     return false;
   }
@@ -183,7 +204,7 @@ public class SnapshotDiffJob {
   @Override
   public int hashCode() {
     return Objects.hash(creationTime, jobId, status, volume, bucket,
-        fromSnapshot, toSnapshot, forceFullDiff, totalDiffEntries);
+        fromSnapshot, toSnapshot, forceFullDiff, totalDiffEntries, reason);
   }
 
   public SnapshotDiffJobProto toProtoBuf() {
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 a156a84f06..f02af22e21 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
@@ -66,6 +66,7 @@ import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CancelP
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.EchoRPCResponse;
 import org.apache.hadoop.ozone.security.OzoneDelegationTokenSelector;
 import org.apache.hadoop.ozone.security.acl.OzoneObj;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
 import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer.StatusAndMessages;
 import org.apache.hadoop.security.KerberosInfo;
@@ -715,19 +716,34 @@ public interface OzoneManagerProtocol
    * @param token to get the index to return diff report from.
    * @param pageSize maximum entries returned to the report.
    * @param forceFullDiff request to force full diff, skipping DAG optimization
-   * @param cancel request to cancel a running snapshot diff job.
    * @return the difference report between two snapshots
    * @throws IOException in case of any exception while generating snapshot 
diff
    */
-  @SuppressWarnings("parameternumber")
   default SnapshotDiffResponse snapshotDiff(String volumeName,
                                             String bucketName,
                                             String fromSnapshot,
                                             String toSnapshot,
                                             String token,
                                             int pageSize,
-                                            boolean forceFullDiff,
-                                            boolean cancel)
+                                            boolean forceFullDiff)
+      throws IOException {
+    throw new UnsupportedOperationException("OzoneManager does not require " +
+        "this to be implemented");
+  }
+
+  /**
+   * Cancel snapshot diff job.
+   * @param volumeName Name of the volume to which the snapshotted bucket 
belong
+   * @param bucketName Name of the bucket to which the snapshots belong
+   * @param fromSnapshot The name of the starting snapshot
+   * @param toSnapshot The name of the ending snapshot
+   * @return the success if cancel succeeds.
+   * @throws IOException in case of any exception while cancelling snap diff 
job
+   */
+  default CancelSnapshotDiffResponse cancelSnapshotDiff(String volumeName,
+                                                        String bucketName,
+                                                        String fromSnapshot,
+                                                        String toSnapshot)
       throws IOException {
     throw new UnsupportedOperationException("OzoneManager does not require " +
         "this to be implemented");
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 ed2d3a69e1..b3584e0015 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
@@ -196,10 +196,10 @@ import org.apache.hadoop.ozone.security.acl.OzoneObj;
 import 
org.apache.hadoop.ozone.security.proto.SecurityProtos.CancelDelegationTokenRequestProto;
 import 
org.apache.hadoop.ozone.security.proto.SecurityProtos.GetDelegationTokenRequestProto;
 import 
org.apache.hadoop.ozone.security.proto.SecurityProtos.RenewDelegationTokenRequestProto;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffReportOzone;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus;
-import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobCancelResult;
 import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer;
 import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer.StatusAndMessages;
 import org.apache.hadoop.security.token.Token;
@@ -1217,8 +1217,7 @@ public final class 
OzoneManagerProtocolClientSideTranslatorPB
                                            String toSnapshot,
                                            String token,
                                            int pageSize,
-                                           boolean forceFullDiff,
-                                           boolean cancel)
+                                           boolean forceFullDiff)
       throws IOException {
     final OzoneManagerProtocolProtos.SnapshotDiffRequest.Builder
         requestBuilder =
@@ -1228,8 +1227,7 @@ public final class 
OzoneManagerProtocolClientSideTranslatorPB
             .setFromSnapshot(fromSnapshot)
             .setToSnapshot(toSnapshot)
             .setPageSize(pageSize)
-            .setForceFullDiff(forceFullDiff)
-            .setCancel(cancel);
+            .setForceFullDiff(forceFullDiff);
 
     if (!StringUtils.isBlank(token)) {
       requestBuilder.setToken(token);
@@ -1247,7 +1245,36 @@ public final class 
OzoneManagerProtocolClientSideTranslatorPB
         diffResponse.getSnapshotDiffReport()),
         JobStatus.fromProtobuf(diffResponse.getJobStatus()),
         diffResponse.getWaitTimeInMs(),
-        JobCancelResult.fromProtobuf(diffResponse.getJobCancelResult()));
+        diffResponse.getReason());
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public CancelSnapshotDiffResponse cancelSnapshotDiff(String volumeName,
+                                                       String bucketName,
+                                                       String fromSnapshot,
+                                                       String toSnapshot)
+      throws IOException {
+    final OzoneManagerProtocolProtos.CancelSnapshotDiffRequest.Builder
+        requestBuilder =
+        OzoneManagerProtocolProtos.CancelSnapshotDiffRequest.newBuilder()
+            .setVolumeName(volumeName)
+            .setBucketName(bucketName)
+            .setFromSnapshot(fromSnapshot)
+            .setToSnapshot(toSnapshot);
+
+    final OMRequest omRequest = createOMRequest(Type.CancelSnapshotDiff)
+        .setCancelSnapshotDiffRequest(requestBuilder)
+        .build();
+
+    final OMResponse omResponse = submitRequest(omRequest);
+    handleError(omResponse);
+    OzoneManagerProtocolProtos.CancelSnapshotDiffResponse diffResponse =
+        omResponse.getCancelSnapshotDiffResponse();
+
+    return new CancelSnapshotDiffResponse(diffResponse.getReason());
   }
 
   /**
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/snapshot/CancelSnapshotDiffResponse.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/snapshot/CancelSnapshotDiffResponse.java
new file mode 100644
index 0000000000..033692f585
--- /dev/null
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/snapshot/CancelSnapshotDiffResponse.java
@@ -0,0 +1,67 @@
+/*
+ * 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
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.snapshot;
+
+/**
+ * POJO for Cancel Snapshot Diff Response.
+ */
+public class CancelSnapshotDiffResponse {
+  private final String message;
+
+  public CancelSnapshotDiffResponse(String message) {
+    this.message = message;
+  }
+
+  public String getMessage() {
+    return message;
+  }
+
+  @Override
+  public String toString() {
+    return message + "\n";
+  }
+
+  /**
+   * Snapshot diff cancel message.
+   */
+  public enum CancelMessage {
+    CANCEL_SUCCEEDED("Snapshot diff job has been cancelled."),
+    CANCEL_FAILED("Failed to cancel the job. Its state has been updated in " +
+        "between cancel flow. Please retry."),
+    CANCEL_JOB_NOT_EXIST("Snapshot diff job doesn't exist for given" +
+        " parameters."),
+    CANCEL_ALREADY_DONE_JOB("Snapshot diff job has already completed."),
+    CANCEL_ALREADY_CANCELLED_JOB(
+        "Snapshot diff job has been cancelled already."),
+    CANCEL_ALREADY_FAILED_JOB(
+        "Snapshot diff job has been failed."),
+    CANCEL_NON_CANCELLABLE(
+        "Snapshot diff job is not in cancellable state.");
+
+    private final String message;
+
+    CancelMessage(String message) {
+      this.message = message;
+    }
+
+    public String getMessage() {
+      return message;
+    }
+  }
+}
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/snapshot/SnapshotDiffResponse.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/snapshot/SnapshotDiffResponse.java
index f79ad36eeb..b4700eb839 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/snapshot/SnapshotDiffResponse.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/snapshot/SnapshotDiffResponse.java
@@ -17,8 +17,8 @@
  */
 package org.apache.hadoop.ozone.snapshot;
 
+import org.apache.commons.lang3.StringUtils;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SnapshotDiffResponse.JobStatusProto;
-import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SnapshotDiffResponse.JobCancelResultProto;
 
 /**
  * POJO for Snapshot Diff Response.
@@ -45,41 +45,10 @@ public class SnapshotDiffResponse {
     }
   }
 
-  /**
-   * Snapshot diff cancel result enum.
-   */
-  public enum JobCancelResult {
-    JOB_NOT_CANCELLED("Job hasn't been cancelled"),
-    NEW_JOB("Cannot cancel a newly submitted job"),
-    JOB_DONE("Job is already DONE"),
-    INVALID_STATUS_TRANSITION("Job is not IN_PROGRESS, cancel failed"),
-    JOB_ALREADY_CANCELLED("Job has already been cancelled"),
-    CANCELLATION_SUCCESS("Job has successfully been cancelled");
-
-    private final String description;
-
-    JobCancelResult(String description) {
-      this.description = description;
-    }
-
-    public String getDescription() {
-      return description;
-    }
-
-    public JobCancelResultProto toProtobuf() {
-      return JobCancelResultProto.valueOf(this.name());
-    }
-
-    public static JobCancelResult fromProtobuf(
-        JobCancelResultProto jobCancelResultProto) {
-      return JobCancelResult.valueOf(jobCancelResultProto.name());
-    }
-  }
-
   private final SnapshotDiffReportOzone snapshotDiffReport;
   private final JobStatus jobStatus;
   private final long waitTimeInMs;
-  private final JobCancelResult jobCancelResult;
+  private final String reason;
 
   public SnapshotDiffResponse(final SnapshotDiffReportOzone snapshotDiffReport,
                               final JobStatus jobStatus,
@@ -87,17 +56,17 @@ public class SnapshotDiffResponse {
     this.snapshotDiffReport = snapshotDiffReport;
     this.jobStatus = jobStatus;
     this.waitTimeInMs = waitTimeInMs;
-    this.jobCancelResult = JobCancelResult.JOB_NOT_CANCELLED;
+    this.reason = StringUtils.EMPTY;
   }
 
   public SnapshotDiffResponse(final SnapshotDiffReportOzone snapshotDiffReport,
                               final JobStatus jobStatus,
                               final long waitTimeInMs,
-                              final JobCancelResult jobCancelResult) {
+                              final String reason) {
     this.snapshotDiffReport = snapshotDiffReport;
     this.jobStatus = jobStatus;
     this.waitTimeInMs = waitTimeInMs;
-    this.jobCancelResult = jobCancelResult;
+    this.reason = reason;
   }
 
   public SnapshotDiffReportOzone getSnapshotDiffReport() {
@@ -112,27 +81,37 @@ public class SnapshotDiffResponse {
     return waitTimeInMs;
   }
 
-  public JobCancelResult getJobCancelResult() {
-    return jobCancelResult;
+  public String getReason() {
+    return reason;
   }
 
   @Override
   public String toString() {
     StringBuilder str = new StringBuilder();
-    if (jobCancelResult == JobCancelResult.JOB_NOT_CANCELLED ||
-        jobCancelResult == JobCancelResult.CANCELLATION_SUCCESS) {
-      if (jobStatus == JobStatus.DONE) {
-        str.append(snapshotDiffReport.toString());
+    switch (jobStatus) {
+    case DONE:
+      str.append(snapshotDiffReport.toString());
+      break;
+    case FAILED:
+      str.append("Snapshot diff job is FAILED due to '");
+      if (StringUtils.isNotEmpty(reason)) {
+        str.append(reason);
       } else {
-        str.append("Snapshot diff job is ");
-        str.append(jobStatus);
-        str.append(". Please retry after ");
-        str.append(waitTimeInMs);
-        str.append(" ms.\n");
+        str.append("Unknown reason.");
       }
-    } else {
-      str.append(jobCancelResult.getDescription());
-      str.append("\n");
+      str.append("'. Please retry after ")
+          .append(waitTimeInMs)
+          .append(" ms.\n");
+      break;
+    case CANCELLED:
+      str.append("Snapshot diff job has been CANCELLED.");
+      break;
+    default:
+      str.append("Snapshot diff job is ")
+          .append(jobStatus)
+          .append(". Please retry after ")
+          .append(waitTimeInMs)
+          .append(" ms.\n");
     }
     return str.toString();
   }
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshot.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshot.java
index d79d6dc670..def5d57b38 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshot.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshot.java
@@ -48,6 +48,7 @@ import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
 import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol;
 import org.apache.hadoop.ozone.om.service.SnapshotDiffCleanupService;
 import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffReportOzone;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
 import org.apache.hadoop.ozone.upgrade.UpgradeFinalizer;
@@ -97,13 +98,11 @@ import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_
 import static 
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.NOT_SUPPORTED_OPERATION_PRIOR_FINALIZATION;
 import static 
org.apache.hadoop.ozone.om.helpers.BucketLayout.FILE_SYSTEM_OPTIMIZED;
 import static org.apache.hadoop.ozone.om.helpers.BucketLayout.OBJECT_STORE;
-import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobCancelResult.CANCELLATION_SUCCESS;
-import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobCancelResult.JOB_ALREADY_CANCELLED;
-import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobCancelResult.JOB_NOT_CANCELLED;
-import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobCancelResult.NEW_JOB;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_ALREADY_CANCELLED_JOB;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_JOB_NOT_EXIST;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_SUCCEEDED;
 import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus.CANCELLED;
 import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus.DONE;
-import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus.QUEUED;
 import static org.awaitility.Awaitility.with;
 import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus.IN_PROGRESS;
 import static org.awaitility.Awaitility.await;
@@ -247,7 +246,7 @@ public class TestOmSnapshot {
         store.snapshotDiff(volumeName, bucketName,
             UUID.randomUUID().toString(),
             UUID.randomUUID().toString(),
-          "", 1000, false, false));
+          "", 1000, false));
     expectFailurePreFinalization(() ->
         store.deleteSnapshot(volumeName, bucketName,
             UUID.randomUUID().toString()));
@@ -694,45 +693,50 @@ public class TestOmSnapshot {
   @Test
   public void testSnapDiffCancel() throws Exception {
     // Create key1 and take snapshot.
-    String key1 = "key-1-" + RandomStringUtils.randomNumeric(5);
+    String key1 = "key-1-" + counter.incrementAndGet();
     createFileKey(ozoneBucket, key1);
-    String fromSnapName = "snap-1-" + RandomStringUtils.randomNumeric(5);
+    String fromSnapName = "snap-1-" + counter.incrementAndGet();
     createSnapshot(volumeName, bucketName, fromSnapName);
 
     // Create key2 and take snapshot.
-    String key2 = "key-2-" + RandomStringUtils.randomNumeric(5);
+    String key2 = "key-2-" + counter.incrementAndGet();
     createFileKey(ozoneBucket, key2);
-    String toSnapName = "snap-2-" + RandomStringUtils.randomNumeric(5);
+    String toSnapName = "snap-2-" + counter.incrementAndGet();
     createSnapshot(volumeName, bucketName, toSnapName);
 
-    SnapshotDiffResponse response = store.snapshotDiff(
-        volumeName, bucketName, fromSnapName, toSnapName,
-        null, 0, false, false);
+    SnapshotDiffResponse response = store.snapshotDiff(volumeName, bucketName,
+        fromSnapName, toSnapName, null, 0, false);
 
     assertEquals(IN_PROGRESS, response.getJobStatus());
 
-    response = store.snapshotDiff(volumeName,
-        bucketName, fromSnapName, toSnapName,
-        null, 0, false, true);
+    CancelSnapshotDiffResponse cancelResponse =
+        store.cancelSnapshotDiff(volumeName,
+            bucketName, fromSnapName, toSnapName);
+
+    assertEquals(CANCEL_SUCCEEDED.getMessage(), cancelResponse.getMessage());
+    response = store.snapshotDiff(volumeName, bucketName, fromSnapName,
+        toSnapName, null, 0, false);
 
     // Job status should be updated to CANCELLED.
     assertEquals(CANCELLED, response.getJobStatus());
 
     // Executing the command again should return the
-    // JOB_ALREADY_CANCELLED JobCancelResult,
-    // but the job status should still be CANCELLED
-    // until the job is picked up by the SnapshotDiffCleanupService
-    // and removed from the snapDiffJobTable.
+    // CANCEL_ALREADY_CANCELLED_JOB message.
+    cancelResponse = store.cancelSnapshotDiff(volumeName, bucketName,
+        fromSnapName, toSnapName);
+
+    assertEquals(CANCEL_ALREADY_CANCELLED_JOB.getMessage(),
+        cancelResponse.getMessage());
+
     response = store.snapshotDiff(volumeName,
         bucketName, fromSnapName, toSnapName,
-        null, 0, false, true);
+        null, 0, false);
     assertEquals(CANCELLED, response.getJobStatus());
-    assertEquals(JOB_ALREADY_CANCELLED, response.getJobCancelResult());
 
-    String fromSnapshotTableKey = SnapshotInfo
-        .getTableKey(volumeName, bucketName, fromSnapName);
-    String toSnapshotTableKey = SnapshotInfo
-        .getTableKey(volumeName, bucketName, toSnapName);
+    String fromSnapshotTableKey =
+        SnapshotInfo.getTableKey(volumeName, bucketName, fromSnapName);
+    String toSnapshotTableKey =
+        SnapshotInfo.getTableKey(volumeName, bucketName, toSnapName);
 
     UUID fromSnapshotID = ozoneManager.getOmSnapshotManager()
         .getSnapshotInfo(fromSnapshotTableKey).getSnapshotId();
@@ -760,56 +764,49 @@ public class TestOmSnapshot {
   @Test
   public void testSnapDiffCancelFailureResponses() throws Exception {
     // Create key1 and take snapshot.
-    String key1 = "key-1-" + RandomStringUtils.randomNumeric(5);
+    String key1 = "key-1-" + counter.incrementAndGet();
     createFileKey(ozoneBucket, key1);
-    String fromSnapName = "snap-1-" + RandomStringUtils.randomNumeric(5);
+    String fromSnapName = "snap-1-" + counter.incrementAndGet();
     createSnapshot(volumeName, bucketName, fromSnapName);
 
     // Create key2 and take snapshot.
-    String key2 = "key-2-" + RandomStringUtils.randomNumeric(5);
+    String key2 = "key-2-" + counter.incrementAndGet();
     createFileKey(ozoneBucket, key2);
-    String toSnapName = "snap-2-" + RandomStringUtils.randomNumeric(5);
+    String toSnapName = "snap-2-" + counter.incrementAndGet();
     createSnapshot(volumeName, bucketName, toSnapName);
 
     // New job that doesn't exist, cancel fails.
-    SnapshotDiffResponse response = store.snapshotDiff(
-        volumeName, bucketName, fromSnapName, toSnapName,
-        null, 0, false, true);
+    CancelSnapshotDiffResponse cancelResponse =
+        store.cancelSnapshotDiff(volumeName, bucketName, fromSnapName,
+            toSnapName);
 
-    Assert.assertEquals(NEW_JOB, response.getJobCancelResult());
-    Assert.assertTrue(response.toString()
-        .contains(NEW_JOB.getDescription()));
-    Assert.assertEquals(QUEUED, response.getJobStatus());
+    assertEquals(CANCEL_JOB_NOT_EXIST.getMessage(),
+        cancelResponse.getMessage());
 
-    // Submit new job.
-    response = store.snapshotDiff(volumeName,
-        bucketName, fromSnapName, toSnapName,
-        null, 0, false, false);
+    SnapshotDiffResponse response = store.snapshotDiff(
+        volumeName, bucketName, fromSnapName, toSnapName,
+        null, 0, false);
 
-    Assert.assertEquals(JOB_NOT_CANCELLED, response.getJobCancelResult());
     Assert.assertEquals(IN_PROGRESS, response.getJobStatus());
-    Assert.assertTrue(response.toString()
-        .contains("Snapshot diff job is " + IN_PROGRESS));
 
     // Cancel success.
-    response = store.snapshotDiff(volumeName,
-        bucketName, fromSnapName, toSnapName,
-        null, 0, false, true);
+    cancelResponse = store.cancelSnapshotDiff(volumeName,
+        bucketName, fromSnapName, toSnapName);
 
-    Assert.assertEquals(CANCELLATION_SUCCESS, response.getJobCancelResult());
-    Assert.assertEquals(CANCELLED, response.getJobStatus());
-    Assert.assertTrue(response.toString()
-        .contains("Snapshot diff job is " + CANCELLED));
+    Assert.assertEquals(CANCEL_SUCCEEDED.getMessage(),
+        cancelResponse.getMessage());
 
-    // Job already cancelled.
-    response = store.snapshotDiff(volumeName,
-        bucketName, fromSnapName, toSnapName,
-        null, 0, false, true);
+    response = store.snapshotDiff(
+        volumeName, bucketName, fromSnapName, toSnapName,
+        null, 0, false);
 
-    Assert.assertEquals(JOB_ALREADY_CANCELLED, response.getJobCancelResult());
     Assert.assertEquals(CANCELLED, response.getJobStatus());
-    Assert.assertTrue(response.toString()
-        .contains(JOB_ALREADY_CANCELLED.getDescription()));
+
+    // Job already cancelled.
+    cancelResponse = store.cancelSnapshotDiff(volumeName,
+        bucketName, fromSnapName, toSnapName);
+    Assert.assertEquals(CANCEL_ALREADY_CANCELLED_JOB.getMessage(),
+        cancelResponse.getMessage());
   }
 
   private SnapshotDiffReportOzone getSnapDiffReport(String volume,
@@ -820,13 +817,12 @@ public class TestOmSnapshot {
     SnapshotDiffResponse response;
     do {
       response = store.snapshotDiff(volume, bucket, fromSnapshot,
-          toSnapshot, null, 0, false, false);
+          toSnapshot, null, 0, false);
       Thread.sleep(response.getWaitTimeInMs());
     } while (response.getJobStatus() != DONE);
 
     return response.getSnapshotDiffReport();
   }
-
   @Test
   public void testSnapDiffNoSnapshot() throws Exception {
     String volume = "vol-" + counter.incrementAndGet();
@@ -844,20 +840,20 @@ public class TestOmSnapshot {
 
     // Destination snapshot is invalid
     OMException omException = assertThrows(OMException.class,
-            () -> store.snapshotDiff(volume, bucket, snap1, snap2,
-                null, 0, false, false));
+        () -> store.snapshotDiff(volume, bucket, snap1, snap2,
+            null, 0, false));
     assertEquals(KEY_NOT_FOUND, omException.getResult());
     // From snapshot is invalid
     omException = assertThrows(OMException.class,
         () -> store.snapshotDiff(volume, bucket, snap2, snap1,
-            null, 0, false, false));
+            null, 0, false));
 
     assertEquals(KEY_NOT_FOUND, omException.getResult());
 
     createSnapshot(volume, bucket, snap2);
 
     omException = assertThrows(OMException.class, () ->
-        store.snapshotDiff(volume, bucket, snap2, snap1, null, 0, false, false)
+        store.snapshotDiff(volume, bucket, snap2, snap1, null, 0, false)
     );
 
     assertEquals(INTERNAL_ERROR, omException.getResult());
@@ -888,17 +884,17 @@ public class TestOmSnapshot {
     LambdaTestUtils.intercept(OMException.class,
             "KEY_NOT_FOUND",
             () -> store.snapshotDiff(volumea, bucketb, snap1, snap2,
-                null, 0, false, false));
+                null, 0, false));
     // Volume is nonexistent
     LambdaTestUtils.intercept(OMException.class,
             "KEY_NOT_FOUND",
             () -> store.snapshotDiff(volumeb, bucketa, snap2, snap1,
-                null, 0, false, false));
+                null, 0, false));
     // Both volume and bucket are nonexistent
     LambdaTestUtils.intercept(OMException.class,
             "KEY_NOT_FOUND",
             () -> store.snapshotDiff(volumeb, bucketb, snap2, snap1,
-                null, 0, false, false));
+                null, 0, false));
   }
 
   @Test
@@ -921,20 +917,20 @@ public class TestOmSnapshot {
     LambdaTestUtils.intercept(OMException.class,
             "KEY_NOT_FOUND",
             () -> store.snapshotDiff(volume, bucket, snap1, nullstr,
-                null, 0, false, false));
+                null, 0, false));
     // From snapshot is empty
     LambdaTestUtils.intercept(OMException.class,
             "KEY_NOT_FOUND",
             () -> store.snapshotDiff(volume, bucket, nullstr, snap1,
-                null, 0, false, false));
+                null, 0, false));
     // Bucket is empty
     assertThrows(IllegalArgumentException.class,
             () -> store.snapshotDiff(volume, nullstr, snap1, snap2,
-                null, 0, false, false));
+                null, 0, false));
     // Volume is empty
     assertThrows(IllegalArgumentException.class,
             () -> store.snapshotDiff(nullstr, bucket, snap1, snap2,
-                null, 0, false, false));
+                null, 0, false));
   }
 
   @Test
@@ -1004,7 +1000,7 @@ public class TestOmSnapshot {
     String snap2 = "snap-2-" + RandomStringUtils.randomNumeric(5);
     createSnapshot(volume, bucket, snap2);
 
-    store.snapshotDiff(volume, bucket, snap1, snap2, null, 0, true, false);
+    store.snapshotDiff(volume, bucket, snap1, snap2, null, 0, true);
 
     String invalidStatus = "invalid";
     String statusErrorMessage = "Invalid job status: " + invalidStatus;
@@ -1059,7 +1055,7 @@ public class TestOmSnapshot {
     Assert.assertEquals(4, getKeyTableSstFiles().size());
     SnapshotDiffReportOzone diff1 =
         store.snapshotDiff(volumeName1, bucketName1, snap1, snap2,
-                null, 0, false, false)
+                null, 0, false)
             .getSnapshotDiffReport();
     Assert.assertEquals(1, diff1.getDiffList().size());
   }
@@ -1225,7 +1221,7 @@ public class TestOmSnapshot {
     createSnapshots(snapshot1, snapshot2);
 
     SnapshotDiffResponse response = store.snapshotDiff(volumeName, bucketName,
-        snapshot1, snapshot2, null, 0, false, false);
+        snapshot1, snapshot2, null, 0, false);
 
     assertEquals(IN_PROGRESS, response.getJobStatus());
 
@@ -1236,7 +1232,7 @@ public class TestOmSnapshot {
         until(() -> cluster.getOzoneManager().isRunning());
 
     response = store.snapshotDiff(volumeName, bucketName,
-        snapshot1, snapshot2, null, 0, false, false);
+        snapshot1, snapshot2, null, 0, false);
 
     // If job was IN_PROGRESS or DONE state when OM restarted, it should be
     // DONE by this time.
@@ -1294,7 +1290,7 @@ public class TestOmSnapshot {
 
     while (true) {
       SnapshotDiffResponse response = store.snapshotDiff(volumeName, 
bucketName,
-          fromSnapshot, toSnapshot, token, pageSize, false, false);
+          fromSnapshot, toSnapshot, token, pageSize, false);
       if (response.getJobStatus() == IN_PROGRESS) {
         Thread.sleep(response.getWaitTimeInMs());
       } else if (response.getJobStatus() == DONE) {
diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHASnapshot.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHASnapshot.java
index 7f071f1137..b294707e2f 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHASnapshot.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOzoneManagerHASnapshot.java
@@ -113,7 +113,7 @@ public class TestOzoneManagerHASnapshot {
 
     SnapshotDiffResponse response =
         store.snapshotDiff(volumeName, bucketName,
-            snapshot1, snapshot2, null, 0, false, false);
+            snapshot1, snapshot2, null, 0, false);
 
     assertEquals(IN_PROGRESS, response.getJobStatus());
 
@@ -131,18 +131,18 @@ public class TestOzoneManagerHASnapshot {
     if (Objects.equals(oldLeader, newLeader)) {
       // If old leader becomes leader again. Job should be done by this time.
       response = store.snapshotDiff(volumeName, bucketName,
-          snapshot1, snapshot2, null, 0, false, false);
+          snapshot1, snapshot2, null, 0, false);
       assertEquals(DONE, response.getJobStatus());
       assertEquals(100, response.getSnapshotDiffReport().getDiffList().size());
     } else {
       // If new leader is different from old leader. SnapDiff request will be
       // new to OM, and job status should be IN_PROGRESS.
       response = store.snapshotDiff(volumeName, bucketName, snapshot1,
-          snapshot2, null, 0, false, false);
+          snapshot2, null, 0, false);
       assertEquals(IN_PROGRESS, response.getJobStatus());
       while (true) {
         response = store.snapshotDiff(volumeName, bucketName, snapshot1,
-                snapshot2, null, 0, false, false);
+                snapshot2, null, 0, false);
         if (DONE == response.getJobStatus()) {
           assertEquals(100,
               response.getSnapshotDiffReport().getDiffList().size());
diff --git 
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto 
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 1b50691cba..d1061838b2 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -137,6 +137,7 @@ enum Type {
   SetTimes = 120;
   RefetchSecretKey = 121;
   ListSnapshotDiffJobs = 122;
+  CancelSnapshotDiff = 123;
 }
 
 message OMRequest {
@@ -259,6 +260,7 @@ message OMRequest {
   optional RefetchSecretKeyRequest          RefetchSecretKeyRequest        = 
121;
 
   optional ListSnapshotDiffJobRequest       ListSnapshotDiffJobRequest     = 
122;
+  optional CancelSnapshotDiffRequest       CancelSnapshotDiffRequest     = 123;
 }
 
 message OMResponse {
@@ -373,6 +375,7 @@ message OMResponse {
   optional RefetchSecretKeyResponse          RefetchSecretKeyResponse      = 
121;
 
   optional ListSnapshotDiffJobResponse       ListSnapshotDiffJobResponse   = 
122;
+  optional CancelSnapshotDiffResponse       cancelSnapshotDiffResponse   = 123;
 }
 
 enum Status {
@@ -816,6 +819,7 @@ message SnapshotDiffJobProto {
   optional string toSnapshot = 7;
   optional bool forceFullDiff = 8;
   optional uint64 totalDiffEntries = 9;
+  optional string message = 10;
 }
 
 message OzoneObj {
@@ -1740,7 +1744,13 @@ message SnapshotDiffRequest {
   optional string token = 5;
   optional uint32 pageSize = 6;
   optional bool forceFullDiff = 7;
-  optional bool cancel = 8;
+}
+
+message CancelSnapshotDiffRequest {
+  optional string volumeName = 1;
+  optional string bucketName = 2;
+  optional string fromSnapshot = 3;
+  optional string toSnapshot = 4;
 }
 
 message ListSnapshotDiffJobRequest {
@@ -1830,19 +1840,14 @@ message SnapshotDiffResponse {
     CANCELLED = 6;
   }
 
-  enum JobCancelResultProto {
-    JOB_NOT_CANCELLED = 1;
-    NEW_JOB = 2;
-    JOB_DONE = 3;
-    INVALID_STATUS_TRANSITION = 4;
-    JOB_ALREADY_CANCELLED = 5;
-    CANCELLATION_SUCCESS = 6;
-  }
-
   optional SnapshotDiffReportProto snapshotDiffReport = 1;
   optional JobStatusProto jobStatus = 2;
   optional int64 waitTimeInMs = 3;
-  optional JobCancelResultProto jobCancelResult = 4;
+  optional string reason = 4;
+}
+
+message CancelSnapshotDiffResponse {
+  optional string reason = 1;
 }
 
 message ListSnapshotDiffJobResponse {
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
index c1fdbc0172..355eb7f832 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
@@ -67,6 +67,7 @@ import org.apache.hadoop.ozone.om.snapshot.SnapshotDiffObject;
 import org.apache.hadoop.ozone.om.helpers.SnapshotDiffJob;
 import org.apache.hadoop.ozone.om.snapshot.SnapshotDiffManager;
 import org.apache.hadoop.ozone.om.snapshot.SnapshotUtils;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffReportOzone;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
 import org.apache.ozone.rocksdiff.RocksDBCheckpointDiffer;
@@ -694,13 +695,14 @@ public final class OmSnapshotManager implements 
AutoCloseable {
         (keyParts[0].compareTo(OM_SNAPSHOT_INDICATOR) == 0);
   }
 
-  public SnapshotDiffResponse cancelSnapshotDiff(final String volume,
-                                                 final String bucket,
-                                                 final String fromSnapshot,
-                                                 final String toSnapshot)
-      throws IOException {
-    return snapshotDiffManager.cancelSnapshotDiff(volume,
-        bucket, fromSnapshot, toSnapshot);
+  public CancelSnapshotDiffResponse cancelSnapshotDiff(
+      final String volume,
+      final String bucket,
+      final String fromSnapshot,
+      final String toSnapshot
+  ) throws IOException {
+    return snapshotDiffManager.cancelSnapshotDiff(volume, bucket, fromSnapshot,
+        toSnapshot);
   }
 
   public SnapshotDiffResponse getSnapshotDiffReport(final String volume,
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
index 477cbe112c..c6588a4e3e 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java
@@ -95,6 +95,7 @@ import org.apache.hadoop.ozone.om.s3.S3SecretStoreProvider;
 import org.apache.hadoop.ozone.om.service.OMRangerBGSyncService;
 import org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils;
 import org.apache.hadoop.ozone.om.upgrade.OMLayoutFeature;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
 import org.apache.hadoop.ozone.util.OzoneNetUtils;
 import org.apache.hadoop.ozone.om.helpers.BucketLayout;
@@ -4526,23 +4527,25 @@ public final class OzoneManager extends 
ServiceRuntimeInfoImpl
         ozoneObj.getKeyName(), false);
   }
 
-  @SuppressWarnings("parameternumber")
   public SnapshotDiffResponse snapshotDiff(String volume,
                                            String bucket,
                                            String fromSnapshot,
                                            String toSnapshot,
                                            String token,
                                            int pageSize,
-                                           boolean forceFullDiff,
-                                           boolean cancel)
+                                           boolean forceFullDiff)
       throws IOException {
-    if (cancel) {
-      return omSnapshotManager.cancelSnapshotDiff(volume, bucket,
-          fromSnapshot, toSnapshot);
-    } else {
-      return omSnapshotManager.getSnapshotDiffReport(volume, bucket,
-          fromSnapshot, toSnapshot, token, pageSize, forceFullDiff);
-    }
+    return omSnapshotManager.getSnapshotDiffReport(volume, bucket,
+        fromSnapshot, toSnapshot, token, pageSize, forceFullDiff);
+  }
+
+  public CancelSnapshotDiffResponse cancelSnapshotDiff(String volume,
+                                                       String bucket,
+                                                       String fromSnapshot,
+                                                       String toSnapshot)
+      throws IOException {
+    return omSnapshotManager.cancelSnapshotDiff(volume, bucket,
+        fromSnapshot, toSnapshot);
   }
 
   public List<SnapshotDiffJob> listSnapshotDiffJobs(String volume,
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotDiffManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotDiffManager.java
index 5fd32ecee0..244c646744 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotDiffManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotDiffManager.java
@@ -52,9 +52,9 @@ import org.apache.hadoop.ozone.om.helpers.WithObjectID;
 import org.apache.hadoop.ozone.om.helpers.WithParentObjectId;
 import org.apache.hadoop.ozone.om.service.SnapshotDeletingService;
 import 
org.apache.hadoop.ozone.om.snapshot.SnapshotDiffObject.SnapshotDiffObjectBuilder;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffReportOzone;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
-import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobCancelResult;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus;
 import org.apache.hadoop.util.ClosableIterator;
 import org.apache.ozone.rocksdb.util.ManagedSstFileReader;
@@ -95,8 +95,10 @@ import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.SynchronousQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import java.util.function.BiFunction;
 import java.util.stream.Stream;
 
+import static org.apache.commons.lang3.StringUtils.leftPad;
 import static 
org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffType.CREATE;
 import static 
org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffType.DELETE;
 import static 
org.apache.hadoop.hdfs.protocol.SnapshotDiffReport.DiffType.MODIFY;
@@ -119,6 +121,13 @@ import static 
org.apache.hadoop.ozone.om.helpers.SnapshotInfo.getTableKey;
 import static 
org.apache.hadoop.ozone.om.snapshot.SnapshotUtils.checkSnapshotActive;
 import static 
org.apache.hadoop.ozone.om.snapshot.SnapshotUtils.dropColumnFamilyHandle;
 import static 
org.apache.hadoop.ozone.om.snapshot.SnapshotUtils.getSnapshotInfo;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_FAILED;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_ALREADY_CANCELLED_JOB;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_ALREADY_DONE_JOB;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_ALREADY_FAILED_JOB;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_JOB_NOT_EXIST;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_NON_CANCELLABLE;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_SUCCEEDED;
 import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus.CANCELLED;
 import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus.DONE;
 import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus.FAILED;
@@ -179,6 +188,12 @@ public class SnapshotDiffManager implements AutoCloseable {
 
   private Optional<ExecutorService> sstDumpToolExecService;
 
+  private final BiFunction<SnapshotInfo, SnapshotInfo, String>
+      generateSnapDiffJobKey =
+          (SnapshotInfo fromSnapshotInfo, SnapshotInfo toSnapshotInfo) ->
+              fromSnapshotInfo.getSnapshotId() + DELIMITER +
+                  toSnapshotInfo.getSnapshotId();
+
   @SuppressWarnings("parameternumber")
   public SnapshotDiffManager(ManagedRocksDB db,
                              RocksDBCheckpointDiffer differ,
@@ -391,68 +406,56 @@ public class SnapshotDiffManager implements AutoCloseable 
{
 
   /**
    * Gets the report key for a particular index of snapshot diff job.
-   * @param jobId Snapshot diff jobId
-   * @param index
-   * @return report Key of the snapshot diff job
    */
 
   static String getReportKeyForIndex(String jobId, long index) {
-    return new StringBuilder(jobId.length() + 21)
-        .append(jobId).append(DELIMITER)
-        .append(org.apache.commons.lang3.StringUtils.leftPad(
-        String.valueOf(index), 20, '0')).toString();
+    return jobId + DELIMITER + leftPad(String.valueOf(index), 20, '0');
   }
 
-  public SnapshotDiffResponse cancelSnapshotDiff(
+  public CancelSnapshotDiffResponse cancelSnapshotDiff(
       final String volumeName,
       final String bucketName,
       final String fromSnapshotName,
-      final String toSnapshotName) throws IOException {
-    SnapshotInfo fsInfo = getSnapshotInfo(ozoneManager,
-        volumeName, bucketName, fromSnapshotName);
-    SnapshotInfo tsInfo = getSnapshotInfo(ozoneManager,
-        volumeName, bucketName, toSnapshotName);
-
-    String snapDiffJobKey = fsInfo.getSnapshotId() + DELIMITER +
-        tsInfo.getSnapshotId();
-    SnapshotDiffJob diffJob = snapDiffJobTable.get(snapDiffJobKey);
+      final String toSnapshotName
+  ) throws IOException {
+    SnapshotInfo fsInfo =
+        getSnapshotInfo(ozoneManager, volumeName, bucketName, 
fromSnapshotName);
+    SnapshotInfo tsInfo =
+        getSnapshotInfo(ozoneManager, volumeName, bucketName, toSnapshotName);
 
-    JobStatus jobStatus;
-    JobCancelResult jobCancelResult;
+    String diffJobKey = generateSnapDiffJobKey.apply(fsInfo, tsInfo);
+    SnapshotDiffJob diffJob = snapDiffJobTable.get(diffJobKey);
 
     if (diffJob == null) {
-      jobCancelResult = JobCancelResult.NEW_JOB;
-      // JobStatus is needed to send a response back to the client.
-      // JobStatus can't be null, so set it to QUEUED.
-      // This won't be printed as part of the response
-      // and the job doesn't exist in the SnapDiffJob table,
-      // so submitting again the job, won't make any difference.
-      jobStatus = QUEUED;
-    } else {
-      if (Objects.equals(diffJob.getStatus(), IN_PROGRESS)) {
-        updateJobStatus(snapDiffJobKey, IN_PROGRESS, CANCELLED);
-        jobCancelResult = JobCancelResult.CANCELLATION_SUCCESS;
-      } else if (Objects.equals(diffJob.getStatus(), CANCELLED)) {
-        jobCancelResult = JobCancelResult.JOB_ALREADY_CANCELLED;
-      } else if (Objects.equals(diffJob.getStatus(), DONE)) {
-        jobCancelResult = JobCancelResult.JOB_DONE;
-      } else {
-        jobCancelResult = JobCancelResult.INVALID_STATUS_TRANSITION;
-      }
-      // Get again the status from the table
-      // in case it's updated to CANCELLED.
-      jobStatus = snapDiffJobTable.get(snapDiffJobKey).getStatus();
+      return new CancelSnapshotDiffResponse(CANCEL_JOB_NOT_EXIST.getMessage());
     }
 
-    OFSPath snapshotRoot = getSnapshotRootPath(volumeName, bucketName);
-    SnapshotDiffReportOzone report = new SnapshotDiffReportOzone(
-        snapshotRoot.toString(), volumeName, bucketName,
-        fromSnapshotName, toSnapshotName, new ArrayList<>(), null);
-
-    // If cancel is a success then return SnapshotDiffReport.
-    // It will check the table and get that the job is cancelled,
-    // and return the appropriate response.
-    return new SnapshotDiffResponse(report, jobStatus, 0L, jobCancelResult);
+    String reason;
+    switch (diffJob.getStatus()) {
+    case  IN_PROGRESS:
+      try {
+        updateJobStatus(diffJobKey, IN_PROGRESS, CANCELLED);
+        reason = CANCEL_SUCCEEDED.getMessage();
+      } catch (IllegalStateException exception) {
+        LOG.warn("Failed to update the job status.", exception);
+        reason = CANCEL_FAILED.getMessage();
+      }
+      break;
+    case DONE:
+      reason = CANCEL_ALREADY_DONE_JOB.getMessage();
+      break;
+    case CANCELLED:
+      reason = CANCEL_ALREADY_CANCELLED_JOB.getMessage();
+      break;
+    case FAILED:
+      reason = CANCEL_ALREADY_FAILED_JOB.getMessage();
+      break;
+    default:
+      reason = CANCEL_NON_CANCELLABLE.getMessage() +
+          "Current status: " + diffJob.getStatus();
+      break;
+    }
+    return new CancelSnapshotDiffResponse(reason);
   }
 
   public List<SnapshotDiffJob> getSnapshotDiffJobList(
@@ -506,8 +509,7 @@ public class SnapshotDiffManager implements AutoCloseable {
     SnapshotInfo tsInfo = getSnapshotInfo(ozoneManager,
         volumeName, bucketName, toSnapshotName);
 
-    String snapDiffJobKey = fsInfo.getSnapshotId() + DELIMITER +
-        tsInfo.getSnapshotId();
+    String snapDiffJobKey = generateSnapDiffJobKey.apply(fsInfo, tsInfo);
 
     SnapshotDiffJob snapDiffJob = getSnapDiffReportStatus(snapDiffJobKey,
         volumeName, bucketName, fromSnapshotName, toSnapshotName,
@@ -530,7 +532,11 @@ public class SnapshotDiffManager implements AutoCloseable {
           new SnapshotDiffReportOzone(snapshotRoot.toString(), volumeName,
               bucketName, fromSnapshotName, toSnapshotName, new ArrayList<>(),
               null),
-          FAILED, defaultWaitTime);
+          FAILED,
+          // waitTime is equal to clean up internal. After that job will be
+          // removed and client can retry.
+          ozoneManager.getOmSnapshotManager().getDiffCleanupServiceInterval(),
+          snapDiffJob.getReason());
     case DONE:
       SnapshotDiffReportOzone report = createPageResponse(snapDiffJob,
           volumeName, bucketName, fromSnapshotName, toSnapshotName, index,
@@ -547,7 +553,7 @@ public class SnapshotDiffManager implements AutoCloseable {
           new SnapshotDiffReportOzone(snapshotRoot.toString(), volumeName,
               bucketName, fromSnapshotName, toSnapshotName, new ArrayList<>(),
               null),
-          CANCELLED, 0L, JobCancelResult.CANCELLATION_SUCCESS);
+          CANCELLED, 0L);
     default:
       throw new IllegalStateException("Unknown snapshot job status: " +
           snapDiffJob.getStatus());
@@ -792,11 +798,9 @@ public class SnapshotDiffManager implements AutoCloseable {
     SnapshotInfo toSnapInfo = getSnapshotInfo(ozoneManager, volumeName,
         bucketName, toSnapshotName);
 
-    String jobKey = fromSnapInfo.getSnapshotId() +
-        DELIMITER + toSnapInfo.getSnapshotId();
-
-    if (snapDiffJobTable.get(jobKey).getStatus()
-        .equals(CANCELLED)) {
+    String jobKey = generateSnapDiffJobKey.apply(fromSnapInfo, toSnapInfo);
+    SnapshotDiffJob diffJob = snapDiffJobTable.get(jobKey);
+    if (diffJob == null || diffJob.getStatus() == CANCELLED) {
       return false;
     }
     checkSnapshotActive(fromSnapInfo, false);
@@ -988,18 +992,20 @@ public class SnapshotDiffManager implements AutoCloseable 
{
         methodCall.call();
       }
     } catch (ExecutionException | IOException | RocksDBException exception) {
-      updateJobStatus(jobKey, IN_PROGRESS, FAILED);
+      updateJobStatusToFailed(jobKey, exception.getMessage());
       LOG.error("Caught checked exception during diff report generation for " +
               "volume: {} bucket: {}, fromSnapshot: {} and toSnapshot: {}",
           volumeName, bucketName, fromSnapshotName, toSnapshotName, exception);
-      // TODO: [SNAPSHOT] Fail gracefully.
+      // TODO: [SNAPSHOT] Fail gracefully. Also check if it is even needed to
+      //  throw this exception.
       throw new RuntimeException(exception);
     } catch (Exception exception) {
-      updateJobStatus(jobKey, IN_PROGRESS, FAILED);
+      updateJobStatusToFailed(jobKey, exception.getMessage());
       LOG.error("Caught unchecked exception during diff report generation " +
               "for volume: {} bucket: {}, fromSnapshot: {} and toSnapshot: {}",
           volumeName, bucketName, fromSnapshotName, toSnapshotName, exception);
-      // TODO: [SNAPSHOT] Fail gracefully.
+      // TODO: [SNAPSHOT] Fail gracefully. Also check if it is even needed to
+      //  throw this exception.
       throw new RuntimeException(exception);
     } finally {
       // Clean up: drop the intermediate column family and close them.
@@ -1170,16 +1176,6 @@ public class SnapshotDiffManager implements 
AutoCloseable {
     return builder.build();
   }
 
-  private String getKeyOrDirectoryName(boolean isDirectory,
-                                       WithObjectID object) {
-    if (isDirectory) {
-      OmDirectoryInfo directoryInfo = (OmDirectoryInfo) object;
-      return directoryInfo.getName();
-    }
-    OmKeyInfo keyInfo = (OmKeyInfo) object;
-    return keyInfo.getKeyName();
-  }
-
   @VisibleForTesting
   @SuppressWarnings("checkstyle:ParameterNumber")
   Set<String> getDeltaFiles(OmSnapshot fromSnapshot,
@@ -1559,6 +1555,25 @@ public class SnapshotDiffManager implements 
AutoCloseable {
     snapDiffJobTable.put(jobKey, snapshotDiffJob);
   }
 
+  private synchronized void updateJobStatusToFailed(String jobKey,
+                                                    String reason) {
+    SnapshotDiffJob snapshotDiffJob = snapDiffJobTable.get(jobKey);
+    if (snapshotDiffJob.getStatus() != IN_PROGRESS) {
+      throw new IllegalStateException("Invalid job status for jobID: " +
+          snapshotDiffJob.getJobId() + ". Job's current status is '" +
+          snapshotDiffJob.getStatus() + "', while '" + IN_PROGRESS +
+          "' is expected.");
+    }
+    snapshotDiffJob.setStatus(FAILED);
+    if (org.apache.commons.lang3.StringUtils.isNotEmpty(reason)) {
+      snapshotDiffJob.setReason(reason);
+    } else {
+      // TODO: [Snapshot] Revisit this when we have proper exception handling.
+      snapshotDiffJob.setReason("Job failed due to unknown reason.");
+    }
+    snapDiffJobTable.put(jobKey, snapshotDiffJob);
+  }
+
   private synchronized void updateJobStatusToDone(String jobKey,
                                                   long totalNumberOfEntries) {
     SnapshotDiffJob snapshotDiffJob = snapDiffJobTable.get(jobKey);
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
index daf348302c..7ccdc4fd59 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java
@@ -27,6 +27,7 @@ import java.util.stream.Collectors;
 import com.google.protobuf.ByteString;
 import com.google.protobuf.ServiceException;
 import org.apache.commons.lang3.RandomUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.hadoop.hdds.client.ECReplicationConfig;
@@ -70,6 +71,8 @@ import 
org.apache.hadoop.ozone.om.request.validation.ValidationContext;
 import org.apache.hadoop.ozone.om.response.OMClientResponse;
 import org.apache.hadoop.ozone.om.upgrade.DisallowedUntilLayoutVersion;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CancelSnapshotDiffRequest;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CancelSnapshotDiffResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ListSnapshotDiffJobRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ListSnapshotDiffJobResponse;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CheckVolumeAccessRequest;
@@ -308,6 +311,11 @@ public class OzoneManagerRequestHandler implements 
RequestHandler {
             request.getSnapshotDiffRequest());
         responseBuilder.setSnapshotDiffResponse(snapshotDiffReport);
         break;
+      case CancelSnapshotDiff:
+        CancelSnapshotDiffResponse cancelSnapshotDiff = cancelSnapshotDiff(
+                request.getCancelSnapshotDiffRequest());
+        responseBuilder.setCancelSnapshotDiffResponse(cancelSnapshotDiff);
+        break;
       case ListSnapshotDiffJobs:
         ListSnapshotDiffJobResponse listSnapDiffResponse =
             listSnapshotDiffJobs(request.getListSnapshotDiffJobRequest());
@@ -1253,14 +1261,15 @@ public class OzoneManagerRequestHandler implements 
RequestHandler {
             snapshotDiffRequest.getToSnapshot(),
             snapshotDiffRequest.getToken(),
             snapshotDiffRequest.getPageSize(),
-            snapshotDiffRequest.getForceFullDiff(),
-            snapshotDiffRequest.getCancel());
+            snapshotDiffRequest.getForceFullDiff());
 
     SnapshotDiffResponse.Builder builder = SnapshotDiffResponse.newBuilder()
         .setJobStatus(response.getJobStatus().toProtobuf())
-        .setWaitTimeInMs(response.getWaitTimeInMs())
-        .setJobCancelResult(response.getJobCancelResult().toProtobuf());
+        .setWaitTimeInMs(response.getWaitTimeInMs());
 
+    if (StringUtils.isNotEmpty(response.getReason())) {
+      builder.setReason(response.getReason());
+    }
     if (response.getSnapshotDiffReport() != null) {
       builder.setSnapshotDiffReport(
           response.getSnapshotDiffReport().toProtobuf());
@@ -1269,6 +1278,27 @@ public class OzoneManagerRequestHandler implements 
RequestHandler {
     return builder.build();
   }
 
+  @DisallowedUntilLayoutVersion(FILESYSTEM_SNAPSHOT)
+  private CancelSnapshotDiffResponse cancelSnapshotDiff(
+      CancelSnapshotDiffRequest cancelSnapshotDiffRequest) throws IOException {
+
+    org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse response =
+        impl.cancelSnapshotDiff(
+            cancelSnapshotDiffRequest.getVolumeName(),
+            cancelSnapshotDiffRequest.getBucketName(),
+            cancelSnapshotDiffRequest.getFromSnapshot(),
+            cancelSnapshotDiffRequest.getToSnapshot());
+
+    CancelSnapshotDiffResponse.Builder builder = CancelSnapshotDiffResponse
+        .newBuilder();
+
+    if (StringUtils.isNotEmpty(response.getMessage())) {
+      builder.setReason(response.getMessage());
+    }
+
+    return builder.build();
+  }
+
   private ListSnapshotDiffJobResponse listSnapshotDiffJobs(
       ListSnapshotDiffJobRequest listSnapshotDiffJobRequest)
       throws IOException {
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestSnapshotDiffManager.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestSnapshotDiffManager.java
index 834b118a12..08dfc2c755 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestSnapshotDiffManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestSnapshotDiffManager.java
@@ -55,9 +55,10 @@ import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
 import org.apache.hadoop.ozone.om.helpers.WithParentObjectId;
 import 
org.apache.hadoop.ozone.om.snapshot.SnapshotDiffObject.SnapshotDiffObjectBuilder;
 import 
org.apache.hadoop.ozone.om.snapshot.SnapshotTestUtils.StubbedPersistentMap;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
+import 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffReportOzone;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
-import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobCancelResult;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus;
 import org.apache.hadoop.security.UserGroupInformation;
 import org.apache.hadoop.util.ClosableIterator;
@@ -142,6 +143,12 @@ import static 
org.apache.hadoop.ozone.om.OmSnapshotManager.SNAP_DIFF_JOB_TABLE_N
 import static 
org.apache.hadoop.ozone.om.OmSnapshotManager.SNAP_DIFF_REPORT_TABLE_NAME;
 import static org.apache.hadoop.ozone.om.helpers.BucketLayout.LEGACY;
 import static org.apache.hadoop.ozone.om.helpers.SnapshotInfo.getTableKey;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_ALREADY_CANCELLED_JOB;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_ALREADY_DONE_JOB;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_ALREADY_FAILED_JOB;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_JOB_NOT_EXIST;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_NON_CANCELLABLE;
+import static 
org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse.CancelMessage.CANCEL_SUCCEEDED;
 import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffReportOzone.getDiffReportEntryCodec;
 import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus.DONE;
 import static 
org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse.JobStatus.FAILED;
@@ -961,26 +968,19 @@ public class TestSnapshotDiffManager {
 
   private static Stream<Arguments> snapDiffCancelFailureScenarios() {
     return Stream.of(
-        Arguments.of(JobStatus.IN_PROGRESS,
-            JobCancelResult.CANCELLATION_SUCCESS, true),
-        Arguments.of(JobStatus.CANCELLED,
-            JobCancelResult.JOB_ALREADY_CANCELLED, true),
-        Arguments.of(JobStatus.DONE,
-            JobCancelResult.JOB_DONE, false),
-        Arguments.of(JobStatus.QUEUED,
-            JobCancelResult.INVALID_STATUS_TRANSITION, false),
-        Arguments.of(JobStatus.FAILED,
-            JobCancelResult.INVALID_STATUS_TRANSITION, false),
-        Arguments.of(JobStatus.REJECTED,
-            JobCancelResult.INVALID_STATUS_TRANSITION, false)
+        Arguments.of(JobStatus.IN_PROGRESS, CANCEL_SUCCEEDED),
+        Arguments.of(JobStatus.CANCELLED, CANCEL_ALREADY_CANCELLED_JOB),
+        Arguments.of(JobStatus.DONE, CANCEL_ALREADY_DONE_JOB),
+        Arguments.of(JobStatus.QUEUED, CANCEL_NON_CANCELLABLE),
+        Arguments.of(JobStatus.FAILED, CANCEL_ALREADY_FAILED_JOB),
+        Arguments.of(JobStatus.REJECTED, CANCEL_NON_CANCELLABLE)
     );
   }
 
   @ParameterizedTest
   @MethodSource("snapDiffCancelFailureScenarios")
   public void testSnapshotDiffCancelFailure(JobStatus jobStatus,
-                                            JobCancelResult cancelResult,
-                                            boolean jobIsCancelled)
+                                            CancelMessage cancelMessage)
       throws IOException {
 
     String volumeName = "vol-" + RandomStringUtils.randomNumeric(5);
@@ -1008,15 +1008,12 @@ public class TestSnapshotDiffManager {
 
     snapDiffJobMap.put(diffJobKey, snapshotDiffJob);
 
-    SnapshotDiffResponse snapshotDiffResponse = snapshotDiffManager
+    CancelSnapshotDiffResponse cancelSnapshotDiff = snapshotDiffManager
         .cancelSnapshotDiff(volumeName, bucketName,
             fromSnapshotName, toSnapshotName);
 
-    assertEquals(cancelResult, snapshotDiffResponse.getJobCancelResult());
-
-    if (jobIsCancelled) {
-      assertEquals(JobStatus.CANCELLED, snapshotDiffResponse.getJobStatus());
-    }
+    assertTrue(cancelSnapshotDiff.getMessage()
+        .startsWith(cancelMessage.getMessage()));
   }
 
   @Test
@@ -1035,14 +1032,14 @@ public class TestSnapshotDiffManager {
     setUpSnapshots(volumeName, bucketName, fromSnapshotName,
         toSnapshotName, fromSnapshotUUID, toSnapshotUUID);
 
-    SnapshotDiffResponse snapshotDiffResponse = snapshotDiffManager
+    CancelSnapshotDiffResponse cancelSnapshotDiff = snapshotDiffManager
         .cancelSnapshotDiff(volumeName, bucketName,
             fromSnapshotName, toSnapshotName);
 
     // The job doesn't exist on the SnapDiffJob table and
     // trying to cancel it should lead to NEW_JOB cancel result.
-    assertEquals(JobCancelResult.NEW_JOB,
-        snapshotDiffResponse.getJobCancelResult());
+    assertEquals(CANCEL_JOB_NOT_EXIST.getMessage(),
+        cancelSnapshotDiff.getMessage());
   }
 
   private static Stream<Arguments> listSnapshotDiffJobsScenarios() {
diff --git 
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneClientAdapterImpl.java
 
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneClientAdapterImpl.java
index 6ea449a757..6090722306 100644
--- 
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneClientAdapterImpl.java
+++ 
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneClientAdapterImpl.java
@@ -707,7 +707,7 @@ public class BasicOzoneClientAdapterImpl implements 
OzoneClientAdapter {
     while (true) {
       snapshotDiffResponse =
           objectStore.snapshotDiff(volume.getName(), bucket.getName(),
-              fromSnapshot, toSnapshot, token, -1, false, false);
+              fromSnapshot, toSnapshot, token, -1, false);
       if (snapshotDiffResponse.getJobStatus() == DONE) {
         break;
       }
diff --git 
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java
 
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java
index 21dd8f25c8..3bdde5333d 100644
--- 
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java
+++ 
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java
@@ -1361,7 +1361,7 @@ public class BasicRootedOzoneClientAdapterImpl
     while (true) {
       snapshotDiffResponse =
           objectStore.snapshotDiff(volume, bucket, fromSnapshot, toSnapshot,
-              token, -1, false, false);
+              token, -1, false);
       if (snapshotDiffResponse.getJobStatus() == DONE) {
         break;
       }
diff --git 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ClientProtocolStub.java
 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ClientProtocolStub.java
index e0bed8e033..e48735afb5 100644
--- 
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ClientProtocolStub.java
+++ 
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ClientProtocolStub.java
@@ -48,6 +48,7 @@ import org.apache.hadoop.ozone.om.protocol.S3Auth;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
 import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
 import org.apache.hadoop.ozone.security.acl.OzoneObj;
+import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
 import org.apache.hadoop.ozone.snapshot.SnapshotDiffResponse;
 import org.apache.hadoop.security.token.Token;
 
@@ -630,8 +631,6 @@ public class ClientProtocolStub implements ClientProtocol {
 
   }
 
-
-
   @Override
   public SnapshotDiffResponse snapshotDiff(String volumeName,
                                            String bucketName,
@@ -639,8 +638,16 @@ public class ClientProtocolStub implements ClientProtocol {
                                            String toSnapshot,
                                            String token,
                                            int pageSize,
-                                           boolean forceFullDiff,
-                                           boolean cancel)
+                                           boolean forceFullDiff)
+      throws IOException {
+    return null;
+  }
+
+  @Override
+  public CancelSnapshotDiffResponse cancelSnapshotDiff(String volumeName,
+                                                       String bucketName,
+                                                       String fromSnapshot,
+                                                       String toSnapshot)
       throws IOException {
     return null;
   }
diff --git 
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/SnapshotDiffHandler.java
 
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/SnapshotDiffHandler.java
index bf63ca4703..619af13a60 100644
--- 
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/SnapshotDiffHandler.java
+++ 
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/SnapshotDiffHandler.java
@@ -18,6 +18,7 @@
 package org.apache.hadoop.ozone.shell.snapshot;
 
 import org.apache.hadoop.ozone.OmUtils;
+import org.apache.hadoop.ozone.client.ObjectStore;
 import org.apache.hadoop.ozone.client.OzoneClient;
 import org.apache.hadoop.ozone.shell.Handler;
 import org.apache.hadoop.ozone.shell.OzoneAddress;
@@ -81,10 +82,26 @@ public class SnapshotDiffHandler extends Handler {
     OmUtils.validateSnapshotName(fromSnapshot);
     OmUtils.validateSnapshotName(toSnapshot);
 
+    if (cancel) {
+      cancelSnapshotDiff(client.getObjectStore(), volumeName, bucketName);
+    } else {
+      getSnapshotDiff(client.getObjectStore(), volumeName, bucketName);
+    }
+  }
+
+  private void getSnapshotDiff(ObjectStore store, String volumeName,
+                               String bucketName) throws IOException {
+    try (PrintStream stream = out()) {
+      stream.print(store.snapshotDiff(volumeName, bucketName, fromSnapshot,
+          toSnapshot, token, pageSize, forceFullDiff));
+    }
+  }
+
+  private void cancelSnapshotDiff(ObjectStore store, String volumeName,
+                                  String bucketName) throws IOException {
     try (PrintStream stream = out()) {
-      stream.print(client.getObjectStore()
-          .snapshotDiff(volumeName, bucketName, fromSnapshot, toSnapshot,
-              token, pageSize, forceFullDiff, cancel));
+      stream.print(store.cancelSnapshotDiff(volumeName, bucketName,
+          fromSnapshot, toSnapshot));
     }
   }
 }


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

Reply via email to