Copilot commented on code in PR #10792:
URL: https://github.com/apache/ozone/pull/10792#discussion_r3606133579


##########
hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java:
##########
@@ -274,6 +280,47 @@ OzoneBucket getBucket(OFSPath ofsPath, boolean 
createIfNotExist)
         createIfNotExist);
   }
 
+  private static String bucketLayoutCacheKey(String volumeStr, String 
bucketStr) {
+    return volumeStr + OZONE_URI_DELIMITER + bucketStr;
+  }
+
+  private BucketLayout validateBucketLayoutForBucket(OzoneBucket bucket)
+      throws IOException {
+    BucketLayout resolvedBucketLayout =
+        OzoneClientUtils.resolveLinkBucketLayout(bucket, objectStore,
+            new HashSet<>());
+    OzoneFSUtils.validateBucketLayout(bucket.getName(), resolvedBucketLayout);
+    return resolvedBucketLayout;
+  }
+
+  private void cacheValidatedBucketLayout(String volumeStr, String bucketStr,
+      BucketLayout layout) {
+    validatedBucketLayouts.putIfAbsent(
+        bucketLayoutCacheKey(volumeStr, bucketStr), layout);
+  }
+
+  private void validateAndCacheBucketLayout(String volumeStr, String bucketStr,
+      OzoneBucket bucket) throws IOException {
+    BucketLayout layout = validateBucketLayoutForBucket(bucket);
+    cacheValidatedBucketLayout(volumeStr, bucketStr, layout);
+  }
+
+  private void resolveAndValidateBucketLayout(String volumeStr, String 
bucketStr)
+      throws IOException {
+    OzoneBucket bucket = proxy.getBucketDetails(volumeStr, bucketStr);
+    validateAndCacheBucketLayout(volumeStr, bucketStr, bucket);
+  }
+
+  private void ensureBucketLayoutValid(OFSPath ofsPath) throws IOException {
+    String volumeStr = ofsPath.getVolumeName();
+    String bucketStr = ofsPath.getBucketName();
+    if (validatedBucketLayouts.containsKey(
+        bucketLayoutCacheKey(volumeStr, bucketStr))) {
+      return;
+    }
+    resolveAndValidateBucketLayout(volumeStr, bucketStr);
+  }

Review Comment:
   ensureBucketLayoutValid() uses containsKey() followed by a separate 
getBucketDetails()+putIfAbsent(). Under concurrent access on a cold bucket, 
multiple threads can observe the cache miss and all issue redundant 
getBucketDetails (GetBucketInfo) RPCs, which undermines the goal of avoiding 
extra OM calls. Using computeIfAbsent() makes the cache population atomic and 
ensures at most one RPC per (volume,bucket) when warming the cache.



##########
hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java:
##########
@@ -132,6 +133,11 @@ public class BasicRootedOzoneClientAdapterImpl
   private BucketLayout defaultOFSBucketLayout;
   private final OzoneConfiguration config;
   private final OzoneClientConfig clientConfig;
+  /**
+   * Cache of successfully validated bucket layouts for read paths.
+   */
+  private final ConcurrentHashMap<String, BucketLayout> validatedBucketLayouts 
=
+      new ConcurrentHashMap<>();

Review Comment:
   validatedBucketLayouts is an unbounded cache that grows monotonically with 
every distinct (volume,bucket) accessed by this client process. In long-lived 
OzoneFS clients that touch many buckets (e.g., gateway services or multi-tenant 
jobs), this can become an unbounded memory growth vector. Consider using a 
bounded/expiring cache (e.g., Guava Cache with maximumSize/expireAfterAccess) 
or otherwise limiting growth/invalidation.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to