yandrey321 opened a new pull request, #11380:
URL: https://github.com/apache/ozone/pull/11380

   ## What changes were proposed in this pull request?
   
   `BasicRootedOzoneClientAdapterImpl.getFileChecksum` issues three OM RPCs per 
call:
   `InfoVolume`, `InfoBucket`, and `LookupKey`. Through a link bucket it is 
five, because the link
   resolution repeats the volume and bucket lookups. Only the key lookup 
carries information the
   checksum needs — the volume and bucket objects were used solely for 
`getName()`.
   
   The `InfoBucket` call existed only to reject OBJECT_STORE buckets, which 
have no file system
   semantics. This patch moves that check to the server, where the bucket is 
already resolved, and the
   other two RPCs then have no reason to exist.
   
   ### Server side
   
   `OmMetadataReader.lookupFile` now validates the resolved bucket layout and 
rejects OBJECT_STORE,
   mirroring what HDDS-15925 (#11226) did for `getFileStatus`. 
`OzoneFSUtils.validateBucketLayout`'s
   `IllegalArgumentException` is wrapped as 
`OMException(NOT_SUPPORTED_OPERATION)` so it reaches the
   client as a normal, non-retryable RPC response instead of escaping the read 
handler's `IOException`
   catch and triggering a client retry storm.
   
   `lookupFile` is the right home for the check: it is the file system twin of 
`lookupKey`, it already
   resolves the bucket, and it previously performed no layout validation at 
all. `lookupKey` cannot take
   the check, because it is shared with OBS and S3 reads.
   
   `lookupFile` is otherwise equivalent to `lookupKey` for these arguments — 
both honor
   `getLatestVersionLocation()`, call `refresh()` and `sortDatanodes()`, check 
`ResourceType.KEY`/`READ`,
   and apply `normalizeKeyArgs(bucket.update(args), bucket)`. Both also call 
`addBlockToken4Read`, which
   is why the checksum cannot instead be routed through `getFileStatus`:
   `KeyManagerImpl.getOzoneFileStatus{,FSO}` never adds block tokens, so the 
returned locations would be
   unusable in secure mode.
   
   ### Client side
   
   `OzoneClientUtils.getFileChecksumWithCombineMode` now takes `(volumeName, 
bucketName, keyName, …)`
   plus a `useLookupFile` flag instead of `OzoneVolume`/`OzoneBucket`. The 
name-based signature is pushed
   down through `ChecksumHelperFactory`, `BaseFileChecksumHelper` and both 
subclasses, which removes the
   implicit coupling that the helpers may only ever call `getName()` on those 
objects.
   
   The ofs adapter gates on the negotiated OM version:
   
   ```java
   boolean omRejectsObs = proxy.getOmVersion()
       .compareTo(OzoneManagerVersion.LOOKUP_FILE_REJECTS_OBS) >= 0;
   ```
   
   New OM: one `LookupFile`. Pre-upgrade OM (a new client against an older 
server during a rolling
   upgrade): keep the client-side layout check and use `LookupKey` — still two 
RPCs rather than three,
   because the `InfoVolume` call is dropped unconditionally. 
`OzoneManagerUtils.reportNotFound` probes
   the volume table and raises `VOLUME_NOT_FOUND` before falling back to 
`BUCKET_NOT_FOUND`, so dropping
   it loses no error fidelity. The fallback retires itself as clusters upgrade.
   
   `NOT_SUPPORTED_OPERATION` is mapped back to `IllegalArgumentException`, so 
the user-visible behavior
   for an OBS bucket is unchanged — the same mapping #11226 uses for 
`getFileStatus`. `NOT_A_FILE`,
   which is how `lookupFile` reports a directory where `lookupKey` reported 
`KEY_NOT_FOUND`, becomes
   `FileNotFoundException`, matching HDFS.
   
   `OzoneManagerVersion.LOOKUP_FILE_REJECTS_OBS(15, …)` is additive. There is 
no protobuf change.
   
   o3fs (`BasicOzoneClientAdapterImpl`) and `ozone sh key checksum` 
deliberately stay on `LookupKey`:
   o3fs validates the layout once in its constructor and has no `InfoBucket` to 
save on this path, and
   the CLI must keep working against OBS buckets.
   
   ### Relation to [PR 11369](https://github.com/apache/ozone/pull/11369)
   
   [PR 11369](https://github.com/apache/ozone/pull/11369) addresses the same 
three RPCs from the client side: it drops the `InfoVolume` call and adds a
   per-bucket layout cache (`ozone.client.fs.bucket.layout.cache.expiry`, 
default 2m;
   `ozone.client.fs.bucket.layout.cache.size`, default 1000) so the 
`InfoBucket` call is paid once per
   bucket instead of once per call.
   
   The two are not in conflict, and #11369's first half — dropping 
`InfoVolume`, which is pure
   redundancy — is carried here. They differ in what the remaining `InfoBucket` 
cost becomes:
   
   | | master | #11369 (client cache) | this PR (server side) |
   |---|---|---|---|
   | OM RPCs per call | 3.00 | 2 − hitRatio | **1.00** |
   | …at a 90% hit ratio | 3.00 | 1.10 | **1.00** |
   | …cold client, or more buckets than the cache holds | 3.00 | 2.00 | 
**1.00** |
   | Staleness window | none | 2 min (default) | none |
   | New configuration | none | 2 keys | none |
   | Client memory | none | up to 1000 layouts | none |
   | Works against an un-upgraded OM | — | yes | falls back to 2.00 |
   
   At the hit ratio #11369 is designed for, the RPC counts are close (1.10 vs 
1.00) and so is the
   measured latency. The case for doing this server-side is that 1.00 is 
unconditional: there is no
   hit-ratio cliff for a cold client or a bucket count above the cache size, no 
window in which a
   deleted-and-recreated bucket resolves against a stale layout, and nothing to 
configure or invalidate.
   The cost is that the single-RPC path needs the OM upgraded; until then the 
client falls back to two
   RPCs, which is still better than master.
   
   A secondary benefit of putting the check in `lookupFile` is that it is not 
client-specific: any
   caller that reaches `lookupFile` on an OBS bucket now gets a clear 
`NOT_SUPPORTED_OPERATION` instead
   of file system semantics silently applied to a bucket that has none.
   
   Workload adapted from #11369's own benchmark so all three arms run identical 
test code:
   2000 `getFileChecksum` calls over 200 FSO buckets, 10 accesses per bucket 
from a seed-shuffled
   sequence (a 90% cache-hit workload — #11369's best case), 4 KiB files, 3 
datanodes,
   `MiniOzoneCluster` on loopback. Each arm was built and installed separately 
and run 3 times;
   figures are medians of 3.
   
   ### OM RPCs per call — exact, identical in all 9 runs
   
   | | master | #11369 | this PR |
   |---|---|---|---|
   | InfoVolume | 2000 | 0 | **0** |
   | InfoBucket | 2000 | 200 | **0** |
   | LookupKey | 2000 | 2000 | 0 |
   | LookupFile | 0 | 0 | 2000 |
   | **per call** | **3.00** | **1.10** | **1.00** |
   
   This is deterministic rather than a timing measurement. It also confirms the 
version gate negotiates
   correctly, since the single-RPC path is taken only when the OM advertises 
`LOOKUP_FILE_REJECTS_OBS`.
   
   ### Latency and throughput (medians of 3)
   
   Single-threaded:
   
   | | master | #11369 | this PR | vs master | vs #11369 |
   |---|---|---|---|---|---|
   | mean | 0.704 ms | 0.556 ms | 0.525 ms | **−25.4%** | −5.6% |
   | p50 | 0.674 ms | 0.508 ms | 0.506 ms | −24.9% | −0.4% (tie) |
   | p99 | 1.008 ms | 0.953 ms | 0.799 ms | −20.7% | −16.2% |
   | throughput | 1420 ops/s | 1798 ops/s | 1903 ops/s | **+34.0%** | +5.9% |
   
   10 concurrent threads sharing one `FileSystem`:
   
   | | master | #11369 | this PR | vs master | vs #11369 |
   |---|---|---|---|---|---|
   | mean | 2.324 ms | 1.785 ms | 1.730 ms | **−25.6%** | −3.1% |
   | p50 | 2.240 ms | 1.701 ms | 1.648 ms | −26.4% | −3.1% |
   | throughput | 4275 ops/s | 5517 ops/s | 5733 ops/s | **+34.1%** | +3.9% |
   
   Every figure above except the single-threaded p50 has non-overlapping run 
ranges between the two
   optimized arms, so the margins are small but reproducible. Run-to-run spread 
within an arm is under
   4%.
   
   ### What the numbers do and do not support
   
   - **Against master the win is unambiguous**: 3.00 → 1.00 RPCs per call, ~25% 
lower mean and p50
     latency, ~34% higher throughput, reproduced in both concurrency regimes, 
the two regimes agreeing
     within 0.3 pp on the mean delta.
   - **Against #11369 on its best-case workload the margin is small** (3–6% on 
latency and throughput,
     16% on single-threaded p99) and should not be the reason to prefer this 
approach. The reason is the
     unconditional 1.00 and the absence of a staleness window.
   - **Concurrent p99 is not resolvable at n=3** on any arm — the ranges 
overlap heavily (master
     2.911–5.797 ms, #11369 3.179–6.378 ms, this PR 2.697–5.489 ms). Tail 
latency on a 10-thread
     2000-call MiniCluster run is dominated by a handful of outliers, and it is 
not what this change
     targets. No p99 claim is made for the concurrent case.
   - **The cold-client row (2.00 for #11369) is derived, not measured** — it 
follows directly from
     `2 − hitRatio` with no cache hits. The measured arm is the 90%-hit case 
only.
   - Latency improves less than RPC count because each call still makes one 
`GetBlockChecksum` round
     trip to a datanode. Two of roughly four hops are removed, and the two 
removed are cheap
     full-cache in-memory volume and bucket reads, which lands at about a 
quarter.
   
   Generated-by: Claude Code (claude-opus)
   
   ## What is the link to the Apache JIRA
   
   https://issues.apache.org/jira/browse/HDDS-15951
   
   ## How was this patch tested?
   
   New unit tests in `TestOMMetadataReader` — 
`lookupFileRejectsObjectStoreLayout`,
   `lookupFileAllowsLegacyLayout` — mirroring the #11226 pair.
   
   Three tests added to `AbstractRootedOzoneFileSystemTest`, so they run under 
`TestOFS`,
   `TestOFSWithFSPaths` and `TestOFSWithFSO` on the existing shared cluster 
rather than standing up
   another one:
   
   - `testGetFileChecksumUsesSingleOmRpc` — asserts `numBucketInfos`, 
`numVolumeInfos` and
     `numKeyLookups` are all unchanged across a `getFileChecksum`. The last of 
these is what proves
     `LookupFile` replaced `LookupKey`.
   - `testGetFileChecksumRejectsObsBucket`
   - `testGetFileChecksumOnDirectory`
   


-- 
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