Skip to content

Commit f20cb4e

Browse files
authored
HDDS-2424. Add the recover-trash command server side handling. (#399)
1 parent b0051d7 commit f20cb4e

File tree

11 files changed

+257
-25
lines changed

11 files changed

+257
-25
lines changed

hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ List<RepeatedOmKeyInfo> listTrash(String volumeName, String bucketName,
342342
* @param bucketName - The bucket name.
343343
* @param keyName - The key user want to recover.
344344
* @param destinationBucket - The bucket user want to recover to.
345-
* @return The recoverTrash
345+
* @return The result of recovering operation is success or not.
346346
* @throws IOException
347347
*/
348348
boolean recoverTrash(String volumeName, String bucketName, String keyName,

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@ public static boolean isReadOnly(
229229
case LookupKey:
230230
case ListKeys:
231231
case ListTrash:
232-
case RecoverTrash:
233232
case ServiceList:
234233
case ListMultiPartUploadParts:
235234
case GetFileStatus:
@@ -264,6 +263,7 @@ public static boolean isReadOnly(
264263
case SetAcl:
265264
case AddAcl:
266265
case PurgeKeys:
266+
case RecoverTrash:
267267
return false;
268268
default:
269269
LOG.error("CmdType {} is not categorized as readOnly or not.", cmdType);
@@ -502,4 +502,18 @@ public static long getOMClientRpcTimeOut(Configuration configuration) {
502502
return OzoneConfiguration.of(configuration)
503503
.getObject(OMClientConfig.class).getRpcTimeOut();
504504
}
505+
506+
/**
507+
* Return OmKeyInfo that would be recovered.
508+
*/
509+
public static OmKeyInfo prepareKeyForRecover(OmKeyInfo keyInfo,
510+
RepeatedOmKeyInfo repeatedOmKeyInfo) {
511+
512+
/* TODO: HDDS-2425. HDDS-2426.*/
513+
if (repeatedOmKeyInfo.getOmKeyInfoList().contains(keyInfo)) {
514+
return keyInfo;
515+
} else {
516+
return null;
517+
}
518+
}
505519
}

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -500,10 +500,12 @@ List<RepeatedOmKeyInfo> listTrash(String volumeName, String bucketName,
500500
* @param bucketName - The bucket name.
501501
* @param keyName - The key user want to recover.
502502
* @param destinationBucket - The bucket user want to recover to.
503-
* @return The recoverTrash
503+
* @return The result of recovering operation is success or not.
504504
* @throws IOException
505505
*/
506-
boolean recoverTrash(String volumeName, String bucketName, String keyName,
507-
String destinationBucket) throws IOException;
506+
default boolean recoverTrash(String volumeName, String bucketName,
507+
String keyName, String destinationBucket) throws IOException {
508+
return false;
509+
}
508510

509511
}

hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,15 +1639,14 @@ public boolean recoverTrash(String volumeName, String bucketName,
16391639
"The destination bucket name cannot be null or empty. " +
16401640
"Please enter a valid destination bucket name.");
16411641

1642-
RecoverTrashRequest recoverRequest = RecoverTrashRequest.newBuilder()
1642+
RecoverTrashRequest.Builder req = RecoverTrashRequest.newBuilder()
16431643
.setVolumeName(volumeName)
16441644
.setBucketName(bucketName)
16451645
.setKeyName(keyName)
1646-
.setDestinationBucket(destinationBucket)
1647-
.build();
1646+
.setDestinationBucket(destinationBucket);
16481647

16491648
OMRequest omRequest = createOMRequest(Type.RecoverTrash)
1650-
.setRecoverTrashRequest(recoverRequest)
1649+
.setRecoverTrashRequest(req)
16511650
.build();
16521651

16531652
RecoverTrashResponse recoverResponse =

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,18 @@ List<OmKeyInfo> listKeys(String volumeName,
202202
List<RepeatedOmKeyInfo> listTrash(String volumeName, String bucketName,
203203
String startKeyName, String keyPrefix, int maxKeys) throws IOException;
204204

205+
/**
206+
* Recover trash allows the user to recover the keys
207+
* that were marked as deleted, but not actually deleted by Ozone Manager.
208+
* @param volumeName - The volume name.
209+
* @param bucketName - The bucket name.
210+
* @param keyName - The key user want to recover.
211+
* @param destinationBucket - The bucket user want to recover to.
212+
* @return The result of recovering operation is success or not.
213+
*/
214+
boolean recoverTrash(String volumeName, String bucketName,
215+
String keyName, String destinationBucket) throws IOException;
216+
205217
/**
206218
* Returns a list of volumes owned by a given user; if user is null, returns
207219
* all volumes.

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,18 @@ public List<RepeatedOmKeyInfo> listTrash(String volumeName, String bucketName,
804804
return deletedKeys;
805805
}
806806

807+
@Override
808+
public boolean recoverTrash(String volumeName, String bucketName,
809+
String keyName, String destinationBucket) throws IOException {
810+
811+
/* TODO: HDDS-2425 and HDDS-2426
812+
core logic stub would be added in later patch.
813+
*/
814+
815+
boolean recoverOperation = true;
816+
return recoverOperation;
817+
}
818+
807819
/**
808820
* @param userName volume owner, null for listing all volumes.
809821
*/

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2319,15 +2319,6 @@ public List<RepeatedOmKeyInfo> listTrash(String volumeName,
23192319
}
23202320
}
23212321

2322-
// TODO: HDDS-2424. recover-trash command server side handling.
2323-
@Override
2324-
public boolean recoverTrash(String volumeName, String bucketName,
2325-
String keyName, String destinationBucket) throws IOException {
2326-
2327-
boolean recoverOperation = true;
2328-
return recoverOperation;
2329-
}
2330-
23312322
/**
23322323
* Sets bucket property from args.
23332324
*

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.apache.hadoop.ozone.om.request.key.OMKeyDeleteRequest;
3535
import org.apache.hadoop.ozone.om.request.key.OMKeyPurgeRequest;
3636
import org.apache.hadoop.ozone.om.request.key.OMKeyRenameRequest;
37+
import org.apache.hadoop.ozone.om.request.key.OMTrashRecoverRequest;
3738
import org.apache.hadoop.ozone.om.request.key.acl.OMKeyAddAclRequest;
3839
import org.apache.hadoop.ozone.om.request.key.acl.OMKeyRemoveAclRequest;
3940
import org.apache.hadoop.ozone.om.request.key.acl.OMKeySetAclRequest;
@@ -140,6 +141,8 @@ public static OMClientRequest createClientRequest(OMRequest omRequest) {
140141
return new OMRenewDelegationTokenRequest(omRequest);
141142
case GetS3Secret:
142143
return new S3GetSecretRequest(omRequest);
144+
case RecoverTrash:
145+
return new OMTrashRecoverRequest(omRequest);
143146
default:
144147
throw new IllegalStateException("Unrecognized write command " +
145148
"type request" + cmdType);
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.ozone.om.request.key;
20+
21+
import java.io.IOException;
22+
23+
import com.google.common.base.Preconditions;
24+
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
25+
import org.apache.hadoop.ozone.om.response.key.OMTrashRecoverResponse;
26+
import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
29+
30+
import org.apache.hadoop.ozone.om.OMMetadataManager;
31+
import org.apache.hadoop.ozone.om.OzoneManager;
32+
import org.apache.hadoop.ozone.om.response.OMClientResponse;
33+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
34+
.RecoverTrashRequest;
35+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
36+
.OMResponse;
37+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
38+
.OMRequest;
39+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
40+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status;
41+
42+
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
43+
44+
/**
45+
* Handles RecoverTrash request.
46+
*/
47+
public class OMTrashRecoverRequest extends OMKeyRequest {
48+
private static final Logger LOG =
49+
LoggerFactory.getLogger(OMTrashRecoverRequest.class);
50+
51+
public OMTrashRecoverRequest(OMRequest omRequest) {
52+
super(omRequest);
53+
}
54+
55+
@Override
56+
public OMRequest preExecute(OzoneManager ozoneManager) {
57+
RecoverTrashRequest recoverTrashRequest = getOmRequest()
58+
.getRecoverTrashRequest();
59+
Preconditions.checkNotNull(recoverTrashRequest);
60+
61+
return getOmRequest().toBuilder().build();
62+
}
63+
64+
@Override
65+
public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
66+
long transactionLogIndex,
67+
OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper) {
68+
RecoverTrashRequest recoverTrashRequest = getOmRequest()
69+
.getRecoverTrashRequest();
70+
Preconditions.checkNotNull(recoverTrashRequest);
71+
72+
String volumeName = recoverTrashRequest.getVolumeName();
73+
String bucketName = recoverTrashRequest.getBucketName();
74+
String keyName = recoverTrashRequest.getKeyName();
75+
String destinationBucket = recoverTrashRequest.getDestinationBucket();
76+
77+
/** TODO: HDDS-2818. New Metrics for Trash Key Recover and Fails.
78+
* OMMetrics omMetrics = ozoneManager.getMetrics();
79+
*/
80+
81+
OMResponse.Builder omResponse = OMResponse.newBuilder()
82+
.setCmdType(Type.RecoverTrash).setStatus(Status.OK)
83+
.setSuccess(true);
84+
85+
OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
86+
boolean acquireLock = false;
87+
OMClientResponse omClientResponse = null;
88+
try {
89+
// Check acl for the destination bucket.
90+
checkBucketAcls(ozoneManager, volumeName, destinationBucket, keyName,
91+
IAccessAuthorizer.ACLType.WRITE);
92+
93+
acquireLock = omMetadataManager.getLock()
94+
.acquireWriteLock(BUCKET_LOCK, volumeName, destinationBucket);
95+
96+
// Validate.
97+
validateBucketAndVolume(omMetadataManager, volumeName, bucketName);
98+
validateBucketAndVolume(omMetadataManager, volumeName, destinationBucket);
99+
100+
101+
/** TODO: HDDS-2425. HDDS-2426.
102+
* Update cache.
103+
* omMetadataManager.getKeyTable().addCacheEntry(
104+
* new CacheKey<>(),
105+
* new CacheValue<>()
106+
* );
107+
*
108+
* Execute recovering trash in non-existing bucket.
109+
* Execute recovering trash in existing bucket.
110+
* omClientResponse = new OMTrashRecoverResponse(omKeyInfo,
111+
* omResponse.setRecoverTrashResponse(
112+
* RecoverTrashResponse.newBuilder())
113+
* .build());
114+
*/
115+
omClientResponse = null;
116+
117+
} catch (IOException ex) {
118+
LOG.error("Fail for recovering trash.", ex);
119+
omClientResponse = new OMTrashRecoverResponse(null,
120+
createErrorOMResponse(omResponse, ex));
121+
} finally {
122+
if (omClientResponse != null) {
123+
omClientResponse.setFlushFuture(
124+
ozoneManagerDoubleBufferHelper.add(omClientResponse,
125+
transactionLogIndex));
126+
}
127+
if (acquireLock) {
128+
omMetadataManager.getLock().releaseWriteLock(BUCKET_LOCK, volumeName,
129+
destinationBucket);
130+
}
131+
}
132+
133+
return omClientResponse;
134+
}
135+
136+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
* <p>
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
* <p>
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package org.apache.hadoop.ozone.om.response.key;
20+
21+
import org.apache.hadoop.ozone.OmUtils;
22+
import org.apache.hadoop.ozone.om.OMMetadataManager;
23+
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
24+
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
25+
import org.apache.hadoop.ozone.om.response.OMClientResponse;
26+
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
27+
.OMResponse;
28+
import org.apache.hadoop.hdds.utils.db.BatchOperation;
29+
30+
import java.io.IOException;
31+
import javax.annotation.Nullable;
32+
import javax.annotation.Nonnull;
33+
34+
/**
35+
* Response for RecoverTrash request.
36+
*/
37+
public class OMTrashRecoverResponse extends OMClientResponse {
38+
private OmKeyInfo omKeyInfo;
39+
40+
public OMTrashRecoverResponse(@Nullable OmKeyInfo omKeyInfo,
41+
@Nonnull OMResponse omResponse) {
42+
super(omResponse);
43+
this.omKeyInfo = omKeyInfo;
44+
}
45+
46+
@Override
47+
public void addToDBBatch(OMMetadataManager omMetadataManager,
48+
BatchOperation batchOperation) throws IOException {
49+
50+
/* TODO: HDDS-2425. HDDS-2426. */
51+
String trashKey = omMetadataManager
52+
.getOzoneKey(omKeyInfo.getVolumeName(),
53+
omKeyInfo.getBucketName(), omKeyInfo.getKeyName());
54+
RepeatedOmKeyInfo repeatedOmKeyInfo = omMetadataManager
55+
.getDeletedTable().get(trashKey);
56+
omKeyInfo = OmUtils.prepareKeyForRecover(omKeyInfo, repeatedOmKeyInfo);
57+
omMetadataManager.getDeletedTable()
58+
.deleteWithBatch(batchOperation, omKeyInfo.getKeyName());
59+
/* TODO: trashKey should be updated to destinationBucket. */
60+
omMetadataManager.getKeyTable()
61+
.putWithBatch(batchOperation, trashKey, omKeyInfo);
62+
}
63+
64+
}

0 commit comments

Comments
 (0)