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 <[email protected]>
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: [email protected]
For additional commands, e-mail: [email protected]