HDDS-11232. Avoid redundant getBucketInfo RPC on OFS getFileStatus#10792
HDDS-11232. Avoid redundant getBucketInfo RPC on OFS getFileStatus#10792jojochuang wants to merge 4 commits into
Conversation
Cache validated bucket layouts per volume/bucket and call GetFileStatus directly after cache warm-up, preserving layout checks and headOp behavior. Co-authored-by: Cursor <cursoragent@cursor.com> Change-Id: Icddbc99fee0cf0e78e52919283f93d29a1986a1c
There was a problem hiding this comment.
Pull request overview
This PR optimizes ofs:// getFileStatus() by caching per-bucket layout validation in BasicRootedOzoneClientAdapterImpl, so repeated getFileStatus() calls can avoid an extra getBucketInfo/getBucketDetails round-trip and rely on a single OM GetFileStatus RPC after warm-up.
Changes:
- Added a
(volume, bucket)-scoped in-memory cache for validated bucket layouts and wired it into the bucket-resolution path. - Updated non-snapshot
getFileStatusto validate bucket layout once (cached) and then callproxy.getOzoneFileStatus(...)directly. - Added integration tests asserting RPC-count behavior after cache warm-up and covering bucket-root stats, OBS-bucket layout rejection, and missing-file behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java | Introduces cached bucket-layout validation and routes getFileStatus through a single OM RPC after warm-up. |
| hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/AbstractRootedOzoneFileSystemTest.java | Adds integration coverage for the single-RPC behavior and additional getFileStatus edge cases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| 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); | ||
| } |
| } finally { | ||
| objectStore.deleteVolume(obsBucket.getVolumeName()); | ||
| } |
Delete the bucket before removing the volume to avoid VOLUME_NOT_EMPTY. Co-authored-by: Cursor <cursoragent@cursor.com> Change-Id: Iddfefe48d716e77cb58501514c919a44194cdae7
| 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); | ||
| } |
| /** | ||
| * Cache of successfully validated bucket layouts for read paths. | ||
| */ | ||
| private final ConcurrentHashMap<String, BucketLayout> validatedBucketLayouts = | ||
| new ConcurrentHashMap<>(); |
Co-authored-by: Cursor <cursoragent@cursor.com> Change-Id: Ifc177a61594da562cc3cbc13b6f622fada55971d
Mock ClientProtocol and warm the layout cache after getFileStatus stopped calling OzoneBucket.getFileStatus for non-snapshot paths. Co-authored-by: Cursor <cursoragent@cursor.com> Change-Id: I34e369396f682c096fa23b0f5df7b8b165feab6f
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
hadoop-ozone/ozonefs-common/src/main/java/org/apache/hadoop/fs/ozone/BasicRootedOzoneClientAdapterImpl.java:756
- validatedBucketLayouts is never invalidated. If a bucket is deleted and later re-created (potentially with a different layout), a cached entry can cause future getFileStatus() calls to skip layout validation and bypass OBJECT_STORE rejection. At minimum, clear the cache entry when OM reports BUCKET_NOT_FOUND so the next call revalidates against the current bucket definition.
} catch (OMException e) {
if (e.getResult() == OMException.ResultCodes.FILE_NOT_FOUND) {
throw new FileNotFoundException(key + ": No such file or directory!");
} else if (e.getResult() == OMException.ResultCodes.BUCKET_NOT_FOUND) {
throw new FileNotFoundException(key + ": Bucket doesn't exist!");
| Field cacheField = | ||
| BasicRootedOzoneClientAdapterImpl.class.getDeclaredField( | ||
| "validatedBucketLayouts"); | ||
| cacheField.setAccessible(true); | ||
| ConcurrentHashMap<String, BucketLayout> cache = | ||
| new ConcurrentHashMap<>(); | ||
| cache.put(volumeName + "/" + bucketName, BucketLayout.FILE_SYSTEM_OPTIMIZED); | ||
| cacheField.set(adapter, cache); |
|
@yandrey321 this PR aims to remove the extra RPC call in most cases. |
Summary
(volume, bucket)inBasicRootedOzoneClientAdapterImplgetFileStatus()onofs://sends one client→OMGetFileStatusRPC instead ofgetBucketInfo+GetFileStatusheadOppropagationTest plan
mvn -pl :ozone-filesystem-common -am compileTestOFS#testGetFileStatusUsesSingleOmRpcAfterCacheWarmand related new casesGenerated-by: Cursor (Composer)
Made with Cursor