This is an automated email from the ASF dual-hosted git repository. sammichen pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/hadoop-ozone.git
The following commit(s) were added to refs/heads/master by this push: new 525ecbb HDDS-3727. Volume space: check quotaUsageInBytes when write key. (#1434) 525ecbb is described below commit 525ecbbd6679f8024318c5a04c29098b903312cc Author: micah zhao <micahz...@tencent.com> AuthorDate: Tue Sep 29 11:19:09 2020 +0800 HDDS-3727. Volume space: check quotaUsageInBytes when write key. (#1434) --- .../hadoop/ozone/om/exceptions/OMException.java | 4 +- .../hadoop/fs/ozone/TestRootedOzoneFileSystem.java | 4 +- .../client/rpc/TestOzoneRpcClientAbstract.java | 83 +++++++++++++++++++++- .../src/main/proto/OmClientProtocol.proto | 2 + .../ozone/om/request/file/OMFileCreateRequest.java | 14 ++-- .../om/request/key/OMAllocateBlockRequest.java | 18 ++--- .../ozone/om/request/key/OMKeyCreateRequest.java | 23 +++--- .../hadoop/ozone/om/request/key/OMKeyRequest.java | 22 ++++++ .../ozone/om/request/TestOMRequestUtils.java | 1 + 9 files changed, 141 insertions(+), 30 deletions(-) diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/exceptions/OMException.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/exceptions/OMException.java index e08dccb..a2f4d6a 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/exceptions/OMException.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/exceptions/OMException.java @@ -229,7 +229,9 @@ public class OMException extends IOException { NOT_SUPPORTED_OPERATION, - PARTIAL_RENAME + PARTIAL_RENAME, + + QUOTA_EXCEEDED } } 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 0dd960e..daea4aa 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 @@ -818,11 +818,11 @@ public class TestRootedOzoneFileSystem { VolumeArgs volumeArgs = new VolumeArgs.Builder() .setAcls(Collections.singletonList(aclWorldAccess)) .setQuotaInCounts(1000) - .setQuotaInBytes("1MB").build(); + .setQuotaInBytes("1TB").build(); // Sanity check Assert.assertNull(volumeArgs.getOwner()); Assert.assertNull(volumeArgs.getAdmin()); - Assert.assertEquals("1MB", volumeArgs.getQuotaInBytes()); + Assert.assertEquals("1TB", volumeArgs.getQuotaInBytes()); Assert.assertEquals(1000, volumeArgs.getQuotaInCounts()); Assert.assertEquals(0, volumeArgs.getMetadata().size()); Assert.assertEquals(1, volumeArgs.getAcls().size()); diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneRpcClientAbstract.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneRpcClientAbstract.java index e45c8bd..44423e1 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneRpcClientAbstract.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/client/rpc/TestOzoneRpcClientAbstract.java @@ -708,8 +708,89 @@ public abstract class TestOzoneRpcClientAbstract { } @Test + public void testCheckUsedBytesQuota() throws IOException { + String volumeName = UUID.randomUUID().toString(); + String bucketName = UUID.randomUUID().toString(); + OzoneVolume volume = null; + + String value = "sample value"; + int blockSize = (int) ozoneManager.getConfiguration().getStorageSize( + OZONE_SCM_BLOCK_SIZE, OZONE_SCM_BLOCK_SIZE_DEFAULT, StorageUnit.BYTES); + int valueLength = value.getBytes().length; + int countException = 0; + + store.createVolume(volumeName); + volume = store.getVolume(volumeName); + // Set quota In Bytes for a smaller value + store.getVolume(volumeName).setQuota( + OzoneQuota.parseQuota("1 Bytes", 100)); + volume.createBucket(bucketName); + OzoneBucket bucket = volume.getBucket(bucketName); + + // Test write key. + // The remaining quota does not satisfy a block size, so the write fails. + try { + writeKey(bucket, UUID.randomUUID().toString(), ONE, value, valueLength); + } catch (IOException ex) { + countException++; + GenericTestUtils.assertExceptionContains("QUOTA_EXCEEDED", ex); + } + // Write failed, volume usedBytes should be 0 + Assert.assertEquals(0L, store.getVolume(volumeName).getUsedBytes()); + + // Test write file. + // The remaining quota does not satisfy a block size, so the write fails. + try { + writeFile(bucket, UUID.randomUUID().toString(), ONE, value, 0); + } catch (IOException ex) { + countException++; + GenericTestUtils.assertExceptionContains("QUOTA_EXCEEDED", ex); + } + // Write failed, volume usedBytes should be 0 + Assert.assertEquals(0L, store.getVolume(volumeName).getUsedBytes()); + + // Write a key(with two blocks), test allocateBlock fails. + store.getVolume(volumeName).setQuota( + OzoneQuota.parseQuota(blockSize + "Bytes", 100)); + try { + OzoneOutputStream out = bucket.createKey(UUID.randomUUID().toString(), + valueLength, STAND_ALONE, ONE, new HashMap<>()); + for (int i = 0; i <= blockSize / value.length(); i++) { + out.write(value.getBytes()); + } + out.close(); + } catch (IOException ex) { + countException++; + GenericTestUtils.assertExceptionContains("QUOTA_EXCEEDED", ex); + } + // AllocateBlock failed, volume usedBytes should be 1 * blockSize. + Assert.assertEquals(blockSize, store.getVolume(volumeName).getUsedBytes()); + + // Write large key(with five blocks), the first four blocks will succeed, + // while the later block will fail. + store.getVolume(volumeName).setQuota( + OzoneQuota.parseQuota(5 * blockSize + "Bytes", 100)); + try { + OzoneOutputStream out = bucket.createKey(UUID.randomUUID().toString(), + valueLength, STAND_ALONE, ONE, new HashMap<>()); + for (int i = 0; i <= (4 * blockSize) / value.length(); i++) { + out.write(value.getBytes()); + } + out.close(); + } catch (IOException ex) { + countException++; + GenericTestUtils.assertExceptionContains("QUOTA_EXCEEDED", ex); + } + // AllocateBlock failed, volume usedBytes should be (4 + 1) * blockSize + Assert.assertEquals(5 * blockSize, + store.getVolume(volumeName).getUsedBytes()); + + Assert.assertEquals(4, countException); + } + + @Test @SuppressWarnings("methodlength") - public void testVolumeAndBucketUsedBytes() throws IOException { + public void testVolumeUsedBytes() throws IOException { String volumeName = UUID.randomUUID().toString(); String bucketName = UUID.randomUUID().toString(); OzoneVolume volume = null; diff --git a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto index a153671..3b70258 100644 --- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto +++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto @@ -314,6 +314,8 @@ enum Status { PARTIAL_RENAME = 65; + QUOTA_EXCEEDED = 66; + } /** diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java index 3ddf13f..367e4ba 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMFileCreateRequest.java @@ -277,6 +277,14 @@ public class OMFileCreateRequest extends OMKeyRequest { .collect(Collectors.toList()); omKeyInfo.appendNewBlocks(newLocationList, false); + omVolumeArgs = getVolumeInfo(omMetadataManager, volumeName); + omBucketInfo = getBucketInfo(omMetadataManager, volumeName, bucketName); + // check volume quota + long preAllocatedSpace = newLocationList.size() + * ozoneManager.getScmBlockSize() + * omKeyInfo.getFactor().getNumber(); + checkVolumeQuotaInBytes(omVolumeArgs, preAllocatedSpace); + // Add to cache entry can be done outside of lock for this openKey. // Even if bucket gets deleted, when commitKey we shall identify if // bucket gets deleted. @@ -290,13 +298,7 @@ public class OMFileCreateRequest extends OMKeyRequest { bucketName, Optional.absent(), Optional.of(missingParentInfos), trxnLogIndex); - long scmBlockSize = ozoneManager.getScmBlockSize(); - omVolumeArgs = getVolumeInfo(omMetadataManager, volumeName); - omBucketInfo = getBucketInfo(omMetadataManager, volumeName, bucketName); - // update usedBytes atomically. - long preAllocatedSpace = newLocationList.size() * scmBlockSize - * omKeyInfo.getFactor().getNumber(); omVolumeArgs.getUsedBytes().add(preAllocatedSpace); omBucketInfo.getUsedBytes().add(preAllocatedSpace); diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMAllocateBlockRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMAllocateBlockRequest.java index 55296da..afd6162 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMAllocateBlockRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMAllocateBlockRequest.java @@ -164,7 +164,7 @@ public class OMAllocateBlockRequest extends OMKeyRequest { getOmRequest()); OMClientResponse omClientResponse = null; - OmKeyInfo openKeyInfo; + OmKeyInfo openKeyInfo = null; IOException exception = null; OmVolumeArgs omVolumeArgs = null; OmBucketInfo omBucketInfo = null; @@ -192,9 +192,16 @@ public class OMAllocateBlockRequest extends OMKeyRequest { KEY_NOT_FOUND); } - // Append new block List<OmKeyLocationInfo> newLocationList = Collections.singletonList( OmKeyLocationInfo.getFromProtobuf(blockLocation)); + omVolumeArgs = getVolumeInfo(omMetadataManager, volumeName); + omBucketInfo = getBucketInfo(omMetadataManager, volumeName, bucketName); + // check volume quota + long preAllocatedSpace = newLocationList.size() + * ozoneManager.getScmBlockSize() + * openKeyInfo.getFactor().getNumber(); + checkVolumeQuotaInBytes(omVolumeArgs, preAllocatedSpace); + // Append new block openKeyInfo.appendNewBlocks(newLocationList, false); // Set modification time. @@ -208,12 +215,7 @@ public class OMAllocateBlockRequest extends OMKeyRequest { new CacheKey<>(openKeyName), new CacheValue<>(Optional.of(openKeyInfo), trxnLogIndex)); - long scmBlockSize = ozoneManager.getScmBlockSize(); - omVolumeArgs = getVolumeInfo(omMetadataManager, volumeName); - omBucketInfo = getBucketInfo(omMetadataManager, volumeName, bucketName); // update usedBytes atomically. - long preAllocatedSpace = newLocationList.size() * scmBlockSize - * openKeyInfo.getFactor().getNumber(); omVolumeArgs.getUsedBytes().add(preAllocatedSpace); omBucketInfo.getUsedBytes().add(preAllocatedSpace); @@ -239,8 +241,6 @@ public class OMAllocateBlockRequest extends OMKeyRequest { auditLog(auditLogger, buildAuditMessage(OMAction.ALLOCATE_BLOCK, auditMap, exception, getOmRequest().getUserInfo())); - - return omClientResponse; } } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java index eeb2ab7..f16153d 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java @@ -286,17 +286,8 @@ public class OMKeyCreateRequest extends OMKeyRequest { .collect(Collectors.toList()); omKeyInfo.appendNewBlocks(newLocationList, false); - // Add to cache entry can be done outside of lock for this openKey. - // Even if bucket gets deleted, when commitKey we shall identify if - // bucket gets deleted. - omMetadataManager.getOpenKeyTable().addCacheEntry( - new CacheKey<>(dbOpenKeyName), - new CacheValue<>(Optional.of(omKeyInfo), trxnLogIndex)); - - long scmBlockSize = ozoneManager.getScmBlockSize(); omVolumeArgs = getVolumeInfo(omMetadataManager, volumeName); omBucketInfo = getBucketInfo(omMetadataManager, volumeName, bucketName); - // Here we refer to the implementation of HDFS: // If the key size is 600MB, when createKey, keyLocationInfo in // keyLocationList is 3, and the every pre-allocated block length is @@ -304,12 +295,22 @@ public class OMKeyCreateRequest extends OMKeyRequest { // ize is 256MB * 3 * 3. We will allocate more 256MB * 3 * 3 - 600mb * 3 // = 504MB in advance, and we will subtract this part when we finally // commitKey. - long preAllocatedSpace = newLocationList.size() * scmBlockSize + long preAllocatedSpace = newLocationList.size() + * ozoneManager.getScmBlockSize() * omKeyInfo.getFactor().getNumber(); + // check volume quota + checkVolumeQuotaInBytes(omVolumeArgs, preAllocatedSpace); + + // Add to cache entry can be done outside of lock for this openKey. + // Even if bucket gets deleted, when commitKey we shall identify if + // bucket gets deleted. + omMetadataManager.getOpenKeyTable().addCacheEntry( + new CacheKey<>(dbOpenKeyName), + new CacheValue<>(Optional.of(omKeyInfo), trxnLogIndex)); + omVolumeArgs.getUsedBytes().add(preAllocatedSpace); omBucketInfo.getUsedBytes().add(preAllocatedSpace); - // Prepare response omResponse.setCreateKeyResponse(CreateKeyResponse.newBuilder() .setKeyInfo(omKeyInfo.getProtobuf()) diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java index a3761a5..e24f4e2 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyRequest.java @@ -33,6 +33,7 @@ import com.google.common.base.Optional; import com.google.common.base.Preconditions; import org.apache.hadoop.hdds.utils.db.cache.CacheKey; import org.apache.hadoop.ozone.OzoneAcl; +import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.om.PrefixManager; import org.apache.hadoop.ozone.om.ResolvedBucket; import org.apache.hadoop.ozone.om.helpers.BucketEncryptionKeyInfo; @@ -534,6 +535,27 @@ public abstract class OMKeyRequest extends OMClientRequest { } /** + * Check volume quota in bytes. + * @param omVolumeArgs + * @param allocateSize + * @throws IOException + */ + protected void checkVolumeQuotaInBytes(OmVolumeArgs omVolumeArgs, + long allocateSize) throws IOException { + if (omVolumeArgs.getQuotaInBytes() > OzoneConsts.QUOTA_RESET) { + long usedBytes = omVolumeArgs.getUsedBytes().sum(); + long quotaInBytes = omVolumeArgs.getQuotaInBytes(); + if (quotaInBytes - usedBytes < allocateSize) { + throw new OMException("The DiskSpace quota of volume:" + + omVolumeArgs.getVolume() + "exceeded: quotaInBytes: " + + quotaInBytes + " Bytes but diskspace consumed: " + (usedBytes + + allocateSize) + " Bytes.", + OMException.ResultCodes.QUOTA_EXCEEDED); + } + } + } + + /** * Check directory exists. If exists return true, else false. * @param volumeName * @param bucketName 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 144750d..b7ee00b 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 @@ -283,6 +283,7 @@ public final class TestOMRequestUtils { OmVolumeArgs omVolumeArgs = OmVolumeArgs.newBuilder().setCreationTime(Time.now()) .setVolume(volumeName).setAdminName(ownerName) + .setQuotaInBytes(Long.MAX_VALUE) .setOwnerName(ownerName).build(); omMetadataManager.getVolumeTable().put( omMetadataManager.getVolumeKey(volumeName), omVolumeArgs); --------------------------------------------------------------------- To unsubscribe, e-mail: ozone-commits-unsubscr...@hadoop.apache.org For additional commands, e-mail: ozone-commits-h...@hadoop.apache.org