This is an automated email from the ASF dual-hosted git repository.

sshenoy 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 a4b23971be HDDS-9803. Limit total number of buckets to avoid 
OutOfMemoryError in OM. (#5705)
a4b23971be is described below

commit a4b23971be395f4ef77ec2a88414fc1bcd5d421e
Author: Sumit Agrawal <[email protected]>
AuthorDate: Thu Dec 7 13:56:34 2023 +0530

    HDDS-9803. Limit total number of buckets to avoid OutOfMemoryError in OM. 
(#5705)
---
 .../common/src/main/resources/ozone-default.xml      |  8 ++++++++
 .../org/apache/hadoop/hdds/utils/db/TypedTable.java  |  3 +++
 .../hadoop/hdds/utils/db/cache/FullTableCache.java   |  5 +++++
 .../hdds/utils/db/cache/PartialTableCache.java       |  5 +++++
 .../hadoop/hdds/utils/db/cache/TableCache.java       |  5 +++++
 .../org/apache/hadoop/ozone/om/OMConfigKeys.java     |  4 ++++
 .../hadoop/ozone/om/exceptions/OMException.java      |  4 +++-
 .../src/main/proto/OmClientProtocol.proto            |  2 ++
 .../om/request/bucket/OMBucketCreateRequest.java     | 20 ++++++++++++++++++++
 .../om/request/TestOMClientRequestWithUserInfo.java  |  1 +
 .../om/request/bucket/TestOMBucketCreateRequest.java | 16 ++++++++++++++++
 11 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/hadoop-hdds/common/src/main/resources/ozone-default.xml 
b/hadoop-hdds/common/src/main/resources/ozone-default.xml
index db16381634..d0c8f4e2bd 100644
--- a/hadoop-hdds/common/src/main/resources/ozone-default.xml
+++ b/hadoop-hdds/common/src/main/resources/ozone-default.xml
@@ -4271,4 +4271,12 @@
       Specify if zero-copy should be enabled for EC GRPC protocol.
     </description>
   </property>
+  <property>
+    <name>ozone.om.max.buckets</name>
+    <value>100000</value>
+    <tag>OZONE, OM</tag>
+    <description>
+      maximum number of buckets across all volumes.
+    </description>
+  </property>
 </configuration>
diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/TypedTable.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/TypedTable.java
index e668413a83..761357f38a 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/TypedTable.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/TypedTable.java
@@ -441,6 +441,9 @@ public class TypedTable<KEY, VALUE> implements Table<KEY, 
VALUE> {
 
   @Override
   public long getEstimatedKeyCount() throws IOException {
+    if (cache.getCacheType() == CacheType.FULL_CACHE) {
+      return cache.size();
+    }
     return rawTable.getEstimatedKeyCount();
   }
 
diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/FullTableCache.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/FullTableCache.java
index e99fcb4165..cb1a3f16a9 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/FullTableCache.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/FullTableCache.java
@@ -210,4 +210,9 @@ public class FullTableCache<KEY, VALUE> implements 
TableCache<KEY, VALUE> {
   public CacheStats getStats() {
     return statsRecorder.snapshot();
   }
+
+  @Override
+  public CacheType getCacheType() {
+    return CacheType.FULL_CACHE;
+  }
 }
diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/PartialTableCache.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/PartialTableCache.java
index c40c4804b5..7f304810ff 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/PartialTableCache.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/PartialTableCache.java
@@ -188,4 +188,9 @@ public class PartialTableCache<KEY, VALUE> implements 
TableCache<KEY, VALUE> {
   public CacheStats getStats() {
     return statsRecorder.snapshot();
   }
+
+  @Override
+  public CacheType getCacheType() {
+    return CacheType.PARTIAL_CACHE;
+  }
 }
diff --git 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/TableCache.java
 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/TableCache.java
index d104e40a55..62de974eac 100644
--- 
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/TableCache.java
+++ 
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/db/cache/TableCache.java
@@ -105,6 +105,11 @@ public interface TableCache<KEY, VALUE> {
    */
   CacheStats getStats();
 
+  /**
+   * Return the cache type.
+   */
+  CacheType getCacheType();
+
   /**
    * Cache completeness.
    */
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
index 9b15326550..72a8d4fdc2 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/OMConfigKeys.java
@@ -586,4 +586,8 @@ public final class OMConfigKeys {
 
   public static final boolean OZONE_OM_UPGRADE_QUOTA_RECALCULATE_ENABLE_DEFAULT
       = true;
+
+  public static final String OZONE_OM_MAX_BUCKET =
+      "ozone.om.max.buckets";
+  public static final int OZONE_OM_MAX_BUCKET_DEFAULT = 100000;
 }
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 20b4fb1ed0..2e5a196852 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
@@ -267,6 +267,8 @@ public class OMException extends IOException {
 
     S3_SECRET_ALREADY_EXISTS,
     
-    INVALID_PATH
+    INVALID_PATH,
+
+    TOO_MANY_BUCKETS
   }
 }
diff --git 
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto 
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 54cafbc0ad..fd83981507 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -524,6 +524,8 @@ enum Status {
     S3_SECRET_ALREADY_EXISTS = 92;
     
     INVALID_PATH = 93;
+
+    TOO_MANY_BUCKETS = 94;
 }
 
 /**
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 58fad4a3d2..0b90fc38d2 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
@@ -31,6 +31,7 @@ import org.apache.hadoop.ozone.OzoneAcl;
 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.OMConfigKeys;
 import org.apache.hadoop.ozone.om.OMMetadataManager;
 import org.apache.hadoop.ozone.om.OMMetrics;
 import org.apache.hadoop.ozone.om.OzoneManager;
@@ -97,6 +98,8 @@ public class OMBucketCreateRequest extends OMClientRequest {
     OmUtils.validateBucketName(bucketInfo.getBucketName(),
         ozoneManager.isStrictS3());
 
+    validateMaxBucket(ozoneManager);
+
     // Get KMS provider.
     KeyProviderCryptoExtension kmsProvider =
         ozoneManager.getKmsProvider();
@@ -142,6 +145,23 @@ public class OMBucketCreateRequest extends OMClientRequest 
{
         .setCreateBucketRequest(newCreateBucketRequest.build()).build();
   }
 
+  private static void validateMaxBucket(OzoneManager ozoneManager)
+      throws IOException {
+    int maxBucket = ozoneManager.getConfiguration().getInt(
+        OMConfigKeys.OZONE_OM_MAX_BUCKET,
+        OMConfigKeys.OZONE_OM_MAX_BUCKET_DEFAULT);
+    if (maxBucket <= 0) {
+      maxBucket = OMConfigKeys.OZONE_OM_MAX_BUCKET_DEFAULT;
+    }
+    long nrOfBuckets = ozoneManager.getMetadataManager().getBucketTable()
+        .getEstimatedKeyCount();
+    if (nrOfBuckets >= maxBucket) {
+      throw new OMException("Cannot create more than " + maxBucket
+          + " buckets",
+          ResultCodes.TOO_MANY_BUCKETS);
+    }
+  }
+
   @Override
   public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
       long transactionLogIndex,
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
index 299a8d5652..3a43485278 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/TestOMClientRequestWithUserInfo.java
@@ -81,6 +81,7 @@ public class TestOMClientRequestWithUserInfo {
         ozoneManager);
     when(ozoneManager.getMetrics()).thenReturn(omMetrics);
     when(ozoneManager.getMetadataManager()).thenReturn(omMetadataManager);
+    when(ozoneManager.getConfiguration()).thenReturn(ozoneConfiguration);
     inetAddress = InetAddress.getByName("127.0.0.1");
   }
 
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 831d670e41..cbfd3f8874 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
@@ -23,6 +23,7 @@ import java.util.UUID;
 
 import org.apache.hadoop.hdds.client.DefaultReplicationConfig;
 import org.apache.hadoop.hdds.client.ECReplicationConfig;
+import org.apache.hadoop.ozone.om.OMConfigKeys;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
 import org.apache.hadoop.ozone.om.helpers.BucketLayout;
 import org.junit.jupiter.api.Assertions;
@@ -65,6 +66,21 @@ public class TestOMBucketCreateRequest extends 
TestBucketRequest {
     assertEquals("Invalid bucket name: b1", omException.getMessage());
   }
 
+  @Test
+  public void preExecuteBucketCrossesMaxLimit() throws Exception {
+    ozoneManager.getConfiguration().setInt(
+        OMConfigKeys.OZONE_OM_MAX_BUCKET, 1);
+    String volumeName = UUID.randomUUID().toString();
+    String bucketName = UUID.randomUUID().toString();
+    OMBucketCreateRequest omBucketCreateRequest = doPreExecute(volumeName,
+        bucketName);
+    doValidateAndUpdateCache(volumeName, bucketName,
+        omBucketCreateRequest.getOmRequest());
+    OMException omException = assertThrows(OMException.class,
+        () -> doPreExecute("volume2", "test2"));
+    assertEquals("Cannot create more than 1 buckets", 
omException.getMessage());
+  }
+
   @Test
   public void testValidateAndUpdateCache() throws Exception {
     String volumeName = UUID.randomUUID().toString();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to