This is an automated email from the ASF dual-hosted git repository.
siyao pushed a commit to branch HDDS-6517-Snapshot
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-6517-Snapshot by this
push:
new ccc814ee7f HDDS-6857. [Snapshot] Implement Snapshot Delete CLI and API
(#4175)
ccc814ee7f is described below
commit ccc814ee7f8a7cac70b6d64dcae12056e375199d
Author: Siyao Meng <[email protected]>
AuthorDate: Tue Jan 31 21:09:53 2023 -0800
HDDS-6857. [Snapshot] Implement Snapshot Delete CLI and API (#4175)
---
.../apache/hadoop/ozone/client/ObjectStore.java | 13 ++
.../ozone/client/protocol/ClientProtocol.java | 10 ++
.../apache/hadoop/ozone/client/rpc/RpcClient.java | 19 ++
.../main/java/org/apache/hadoop/ozone/OmUtils.java | 1 +
.../org/apache/hadoop/ozone/audit/OMAction.java | 2 +
.../ozone/om/protocol/OzoneManagerProtocol.java | 13 ++
...OzoneManagerProtocolClientSideTranslatorPB.java | 31 +++-
.../src/main/proto/OmClientProtocol.proto | 15 +-
.../java/org/apache/hadoop/ozone/om/OMMetrics.java | 10 ++
.../om/ratis/utils/OzoneManagerRatisUtils.java | 3 +
.../request/snapshot/OMSnapshotCreateRequest.java | 10 +-
...teRequest.java => OMSnapshotDeleteRequest.java} | 185 ++++++++++++--------
.../snapshot/OMSnapshotCreateResponse.java | 3 +-
...Response.java => OMSnapshotDeleteResponse.java} | 32 ++--
.../ozone/om/request/OMRequestTestUtils.java | 25 ++-
.../snapshot/TestOMSnapshotCreateRequest.java | 10 +-
...quest.java => TestOMSnapshotDeleteRequest.java} | 194 ++++++++++++++-------
.../snapshot/TestOMSnapshotDeleteResponse.java | 125 +++++++++++++
.../hadoop/ozone/client/ClientProtocolStub.java | 7 +
.../shell/snapshot/CreateSnapshotHandler.java | 11 +-
...shotHandler.java => DeleteSnapshotHandler.java} | 24 ++-
.../ozone/shell/snapshot/ListSnapshotHandler.java | 3 +-
.../ozone/shell/snapshot/SnapshotCommands.java | 3 +-
23 files changed, 556 insertions(+), 193 deletions(-)
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 d22ba6061a..3a0a5cd8e8 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
@@ -537,6 +537,18 @@ public class ObjectStore {
return proxy.createSnapshot(volumeName, bucketName, snapshotName);
}
+ /**
+ * Delete snapshot.
+ * @param volumeName vol to be used
+ * @param bucketName bucket to be used
+ * @param snapshotName name of the snapshot to be deleted
+ * @throws IOException
+ */
+ public void deleteSnapshot(String volumeName,
+ String bucketName, String snapshotName) throws IOException {
+ proxy.deleteSnapshot(volumeName, bucketName, snapshotName);
+ }
+
/**
* List snapshots in a volume/bucket.
* @param volumeName volume name
@@ -548,6 +560,7 @@ public class ObjectStore {
throws IOException {
return proxy.listSnapshot(volumeName, bucketName);
}
+
public SnapshotDiffReport snapshotDiff(String volumeName, String bucketName,
String fromSnapshot, String
toSnapshot)
throws IOException {
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 edc5eeb61e..b0400ac328 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
@@ -1030,6 +1030,16 @@ public interface ClientProtocol {
String createSnapshot(String volumeName,
String bucketName, String snapshotName) throws IOException;
+ /**
+ * Delete snapshot.
+ * @param volumeName vol to be used
+ * @param bucketName bucket to be used
+ * @param snapshotName name of the snapshot to be deleted
+ * @throws IOException
+ */
+ void deleteSnapshot(String volumeName,
+ String bucketName, String snapshotName) throws IOException;
+
/**
* List snapshots in a volume/bucket.
* @param volumeName volume name
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 b4b9e2aca7..4d1596c216 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
@@ -952,6 +952,25 @@ public class RpcClient implements ClientProtocol {
bucketName, snapshotName);
}
+ /**
+ * Delete Snapshot.
+ * @param volumeName vol to be used
+ * @param bucketName bucket to be used
+ * @param snapshotName name of the snapshot to be deleted
+ * @throws IOException
+ */
+ @Override
+ public void deleteSnapshot(String volumeName,
+ String bucketName, String snapshotName) throws IOException {
+ Preconditions.checkArgument(Strings.isNotBlank(volumeName),
+ "volume can't be null or empty.");
+ Preconditions.checkArgument(Strings.isNotBlank(bucketName),
+ "bucket can't be null or empty.");
+ Preconditions.checkArgument(Strings.isNotBlank(snapshotName),
+ "snapshot name can't be null or empty.");
+ ozoneManagerClient.deleteSnapshot(volumeName, bucketName, snapshotName);
+ }
+
@Override
public SnapshotDiffReport snapshotDiff(String volumeName, String bucketName,
String fromSnapshot, String
toSnapshot)
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 10f3cbc439..1419a4cdab 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
@@ -325,6 +325,7 @@ public final class OmUtils {
case TenantRevokeAdmin:
case SetRangerServiceVersion:
case CreateSnapshot:
+ case DeleteSnapshot:
return false;
default:
LOG.error("CmdType {} is not categorized as readOnly or not.", cmdType);
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
index c691b18ac0..72c0c8c0f9 100644
---
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
@@ -89,7 +89,9 @@ public enum OMAction implements AuditAction {
TENANT_ASSIGN_ADMIN,
TENANT_REVOKE_ADMIN,
TENANT_LIST_USER,
+
CREATE_SNAPSHOT,
+ DELETE_SNAPSHOT,
LIST_SNAPSHOT;
@Override
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 f34be56c0d..ed08f66013 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
@@ -649,6 +649,19 @@ public interface OzoneManagerProtocol
"this to be implemented");
}
+ /**
+ * Delete snapshot.
+ * @param volumeName vol to be used
+ * @param bucketName bucket to be used
+ * @param snapshotName name of the snapshot to be deleted
+ * @throws IOException
+ */
+ default void deleteSnapshot(String volumeName,
+ String bucketName, String snapshotName) throws IOException {
+ throw new UnsupportedOperationException("OzoneManager does not require " +
+ "this to be implemented");
+ }
+
/**
* List snapshots in a volume/bucket.
* @param volumeName volume name
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 47c8b8e12e..998bca29d8 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
@@ -84,6 +84,7 @@ import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateF
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateFileResponse;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateKeyRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateKeyResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateSnapshotRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateTenantRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateVolumeRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DBUpdatesRequest;
@@ -92,6 +93,7 @@ import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteB
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteKeyArgs;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteKeyRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteKeysRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteSnapshotRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteVolumeRequest;
@@ -1108,9 +1110,8 @@ public final class
OzoneManagerProtocolClientSideTranslatorPB
String bucketName, String snapshotName)
throws IOException {
- final OzoneManagerProtocolProtos.CreateSnapshotRequest.Builder
- requestBuilder =
- OzoneManagerProtocolProtos.CreateSnapshotRequest.newBuilder()
+ final CreateSnapshotRequest.Builder requestBuilder =
+ CreateSnapshotRequest.newBuilder()
.setVolumeName(volumeName)
.setBucketName(bucketName);
if (!StringUtils.isBlank(snapshotName)) {
@@ -1127,6 +1128,30 @@ public final class
OzoneManagerProtocolClientSideTranslatorPB
return snapshotInfo.getName();
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void deleteSnapshot(String volumeName,
+ String bucketName, String snapshotName)
+ throws IOException {
+
+ final DeleteSnapshotRequest.Builder requestBuilder =
+ DeleteSnapshotRequest.newBuilder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .setSnapshotName(snapshotName);
+
+ final OMRequest omRequest = createOMRequest(Type.DeleteSnapshot)
+ .setDeleteSnapshotRequest(requestBuilder)
+ .build();
+ final OMResponse omResponse = submitRequest(omRequest);
+ handleError(omResponse);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
@Override
public List<SnapshotInfo> listSnapshot(String volumeName, String bucketName)
throws IOException {
diff --git
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 8fba86d714..81e776d6b4 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -129,6 +129,7 @@ enum Type {
CreateSnapshot = 112;
ListSnapshot = 113;
SnapshotDiff = 114;
+ DeleteSnapshot = 115;
}
message OMRequest {
@@ -240,6 +241,7 @@ message OMRequest {
optional CreateSnapshotRequest CreateSnapshotRequest =
112;
optional ListSnapshotRequest ListSnapshotRequest =
113;
optional SnapshotDiffRequest snapshotDiffRequest =
114;
+ optional DeleteSnapshotRequest DeleteSnapshotRequest =
115;
}
@@ -345,6 +347,7 @@ message OMResponse {
optional CreateSnapshotResponse CreateSnapshotResponse =
112;
optional ListSnapshotResponse ListSnapshotResponse =
113;
optional SnapshotDiffResponse snapshotDiffResponse =
114;
+ optional DeleteSnapshotResponse DeleteSnapshotResponse =
115;
}
enum Status {
@@ -1680,6 +1683,13 @@ message SnapshotDiffRequest {
optional string toSnapshot = 4;
}
+message DeleteSnapshotRequest {
+ optional string volumeName = 1;
+ optional string bucketName = 2;
+ optional string snapshotName = 3;
+ optional uint64 deletionTime = 4;
+}
+
message DeleteTenantRequest {
optional string tenantId = 1;
}
@@ -1725,11 +1735,14 @@ message ListSnapshotResponse {
repeated SnapshotInfo snapshotInfo = 1;
}
-
message SnapshotDiffResponse {
optional SnapshotDiffReportProto snapshotDiffReport = 1;
}
+message DeleteSnapshotResponse {
+
+}
+
message SnapshotDiffReportProto {
optional string volumeName = 1;
optional string bucketName = 2;
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
index e85a033d18..d194360130 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetrics.java
@@ -69,6 +69,7 @@ public class OMMetrics implements OmMetadataReaderMetrics {
private @Metric MutableCounterLong numInitiateMultipartUploads;
private @Metric MutableCounterLong numCompleteMultipartUploads;
private @Metric MutableCounterLong numSnapshotCreates;
+ private @Metric MutableCounterLong numSnapshotDeletes;
private @Metric MutableCounterLong numSnapshotLists;
private @Metric MutableCounterLong numGetFileStatus;
@@ -119,6 +120,7 @@ public class OMMetrics implements OmMetadataReaderMetrics {
private @Metric MutableCounterLong numListMultipartUploadPartFails;
private @Metric MutableCounterLong numOpenKeyDeleteRequestFails;
private @Metric MutableCounterLong numSnapshotCreateFails;
+ private @Metric MutableCounterLong numSnapshotDeleteFails;
private @Metric MutableCounterLong numSnapshotListFails;
private @Metric MutableCounterLong numSnapshotActive;
private @Metric MutableCounterLong numSnapshotDeleted;
@@ -443,6 +445,14 @@ public class OMMetrics implements OmMetadataReaderMetrics {
numSnapshotCreateFails.incr();
}
+ public void incNumSnapshotDeletes() {
+ numSnapshotDeletes.incr();
+ }
+
+ public void incNumSnapshotDeleteFails() {
+ numSnapshotDeleteFails.incr();
+ }
+
public void incNumSnapshotLists() {
numSnapshotLists.incr();
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
index ad730cd5bc..e556fb5065 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java
@@ -71,6 +71,7 @@ import
org.apache.hadoop.ozone.om.request.security.OMCancelDelegationTokenReques
import org.apache.hadoop.ozone.om.request.security.OMGetDelegationTokenRequest;
import
org.apache.hadoop.ozone.om.request.security.OMRenewDelegationTokenRequest;
import org.apache.hadoop.ozone.om.request.snapshot.OMSnapshotCreateRequest;
+import org.apache.hadoop.ozone.om.request.snapshot.OMSnapshotDeleteRequest;
import org.apache.hadoop.ozone.om.request.upgrade.OMCancelPrepareRequest;
import org.apache.hadoop.ozone.om.request.upgrade.OMFinalizeUpgradeRequest;
import org.apache.hadoop.ozone.om.request.upgrade.OMPrepareRequest;
@@ -212,6 +213,8 @@ public final class OzoneManagerRatisUtils {
return new OMSetRangerServiceVersionRequest(omRequest);
case CreateSnapshot:
return new OMSnapshotCreateRequest(omRequest);
+ case DeleteSnapshot:
+ return new OMSnapshotDeleteRequest(omRequest);
case DeleteOpenKeys:
BucketLayout bktLayout = BucketLayout.DEFAULT;
if (omRequest.getDeleteOpenKeysRequest().hasBucketLayout()) {
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotCreateRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotCreateRequest.java
index 3f1af514c1..60e3e2c7ca 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotCreateRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotCreateRequest.java
@@ -96,7 +96,7 @@ public class OMSnapshotCreateRequest extends OMClientRequest {
if (!ozoneManager.isAdmin(ugi) &&
!ozoneManager.isOwner(ugi, bucketOwner)) {
throw new OMException(
- "Only bucket owners/admins can create snapshots",
+ "Only bucket owners and Ozone admins can create snapshots",
OMException.ResultCodes.PERMISSION_DENIED);
}
return omRequest;
@@ -135,7 +135,7 @@ public class OMSnapshotCreateRequest extends
OMClientRequest {
//Check if snapshot already exists
if (omMetadataManager.getSnapshotInfoTable().isExist(key)) {
- LOG.debug("snapshot: {} already exists ", key);
+ LOG.debug("Snapshot '{}' already exists under '{}'", key,
snapshotPath);
throw new OMException("Snapshot already exists", FILE_ALREADY_EXISTS);
}
@@ -177,11 +177,11 @@ public class OMSnapshotCreateRequest extends
OMClientRequest {
snapshotInfo.toAuditMap(), exception, userInfo));
if (exception == null) {
- LOG.info("created snapshot: name {} in snapshotPath: {}", snapshotName,
- snapshotPath);
+ LOG.info("Created snapshot '{}' under path '{}'",
+ snapshotName, snapshotPath);
} else {
omMetrics.incNumSnapshotCreateFails();
- LOG.error("Snapshot creation failed for name:{} in snapshotPath:{}",
+ LOG.error("Failed to create snapshot '{}' under path '{}'",
snapshotName, snapshotPath);
}
return omClientResponse;
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotCreateRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotDeleteRequest.java
similarity index 51%
copy from
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotCreateRequest.java
copy to
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotDeleteRequest.java
index 3f1af514c1..833c7c8429 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotCreateRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/snapshot/OMSnapshotDeleteRequest.java
@@ -19,7 +19,6 @@
package org.apache.hadoop.ozone.om.request.snapshot;
import com.google.common.base.Optional;
-import org.apache.hadoop.hdds.utils.db.RDBStore;
import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
import org.apache.hadoop.ozone.OmUtils;
@@ -34,130 +33,161 @@ 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.snapshot.OMSnapshotCreateResponse;
-import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
-import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateSnapshotRequest;
-import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateSnapshotResponse;
+import org.apache.hadoop.ozone.om.response.snapshot.OMSnapshotDeleteResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteSnapshotRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteSnapshotResponse;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.UserInfo;
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
import org.apache.hadoop.ozone.security.acl.OzoneObj;
import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.util.Time;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
-import static
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FILE_ALREADY_EXISTS;
+import static
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FILE_NOT_FOUND;
import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.SNAPSHOT_LOCK;
-
/**
- * Handles CreateSnapshot Request.
+ * Handles DeleteSnapshot Request.
*/
-public class OMSnapshotCreateRequest extends OMClientRequest {
+public class OMSnapshotDeleteRequest extends OMClientRequest {
private static final Logger LOG =
- LoggerFactory.getLogger(OMSnapshotCreateRequest.class);
-
- private final String snapshotPath;
- private final String volumeName;
- private final String bucketName;
- private final String snapshotName;
- private final String snapshotId;
- private final SnapshotInfo snapshotInfo;
+ LoggerFactory.getLogger(OMSnapshotDeleteRequest.class);
- public OMSnapshotCreateRequest(OMRequest omRequest) {
+ public OMSnapshotDeleteRequest(OMRequest omRequest) {
super(omRequest);
- CreateSnapshotRequest createSnapshotRequest = omRequest
- .getCreateSnapshotRequest();
- volumeName = createSnapshotRequest.getVolumeName();
- bucketName = createSnapshotRequest.getBucketName();
- snapshotId = createSnapshotRequest.getSnapshotId();
-
- String possibleName = createSnapshotRequest.getSnapshotName();
- snapshotInfo = SnapshotInfo.newInstance(volumeName,
- bucketName,
- possibleName,
- snapshotId);
- snapshotName = snapshotInfo.getName();
- snapshotPath = snapshotInfo.getSnapshotPath();
}
@Override
public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+
final OMRequest omRequest = super.preExecute(ozoneManager);
- // Verify name
+
+ final DeleteSnapshotRequest deleteSnapshotRequest =
+ omRequest.getDeleteSnapshotRequest();
+
+ final String snapshotName = deleteSnapshotRequest.getSnapshotName();
+ // Verify snapshot name. TODO: Can remove
OmUtils.validateSnapshotName(snapshotName);
+ String volumeName = deleteSnapshotRequest.getVolumeName();
+ String bucketName = deleteSnapshotRequest.getBucketName();
+
+ // Permission check
UserGroupInformation ugi = createUGI();
String bucketOwner = ozoneManager.getBucketOwner(volumeName, bucketName,
IAccessAuthorizer.ACLType.READ, OzoneObj.ResourceType.BUCKET);
if (!ozoneManager.isAdmin(ugi) &&
!ozoneManager.isOwner(ugi, bucketOwner)) {
throw new OMException(
- "Only bucket owners/admins can create snapshots",
+ "Only bucket owners and Ozone admins can delete snapshots",
OMException.ResultCodes.PERMISSION_DENIED);
}
- return omRequest;
+
+ // Set deletion time here so OM leader and follower would have the
+ // exact same timestamp.
+ OMRequest.Builder omRequestBuilder = omRequest.toBuilder()
+ .setDeleteSnapshotRequest(
+ DeleteSnapshotRequest.newBuilder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .setSnapshotName(snapshotName)
+ .setDeletionTime(Time.now()));
+
+ return omRequestBuilder.build();
}
-
+
@Override
public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
long transactionLogIndex,
OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper) {
OMMetrics omMetrics = ozoneManager.getMetrics();
- omMetrics.incNumSnapshotCreates();
- omMetrics.incNumSnapshotActive();
+ omMetrics.incNumSnapshotDeletes();
- boolean acquiredBucketLock = false, acquiredSnapshotLock = false;
+ boolean acquiredBucketLock = false;
+ boolean acquiredSnapshotLock = false;
IOException exception = null;
OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
-
+
OMResponse.Builder omResponse = OmResponseUtil.getOMResponseBuilder(
getOmRequest());
OMClientResponse omClientResponse = null;
AuditLogger auditLogger = ozoneManager.getAuditLogger();
- OzoneManagerProtocolProtos.UserInfo userInfo =
getOmRequest().getUserInfo();
- String key = snapshotInfo.getTableKey();
+ UserInfo userInfo = getOmRequest().getUserInfo();
+
+ final DeleteSnapshotRequest request =
+ getOmRequest().getDeleteSnapshotRequest();
+
+ final String volumeName = request.getVolumeName();
+ final String bucketName = request.getBucketName();
+ final String snapshotName = request.getSnapshotName();
+ final long deletionTime = request.getDeletionTime();
+
+ SnapshotInfo snapshotInfo = null;
+
try {
- // Lock bucket so it doesn't
- // get deleted while creating snapshot
+ // Acquire bucket lock
acquiredBucketLock =
- omMetadataManager.getLock().acquireReadLock(BUCKET_LOCK,
+ omMetadataManager.getLock().acquireWriteLock(BUCKET_LOCK,
volumeName, bucketName);
acquiredSnapshotLock =
omMetadataManager.getLock().acquireWriteLock(SNAPSHOT_LOCK,
volumeName, bucketName, snapshotName);
- //Check if snapshot already exists
- if (omMetadataManager.getSnapshotInfoTable().isExist(key)) {
- LOG.debug("snapshot: {} already exists ", key);
- throw new OMException("Snapshot already exists", FILE_ALREADY_EXISTS);
+ // Retrieve SnapshotInfo from the table
+ String tableKey = SnapshotInfo.getTableKey(volumeName, bucketName,
+ snapshotName);
+ snapshotInfo =
+ omMetadataManager.getSnapshotInfoTable().get(tableKey);
+
+ if (snapshotInfo == null) {
+ // Snapshot does not exist
+ throw new OMException("Snapshot does not exist", FILE_NOT_FOUND);
+ }
+
+ if (!snapshotInfo.getSnapshotStatus().equals(
+ SnapshotInfo.SnapshotStatus.SNAPSHOT_ACTIVE)) {
+ // If the snapshot is not in active state, throw exception as well
+ switch (snapshotInfo.getSnapshotStatus()) {
+ case SNAPSHOT_DELETED:
+ throw new OMException("Snapshot is already deleted. "
+ + "Pending reclamation.", FILE_NOT_FOUND);
+ case SNAPSHOT_RECLAIMED:
+ throw new OMException("Snapshot is already deleted and reclaimed.",
+ FILE_NOT_FOUND);
+ default:
+ // Unknown snapshot non-active state
+ throw new OMException("Snapshot exists but no longer in active
state",
+ FILE_NOT_FOUND);
+ }
}
- // Note down RDB latest transaction sequence number, which is used
- // as snapshot generation in the differ.
- final long dbLatestSequenceNumber =
- ((RDBStore) omMetadataManager.getStore()).getDb()
- .getLatestSequenceNumber();
- snapshotInfo.setDbTxSequenceNumber(dbLatestSequenceNumber);
-
- omMetadataManager.getSnapshotInfoTable()
- .addCacheEntry(new CacheKey<>(key),
- new CacheValue<>(Optional.of(snapshotInfo), transactionLogIndex));
-
- omResponse.setCreateSnapshotResponse(
- CreateSnapshotResponse.newBuilder()
- .setSnapshotInfo(snapshotInfo.getProtobuf()));
- omClientResponse = new OMSnapshotCreateResponse(
- omResponse.build(), volumeName, bucketName, snapshotName);
+ // Mark snapshot as deleted
+ snapshotInfo.setSnapshotStatus(
+ SnapshotInfo.SnapshotStatus.SNAPSHOT_DELETED);
+ snapshotInfo.setDeletionTime(deletionTime);
+
+ // Update table cache first
+ omMetadataManager.getSnapshotInfoTable().addCacheEntry(
+ new CacheKey<>(tableKey),
+ new CacheValue<>(Optional.of(snapshotInfo), transactionLogIndex));
+
+ omResponse.setDeleteSnapshotResponse(
+ DeleteSnapshotResponse.newBuilder());
+ omClientResponse = new OMSnapshotDeleteResponse(
+ omResponse.build(), tableKey, snapshotInfo);
+
} catch (IOException ex) {
exception = ex;
- omClientResponse = new OMSnapshotCreateResponse(
+ omClientResponse = new OMSnapshotDeleteResponse(
createErrorOMResponse(omResponse, exception));
} finally {
addResponseToDoubleBuffer(transactionLogIndex, omClientResponse,
@@ -167,24 +197,31 @@ public class OMSnapshotCreateRequest extends
OMClientRequest {
bucketName, snapshotName);
}
if (acquiredBucketLock) {
- omMetadataManager.getLock().releaseReadLock(BUCKET_LOCK, volumeName,
+ omMetadataManager.getLock().releaseWriteLock(BUCKET_LOCK, volumeName,
bucketName);
}
}
- // Performing audit logging outside the lock.
- auditLog(auditLogger, buildAuditMessage(OMAction.CREATE_SNAPSHOT,
+ if (snapshotInfo == null) {
+ // Dummy SnapshotInfo for logging and audit logging when erred
+ snapshotInfo = SnapshotInfo.newInstance(volumeName, bucketName,
+ snapshotName, null);
+ }
+
+ // Perform audit logging outside the lock
+ auditLog(auditLogger, buildAuditMessage(OMAction.DELETE_SNAPSHOT,
snapshotInfo.toAuditMap(), exception, userInfo));
-
+
+ final String snapshotPath = snapshotInfo.getSnapshotPath();
if (exception == null) {
- LOG.info("created snapshot: name {} in snapshotPath: {}", snapshotName,
- snapshotPath);
+ LOG.info("Deleted snapshot '{}' under path '{}'",
+ snapshotName, snapshotPath);
} else {
- omMetrics.incNumSnapshotCreateFails();
- LOG.error("Snapshot creation failed for name:{} in snapshotPath:{}",
+ omMetrics.incNumSnapshotDeleteFails();
+ LOG.error("Failed to delete snapshot '{}' under path '{}'",
snapshotName, snapshotPath);
}
return omClientResponse;
}
-
+
}
\ No newline at end of file
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotCreateResponse.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotCreateResponse.java
index f59588ba0f..e5ba1c0511 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotCreateResponse.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotCreateResponse.java
@@ -31,12 +31,11 @@ import java.io.IOException;
import static
org.apache.hadoop.ozone.om.OmMetadataManagerImpl.SNAPSHOT_INFO_TABLE;
/**
- * Response for OMSnapshotCreateResponse.
+ * Response for OMSnapshotCreateRequest.
*/
@CleanupTableInfo(cleanupTables = {SNAPSHOT_INFO_TABLE})
public class OMSnapshotCreateResponse extends OMClientResponse {
- @SuppressWarnings("checkstyle:parameternumber")
public OMSnapshotCreateResponse(@Nonnull OMResponse omResponse,
@Nonnull String volumeName, @Nonnull String bucketName,
@Nonnull String snapshotName) {
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotCreateResponse.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotDeleteResponse.java
similarity index 70%
copy from
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotCreateResponse.java
copy to
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotDeleteResponse.java
index f59588ba0f..654d62bb4b 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotCreateResponse.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotDeleteResponse.java
@@ -20,7 +20,6 @@ package org.apache.hadoop.ozone.om.response.snapshot;
import org.apache.hadoop.hdds.utils.db.BatchOperation;
import org.apache.hadoop.ozone.om.OMMetadataManager;
-import org.apache.hadoop.ozone.om.OmSnapshotManager;
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
import org.apache.hadoop.ozone.om.response.CleanupTableInfo;
import org.apache.hadoop.ozone.om.response.OMClientResponse;
@@ -28,26 +27,31 @@ import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRespo
import javax.annotation.Nonnull;
import java.io.IOException;
+
import static
org.apache.hadoop.ozone.om.OmMetadataManagerImpl.SNAPSHOT_INFO_TABLE;
/**
- * Response for OMSnapshotCreateResponse.
+ * Response for OMSnapshotDeleteRequest.
*/
@CleanupTableInfo(cleanupTables = {SNAPSHOT_INFO_TABLE})
-public class OMSnapshotCreateResponse extends OMClientResponse {
+public class OMSnapshotDeleteResponse extends OMClientResponse {
+
+ private String tableKey;
+ private SnapshotInfo snapshotInfo;
- @SuppressWarnings("checkstyle:parameternumber")
- public OMSnapshotCreateResponse(@Nonnull OMResponse omResponse,
- @Nonnull String volumeName, @Nonnull String bucketName,
- @Nonnull String snapshotName) {
+ public OMSnapshotDeleteResponse(@Nonnull OMResponse omResponse,
+ @Nonnull String tableKey,
+ @Nonnull SnapshotInfo snapshotInfo) {
super(omResponse);
+ this.tableKey = tableKey;
+ this.snapshotInfo = snapshotInfo;
}
/**
* For when the request is not successful.
* For a successful request, the other constructor should be used.
*/
- public OMSnapshotCreateResponse(@Nonnull OMResponse omResponse) {
+ public OMSnapshotDeleteResponse(@Nonnull OMResponse omResponse) {
super(omResponse);
checkStatusNotOK();
}
@@ -56,18 +60,8 @@ public class OMSnapshotCreateResponse extends
OMClientResponse {
public void addToDBBatch(OMMetadataManager omMetadataManager,
BatchOperation batchOperation) throws IOException {
- SnapshotInfo snapshotInfo =
- SnapshotInfo.getFromProtobuf(
- getOMResponse().getCreateSnapshotResponse().getSnapshotInfo());
-
- // Create the snapshot checkpoint
- OmSnapshotManager.createOmSnapshotCheckpoint(omMetadataManager,
- snapshotInfo);
-
- String key = snapshotInfo.getTableKey();
-
// Add to db
omMetadataManager.getSnapshotInfoTable().putWithBatch(batchOperation,
- key, snapshotInfo);
+ tableKey, snapshotInfo);
}
}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
index 9549f746e5..2dbe188180 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/OMRequestTestUtils.java
@@ -1134,7 +1134,30 @@ public final class OMRequestTestUtils {
return OMRequest.newBuilder()
.setCreateSnapshotRequest(createSnapshotRequest)
- .setCmdType(OzoneManagerProtocolProtos.Type.CreateSnapshot)
+ .setCmdType(Type.CreateSnapshot)
+ .setClientId(UUID.randomUUID().toString())
+ .build();
+ }
+
+ /**
+ * Create OMRequest for Delete Snapshot.
+ * @param volumeName vol to be used
+ * @param bucketName bucket to be used
+ * @param snapshotName name of the snapshot to be deleted
+ */
+ public static OMRequest deleteSnapshotRequest(String volumeName,
+ String bucketName, String snapshotName) {
+ OzoneManagerProtocolProtos.DeleteSnapshotRequest deleteSnapshotRequest =
+ OzoneManagerProtocolProtos.DeleteSnapshotRequest.newBuilder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .setSnapshotName(snapshotName)
+ .setDeletionTime(Time.now())
+ .build();
+
+ return OMRequest.newBuilder()
+ .setDeleteSnapshotRequest(deleteSnapshotRequest)
+ .setCmdType(Type.DeleteSnapshot)
.setClientId(UUID.randomUUID().toString())
.build();
}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotCreateRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotCreateRequest.java
index 35f51bf1d5..972920e46d 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotCreateRequest.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotCreateRequest.java
@@ -132,7 +132,7 @@ public class TestOMSnapshotCreateRequest {
volumeName, bucketName, snapshotName);
// Check bad owner
LambdaTestUtils.intercept(OMException.class,
- "Only bucket owners/admins can create snapshots",
+ "Only bucket owners and Ozone admins can create snapshots",
() -> doPreExecute(omRequest));
}
@@ -258,6 +258,14 @@ public class TestOMSnapshotCreateRequest {
private OMSnapshotCreateRequest doPreExecute(
OMRequest originalRequest) throws Exception {
+ return doPreExecute(originalRequest, ozoneManager);
+ }
+
+ /**
+ * Static helper method so this could be used in TestOMSnapshotDeleteRequest.
+ */
+ static OMSnapshotCreateRequest doPreExecute(
+ OMRequest originalRequest, OzoneManager ozoneManager) throws Exception {
OMSnapshotCreateRequest omSnapshotCreateRequest =
new OMSnapshotCreateRequest(originalRequest);
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotCreateRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotDeleteRequest.java
similarity index 57%
copy from
hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotCreateRequest.java
copy to
hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotDeleteRequest.java
index 35f51bf1d5..14b7955cbe 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotCreateRequest.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/snapshot/TestOMSnapshotDeleteRequest.java
@@ -20,12 +20,12 @@
package org.apache.hadoop.ozone.om.request.snapshot;
-import java.util.UUID;
-
+import com.google.common.base.Optional;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
import org.apache.hadoop.ozone.audit.AuditLogger;
import org.apache.hadoop.ozone.audit.AuditMessage;
-
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.OMMetrics;
@@ -34,33 +34,34 @@ import org.apache.hadoop.ozone.om.OzoneManager;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
+import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
import org.apache.hadoop.ozone.om.upgrade.OMLayoutVersionManager;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
import org.apache.ozone.test.LambdaTestUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
-
-
-import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
- .OMRequest;
-import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
- .OMResponse;
-import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
-import org.apache.hadoop.ozone.om.response.OMClientResponse;
-import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
import org.junit.rules.TemporaryFolder;
import org.mockito.Mockito;
+import java.util.UUID;
+
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
- * Tests OMSnapshotCreateRequest class, which handles CreateSnapshot request.
+ * Tests OMSnapshotDeleteRequest class, which handles DeleteSnapshot request.
+ * Mostly mirrors TestOMSnapshotCreateRequest.
+ * testEntryNotExist() and testEntryExists() are unique.
*/
-public class TestOMSnapshotCreateRequest {
+public class TestOMSnapshotDeleteRequest {
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@@ -118,7 +119,7 @@ public class TestOMSnapshotCreateRequest {
// set the owner
when(ozoneManager.isOwner(any(), any())).thenReturn(true);
OMRequest omRequest =
- OMRequestTestUtils.createSnapshotRequest(
+ OMRequestTestUtils.deleteSnapshotRequest(
volumeName, bucketName, snapshotName);
// should not throw
doPreExecute(omRequest);
@@ -128,11 +129,11 @@ public class TestOMSnapshotCreateRequest {
public void testPreExecuteBadOwner() throws Exception {
// owner not set
OMRequest omRequest =
- OMRequestTestUtils.createSnapshotRequest(
+ OMRequestTestUtils.deleteSnapshotRequest(
volumeName, bucketName, snapshotName);
// Check bad owner
LambdaTestUtils.intercept(OMException.class,
- "Only bucket owners/admins can create snapshots",
+ "Only bucket owners and Ozone admins can delete snapshots",
() -> doPreExecute(omRequest));
}
@@ -141,7 +142,7 @@ public class TestOMSnapshotCreateRequest {
// check invalid snapshot name
String badName = "a?b";
OMRequest omRequest =
- OMRequestTestUtils.createSnapshotRequest(
+ OMRequestTestUtils.deleteSnapshotRequest(
volumeName, bucketName, badName);
LambdaTestUtils.intercept(OMException.class,
"Invalid snapshot name: " + badName,
@@ -152,12 +153,11 @@ public class TestOMSnapshotCreateRequest {
public void testPreExecuteNameOnlyNumbers() throws Exception {
// check invalid snapshot name containing only numbers
String badNameON = "1234";
- OMRequest omRequest =
- OMRequestTestUtils.createSnapshotRequest(
- volumeName, bucketName, badNameON);
+ OMRequest omRequest = OMRequestTestUtils.deleteSnapshotRequest(
+ volumeName, bucketName, badNameON);
LambdaTestUtils.intercept(OMException.class,
- "Invalid snapshot name: " + badNameON,
- () -> doPreExecute(omRequest));
+ "Invalid snapshot name: " + badNameON,
+ () -> doPreExecute(omRequest));
}
@Test
@@ -170,26 +170,26 @@ public class TestOMSnapshotCreateRequest {
// name length = 63
when(ozoneManager.isOwner(any(), any())).thenReturn(true);
- OMRequest omRequest = OMRequestTestUtils.createSnapshotRequest(
- volumeName, bucketName, name63);
+ OMRequest omRequest = OMRequestTestUtils.deleteSnapshotRequest(
+ volumeName, bucketName, name63);
// should not throw any error
doPreExecute(omRequest);
// name length = 64
- OMRequest omRequest2 = OMRequestTestUtils.createSnapshotRequest(
- volumeName, bucketName, name64);
+ OMRequest omRequest2 = OMRequestTestUtils.deleteSnapshotRequest(
+ volumeName, bucketName, name64);
LambdaTestUtils.intercept(OMException.class,
- "Invalid snapshot name: " + name64,
- () -> doPreExecute(omRequest2));
+ "Invalid snapshot name: " + name64,
+ () -> doPreExecute(omRequest2));
}
@Test
public void testValidateAndUpdateCache() throws Exception {
when(ozoneManager.isAdmin(any())).thenReturn(true);
OMRequest omRequest =
- OMRequestTestUtils.createSnapshotRequest(
+ OMRequestTestUtils.deleteSnapshotRequest(
volumeName, bucketName, snapshotName);
- OMSnapshotCreateRequest omSnapshotCreateRequest =
+ OMSnapshotDeleteRequest omSnapshotDeleteRequest =
doPreExecute(omRequest);
String key = SnapshotInfo.getTableKey(volumeName,
bucketName, snapshotName);
@@ -199,71 +199,133 @@ public class TestOMSnapshotCreateRequest {
Assert.assertNull(omMetadataManager.getSnapshotInfoTable().get(key));
// add key to cache
+ SnapshotInfo snapshotInfo = SnapshotInfo.newInstance(
+ volumeName, bucketName, snapshotName, null);
+ Assert.assertEquals(SnapshotInfo.SnapshotStatus.SNAPSHOT_ACTIVE,
+ snapshotInfo.getSnapshotStatus());
+ omMetadataManager.getSnapshotInfoTable().addCacheEntry(
+ new CacheKey<>(key),
+ new CacheValue<>(Optional.of(snapshotInfo), 1L));
+
+ // Trigger validateAndUpdateCache
OMClientResponse omClientResponse =
- omSnapshotCreateRequest.validateAndUpdateCache(ozoneManager, 1,
+ omSnapshotDeleteRequest.validateAndUpdateCache(ozoneManager, 2L,
ozoneManagerDoubleBufferHelper);
-
+
// check cache
- SnapshotInfo snapshotInfo =
- omMetadataManager.getSnapshotInfoTable().get(key);
+ snapshotInfo = omMetadataManager.getSnapshotInfoTable().get(key);
Assert.assertNotNull(snapshotInfo);
+ Assert.assertEquals(SnapshotInfo.SnapshotStatus.SNAPSHOT_DELETED,
+ snapshotInfo.getSnapshotStatus());
+
+ OMResponse omResponse = omClientResponse.getOMResponse();
+
+ // check response success flag
+ Assert.assertTrue(omResponse.getSuccess());
+
+ Assert.assertNotNull(omResponse.getDeleteSnapshotResponse());
+ Assert.assertEquals(Type.DeleteSnapshot, omResponse.getCmdType());
+ Assert.assertEquals(Status.OK, omResponse.getStatus());
+ }
+
+ /**
+ * Expect snapshot deletion failure when snapshot entry does not exist.
+ */
+ @Test
+ public void testEntryNotExist() throws Exception {
+ when(ozoneManager.isAdmin(any())).thenReturn(true);
+ OMRequest omRequest = OMRequestTestUtils.deleteSnapshotRequest(
+ volumeName, bucketName, snapshotName);
+ OMSnapshotDeleteRequest omSnapshotDeleteRequest = doPreExecute(omRequest);
+ String key = SnapshotInfo.getTableKey(volumeName, bucketName,
snapshotName);
- // verify table data with response data.
- SnapshotInfo snapshotInfoFromProto = SnapshotInfo.getFromProtobuf(
- omClientResponse.getOMResponse()
- .getCreateSnapshotResponse().getSnapshotInfo());
- Assert.assertEquals(snapshotInfoFromProto, snapshotInfo);
+ // Entry does not exist
+ Assert.assertNull(omMetadataManager.getSnapshotInfoTable().get(key));
+
+ // Trigger delete snapshot validateAndUpdateCache
+ OMClientResponse omClientResponse =
+ omSnapshotDeleteRequest.validateAndUpdateCache(ozoneManager, 1L,
+ ozoneManagerDoubleBufferHelper);
OMResponse omResponse = omClientResponse.getOMResponse();
- Assert.assertNotNull(omResponse.getCreateSnapshotResponse());
- Assert.assertEquals(OzoneManagerProtocolProtos.Type.CreateSnapshot,
- omResponse.getCmdType());
- Assert.assertEquals(OzoneManagerProtocolProtos.Status.OK,
- omResponse.getStatus());
+ Assert.assertNotNull(omResponse.getDeleteSnapshotResponse());
+ Assert.assertEquals(Status.FILE_NOT_FOUND, omResponse.getStatus());
}
+ /**
+ * Expect successful snapshot deletion when snapshot entry exists.
+ * But a second deletion would result in an error.
+ */
@Test
public void testEntryExists() throws Exception {
when(ozoneManager.isAdmin(any())).thenReturn(true);
- OMRequest omRequest =
- OMRequestTestUtils.createSnapshotRequest(
+ String key = SnapshotInfo.getTableKey(volumeName, bucketName,
snapshotName);
+
+ OMRequest omRequest1 = OMRequestTestUtils.createSnapshotRequest(
volumeName, bucketName, snapshotName);
- OMSnapshotCreateRequest omSnapshotCreateRequest = doPreExecute(omRequest);
- String key = SnapshotInfo.getTableKey(volumeName,
- bucketName, snapshotName);
+ OMSnapshotCreateRequest omSnapshotCreateRequest =
+ TestOMSnapshotCreateRequest.doPreExecute(omRequest1, ozoneManager);
Assert.assertNull(omMetadataManager.getSnapshotInfoTable().get(key));
- //create entry
- omSnapshotCreateRequest.validateAndUpdateCache(ozoneManager, 1,
+ // Create snapshot entry
+ omSnapshotCreateRequest.validateAndUpdateCache(ozoneManager, 1L,
ozoneManagerDoubleBufferHelper);
SnapshotInfo snapshotInfo =
omMetadataManager.getSnapshotInfoTable().get(key);
Assert.assertNotNull(snapshotInfo);
+ Assert.assertEquals(SnapshotInfo.SnapshotStatus.SNAPSHOT_ACTIVE,
+ snapshotInfo.getSnapshotStatus());
- // Now try to create again to verify error
- omRequest =
- OMRequestTestUtils.createSnapshotRequest(
+ OMRequest omRequest2 = OMRequestTestUtils.deleteSnapshotRequest(
volumeName, bucketName, snapshotName);
- omSnapshotCreateRequest = doPreExecute(omRequest);
+ OMSnapshotDeleteRequest omSnapshotDeleteRequest = doPreExecute(omRequest2);
+
+ // Delete snapshot entry
OMClientResponse omClientResponse =
- omSnapshotCreateRequest.validateAndUpdateCache(ozoneManager, 2,
+ omSnapshotDeleteRequest.validateAndUpdateCache(ozoneManager, 2L,
ozoneManagerDoubleBufferHelper);
-
+
+ snapshotInfo = omMetadataManager.getSnapshotInfoTable().get(key);
+ // The snapshot entry should still exist in the table,
+ // but marked as DELETED.
+ Assert.assertNotNull(snapshotInfo);
+ Assert.assertEquals(SnapshotInfo.SnapshotStatus.SNAPSHOT_DELETED,
+ snapshotInfo.getSnapshotStatus());
+ Assert.assertTrue(snapshotInfo.getDeletionTime() > 0L);
+
+ // Response should be successful
OMResponse omResponse = omClientResponse.getOMResponse();
- Assert.assertNotNull(omResponse.getCreateSnapshotResponse());
- Assert.assertEquals(OzoneManagerProtocolProtos.Status.FILE_ALREADY_EXISTS,
- omResponse.getStatus());
+ Assert.assertNotNull(omResponse.getDeleteSnapshotResponse());
+ Assert.assertEquals(Status.OK, omResponse.getStatus());
+
+ // Now delete snapshot entry again, expect error
+ omRequest2 = OMRequestTestUtils.deleteSnapshotRequest(
+ volumeName, bucketName, snapshotName);
+ omSnapshotDeleteRequest = doPreExecute(omRequest2);
+ omClientResponse =
+ omSnapshotDeleteRequest.validateAndUpdateCache(ozoneManager, 3L,
+ ozoneManagerDoubleBufferHelper);
+
+ // Snapshot entry should still be there.
+ snapshotInfo = omMetadataManager.getSnapshotInfoTable().get(key);
+ Assert.assertNotNull(snapshotInfo);
+ Assert.assertEquals(SnapshotInfo.SnapshotStatus.SNAPSHOT_DELETED,
+ snapshotInfo.getSnapshotStatus());
+
+ omResponse = omClientResponse.getOMResponse();
+ Assert.assertNotNull(omResponse.getDeleteSnapshotResponse());
+ Assert.assertEquals(Status.FILE_NOT_FOUND, omResponse.getStatus());
}
- private OMSnapshotCreateRequest doPreExecute(
+ private OMSnapshotDeleteRequest doPreExecute(
OMRequest originalRequest) throws Exception {
- OMSnapshotCreateRequest omSnapshotCreateRequest =
- new OMSnapshotCreateRequest(originalRequest);
+ OMSnapshotDeleteRequest omSnapshotDeleteRequest =
+ new OMSnapshotDeleteRequest(originalRequest);
OMRequest modifiedRequest =
- omSnapshotCreateRequest.preExecute(ozoneManager);
- return new OMSnapshotCreateRequest(modifiedRequest);
+ omSnapshotDeleteRequest.preExecute(ozoneManager);
+ return new OMSnapshotDeleteRequest(modifiedRequest);
}
}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotDeleteResponse.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotDeleteResponse.java
new file mode 100644
index 0000000000..67a2afeea7
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotDeleteResponse.java
@@ -0,0 +1,125 @@
+/*
+ * 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.om.response.snapshot;
+
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.hdds.utils.db.BatchOperation;
+import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.ozone.om.OMConfigKeys;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
+import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateSnapshotResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.util.UUID;
+
+import static org.apache.hadoop.ozone.OzoneConsts.OM_DB_NAME;
+import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
+import static org.apache.hadoop.ozone.OzoneConsts.OM_SNAPSHOT_DIR;
+
+/**
+ * This class tests OMSnapshotDeleteResponse.
+ * TODO: WIP
+ */
+public class TestOMSnapshotDeleteResponse {
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ private OMMetadataManager omMetadataManager;
+ private BatchOperation batchOperation;
+ private String fsPath;
+
+ @Before
+ public void setup() throws Exception {
+ OzoneConfiguration ozoneConfiguration = new OzoneConfiguration();
+ fsPath = folder.newFolder().getAbsolutePath();
+ ozoneConfiguration.set(OMConfigKeys.OZONE_OM_DB_DIRS,
+ fsPath);
+ omMetadataManager = new OmMetadataManagerImpl(ozoneConfiguration);
+ batchOperation = omMetadataManager.getStore().initBatchOperation();
+ }
+
+ @After
+ public void tearDown() {
+ if (batchOperation != null) {
+ batchOperation.close();
+ }
+ }
+
+ @Test
+ public void testAddToDBBatch() throws Exception {
+ String volumeName = UUID.randomUUID().toString();
+ String bucketName = UUID.randomUUID().toString();
+ String snapshotName = UUID.randomUUID().toString();
+ String snapshotId = UUID.randomUUID().toString();
+ SnapshotInfo snapshotInfo = SnapshotInfo.newInstance(volumeName,
+ bucketName,
+ snapshotName,
+ snapshotId);
+
+ // confirm table is empty
+ Assert.assertEquals(0,
+ omMetadataManager
+ .countRowsInTable(omMetadataManager.getSnapshotInfoTable()));
+
+ // Prepare the table, write an entry with SnapshotCreate
+ OMSnapshotCreateResponse omSnapshotCreateResponse =
+ new OMSnapshotCreateResponse(OMResponse.newBuilder()
+ .setCmdType(OzoneManagerProtocolProtos.Type.CreateSnapshot)
+ .setStatus(OzoneManagerProtocolProtos.Status.OK)
+ .setCreateSnapshotResponse(
+ CreateSnapshotResponse.newBuilder()
+ .setSnapshotInfo(snapshotInfo.getProtobuf())
+ .build()).build(), volumeName, bucketName, snapshotName);
+ omSnapshotCreateResponse.addToDBBatch(omMetadataManager, batchOperation);
+ omMetadataManager.getStore().commitBatchOperation(batchOperation);
+
+ // Confirm snapshot directory was created
+ String snapshotDir = fsPath + OM_KEY_PREFIX +
+ OM_SNAPSHOT_DIR + OM_KEY_PREFIX + OM_DB_NAME +
+ snapshotInfo.getCheckpointDirName();
+ Assert.assertTrue((new File(snapshotDir)).exists());
+
+ // Confirm table has 1 entry
+ Assert.assertEquals(1, omMetadataManager
+ .countRowsInTable(omMetadataManager.getSnapshotInfoTable()));
+
+ // Check contents of entry
+ Table.KeyValue<String, SnapshotInfo> keyValue =
+ omMetadataManager.getSnapshotInfoTable().iterator().next();
+ SnapshotInfo storedInfo = keyValue.getValue();
+ Assert.assertEquals(snapshotInfo.getTableKey(), keyValue.getKey());
+ Assert.assertEquals(snapshotInfo, storedInfo);
+
+ // TODO: OMSnapshotDeleteResponse
+ // Confirm that the snapshot directory is gone
+ // Confirm that the table still has 1 entry, and its content
+ }
+}
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 e876b7fec1..aa1cb345df 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
@@ -616,6 +616,13 @@ public class ClientProtocolStub implements ClientProtocol {
return "";
}
+ @Override
+ public void deleteSnapshot(String volumeName,
+ String bucketName, String snapshotName)
+ throws IOException {
+
+ }
+
@Override
public List<OzoneSnapshot> listSnapshot(String volumeName, String bucketName)
throws IOException {
diff --git
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/CreateSnapshotHandler.java
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/CreateSnapshotHandler.java
index c92ffec40e..71ce63f75d 100644
---
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/CreateSnapshotHandler.java
+++
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/CreateSnapshotHandler.java
@@ -27,17 +27,16 @@ import picocli.CommandLine;
import java.io.IOException;
/**
- * ozone snapshot create.
+ * ozone sh snapshot create.
*/
@CommandLine.Command(name = "create",
- description = "create snapshot")
+ description = "Create a snapshot")
public class CreateSnapshotHandler extends Handler {
@CommandLine.Mixin
private BucketUri snapshotPath;
-
- @CommandLine.Parameters(description = "optional snapshot name",
+ @CommandLine.Parameters(description = "Snapshot name (Optional)",
index = "1", arity = "0..1")
private String snapshotName;
@@ -56,8 +55,8 @@ public class CreateSnapshotHandler extends Handler {
String newName = client.getObjectStore()
.createSnapshot(volumeName, bucketName, snapshotName);
if (isVerbose()) {
- out().format("created snapshot '%s/%s %s'.%n", volumeName, bucketName,
- newName);
+ out().format("Created snapshot '%s' under '%s/%s'.%n",
+ newName, volumeName, bucketName);
}
}
}
diff --git
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/CreateSnapshotHandler.java
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/DeleteSnapshotHandler.java
similarity index 74%
copy from
hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/CreateSnapshotHandler.java
copy to
hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/DeleteSnapshotHandler.java
index c92ffec40e..86faac229f 100644
---
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/CreateSnapshotHandler.java
+++
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/DeleteSnapshotHandler.java
@@ -17,7 +17,6 @@
*/
package org.apache.hadoop.ozone.shell.snapshot;
-import org.apache.hadoop.ozone.OmUtils;
import org.apache.hadoop.ozone.client.OzoneClient;
import org.apache.hadoop.ozone.shell.Handler;
import org.apache.hadoop.ozone.shell.OzoneAddress;
@@ -27,18 +26,17 @@ import picocli.CommandLine;
import java.io.IOException;
/**
- * ozone snapshot create.
+ * ozone snapshot delete.
*/
[email protected](name = "create",
- description = "create snapshot")
-public class CreateSnapshotHandler extends Handler {
[email protected](name = "delete",
+ description = "Delete a snapshot")
+public class DeleteSnapshotHandler extends Handler {
@CommandLine.Mixin
private BucketUri snapshotPath;
-
- @CommandLine.Parameters(description = "optional snapshot name",
- index = "1", arity = "0..1")
+ @CommandLine.Parameters(description = "Snapshot name",
+ index = "1", arity = "1")
private String snapshotName;
@Override
@@ -52,12 +50,12 @@ public class CreateSnapshotHandler extends Handler {
String volumeName = snapshotPath.getValue().getVolumeName();
String bucketName = snapshotPath.getValue().getBucketName();
- OmUtils.validateSnapshotName(snapshotName);
- String newName = client.getObjectStore()
- .createSnapshot(volumeName, bucketName, snapshotName);
+
+ client.getObjectStore()
+ .deleteSnapshot(volumeName, bucketName, snapshotName);
if (isVerbose()) {
- out().format("created snapshot '%s/%s %s'.%n", volumeName, bucketName,
- newName);
+ out().format("Deleted snapshot '%s' under '%s/%s'.%n",
+ snapshotName, volumeName, bucketName);
}
}
}
diff --git
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/ListSnapshotHandler.java
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/ListSnapshotHandler.java
index e3440d04e5..7ad4041bef 100644
---
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/ListSnapshotHandler.java
+++
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/ListSnapshotHandler.java
@@ -28,11 +28,12 @@ import java.io.IOException;
import java.util.List;
/**
+ * ozone sh snapshot list.
* a handler for Ozone shell CLI command 'list snapshot'.
*/
@CommandLine.Command(name = "list",
aliases = "ls",
- description = "list snapshot for the buckets.")
+ description = "List snapshots for the buckets.")
public class ListSnapshotHandler extends Handler {
@CommandLine.Mixin
diff --git
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/SnapshotCommands.java
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/SnapshotCommands.java
index 6d3f8d3a2f..a2169e04dc 100644
---
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/SnapshotCommands.java
+++
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/snapshot/SnapshotCommands.java
@@ -39,8 +39,9 @@ import picocli.CommandLine.ParentCommand;
description = "Snapshot specific operations",
subcommands = {
CreateSnapshotHandler.class,
+ DeleteSnapshotHandler.class,
ListSnapshotHandler.class,
- SnapshotDiffHandler.class,
+ SnapshotDiffHandler.class
},
mixinStandardHelpOptions = true,
versionProvider = HddsVersionProvider.class)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]