This is an automated email from the ASF dual-hosted git repository.
weichiu 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 a92e10741a HDDS-8278. O3fs/ofs to support setTimes() API (#4720)
a92e10741a is described below
commit a92e10741a5b3e4a2603f1fd436353994511f5b1
Author: Wei-Chiu Chuang <[email protected]>
AuthorDate: Wed May 31 15:35:21 2023 -0700
HDDS-8278. O3fs/ofs to support setTimes() API (#4720)
---
.../apache/hadoop/ozone/client/OzoneBucket.java | 14 ++
.../ozone/client/protocol/ClientProtocol.java | 13 ++
.../apache/hadoop/ozone/client/rpc/RpcClient.java | 10 +
.../main/java/org/apache/hadoop/ozone/OmUtils.java | 1 +
.../org/apache/hadoop/ozone/audit/OMAction.java | 3 +-
.../ozone/om/protocol/OzoneManagerProtocol.java | 12 +
...OzoneManagerProtocolClientSideTranslatorPB.java | 22 ++
.../hadoop/fs/ozone/TestOzoneFileSystem.java | 24 ++
.../hadoop/fs/ozone/TestRootedOzoneFileSystem.java | 27 +++
.../src/main/proto/OmClientProtocol.proto | 12 +
.../java/org/apache/hadoop/ozone/om/OMMetrics.java | 5 +
.../org/apache/hadoop/ozone/om/OzoneManager.java | 5 +
.../om/ratis/utils/OzoneManagerRatisUtils.java | 5 +
.../BucketLayoutAwareOMKeyRequestFactory.java | 11 +
.../ozone/om/request/key/OMKeySetTimesRequest.java | 244 +++++++++++++++++++++
.../request/key/OMKeySetTimesRequestWithFSO.java | 162 ++++++++++++++
.../om/response/key/OMKeySetTimesResponse.java | 78 +++++++
.../response/key/OMKeySetTimesResponseWithFSO.java | 84 +++++++
.../request/TestBucketLayoutAwareOMKeyFactory.java | 6 +-
.../om/request/key/TestOMSetTimesRequest.java | 114 ++++++++++
.../request/key/TestOMSetTimesRequestWithFSO.java | 106 +++++++++
.../fs/ozone/BasicOzoneClientAdapterImpl.java | 6 +
.../hadoop/fs/ozone/BasicOzoneFileSystem.java | 10 +
.../ozone/BasicRootedOzoneClientAdapterImpl.java | 8 +
.../fs/ozone/BasicRootedOzoneFileSystem.java | 14 ++
.../apache/hadoop/fs/ozone/OzoneClientAdapter.java | 2 +
.../java/org/apache/hadoop/fs/ozone/Statistic.java | 4 +-
.../hadoop/ozone/client/ClientProtocolStub.java | 5 +
28 files changed, 1002 insertions(+), 5 deletions(-)
diff --git
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
index 57c612f224..300ae817c4 100644
---
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
+++
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
@@ -890,6 +890,20 @@ public class OzoneBucket extends WithMetadata {
return result;
}
+ /**
+ * Builder for OmBucketInfo.
+ /**
+ * Set time to a key in this bucket.
+ * @param keyName Full path name to the key in the bucket.
+ * @param mtime Modification time. Unchanged if -1.
+ * @param atime Access time. Unchanged if -1.
+ * @throws IOException
+ */
+ public void setTimes(String keyName, long mtime, long atime)
+ throws IOException {
+ proxy.setTimes(ozoneObj, keyName, mtime, atime);
+ }
+
public void setSourcePathExist(boolean b) {
this.sourcePathExist = b;
}
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 1647d11e31..ceb3fcad1c 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
@@ -1071,4 +1071,17 @@ public interface ClientProtocol {
String token, int pageSize,
boolean forceFullDiff)
throws IOException;
+
+ /**
+ * Time to be set for given Ozone object. This operations updates
modification
+ * time and access time for the given key.
+ * @param obj Ozone object.
+ * @param keyName Full path name to the key in the bucket.
+ * @param mtime Modification time. Unchanged if -1.
+ * @param atime Access time. Unchanged if -1.
+ *
+ * @throws IOException if there is error.
+ * */
+ void setTimes(OzoneObj obj, String keyName, long mtime, long atime)
+ 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 06a1d3d61d..81d10381a9 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
@@ -2341,6 +2341,16 @@ public class RpcClient implements ClientProtocol {
return ozoneManagerClient.setBucketOwner(builder.build());
}
+ @Override
+ public void setTimes(OzoneObj obj, String keyName, long mtime, long atime)
+ throws IOException {
+ OmKeyArgs.Builder builder = new OmKeyArgs.Builder()
+ .setVolumeName(obj.getVolumeName())
+ .setBucketName(obj.getBucketName())
+ .setKeyName(keyName);
+ ozoneManagerClient.setTimes(builder.build(), mtime, atime);
+ }
+
public ExecutorService getECReconstructExecutor() {
// local ref to a volatile to ensure access
// to a completed initialized object
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 9d510aa739..f366ae1875 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
@@ -315,6 +315,7 @@ public final class OmUtils {
case SnapshotMoveDeletedKeys:
case SnapshotPurge:
case RecoverLease:
+ case SetTimes:
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 c7ee247569..3b96267c97 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
@@ -98,7 +98,8 @@ public enum OMAction implements AuditAction {
CREATE_SNAPSHOT,
LIST_SNAPSHOT,
DELETE_SNAPSHOT,
- SNAPSHOT_MOVE_DELETED_KEYS;
+ SNAPSHOT_MOVE_DELETED_KEYS,
+ SET_TIMES;
@Override
public String getAction() {
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 713953b634..1a9f3c6a0b 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
@@ -998,4 +998,16 @@ public interface OzoneManagerProtocol
*/
boolean recoverLease(String volumeName, String bucketName,
String keyName) throws IOException;
+
+ /**
+ * Update modification time and access time of a file.
+ * Access time is currently ignored by Ozone Manager.
+ *
+ * @param keyArgs - The key argument.
+ * @param mtime - modification time.
+ * @param atime - access time. Ignored by Ozone Manager.
+ * @throws IOException
+ */
+ void setTimes(OmKeyArgs keyArgs, long mtime, long atime)
+ throws IOException;
}
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 5501bf1a14..39206e5094 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
@@ -171,6 +171,7 @@ import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetAclR
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetBucketPropertyRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetS3SecretRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetS3SecretResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetTimesRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetVolumePropertyRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantAssignAdminRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantAssignUserAccessIdRequest;
@@ -2210,6 +2211,27 @@ public final class
OzoneManagerProtocolClientSideTranslatorPB
return recoverLeaseResponse.getResponse();
}
+ @Override
+ public void setTimes(OmKeyArgs args, long mtime, long atime)
+ throws IOException {
+ KeyArgs keyArgs = KeyArgs.newBuilder()
+ .setVolumeName(args.getVolumeName())
+ .setBucketName(args.getBucketName())
+ .setKeyName(args.getKeyName())
+ .build();
+ SetTimesRequest setTimesRequest =
+ SetTimesRequest.newBuilder()
+ .setKeyArgs(keyArgs)
+ .setMtime(mtime)
+ .setAtime(atime)
+ .build();
+
+ OMRequest omRequest = createOMRequest(Type.SetTimes)
+ .setSetTimesRequest(setTimesRequest).build();
+
+ handleError(submitRequest(omRequest));
+ }
+
@VisibleForTesting
public OmTransport getTransport() {
return transport;
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystem.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystem.java
index 754470960b..3ae28b9121 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystem.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestOzoneFileSystem.java
@@ -1752,4 +1752,28 @@ public class TestOzoneFileSystem {
assertHasPathCapabilities(fs, root, FS_ACLS);
assertHasPathCapabilities(fs, root, FS_CHECKSUMS);
}
+
+ @Test
+ public void testSetTimes() throws Exception {
+ // Create a file
+ String testKeyName = "testKey1";
+ Path path = new Path(OZONE_URI_DELIMITER, testKeyName);
+ try (FSDataOutputStream stream = fs.create(path)) {
+ stream.write(1);
+ }
+
+ long mtime = 1000;
+ fs.setTimes(path, mtime, 2000);
+
+ FileStatus fileStatus = fs.getFileStatus(path);
+ // verify that mtime is updated as expected.
+ Assert.assertEquals(mtime, fileStatus.getModificationTime());
+
+ long mtimeDontUpdate = -1;
+ fs.setTimes(path, mtimeDontUpdate, 2000);
+
+ fileStatus = fs.getFileStatus(path);
+ // verify that mtime is NOT updated as expected.
+ Assert.assertEquals(mtime, fileStatus.getModificationTime());
+ }
}
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java
index 25f3dff3c1..4ea79970f2 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestRootedOzoneFileSystem.java
@@ -2516,4 +2516,31 @@ public class TestRootedOzoneFileSystem {
() -> ofs.getSnapshotDiffReport(volumePath1, finalFromSnap,
finalToSnap));
}
+
+ @Test
+ public void testSetTimes() throws Exception {
+ // Create a file
+ OzoneBucket bucket1 =
+ TestDataUtil.createVolumeAndBucket(client, bucketLayout);
+ Path volumePath1 = new Path(OZONE_URI_DELIMITER, bucket1.getVolumeName());
+ Path bucketPath1 = new Path(volumePath1, bucket1.getName());
+ Path path = new Path(bucketPath1, "key1");
+ try (FSDataOutputStream stream = fs.create(path)) {
+ stream.write(1);
+ }
+
+ long mtime = 1000;
+ fs.setTimes(path, mtime, 2000);
+
+ FileStatus fileStatus = fs.getFileStatus(path);
+ // verify that mtime is updated as expected.
+ Assert.assertEquals(mtime, fileStatus.getModificationTime());
+
+ long mtimeDontUpdate = -1;
+ fs.setTimes(path, mtimeDontUpdate, 2000);
+
+ fileStatus = fs.getFileStatus(path);
+ // verify that mtime is NOT updated as expected.
+ Assert.assertEquals(mtime, fileStatus.getModificationTime());
+ }
}
diff --git
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 3596cb2a40..869713bf3c 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -134,6 +134,7 @@ enum Type {
TransferLeadership = 117;
SnapshotPurge = 118;
RecoverLease = 119;
+ SetTimes = 120;
}
message OMRequest {
@@ -252,6 +253,7 @@ message OMRequest {
optional SnapshotPurgeRequest SnapshotPurgeRequest =
118;
optional RecoverLeaseRequest RecoverLeaseRequest =
119;
+ optional SetTimesRequest SetTimesRequest =
120;
}
message OMResponse {
@@ -362,6 +364,7 @@ message OMResponse {
optional hdds.TransferLeadershipResponseProto TransferOmLeadershipResponse
= 117;
optional SnapshotPurgeResponse SnapshotPurgeResponse =
118;
optional RecoverLeaseResponse RecoverLeaseResponse =
119;
+ optional SetTimesResponse SetTimesResponse =
120;
}
enum Status {
@@ -1878,6 +1881,15 @@ message RecoverLeaseResponse {
optional bool response = 1;
}
+message SetTimesRequest {
+ required KeyArgs keyArgs = 1;
+ required uint64 mtime = 2;
+ required uint64 atime = 3;
+}
+
+message SetTimesResponse {
+}
+
/**
The OM service that takes care of Ozone namespace.
*/
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 5151e0dfc7..4a15a43ffb 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
@@ -89,6 +89,7 @@ public class OMMetrics implements OmMetadataReaderMetrics {
private @Metric MutableCounterLong numSetAcl;
private @Metric MutableCounterLong numGetAcl;
private @Metric MutableCounterLong numRemoveAcl;
+ private @Metric MutableCounterLong numSetTime;
private @Metric MutableCounterLong numGetKeyInfo;
// Failure Metrics
@@ -832,6 +833,10 @@ public class OMMetrics implements OmMetadataReaderMetrics {
numRemoveAcl.incr();
}
+ public void incNumSetTime() {
+ numSetTime.incr();
+ }
+
@Override
public void incNumGetKeyInfo() {
numGetKeyInfo.incr();
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 45982556ce..9e57c4db8a 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
@@ -4499,6 +4499,11 @@ public final class OzoneManager extends
ServiceRuntimeInfoImpl
return false;
}
+ @Override
+ public void setTimes(OmKeyArgs keyArgs, long mtime, long atime)
+ throws IOException {
+ }
+
/**
* Write down Layout version of a finalized feature to DB on finalization.
* @param lvm OMLayoutVersionManager
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 b092e05850..595cf80b4d 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
@@ -314,6 +314,11 @@ public final class OzoneManagerRatisUtils {
volumeName = keyArgs.getVolumeName();
bucketName = keyArgs.getBucketName();
break;
+ case SetTimes:
+ keyArgs = omRequest.getSetTimesRequest().getKeyArgs();
+ volumeName = keyArgs.getVolumeName();
+ bucketName = keyArgs.getBucketName();
+ break;
default:
throw new IllegalStateException("Unrecognized write command " +
"type request" + cmdType);
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/BucketLayoutAwareOMKeyRequestFactory.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/BucketLayoutAwareOMKeyRequestFactory.java
index 051e6e71e9..4321b7872c 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/BucketLayoutAwareOMKeyRequestFactory.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/BucketLayoutAwareOMKeyRequestFactory.java
@@ -36,6 +36,8 @@ import
org.apache.hadoop.ozone.om.request.key.OMAllocateBlockRequest;
import org.apache.hadoop.ozone.om.request.key.OMAllocateBlockRequestWithFSO;
import org.apache.hadoop.ozone.om.request.key.OMKeyCommitRequest;
import org.apache.hadoop.ozone.om.request.key.OMKeyCommitRequestWithFSO;
+import org.apache.hadoop.ozone.om.request.key.OMKeySetTimesRequest;
+import org.apache.hadoop.ozone.om.request.key.OMKeySetTimesRequestWithFSO;
import org.apache.hadoop.ozone.om.request.key.OMKeysDeleteRequest;
import org.apache.hadoop.ozone.om.request.key.OMKeysRenameRequest;
import org.apache.hadoop.ozone.om.request.key.OmKeysDeleteRequestWithFSO;
@@ -180,6 +182,15 @@ public final class BucketLayoutAwareOMKeyRequestFactory {
addRequestClass(Type.CompleteMultiPartUpload,
S3MultipartUploadCompleteRequestWithFSO.class,
BucketLayout.FILE_SYSTEM_OPTIMIZED);
+
+ // SetTimes
+ addRequestClass(Type.SetTimes,
+ OMKeySetTimesRequest.class,
+ BucketLayout.OBJECT_STORE
+ );
+ addRequestClass(Type.SetTimes,
+ OMKeySetTimesRequestWithFSO.class,
+ BucketLayout.FILE_SYSTEM_OPTIMIZED);
}
private BucketLayoutAwareOMKeyRequestFactory() {
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequest.java
new file mode 100644
index 0000000000..6dce387d1b
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequest.java
@@ -0,0 +1,244 @@
+/**
+ * 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 java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
+import org.apache.hadoop.ozone.OzoneConsts;
+import org.apache.hadoop.ozone.audit.AuditLogger;
+import org.apache.hadoop.ozone.audit.OMAction;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
+import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
+import org.apache.hadoop.ozone.om.response.key.OMKeySetTimesResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetTimesRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetTimesResponse;
+import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
+import org.apache.hadoop.ozone.security.acl.OzoneObj;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+
+import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
+
+/**
+ * Handle add SetTimes request for key.
+ */
+public class OMKeySetTimesRequest extends OMKeyRequest {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(OMKeySetTimesRequest.class);
+
+ @Override
+ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+ OMRequest request = super.preExecute(ozoneManager);
+ SetTimesRequest setTimesRequest = request.getSetTimesRequest();
+ String keyPath = setTimesRequest.getKeyArgs().getKeyName();
+ String normalizedKeyPath =
+ validateAndNormalizeKey(ozoneManager.getEnableFileSystemPaths(),
+ keyPath, getBucketLayout());
+
+ OzoneManagerProtocolProtos.KeyArgs keyArgs =
+ OzoneManagerProtocolProtos.KeyArgs.newBuilder()
+ .setVolumeName(getVolumeName())
+ .setBucketName(getBucketName())
+ .setKeyName(normalizedKeyPath)
+ .build();
+
+ return request.toBuilder()
+ .setSetTimesRequest(
+ setTimesRequest.toBuilder()
+ .setKeyArgs(keyArgs)
+ .setMtime(getModificationTime()))
+ .build();
+ }
+
+ private final String volumeName;
+ private final String bucketName;
+ private final String keyName;
+ private final long modificationTime;
+
+ public OMKeySetTimesRequest(OMRequest omRequest, BucketLayout bucketLayout) {
+ super(omRequest, bucketLayout);
+ OzoneManagerProtocolProtos.SetTimesRequest setTimesRequest =
+ getOmRequest().getSetTimesRequest();
+ volumeName = setTimesRequest.getKeyArgs().getVolumeName();
+ bucketName = setTimesRequest.getKeyArgs().getBucketName();
+ keyName = setTimesRequest.getKeyArgs().getKeyName();
+ // ignore accessTime
+ modificationTime = setTimesRequest.getMtime();
+ }
+
+ protected String getVolumeName() {
+ return volumeName;
+ }
+
+ protected String getBucketName() {
+ return bucketName;
+ }
+
+ protected String getKeyName() {
+ return keyName;
+ }
+
+ protected long getModificationTime() {
+ return modificationTime;
+ }
+
+ protected OMResponse.Builder onInit() {
+ return OmResponseUtil.getOMResponseBuilder(getOmRequest());
+ }
+
+ private OMClientResponse onSuccess(OMResponse.Builder omResponse,
+ OmKeyInfo omKeyInfo, boolean operationResult) {
+ omResponse.setSuccess(operationResult);
+ omResponse.setSetTimesResponse(SetTimesResponse.newBuilder());
+ return new OMKeySetTimesResponse(omResponse.build(), omKeyInfo);
+ }
+
+ /**
+ * Get the om client response on failure case with lock.
+ * @param omResponse
+ * @param exception
+ * @return OMClientResponse
+ */
+ protected OMClientResponse onFailure(OMResponse.Builder omResponse,
+ IOException exception) {
+ return new OMKeySetTimesResponse(createErrorOMResponse(
+ omResponse, exception), getBucketLayout());
+ }
+
+ protected void onComplete(Result result, IOException exception,
+ AuditLogger auditLogger, Map<String, String> auditMap) {
+ switch (result) {
+ case SUCCESS:
+ LOG.debug("Set mtime: {} to path: {} success!", modificationTime,
+ getKeyName());
+ break;
+ case FAILURE:
+ LOG.warn("Set mtime {} to path {} failed!", modificationTime,
+ getKeyName(), exception);
+ break;
+ default:
+ LOG.error("Unrecognized Result for OMKeySetTimesRequest: {}",
+ getOmRequest());
+ }
+
+ auditMap.put(OzoneConsts.VOLUME, getVolumeName());
+ auditMap.put(OzoneConsts.BUCKET, getBucketName());
+ auditMap.put(OzoneConsts.KEY, getKeyName());
+ auditMap.put(OzoneConsts.MODIFICATION_TIME,
+ String.valueOf(getModificationTime()));
+ auditLog(auditLogger, buildAuditMessage(OMAction.SET_TIMES, auditMap,
+ exception, getOmRequest().getUserInfo()));
+ }
+
+ protected void apply(OmKeyInfo omKeyInfo) {
+ // No need to check not null here, this will never be called with null.
+ long mtime = getModificationTime();
+ if (mtime >= 0) {
+ omKeyInfo.setModificationTime(getModificationTime());
+ }
+ }
+
+ @Override
+ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
+ long trxnLogIndex, OzoneManagerDoubleBufferHelper omDoubleBufferHelper) {
+ ozoneManager.getMetrics().incNumSetTime();
+ OmKeyInfo omKeyInfo;
+
+ OMResponse.Builder omResponse = onInit();
+ OMClientResponse omClientResponse = null;
+ IOException exception = null;
+
+ OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
+ boolean lockAcquired = false;
+ String volume = null;
+ String bucket = null;
+ String key;
+ boolean operationResult = false;
+ Result result;
+ try {
+ if (getModificationTime() < -1) {
+ throw new OMException(OMException.ResultCodes.INVALID_REQUEST);
+ }
+ volume = getVolumeName();
+ bucket = getBucketName();
+ key = getKeyName();
+
+ // check Acl
+ if (ozoneManager.getAclsEnabled()) {
+ checkAcls(ozoneManager, OzoneObj.ResourceType.KEY,
+ OzoneObj.StoreType.OZONE, IAccessAuthorizer.ACLType.WRITE_ACL,
+ volume, bucket, key);
+ }
+ lockAcquired = omMetadataManager.getLock().acquireWriteLock(
+ BUCKET_LOCK, volume, bucket);
+
+ String dbKey = omMetadataManager.getOzoneKey(volume, bucket, key);
+ omKeyInfo = omMetadataManager.getKeyTable(getBucketLayout())
+ .get(dbKey);
+
+ if (omKeyInfo == null) {
+ throw new OMException(OMException.ResultCodes.KEY_NOT_FOUND);
+ }
+
+ operationResult = true;
+ apply(omKeyInfo);
+ omKeyInfo.setUpdateID(trxnLogIndex, ozoneManager.isRatisEnabled());
+
+ // update cache.
+ omMetadataManager.getKeyTable(getBucketLayout())
+ .addCacheEntry(new CacheKey<>(dbKey),
+ CacheValue.get(trxnLogIndex, omKeyInfo));
+
+ omClientResponse = onSuccess(omResponse, omKeyInfo, operationResult);
+ result = Result.SUCCESS;
+ } catch (IOException ex) {
+ result = Result.FAILURE;
+ exception = ex;
+ omClientResponse = onFailure(omResponse, ex);
+ } finally {
+ addResponseToDoubleBuffer(trxnLogIndex, omClientResponse,
+ omDoubleBufferHelper);
+ if (lockAcquired) {
+ omMetadataManager.getLock().releaseWriteLock(BUCKET_LOCK, volume,
+ bucket);
+ }
+ }
+
+ Map<String, String> auditMap = new LinkedHashMap<>();
+ onComplete(result, exception, ozoneManager.getAuditLogger(), auditMap);
+
+ return omClientResponse;
+ }
+}
+
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequestWithFSO.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequestWithFSO.java
new file mode 100644
index 0000000000..fa9f7a20e3
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeySetTimesRequestWithFSO.java
@@ -0,0 +1,162 @@
+/**
+ * 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 org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus;
+import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
+import org.apache.hadoop.ozone.om.request.file.OMFileRequest;
+import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
+import org.apache.hadoop.ozone.om.response.key.OMKeySetTimesResponseWithFSO;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
+import org.apache.hadoop.ozone.security.acl.OzoneObj;
+
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import static
org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_NOT_FOUND;
+import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
+
+/**
+ * Handle set times request for bucket for prefix layout.
+ */
+public class OMKeySetTimesRequestWithFSO extends OMKeySetTimesRequest {
+
+ @Override
+ public OzoneManagerProtocolProtos.OMRequest preExecute(
+ OzoneManager ozoneManager) throws IOException {
+ return super.preExecute(ozoneManager);
+ }
+
+ public OMKeySetTimesRequestWithFSO(
+ OzoneManagerProtocolProtos.OMRequest omReq, BucketLayout bucketLayout) {
+ super(omReq, bucketLayout);
+ }
+
+ @Override
+ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
+ long trxnLogIndex, OzoneManagerDoubleBufferHelper omDoubleBufferHelper) {
+ OmKeyInfo omKeyInfo = null;
+
+ OzoneManagerProtocolProtos.OMResponse.Builder omResponse = onInit();
+ OMClientResponse omClientResponse = null;
+ IOException exception = null;
+
+ OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
+ boolean lockAcquired = false;
+ String volume = null;
+ String bucket = null;
+ String key = null;
+ boolean operationResult = false;
+ Result result = null;
+ try {
+ volume = getVolumeName();
+ bucket = getBucketName();
+ key = getKeyName();
+
+ // check Acl
+ if (ozoneManager.getAclsEnabled()) {
+ checkAcls(ozoneManager, OzoneObj.ResourceType.KEY,
+ OzoneObj.StoreType.OZONE, IAccessAuthorizer.ACLType.WRITE_ACL,
+ volume, bucket, key);
+ }
+ lockAcquired = omMetadataManager.getLock()
+ .acquireWriteLock(BUCKET_LOCK, volume, bucket);
+ OzoneFileStatus keyStatus = OMFileRequest
+ .getOMKeyInfoIfExists(omMetadataManager, volume, bucket, key, 0);
+ if (keyStatus == null) {
+ throw new OMException("Key not found. Key:" + key, KEY_NOT_FOUND);
+ }
+ omKeyInfo = keyStatus.getKeyInfo();
+ final long volumeId = omMetadataManager.getVolumeId(volume);
+ final long bucketId = omMetadataManager.getBucketId(volume, bucket);
+ final String dbKey = omMetadataManager.getOzonePathKey(volumeId,
bucketId,
+ omKeyInfo.getParentObjectID(), omKeyInfo.getFileName());
+ boolean isDirectory = keyStatus.isDirectory();
+ operationResult = true;
+ apply(omKeyInfo);
+ omKeyInfo.setUpdateID(trxnLogIndex, ozoneManager.isRatisEnabled());
+
+ // update cache.
+ if (isDirectory) {
+ Table<String, OmDirectoryInfo> dirTable =
+ omMetadataManager.getDirectoryTable();
+ dirTable.addCacheEntry(new CacheKey<>(dbKey),
+ CacheValue.get(trxnLogIndex,
+ OMFileRequest.getDirectoryInfo(omKeyInfo)));
+ } else {
+ omMetadataManager.getKeyTable(getBucketLayout())
+ .addCacheEntry(new CacheKey<>(dbKey),
+ CacheValue.get(trxnLogIndex, omKeyInfo));
+ }
+ omClientResponse = onSuccess(omResponse, omKeyInfo, operationResult,
+ isDirectory, volumeId, bucketId);
+ result = Result.SUCCESS;
+ } catch (IOException ex) {
+ result = Result.FAILURE;
+ exception = ex;
+ omClientResponse = onFailure(omResponse, ex);
+ } finally {
+ addResponseToDoubleBuffer(trxnLogIndex, omClientResponse,
+ omDoubleBufferHelper);
+ if (lockAcquired) {
+ omMetadataManager.getLock()
+ .releaseWriteLock(BUCKET_LOCK, volume, bucket);
+ }
+ }
+
+ Map<String, String> auditMap = new LinkedHashMap<>();
+ onComplete(result, exception, ozoneManager.getAuditLogger(), auditMap);
+
+ return omClientResponse;
+ }
+
+ @Override
+ protected OzoneManagerProtocolProtos.OMResponse.Builder onInit() {
+ return OmResponseUtil.getOMResponseBuilder(getOmRequest());
+ }
+
+ private OMClientResponse onSuccess(OMResponse.Builder omResponse,
+ OmKeyInfo omKeyInfo, boolean operationResult, boolean isDir,
+ long volumeId, long bucketId) {
+ omResponse.setSuccess(operationResult);
+ omResponse.setSetTimesResponse(
+ OzoneManagerProtocolProtos.SetTimesResponse.newBuilder());
+ return new OMKeySetTimesResponseWithFSO(omResponse.build(), omKeyInfo,
+ isDir, getBucketLayout(), volumeId, bucketId);
+ }
+
+ @Override
+ protected OMClientResponse onFailure(OMResponse.Builder omResponse,
+ IOException exception) {
+ return new OMKeySetTimesResponseWithFSO(createErrorOMResponse(
+ omResponse, exception), getBucketLayout());
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeySetTimesResponse.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeySetTimesResponse.java
new file mode 100644
index 0000000000..895bdfdf91
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeySetTimesResponse.java
@@ -0,0 +1,78 @@
+/**
+ * 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 java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.response.CleanupTableInfo;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import org.apache.hadoop.hdds.utils.db.BatchOperation;
+
+import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.KEY_TABLE;
+
+/**
+ * Response for Bucket acl request.
+ */
+@CleanupTableInfo(cleanupTables = KEY_TABLE)
+public class OMKeySetTimesResponse extends OmKeyResponse {
+
+ private OmKeyInfo omKeyInfo;
+
+ public OMKeySetTimesResponse(@Nonnull OMResponse omResponse,
+ @Nonnull OmKeyInfo omKeyInfo) {
+ super(omResponse);
+ this.omKeyInfo = omKeyInfo;
+ }
+
+ public OMKeySetTimesResponse(@Nonnull OMResponse omResponse,
+ @Nonnull OmKeyInfo omKeyInfo,
+ @Nonnull BucketLayout bucketLayout) {
+ super(omResponse, bucketLayout);
+ this.omKeyInfo = omKeyInfo;
+ }
+
+ /**
+ * For when the request is not successful.
+ * For a successful request, the other constructor should be used.
+ */
+ public OMKeySetTimesResponse(@Nonnull OMResponse omResponse,
+ @Nonnull BucketLayout bucketLayout) {
+ super(omResponse, bucketLayout);
+ }
+
+ @Override
+ public void addToDBBatch(OMMetadataManager omMetadataManager,
+ BatchOperation batchOperation) throws IOException {
+
+ String dbKey = omMetadataManager.getOzoneKey(omKeyInfo.getVolumeName(),
+ omKeyInfo.getBucketName(), omKeyInfo.getKeyName());
+ omMetadataManager.getKeyTable(getBucketLayout())
+ .putWithBatch(batchOperation, dbKey, omKeyInfo);
+ }
+
+ public OmKeyInfo getOmKeyInfo() {
+ return omKeyInfo;
+ }
+}
+
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeySetTimesResponseWithFSO.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeySetTimesResponseWithFSO.java
new file mode 100644
index 0000000000..024e9eb6ca
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeySetTimesResponseWithFSO.java
@@ -0,0 +1,84 @@
+/**
+ * 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.hdds.utils.db.BatchOperation;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.request.file.OMFileRequest;
+import org.apache.hadoop.ozone.om.response.CleanupTableInfo;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import org.jetbrains.annotations.NotNull;
+
+import javax.annotation.Nonnull;
+import java.io.IOException;
+
+import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.DIRECTORY_TABLE;
+import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.FILE_TABLE;
+
+/**
+ * Response for Bucket acl request for prefix layout.
+ */
+@CleanupTableInfo(cleanupTables = { FILE_TABLE, DIRECTORY_TABLE })
+public class OMKeySetTimesResponseWithFSO extends OMKeySetTimesResponse {
+
+ private boolean isDirectory;
+ private long volumeId;
+ private long bucketId;
+
+ public OMKeySetTimesResponseWithFSO(
+ @NotNull OzoneManagerProtocolProtos.OMResponse omResponse,
+ @NotNull OmKeyInfo omKeyInfo, boolean isDirectory,
+ @Nonnull BucketLayout bucketLayout, @Nonnull long volumeId,
+ @Nonnull long bucketId) {
+ super(omResponse, omKeyInfo, bucketLayout);
+ this.isDirectory = isDirectory;
+ this.volumeId = volumeId;
+ this.bucketId = bucketId;
+ }
+
+ /**
+ * For when the request is not successful.
+ * For a successful request, the other constructor should be used.
+ *
+ * @param omResponse
+ */
+ public OMKeySetTimesResponseWithFSO(
+ @NotNull OzoneManagerProtocolProtos.OMResponse omResponse,
+ BucketLayout bucketLayout) {
+ super(omResponse, bucketLayout);
+ }
+
+ @Override
+ public void addToDBBatch(OMMetadataManager omMetadataManager,
+ BatchOperation batchOperation) throws IOException {
+
+ String ozoneDbKey = omMetadataManager.getOzonePathKey(volumeId, bucketId,
+ getOmKeyInfo().getParentObjectID(), getOmKeyInfo().getFileName());
+ if (isDirectory) {
+ OmDirectoryInfo dirInfo = OMFileRequest.getDirectoryInfo(getOmKeyInfo());
+ omMetadataManager.getDirectoryTable()
+ .putWithBatch(batchOperation, ozoneDbKey, dirInfo);
+ } else {
+ omMetadataManager.getKeyTable(getBucketLayout())
+ .putWithBatch(batchOperation, ozoneDbKey, getOmKeyInfo());
+ }
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestBucketLayoutAwareOMKeyFactory.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestBucketLayoutAwareOMKeyFactory.java
index 18491a98db..7003799fbe 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestBucketLayoutAwareOMKeyFactory.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestBucketLayoutAwareOMKeyFactory.java
@@ -109,9 +109,9 @@ public class TestBucketLayoutAwareOMKeyFactory {
LOG.info("Validated request class instantiation for cmdType " + k);
});
- Assert.assertEquals(12, omKeyReqsFSO.size());
- Assert.assertEquals(13, omKeyReqsLegacy.size());
- Assert.assertEquals(13, omKeyReqsOBS.size());
+ Assert.assertEquals(13, omKeyReqsFSO.size());
+ Assert.assertEquals(14, omKeyReqsLegacy.size());
+ Assert.assertEquals(14, omKeyReqsOBS.size());
// Check if the number of instantiated OMKeyRequest classes is equal to
// the number of keys in the mapping.
Assert.assertEquals(
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMSetTimesRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMSetTimesRequest.java
new file mode 100644
index 0000000000..4f7dd5cd04
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMSetTimesRequest.java
@@ -0,0 +1,114 @@
+/**
+ * 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 java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.SetTimesRequest;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+
+/**
+ * Test cases for OMSetTimesRequest.
+ */
+public class TestOMSetTimesRequest extends TestOMKeyRequest {
+
+ /**
+ * Verify that setTimes() on key works as expected.
+ * @throws Exception
+ */
+ @Test
+ public void testKeySetTimesRequest() throws Exception {
+ OMRequestTestUtils.addVolumeAndBucketToDB(volumeName, bucketName,
+ omMetadataManager, getBucketLayout());
+ String ozoneKey = addKeyToTable();
+
+ long mtime = 2000;
+ executeAndReturn(mtime);
+ // Verify result of setting times.
+ long keyMtime =
+ omMetadataManager.getKeyTable(getBucketLayout()).get(ozoneKey)
+ .getModificationTime();
+ Assert.assertEquals(mtime, keyMtime);
+
+ long newMtime = -1;
+ executeAndReturn(newMtime);
+ keyMtime =
+ omMetadataManager.getKeyTable(getBucketLayout()).get(ozoneKey)
+ .getModificationTime();
+ Assert.assertEquals(mtime, keyMtime);
+ }
+
+ protected void executeAndReturn(long mtime)
+ throws IOException {
+ long atime = 1000;
+ OMRequest setTimesRequest = createSetTimesKeyRequest(mtime, atime);
+ OMKeySetTimesRequest omKeySetTimesRequest =
+ getOmKeySetTimesRequest(setTimesRequest);
+ OMRequest preExecuteRequest =
omKeySetTimesRequest.preExecute(ozoneManager);
+ omKeySetTimesRequest = getOmKeySetTimesRequest(preExecuteRequest);
+
+ OMClientResponse omClientResponse = omKeySetTimesRequest
+ .validateAndUpdateCache(ozoneManager, 100L,
+ ozoneManagerDoubleBufferHelper);
+ OMResponse omSetTimesResponse = omClientResponse.getOMResponse();
+ Assert.assertNotNull(omSetTimesResponse.getSetTimesResponse());
+ Assert.assertEquals(OzoneManagerProtocolProtos.Status.OK,
+ omSetTimesResponse.getStatus());
+ }
+
+ private OMRequest createSetTimesKeyRequest(long mtime, long atime) {
+ OzoneManagerProtocolProtos.KeyArgs keyArgs =
+ OzoneManagerProtocolProtos.KeyArgs.newBuilder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .setKeyName(keyName)
+ .build();
+ SetTimesRequest setTimesRequest = SetTimesRequest.newBuilder()
+ .setKeyArgs(keyArgs)
+ .setMtime(mtime)
+ .setAtime(atime)
+ .build();
+
+ return OMRequest.newBuilder().setClientId(UUID.randomUUID().toString())
+ .setCmdType(OzoneManagerProtocolProtos.Type.SetTimes)
+ .setSetTimesRequest(setTimesRequest)
+ .build();
+ }
+
+ protected String addKeyToTable() throws Exception {
+ OMRequestTestUtils.addKeyToTable(false, false, volumeName, bucketName,
+ keyName, clientID, replicationType, replicationFactor, 1L,
+ omMetadataManager);
+
+ return omMetadataManager.getOzoneKey(volumeName, bucketName,
+ keyName);
+ }
+
+ protected OMKeySetTimesRequest getOmKeySetTimesRequest(
+ OMRequest setTimesRequest) {
+ return new OMKeySetTimesRequest(setTimesRequest, getBucketLayout());
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMSetTimesRequestWithFSO.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMSetTimesRequestWithFSO.java
new file mode 100644
index 0000000000..93d48cb9e9
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMSetTimesRequestWithFSO.java
@@ -0,0 +1,106 @@
+/**
+ * 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 org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.ozone.om.helpers.BucketLayout;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus;
+import org.apache.hadoop.ozone.om.request.OMRequestTestUtils;
+import org.apache.hadoop.ozone.om.request.file.OMFileRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import org.apache.hadoop.util.Time;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test cases for TestOMSetTimesRequestWithFSO.
+ */
+public class TestOMSetTimesRequestWithFSO extends TestOMSetTimesRequest {
+
+ private static final String PARENT_DIR = "c/d/e";
+ private static final String FILE_NAME = "file1";
+
+ /**
+ * Verify that setTimes() on directory works as expected.
+ * @throws Exception
+ */
+ @Test
+ public void testDirSetTimesRequest() throws Exception {
+ OMRequestTestUtils.addVolumeAndBucketToDB(volumeName, bucketName,
+ omMetadataManager, getBucketLayout());
+ addKeyToTable();
+ keyName = PARENT_DIR;
+
+ long mtime = 2000;
+ executeAndReturn(mtime);
+ OzoneFileStatus keyStatus = OMFileRequest.getOMKeyInfoIfExists(
+ omMetadataManager, volumeName, bucketName, keyName, 0);
+ assertNotNull(keyStatus);
+ assertTrue(keyStatus.isDirectory());
+ long keyMtime = keyStatus.getKeyInfo().getModificationTime();
+ Assert.assertEquals(mtime, keyMtime);
+
+ long newMtime = -1;
+ executeAndReturn(newMtime);
+ keyStatus = OMFileRequest.getOMKeyInfoIfExists(
+ omMetadataManager, volumeName, bucketName, keyName, 0);
+ assertNotNull(keyStatus);
+ assertTrue(keyStatus.isDirectory());
+ keyMtime = keyStatus.getKeyInfo().getModificationTime();
+ Assert.assertEquals(mtime, keyMtime);
+ }
+
+ protected String addKeyToTable() throws Exception {
+ String key = PARENT_DIR + "/" + FILE_NAME;
+ keyName = key; // updated key name
+
+ // Create parent dirs for the path
+ long parentId = OMRequestTestUtils
+ .addParentsToDirTable(volumeName, bucketName, PARENT_DIR,
+ omMetadataManager);
+
+ OmKeyInfo omKeyInfo = OMRequestTestUtils
+ .createOmKeyInfo(volumeName, bucketName, key,
+ HddsProtos.ReplicationType.RATIS, HddsProtos.ReplicationFactor.ONE,
+ parentId + 1, parentId, 100, Time.now());
+ OMRequestTestUtils
+ .addFileToKeyTable(false, false, FILE_NAME, omKeyInfo, -1, 50,
+ omMetadataManager);
+ final long volumeId = omMetadataManager.getVolumeId(
+ omKeyInfo.getVolumeName());
+ final long bucketId = omMetadataManager.getBucketId(
+ omKeyInfo.getVolumeName(), omKeyInfo.getBucketName());
+ return omMetadataManager.getOzonePathKey(
+ volumeId, bucketId, omKeyInfo.getParentObjectID(), FILE_NAME);
+ }
+
+ protected OMKeySetTimesRequest getOmKeySetTimesRequest(
+ OMRequest setTimesRequest) {
+ return new OMKeySetTimesRequestWithFSO(setTimesRequest, getBucketLayout());
+ }
+
+ @Override
+ public BucketLayout getBucketLayout() {
+ return BucketLayout.FILE_SYSTEM_OPTIMIZED;
+ }
+}
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 669b1ea18b..4905fd1d30 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
@@ -706,4 +706,10 @@ public class BasicOzoneClientAdapterImpl implements
OzoneClientAdapter {
}
return snapshotDiffResponse.getSnapshotDiffReport();
}
+
+ @Override
+ public void setTimes(String key, long mtime, long atime) throws IOException {
+ incrementCounter(Statistic.INVOCATION_SET_TIMES, 1);
+ bucket.setTimes(key, mtime, atime);
+ }
}
diff --git
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneFileSystem.java
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneFileSystem.java
index 3dd8276394..573ffcd461 100644
---
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneFileSystem.java
+++
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicOzoneFileSystem.java
@@ -938,6 +938,16 @@ public class BasicOzoneFileSystem extends FileSystem {
OM_SNAPSHOT_INDICATOR + OZONE_URI_DELIMITER + snapshot);
}
+ @Override
+ public void setTimes(Path f, long mtime, long atime) throws IOException {
+ incrementCounter(Statistic.INVOCATION_SET_TIMES, 1);
+ statistics.incrementWriteOps(1);
+ LOG.trace("setTimes() path:{}", f);
+ Path qualifiedPath = makeQualified(f);
+ String key = pathToKey(qualifiedPath);
+ adapter.setTimes(key, mtime, atime);
+ }
+
/**
* A private class implementation for iterating list of file status.
*
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 8902dd43dc..d0e6ab2c77 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
@@ -1364,4 +1364,12 @@ public class BasicRootedOzoneClientAdapterImpl
return ozoneClient.getProxy().getOzoneManagerClient().recoverLease(
volume.getName(), bucket.getName(), ofsPath.getKeyName());
}
+
+ public void setTimes(String key, long mtime, long atime) throws IOException {
+ incrementCounter(Statistic.INVOCATION_SET_TIMES, 1);
+ OFSPath ofsPath = new OFSPath(key, config);
+
+ OzoneBucket bucket = getBucket(ofsPath, false);
+ bucket.setTimes(ofsPath.getKeyName(), mtime, atime);
+ }
}
diff --git
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneFileSystem.java
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneFileSystem.java
index ca8a0b0d68..4934bb341c 100644
---
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneFileSystem.java
+++
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneFileSystem.java
@@ -1549,4 +1549,18 @@ public class BasicRootedOzoneFileSystem extends
FileSystem {
return adapterImpl.recoverLease(f);
}
+ @Override
+ public void setTimes(Path f, long mtime, long atime) throws IOException {
+ incrementCounter(Statistic.INVOCATION_SET_TIMES, 1);
+ statistics.incrementWriteOps(1);
+ LOG.trace("setTimes() path:{}", f);
+ Path qualifiedPath = makeQualified(f);
+ String key = pathToKey(qualifiedPath);
+ // Handle DistCp /NONE path
+ if (key.equals("NONE")) {
+ throw new FileNotFoundException("File not found. path /NONE.");
+ }
+ adapter.setTimes(key, mtime, atime);
+ }
+
}
diff --git
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientAdapter.java
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientAdapter.java
index 50fe9a71c1..afc8fd39e2 100644
---
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientAdapter.java
+++
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/OzoneClientAdapter.java
@@ -91,4 +91,6 @@ public interface OzoneClientAdapter {
SnapshotDiffReport getSnapshotDiffReport(Path snapshotDir,
String fromSnapshot, String toSnapshot)
throws IOException, InterruptedException;
+
+ void setTimes(String key, long mtime, long atime) throws IOException;
}
diff --git
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/Statistic.java
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/Statistic.java
index 136d999859..09b9cdd777 100644
---
a/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/Statistic.java
+++
b/hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/Statistic.java
@@ -72,7 +72,9 @@ public enum Statistic {
INVOCATION_OPEN(CommonStatisticNames.OP_OPEN,
"Calls of open()"),
INVOCATION_RENAME(CommonStatisticNames.OP_RENAME,
- "Calls of rename()");
+ "Calls of rename()"),
+ INVOCATION_SET_TIMES(CommonStatisticNames.OP_SET_TIMES,
+ "Calls of setTimes()");
private static final Map<String, Statistic> SYMBOL_MAP =
new HashMap<>(Statistic.values().length);
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 ff464604f8..69f8a2f499 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
@@ -642,4 +642,9 @@ public class ClientProtocolStub implements ClientProtocol {
return null;
}
+ @Override
+ public void setTimes(OzoneObj obj, String keyName, long mtime, long atime)
+ throws IOException {
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]