diff --git a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java index e027c82abf73..54e44b1e43e0 100644 --- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java +++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java @@ -280,6 +280,7 @@ private OzoneConsts() { public static final String RESOURCE_TYPE = "resourceType"; public static final String IS_VERSION_ENABLED = "isVersionEnabled"; public static final String CREATION_TIME = "creationTime"; + public static final String MODIFICATION_TIME = "modificationTime"; public static final String DATA_SIZE = "dataSize"; public static final String REPLICATION_TYPE = "replicationType"; public static final String REPLICATION_FACTOR = "replicationFactor"; 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 87710ea01156..89242115ae59 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 @@ -38,6 +38,7 @@ import org.apache.hadoop.ozone.om.helpers.WithMetadata; import org.apache.hadoop.ozone.security.acl.OzoneObj; import org.apache.hadoop.ozone.security.acl.OzoneObjInfo; +import org.apache.hadoop.util.Time; import java.io.IOException; import java.time.Instant; @@ -96,6 +97,11 @@ public class OzoneBucket extends WithMetadata { */ private Instant creationTime; + /** + * Modification time of the bucket. + */ + private Instant modificationTime; + /** * Bucket Encryption key name if bucket encryption is enabled. */ @@ -144,6 +150,21 @@ public OzoneBucket(ConfigurationSource conf, ClientProtocol proxy, this.creationTime = Instant.ofEpochMilli(creationTime); this.metadata = metadata; this.encryptionKeyName = encryptionKeyName; + modificationTime = Instant.now(); + if (modificationTime.isBefore(this.creationTime)) { + modificationTime = Instant.ofEpochSecond( + this.creationTime.getEpochSecond(), this.creationTime.getNano()); + } + } + + @SuppressWarnings("parameternumber") + public OzoneBucket(ConfigurationSource conf, ClientProtocol proxy, + String volumeName, String bucketName, StorageType storageType, + Boolean versioning, long creationTime, long modificationTime, + Map metadata, String encryptionKeyName) { + this(conf, proxy, volumeName, bucketName, storageType, versioning, + creationTime, metadata, encryptionKeyName); + this.modificationTime = Instant.ofEpochMilli(modificationTime); } /** @@ -166,6 +187,24 @@ public OzoneBucket(ConfigurationSource conf, ClientProtocol proxy, this.listCacheSize = HddsClientUtils.getListCacheSize(conf); this.creationTime = Instant.ofEpochMilli(creationTime); this.metadata = metadata; + modificationTime = Instant.now(); + if (modificationTime.isBefore(this.creationTime)) { + modificationTime = Instant.ofEpochSecond( + this.creationTime.getEpochSecond(), this.creationTime.getNano()); + } + } + + /** + * @param modificationTime modification time of the bucket. + */ + @SuppressWarnings("parameternumber") + public OzoneBucket(ConfigurationSource conf, ClientProtocol proxy, + String volumeName, String bucketName, StorageType storageType, + Boolean versioning, long creationTime, long modificationTime, + Map metadata) { + this(conf, proxy, volumeName, bucketName, storageType, versioning, + creationTime, metadata); + this.modificationTime = Instant.ofEpochMilli(modificationTime); } @VisibleForTesting @@ -187,9 +226,14 @@ public OzoneBucket(ConfigurationSource conf, ClientProtocol proxy, .setVolumeName(volumeName) .setResType(OzoneObj.ResourceType.BUCKET) .setStoreType(OzoneObj.StoreType.OZONE).build(); + long modifiedTime = Time.now(); + if (modifiedTime < creationTime) { + this.modificationTime = Instant.ofEpochMilli(creationTime); + } else { + this.modificationTime = Instant.ofEpochMilli(modifiedTime); + } } - /** * Returns Volume Name. * @@ -245,6 +289,15 @@ public Instant getCreationTime() { return creationTime; } + /** + * Returns modification time of the Bucket. + * + * @return modification time of the bucket + */ + public Instant getModificationTime() { + return modificationTime; + } + /** * Return the bucket encryption key name. * @return the bucket encryption key name diff --git a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneVolume.java b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneVolume.java index 07c1e263a56d..9978cc7486d2 100644 --- a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneVolume.java +++ b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneVolume.java @@ -68,6 +68,10 @@ public class OzoneVolume extends WithMetadata { * Creation time of the volume. */ private Instant creationTime; + /** + * Modification time of the volume. + */ + private Instant modificationTime; /** * Volume ACLs. */ @@ -89,10 +93,8 @@ public class OzoneVolume extends WithMetadata { */ @SuppressWarnings("parameternumber") public OzoneVolume(ConfigurationSource conf, ClientProtocol proxy, - String name, - String admin, String owner, long quotaInBytes, - long creationTime, List acls, - Map metadata) { + String name, String admin, String owner, long quotaInBytes, + long creationTime, List acls, Map metadata) { Preconditions.checkNotNull(proxy, "Client proxy is not set."); this.proxy = proxy; this.name = name; @@ -103,21 +105,50 @@ public OzoneVolume(ConfigurationSource conf, ClientProtocol proxy, this.acls = acls; this.listCacheSize = HddsClientUtils.getListCacheSize(conf); this.metadata = metadata; + modificationTime = Instant.now(); + if (modificationTime.isBefore(this.creationTime)) { + modificationTime = Instant.ofEpochSecond( + this.creationTime.getEpochSecond(), this.creationTime.getNano()); + } + } + + /** + * @param modificationTime modification time of the volume. + */ + @SuppressWarnings("parameternumber") + public OzoneVolume(ConfigurationSource conf, ClientProtocol proxy, + String name, String admin, String owner, long quotaInBytes, + long creationTime, long modificationTime, List acls, + Map metadata) { + this(conf, proxy, name, admin, owner, quotaInBytes, + creationTime, acls, metadata); + this.modificationTime = Instant.ofEpochMilli(modificationTime); } @SuppressWarnings("parameternumber") public OzoneVolume(ConfigurationSource conf, ClientProtocol proxy, - String name, - String admin, String owner, long quotaInBytes, + String name, String admin, String owner, long quotaInBytes, long creationTime, List acls) { this(conf, proxy, name, admin, owner, quotaInBytes, creationTime, acls, new HashMap<>()); + modificationTime = Instant.now(); + if (modificationTime.isBefore(this.creationTime)) { + modificationTime = Instant.ofEpochSecond( + this.creationTime.getEpochSecond(), this.creationTime.getNano()); + } + } + + @SuppressWarnings("parameternumber") + public OzoneVolume(ConfigurationSource conf, ClientProtocol proxy, + String name, String admin, String owner, long quotaInBytes, + long creationTime, long modificationTime, List acls) { + this(conf, proxy, name, admin, owner, quotaInBytes, creationTime, acls); + this.modificationTime = Instant.ofEpochMilli(modificationTime); } @VisibleForTesting protected OzoneVolume(String name, String admin, String owner, - long quotaInBytes, - long creationTime, List acls) { + long quotaInBytes, long creationTime, List acls) { this.proxy = null; this.name = name; this.admin = admin; @@ -126,6 +157,19 @@ protected OzoneVolume(String name, String admin, String owner, this.creationTime = Instant.ofEpochMilli(creationTime); this.acls = acls; this.metadata = new HashMap<>(); + modificationTime = Instant.now(); + if (modificationTime.isBefore(this.creationTime)) { + modificationTime = Instant.ofEpochSecond( + this.creationTime.getEpochSecond(), this.creationTime.getNano()); + } + } + + @VisibleForTesting + protected OzoneVolume(String name, String admin, String owner, + long quotaInBytes, long creationTime, long modificationTime, + List acls) { + this(name, admin, owner, quotaInBytes, creationTime, acls); + this.modificationTime = Instant.ofEpochMilli(modificationTime); } /** @@ -173,6 +217,15 @@ public Instant getCreationTime() { return creationTime; } + /** + * Returns modification time of the volume. + * + * @return modification time. + */ + public Instant getModificationTime() { + return modificationTime; + } + /** * Returns OzoneAcl list associated with the Volume. * 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 843769996068..80eea3655c37 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 @@ -345,6 +345,7 @@ public OzoneVolume getVolumeDetails(String volumeName) volume.getOwnerName(), volume.getQuotaInBytes(), volume.getCreationTime(), + volume.getModificationTime(), volume.getAclMap().ozoneAclGetProtobuf().stream(). map(OzoneAcl::fromProtobuf).collect(Collectors.toList()), volume.getMetadata()); @@ -377,6 +378,7 @@ public List listVolumes(String volumePrefix, String prevVolume, volume.getOwnerName(), volume.getQuotaInBytes(), volume.getCreationTime(), + volume.getModificationTime(), volume.getAclMap().ozoneAclGetProtobuf().stream(). map(OzoneAcl::fromProtobuf).collect(Collectors.toList()))) .collect(Collectors.toList()); @@ -397,6 +399,7 @@ public List listVolumes(String user, String volumePrefix, volume.getOwnerName(), volume.getQuotaInBytes(), volume.getCreationTime(), + volume.getModificationTime(), volume.getAclMap().ozoneAclGetProtobuf().stream(). map(OzoneAcl::fromProtobuf).collect(Collectors.toList()), volume.getMetadata())) @@ -604,6 +607,7 @@ public OzoneBucket getBucketDetails( bucketInfo.getStorageType(), bucketInfo.getIsVersionEnabled(), bucketInfo.getCreationTime(), + bucketInfo.getModificationTime(), bucketInfo.getMetadata(), bucketInfo.getEncryptionKeyInfo() != null ? bucketInfo .getEncryptionKeyInfo().getKeyName() : null); @@ -624,6 +628,7 @@ public List listBuckets(String volumeName, String bucketPrefix, bucket.getStorageType(), bucket.getIsVersionEnabled(), bucket.getCreationTime(), + bucket.getModificationTime(), bucket.getMetadata(), bucket.getEncryptionKeyInfo() != null ? bucket .getEncryptionKeyInfo().getKeyName() : null)) diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java index f8c4d7a7d652..e9a8cbcd6fb0 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmBucketInfo.java @@ -66,6 +66,10 @@ public final class OmBucketInfo extends WithObjectID implements Auditable { * Creation time of bucket. */ private final long creationTime; + /** + * modification time of bucket. + */ + private long modificationTime; /** * Bucket encryption key info if encryption is enabled. @@ -80,6 +84,7 @@ public final class OmBucketInfo extends WithObjectID implements Auditable { * @param isVersionEnabled - Bucket version flag. * @param storageType - Storage type to be used. * @param creationTime - Bucket creation time. + * @param modificationTime - Bucket modification time. * @param metadata - metadata. * @param bekInfo - bucket encryption key info. */ @@ -90,6 +95,7 @@ private OmBucketInfo(String volumeName, boolean isVersionEnabled, StorageType storageType, long creationTime, + long modificationTime, long objectID, long updateID, Map metadata, @@ -100,6 +106,7 @@ private OmBucketInfo(String volumeName, this.isVersionEnabled = isVersionEnabled; this.storageType = storageType; this.creationTime = creationTime; + this.modificationTime = modificationTime; this.objectID = objectID; this.updateID = updateID; this.metadata = metadata; @@ -184,6 +191,15 @@ public long getCreationTime() { return creationTime; } + /** + * Returns modification time. + * @return long + */ + public long getModificationTime() { + return modificationTime; + } + + /** * Returns bucket encryption key info. * @return bucket encryption key info @@ -217,6 +233,8 @@ public Map toAuditMap() { auditMap.put(OzoneConsts.CREATION_TIME, String.valueOf(this.creationTime)); auditMap.put(OzoneConsts.BUCKET_ENCRYPTION_KEY, (bekInfo != null) ? bekInfo.getKeyName() : null); + auditMap.put(OzoneConsts.MODIFICATION_TIME, + String.valueOf(this.modificationTime)); return auditMap; } @@ -230,6 +248,7 @@ public OmBucketInfo copyObject() { .setStorageType(storageType) .setIsVersionEnabled(isVersionEnabled) .setCreationTime(creationTime) + .setModificationTime(modificationTime) .setObjectID(objectID) .setUpdateID(updateID) .setBucketEncryptionKey(bekInfo != null ? @@ -257,6 +276,7 @@ public static class Builder { private Boolean isVersionEnabled; private StorageType storageType; private long creationTime; + private long modificationTime; private long objectID; private long updateID; private Map metadata; @@ -309,6 +329,11 @@ public Builder setCreationTime(long createdOn) { return this; } + public Builder setModificationTime(long modifiedOn) { + this.modificationTime = modifiedOn; + return this; + } + public Builder setObjectID(long obId) { this.objectID = obId; return this; @@ -349,7 +374,8 @@ public OmBucketInfo build() { Preconditions.checkNotNull(storageType); return new OmBucketInfo(volumeName, bucketName, acls, isVersionEnabled, - storageType, creationTime, objectID, updateID, metadata, bekInfo); + storageType, creationTime, modificationTime, objectID, updateID, + metadata, bekInfo); } } @@ -364,6 +390,7 @@ public BucketInfo getProtobuf() { .setIsVersionEnabled(isVersionEnabled) .setStorageType(storageType.toProto()) .setCreationTime(creationTime) + .setModificationTime(modificationTime) .setObjectID(objectID) .setUpdateID(updateID) .addAllMetadata(KeyValueUtil.toProtobuf(metadata)); @@ -386,7 +413,8 @@ public static OmBucketInfo getFromProtobuf(BucketInfo bucketInfo) { OzoneAcl::fromProtobuf).collect(Collectors.toList())) .setIsVersionEnabled(bucketInfo.getIsVersionEnabled()) .setStorageType(StorageType.valueOf(bucketInfo.getStorageType())) - .setCreationTime(bucketInfo.getCreationTime()); + .setCreationTime(bucketInfo.getCreationTime()) + .setModificationTime(bucketInfo.getModificationTime()); if (bucketInfo.hasObjectID()) { obib.setObjectID(bucketInfo.getObjectID()); } @@ -424,6 +452,7 @@ public boolean equals(Object o) { } OmBucketInfo that = (OmBucketInfo) o; return creationTime == that.creationTime && + modificationTime == that.modificationTime && volumeName.equals(that.volumeName) && bucketName.equals(that.bucketName) && Objects.equals(acls, that.acls) && diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmVolumeArgs.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmVolumeArgs.java index 26d0b2337cfd..b9caf9d87c2c 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmVolumeArgs.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmVolumeArgs.java @@ -42,6 +42,7 @@ public final class OmVolumeArgs extends WithObjectID implements Auditable { private String ownerName; private final String volume; private long creationTime; + private long modificationTime; private long quotaInBytes; private final OmOzoneAclMap aclMap; @@ -62,8 +63,8 @@ public final class OmVolumeArgs extends WithObjectID implements Auditable { "builder."}) private OmVolumeArgs(String adminName, String ownerName, String volume, long quotaInBytes, Map metadata, - OmOzoneAclMap aclMap, long creationTime, long objectID, - long updateID) { + OmOzoneAclMap aclMap, long creationTime, + long modificationTime, long objectID, long updateID) { this.adminName = adminName; this.ownerName = ownerName; this.volume = volume; @@ -71,6 +72,7 @@ private OmVolumeArgs(String adminName, String ownerName, String volume, this.metadata = metadata; this.aclMap = aclMap; this.creationTime = creationTime; + this.modificationTime = modificationTime; this.objectID = objectID; this.updateID = updateID; } @@ -88,6 +90,10 @@ public void setCreationTime(long time) { this.creationTime = time; } + public void setModificationTime(long time) { + this.modificationTime = time; + } + public void addAcl(OzoneAcl acl) throws OMException { this.aclMap.addAcl(acl); } @@ -132,6 +138,14 @@ public long getCreationTime() { return creationTime; } + /** + * Returns modification time. + * @return long + */ + public long getModificationTime() { + return modificationTime; + } + /** * Returns Quota in Bytes. * @return long, Quota in bytes. @@ -159,6 +173,8 @@ public Map toAuditMap() { auditMap.put(OzoneConsts.OWNER, this.ownerName); auditMap.put(OzoneConsts.VOLUME, this.volume); auditMap.put(OzoneConsts.CREATION_TIME, String.valueOf(this.creationTime)); + auditMap.put(OzoneConsts.MODIFICATION_TIME, + String.valueOf(this.modificationTime)); auditMap.put(OzoneConsts.QUOTA_IN_BYTES, String.valueOf(this.quotaInBytes)); auditMap.put(OzoneConsts.OBJECT_ID, String.valueOf(this.getObjectID())); auditMap.put(OzoneConsts.UPDATE_ID, String.valueOf(this.getUpdateID())); @@ -190,6 +206,7 @@ public static class Builder { private String ownerName; private String volume; private long creationTime; + private long modificationTime; private long quotaInBytes; private Map metadata; private OmOzoneAclMap aclMap; @@ -245,6 +262,11 @@ public Builder setCreationTime(long createdOn) { return this; } + public Builder setModificationTime(long modifiedOn) { + this.modificationTime = modifiedOn; + return this; + } + public Builder setQuotaInBytes(long quota) { this.quotaInBytes = quota; return this; @@ -276,7 +298,7 @@ public OmVolumeArgs build() { Preconditions.checkNotNull(ownerName); Preconditions.checkNotNull(volume); return new OmVolumeArgs(adminName, ownerName, volume, quotaInBytes, - metadata, aclMap, creationTime, objectID, updateID); + metadata, aclMap, creationTime, modificationTime, objectID, updateID); } } @@ -292,6 +314,7 @@ public VolumeInfo getProtobuf() { .addAllVolumeAcls(aclList) .setCreationTime( creationTime == 0 ? System.currentTimeMillis() : creationTime) + .setModificationTime(modificationTime) .setObjectID(objectID) .setUpdateID(updateID) .build(); @@ -309,6 +332,7 @@ public static OmVolumeArgs getFromProtobuf(VolumeInfo volInfo) KeyValueUtil.getFromProtobuf(volInfo.getMetadataList()), aclMap, volInfo.getCreationTime(), + volInfo.getModificationTime(), volInfo.getObjectID(), volInfo.getUpdateID()); } @@ -336,6 +360,7 @@ public OmVolumeArgs copyObject() { OmOzoneAclMap cloneAclMap = aclMap.copyObject(); return new OmVolumeArgs(adminName, ownerName, volume, quotaInBytes, - cloneMetadata, cloneAclMap, creationTime, objectID, updateID); + cloneMetadata, cloneAclMap, creationTime, modificationTime, + objectID, updateID); } } diff --git a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto index 569be740e293..83877bf34c8b 100644 --- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto +++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto @@ -346,6 +346,7 @@ message VolumeInfo { optional uint64 creationTime = 7; optional uint64 objectID = 8; optional uint64 updateID = 9; + optional uint64 modificationTime = 10; } /** @@ -403,6 +404,7 @@ message SetVolumePropertyRequest { required string volumeName = 1; optional string ownerName = 2; optional uint64 quotaInBytes = 3; + optional uint64 modificationTime = 4; } message SetVolumePropertyResponse { @@ -478,6 +480,7 @@ message BucketInfo { optional BucketEncryptionInfoProto beinfo = 8; optional uint64 objectID = 9; optional uint64 updateID = 10; + optional uint64 modificationTime = 11; } enum StorageTypeProto { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java index 12d86ba92541..8181a64e3a72 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/bucket/OMBucketCreateRequest.java @@ -104,8 +104,10 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException { BucketInfo.Builder newBucketInfo = bucketInfo.toBuilder(); - // Set creation time. - newBucketInfo.setCreationTime(Time.now()); + // Set creation time & modification time. + long initialTime = Time.now(); + newBucketInfo.setCreationTime(initialTime) + .setModificationTime(initialTime); if (bucketInfo.hasBeinfo()) { newBucketInfo.setBeinfo(getBeinfo(kmsProvider, bucketInfo)); diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeCreateRequest.java index dcd66c7761bd..765a20cfca30 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeCreateRequest.java @@ -76,9 +76,13 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException { // Verify resource name OmUtils.validateVolumeName(volumeInfo.getVolume()); - // Set creation time + // Set creation time & set modification time + long initialTime = Time.now(); VolumeInfo updatedVolumeInfo = - volumeInfo.toBuilder().setCreationTime(Time.now()).build(); + volumeInfo.toBuilder() + .setCreationTime(initialTime) + .setModificationTime(initialTime) + .build(); return getOmRequest().toBuilder().setCreateVolumeRequest( CreateVolumeRequest.newBuilder().setVolumeInfo(updatedVolumeInfo)) diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetOwnerRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetOwnerRequest.java index 898f345ba422..1eea419ef607 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetOwnerRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetOwnerRequest.java @@ -23,6 +23,7 @@ import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; +import org.apache.hadoop.util.Time; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Optional; @@ -65,11 +66,24 @@ public OMVolumeSetOwnerRequest(OMRequest omRequest) { super(omRequest); } + @Override + public OMRequest preExecute(OzoneManager ozoneManager) throws IOException { + + long modificationTime = Time.now(); + SetVolumePropertyRequest modifiedRequest = getOmRequest() + .getSetVolumePropertyRequest().toBuilder() + .setModificationTime(modificationTime).build(); + + return getOmRequest().toBuilder() + .setSetVolumePropertyRequest(modifiedRequest.toBuilder()) + .setUserInfo(getUserInfo()) + .build(); + } + @Override public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, long transactionLogIndex, OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper) { - SetVolumePropertyRequest setVolumePropertyRequest = getOmRequest().getSetVolumePropertyRequest(); Preconditions.checkNotNull(setVolumePropertyRequest); @@ -134,7 +148,6 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, transactionLogIndex, setVolumePropertyRequest); return new OMVolumeSetOwnerResponse(createReplayOMResponse(omResponse)); } - oldOwner = omVolumeArgs.getOwnerName(); // Return OK immediately if newOwner is the same as oldOwner. @@ -167,6 +180,10 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, omVolumeArgs.setUpdateID(transactionLogIndex, ozoneManager.isRatisEnabled()); + // Update modificationTime. + omVolumeArgs.setModificationTime( + setVolumePropertyRequest.getModificationTime()); + // Update cache. omMetadataManager.getUserTable().addCacheEntry( new CacheKey<>(omMetadataManager.getUserKey(newOwner)), @@ -184,7 +201,6 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, SetVolumePropertyResponse.newBuilder().setResponse(true).build()); omClientResponse = new OMVolumeSetOwnerResponse(omResponse.build(), oldOwner, oldOwnerVolumeList, newOwnerVolumeList, omVolumeArgs); - } catch (IOException ex) { exception = ex; omClientResponse = new OMVolumeSetOwnerResponse( diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetQuotaRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetQuotaRequest.java index 91b02a202418..7e0cb72e237d 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetQuotaRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/volume/OMVolumeSetQuotaRequest.java @@ -25,6 +25,7 @@ import com.google.common.base.Preconditions; import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper; import org.apache.hadoop.ozone.om.request.util.OmResponseUtil; +import org.apache.hadoop.util.Time; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -65,6 +66,20 @@ public OMVolumeSetQuotaRequest(OMRequest omRequest) { super(omRequest); } + @Override + public OMRequest preExecute(OzoneManager ozoneManager) throws IOException { + + long modificationTime = Time.now(); + SetVolumePropertyRequest modifiedRequest = getOmRequest() + .getSetVolumePropertyRequest().toBuilder() + .setModificationTime(modificationTime).build(); + + return getOmRequest().toBuilder() + .setSetVolumePropertyRequest(modifiedRequest.toBuilder()) + .setUserInfo(getUserInfo()) + .build(); + } + @Override public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, long transactionLogIndex, @@ -133,6 +148,8 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, omVolumeArgs.setQuotaInBytes(setVolumePropertyRequest.getQuotaInBytes()); omVolumeArgs.setUpdateID(transactionLogIndex, ozoneManager.isRatisEnabled()); + omVolumeArgs.setModificationTime( + setVolumePropertyRequest.getModificationTime()); // update cache. omMetadataManager.getVolumeTable().addCacheEntry( diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMRequestUtils.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMRequestUtils.java index c5aa9fe103b9..dadeacb1943c 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMRequestUtils.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMRequestUtils.java @@ -350,7 +350,7 @@ public static OMRequest createSetVolumePropertyRequest(String volumeName, String newOwner) { SetVolumePropertyRequest setVolumePropertyRequest = SetVolumePropertyRequest.newBuilder().setVolumeName(volumeName) - .setOwnerName(newOwner).build(); + .setOwnerName(newOwner).setModificationTime(Time.now()).build(); return OMRequest.newBuilder().setClientId(UUID.randomUUID().toString()) .setCmdType(OzoneManagerProtocolProtos.Type.SetVolumeProperty) @@ -368,7 +368,7 @@ public static OMRequest createSetVolumePropertyRequest(String volumeName, long quota) { SetVolumePropertyRequest setVolumePropertyRequest = SetVolumePropertyRequest.newBuilder().setVolumeName(volumeName) - .setQuotaInBytes(quota).build(); + .setQuotaInBytes(quota).setModificationTime(Time.now()).build(); return OMRequest.newBuilder().setClientId(UUID.randomUUID().toString()) .setCmdType(OzoneManagerProtocolProtos.Type.SetVolumeProperty) diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/bucket/TestOMBucketCreateRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/bucket/TestOMBucketCreateRequest.java index ab5ad6b46580..7bef6b8957ab 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/bucket/TestOMBucketCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/bucket/TestOMBucketCreateRequest.java @@ -168,6 +168,8 @@ private void doValidateAndUpdateCache(String volumeName, String bucketName, Assert.assertEquals(bucketInfoFromProto.getCreationTime(), dbBucketInfo.getCreationTime()); + Assert.assertEquals(bucketInfoFromProto.getModificationTime(), + dbBucketInfo.getModificationTime()); Assert.assertEquals(bucketInfoFromProto.getAcls(), dbBucketInfo.getAcls()); Assert.assertEquals(bucketInfoFromProto.getIsVersionEnabled(), diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeCreateRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeCreateRequest.java index 05d0eba8de2b..27973ed70d83 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeCreateRequest.java @@ -139,6 +139,11 @@ public void testValidateAndUpdateCacheSuccess() throws Exception { Assert.assertEquals(expectedObjId, omVolumeArgs.getObjectID()); Assert.assertEquals(txLogIndex, omVolumeArgs.getUpdateID()); + // Initial modificationTime should be equal to creationTime. + long creationTime = omVolumeArgs.getCreationTime(); + long modificationTime = omVolumeArgs.getModificationTime(); + Assert.assertEquals(creationTime, modificationTime); + // Check data from table and request. Assert.assertEquals(volumeInfo.getVolume(), omVolumeArgs.getVolume()); Assert.assertEquals(volumeInfo.getOwnerName(), omVolumeArgs.getOwnerName()); @@ -236,6 +241,8 @@ private void verifyRequest(OMRequest modifiedRequest, updated.getOwnerName()); Assert.assertNotEquals(original.getCreationTime(), updated.getCreationTime()); + Assert.assertNotEquals(original.getModificationTime(), + updated.getModificationTime()); } @Test diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeSetOwnerRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeSetOwnerRequest.java index c71c1a8b50b5..0e1ac5475277 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeSetOwnerRequest.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeSetOwnerRequest.java @@ -92,6 +92,13 @@ public void testValidateAndUpdateCacheSuccess() throws Exception { .getVolumeTable().get(volumeKey).getOwnerName(); Assert.assertEquals(newOwner, fromDBOwner); + // modificationTime should be greater than creationTime. + long creationTime = omMetadataManager.getVolumeTable() + .get(volumeKey).getCreationTime(); + long modificationTime = omMetadataManager.getVolumeTable() + .get(volumeKey).getModificationTime(); + Assert.assertTrue(modificationTime > creationTime); + OzoneManagerProtocolProtos.UserVolumeInfo newOwnerVolumeList = omMetadataManager.getUserTable().get(newOwnerKey); diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeSetQuotaRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeSetQuotaRequest.java index c981c9ffb372..bd90222dc32e 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeSetQuotaRequest.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/volume/TestOMVolumeSetQuotaRequest.java @@ -92,6 +92,13 @@ public void testValidateAndUpdateCacheSuccess() throws Exception { .getVolumeTable().get(volumeKey).getQuotaInBytes(); Assert.assertEquals(quotaSet, quotaAfterSet); Assert.assertNotEquals(quotaBeforeSet, quotaAfterSet); + + // modificationTime should be greater than creationTime. + long creationTime = omMetadataManager + .getVolumeTable().get(volumeKey).getCreationTime(); + long modificationTime = omMetadataManager + .getVolumeTable().get(volumeKey).getModificationTime(); + Assert.assertTrue(modificationTime > creationTime); } @Test diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ObjectStoreStub.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ObjectStoreStub.java index b0b8d43c5880..b83cf6cbbc58 100644 --- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ObjectStoreStub.java +++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ObjectStoreStub.java @@ -29,6 +29,7 @@ import org.apache.hadoop.hdds.conf.OzoneConfiguration; import org.apache.hadoop.hdds.scm.client.HddsClientUtils; import org.apache.hadoop.ozone.om.exceptions.OMException; +import org.apache.hadoop.util.Time; import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.BUCKET_ALREADY_EXISTS; import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.BUCKET_NOT_EMPTY; @@ -59,14 +60,13 @@ public void createVolume(String volumeName) throws IOException { } @Override - public void createVolume(String volumeName, VolumeArgs volumeArgs) - throws IOException { + public void createVolume(String volumeName, VolumeArgs volumeArgs) { OzoneVolumeStub volume = new OzoneVolumeStub(volumeName, volumeArgs.getAdmin(), volumeArgs.getOwner(), Long.parseLong(volumeArgs.getQuota()), - System.currentTimeMillis(), + Time.now(), volumeArgs.getAcls()); volumes.put(volumeName, volume); } diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/OzoneVolumeStub.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/OzoneVolumeStub.java index 67aa68aa3b8b..8538bb226c8e 100644 --- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/OzoneVolumeStub.java +++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/OzoneVolumeStub.java @@ -29,6 +29,7 @@ import org.apache.hadoop.hdds.protocol.StorageType; import org.apache.hadoop.ozone.OzoneAcl; import org.apache.hadoop.ozone.om.exceptions.OMException; +import org.apache.hadoop.util.Time; /** * Ozone volume with in-memory state for testing. @@ -38,9 +39,9 @@ public class OzoneVolumeStub extends OzoneVolume { private Map buckets = new HashMap<>(); public OzoneVolumeStub(String name, String admin, String owner, - long quotaInBytes, - long creationTime, List acls) { - super(name, admin, owner, quotaInBytes, creationTime, acls); + long quotaInBytes, long creationTime, List acls) { + super(name, admin, owner, quotaInBytes, + creationTime, acls); } @Override @@ -58,8 +59,7 @@ public void createBucket(String bucketName, BucketArgs bucketArgs) { bucketName, bucketArgs.getStorageType(), bucketArgs.getVersioning(), - System.currentTimeMillis())); - + Time.now())); } @Override diff --git a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/volume/UpdateVolumeHandler.java b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/volume/UpdateVolumeHandler.java index 52ba5f091809..ba55e086384b 100644 --- a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/volume/UpdateVolumeHandler.java +++ b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/volume/UpdateVolumeHandler.java @@ -63,6 +63,8 @@ protected void execute(OzoneClient client, OzoneAddress address) } } - printObjectAsJson(volume); + // For printing newer modificationTime. + OzoneVolume updatedVolume = client.getObjectStore().getVolume(volumeName); + printObjectAsJson(updatedVolume); } }