-
Notifications
You must be signed in to change notification settings - Fork 587
HDDS-2424. Add the recover-trash command server side handling. #399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4097f78
9cd630c
dbd1f6e
cacad8c
0124f7d
1114163
4dcc334
a77b242
e0e5948
a2b4608
632bc91
8e0d302
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| /** | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * <p> | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * <p> | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.hadoop.ozone.om.request.key; | ||
|
|
||
| import java.io.IOException; | ||
|
|
||
| import com.google.common.base.Preconditions; | ||
| import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper; | ||
| import org.apache.hadoop.ozone.om.response.key.OMTrashRecoverResponse; | ||
| import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import org.apache.hadoop.ozone.om.OMMetadataManager; | ||
| import org.apache.hadoop.ozone.om.OzoneManager; | ||
| import org.apache.hadoop.ozone.om.response.OMClientResponse; | ||
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos | ||
| .RecoverTrashRequest; | ||
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos | ||
| .OMResponse; | ||
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos | ||
| .OMRequest; | ||
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; | ||
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status; | ||
|
|
||
| import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK; | ||
|
|
||
| /** | ||
| * Handles RecoverTrash request. | ||
| */ | ||
| public class OMTrashRecoverRequest extends OMKeyRequest { | ||
| private static final Logger LOG = | ||
| LoggerFactory.getLogger(OMTrashRecoverRequest.class); | ||
|
|
||
| public OMTrashRecoverRequest(OMRequest omRequest) { | ||
| super(omRequest); | ||
| } | ||
|
|
||
| @Override | ||
| public OMRequest preExecute(OzoneManager ozoneManager) { | ||
| RecoverTrashRequest recoverTrashRequest = getOmRequest() | ||
| .getRecoverTrashRequest(); | ||
| Preconditions.checkNotNull(recoverTrashRequest); | ||
|
|
||
| return getOmRequest().toBuilder().build(); | ||
| } | ||
|
|
||
| @Override | ||
| public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, | ||
| long transactionLogIndex, | ||
| OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper) { | ||
| RecoverTrashRequest recoverTrashRequest = getOmRequest() | ||
| .getRecoverTrashRequest(); | ||
| Preconditions.checkNotNull(recoverTrashRequest); | ||
|
|
||
| String volumeName = recoverTrashRequest.getVolumeName(); | ||
| String bucketName = recoverTrashRequest.getBucketName(); | ||
| String keyName = recoverTrashRequest.getKeyName(); | ||
| String destinationBucket = recoverTrashRequest.getDestinationBucket(); | ||
|
|
||
| /** TODO: HDDS-2818. New Metrics for Trash Key Recover and Fails. | ||
| * OMMetrics omMetrics = ozoneManager.getMetrics(); | ||
| */ | ||
|
|
||
| OMResponse.Builder omResponse = OMResponse.newBuilder() | ||
| .setCmdType(Type.RecoverTrash).setStatus(Status.OK) | ||
| .setSuccess(true); | ||
|
|
||
| OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager(); | ||
| boolean acquireLock = false; | ||
| OMClientResponse omClientResponse = null; | ||
| try { | ||
| // Check acl for the destination bucket. | ||
| checkBucketAcls(ozoneManager, volumeName, destinationBucket, keyName, | ||
| IAccessAuthorizer.ACLType.WRITE); | ||
|
|
||
| acquireLock = omMetadataManager.getLock() | ||
| .acquireWriteLock(BUCKET_LOCK, volumeName, destinationBucket); | ||
|
|
||
| // Validate. | ||
| validateBucketAndVolume(omMetadataManager, volumeName, bucketName); | ||
| validateBucketAndVolume(omMetadataManager, volumeName, destinationBucket); | ||
|
|
||
|
|
||
| /** TODO: HDDS-2425. HDDS-2426. | ||
| * Update cache. | ||
| * omMetadataManager.getKeyTable().addCacheEntry( | ||
| * new CacheKey<>(), | ||
| * new CacheValue<>() | ||
| * ); | ||
| * | ||
| * Execute recovering trash in non-existing bucket. | ||
| * Execute recovering trash in existing bucket. | ||
| * omClientResponse = new OMTrashRecoverResponse(omKeyInfo, | ||
| * omResponse.setRecoverTrashResponse( | ||
| * RecoverTrashResponse.newBuilder()) | ||
| * .build()); | ||
| */ | ||
| omClientResponse = null; | ||
|
|
||
| } catch (IOException ex) { | ||
| LOG.error("Fail for recovering trash.", ex); | ||
| omClientResponse = new OMTrashRecoverResponse(null, | ||
| createErrorOMResponse(omResponse, ex)); | ||
| } finally { | ||
| if (omClientResponse != null) { | ||
| omClientResponse.setFlushFuture( | ||
| ozoneManagerDoubleBufferHelper.add(omClientResponse, | ||
| transactionLogIndex)); | ||
| } | ||
| if (acquireLock) { | ||
| omMetadataManager.getLock().releaseWriteLock(BUCKET_LOCK, volumeName, | ||
| destinationBucket); | ||
| } | ||
| } | ||
|
|
||
| return omClientResponse; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| /** | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * <p> | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * <p> | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| package org.apache.hadoop.ozone.om.response.key; | ||
|
|
||
| import org.apache.hadoop.ozone.OmUtils; | ||
| import org.apache.hadoop.ozone.om.OMMetadataManager; | ||
| import org.apache.hadoop.ozone.om.helpers.OmKeyInfo; | ||
| import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; | ||
| import org.apache.hadoop.ozone.om.response.OMClientResponse; | ||
| import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos | ||
| .OMResponse; | ||
| import org.apache.hadoop.hdds.utils.db.BatchOperation; | ||
|
|
||
| import java.io.IOException; | ||
| import javax.annotation.Nullable; | ||
| import javax.annotation.Nonnull; | ||
|
|
||
| /** | ||
| * Response for RecoverTrash request. | ||
| */ | ||
| public class OMTrashRecoverResponse extends OMClientResponse { | ||
| private OmKeyInfo omKeyInfo; | ||
|
|
||
| public OMTrashRecoverResponse(@Nullable OmKeyInfo omKeyInfo, | ||
cxorm marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| @Nonnull OMResponse omResponse) { | ||
| super(omResponse); | ||
| this.omKeyInfo = omKeyInfo; | ||
| } | ||
|
|
||
| @Override | ||
| public void addToDBBatch(OMMetadataManager omMetadataManager, | ||
| BatchOperation batchOperation) throws IOException { | ||
|
|
||
| /* TODO: HDDS-2425. HDDS-2426. */ | ||
| String trashKey = omMetadataManager | ||
| .getOzoneKey(omKeyInfo.getVolumeName(), | ||
| omKeyInfo.getBucketName(), omKeyInfo.getKeyName()); | ||
| RepeatedOmKeyInfo repeatedOmKeyInfo = omMetadataManager | ||
| .getDeletedTable().get(trashKey); | ||
| omKeyInfo = OmUtils.prepareKeyForRecover(omKeyInfo, repeatedOmKeyInfo); | ||
| omMetadataManager.getDeletedTable() | ||
| .deleteWithBatch(batchOperation, omKeyInfo.getKeyName()); | ||
| /* TODO: trashKey should be updated to destinationBucket. */ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One question:
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you @bharatviswa504 for the question. Refer to processing of So I think we could recover the latest deleted key from the Would you please give me advice if I miss something ?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am fine with recovering last delete key if that is the expected behavior.
And also doing this way, is also not correct from my understanding, let us say, we put those keys in delete table, and background delete key service will pick them up and send to SCM for deletion, at this point we got a recover trash command, so there is a chance that we recover the key which might have no data, as we submitted the request to SCM for deletion, and SCM, in turn, it will send to DN. How we shall handle this kind of scenarios? Because deletion from delete table will happen when key purge request happens. Code snippet link #link
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. /pending I'm tracing the background part. (Hope soon)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you @bharatviswa504 for taking time to review this. Here is my thought, So I think we can compare the Code snippet would be added after this line might like if (trashEnable(info.getBucketName()) &&
(Time.now() - info.getModificationTime()) < RECOVERY_WINDOW) {
/* Would not delete key in this situation. */
}note Could you please give me your thoughts or ideas if I miss something, thank you. And here is discussion about trash-recovery. |
||
| omMetadataManager.getKeyTable() | ||
| .putWithBatch(batchOperation, trashKey, omKeyInfo); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -55,6 +55,7 @@ public class TestTrashService { | |
| public TemporaryFolder tempFolder = new TemporaryFolder(); | ||
|
|
||
| private KeyManager keyManager; | ||
| private OmMetadataManagerImpl omMetadataManager; | ||
| private String volumeName; | ||
| private String bucketName; | ||
|
|
||
|
|
@@ -69,8 +70,8 @@ public void setup() throws IOException { | |
| System.setProperty(DBConfigFromFile.CONFIG_DIR, "/"); | ||
| ServerUtils.setOzoneMetaDirPath(configuration, folder.toString()); | ||
|
|
||
| OmMetadataManagerImpl omMetadataManager = | ||
| new OmMetadataManagerImpl(configuration); | ||
| omMetadataManager = new OmMetadataManagerImpl(configuration); | ||
|
|
||
| keyManager = new KeyManagerImpl( | ||
| new ScmBlockLocationTestingClient(null, null, 0), | ||
| omMetadataManager, configuration, UUID.randomUUID().toString(), null); | ||
|
|
@@ -86,11 +87,9 @@ public void testRecoverTrash() throws IOException { | |
| String destinationBucket = "destBucket"; | ||
| createAndDeleteKey(keyName); | ||
|
|
||
| /* TODO:HDDS-2424. */ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, what i means is like this TODO comment. |
||
| // boolean recoverOperation = | ||
| // ozoneManager.recoverTrash( | ||
| // volumeName, bucketName, keyName, destinationBucket); | ||
| // Assert.assertTrue(recoverOperation); | ||
| boolean recoverOperation = omMetadataManager | ||
| .recoverTrash(volumeName, bucketName, keyName, destinationBucket); | ||
| Assert.assertTrue(recoverOperation); | ||
| } | ||
|
|
||
| private void createAndDeleteKey(String keyName) throws IOException { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bharatviswa504
What do you think about this
cleanup write-request?Could we set the write-operation with a
defaultorwe need a separated interface addressed the
write-operation?