Andrey Yarovoy created HDDS-16948:
-------------------------------------
Summary: Remove the per-call InfoBucket from rooted-ofs open
Key: HDDS-16948
URL: https://issues.apache.org/jira/browse/HDDS-16948
Project: Apache Ozone
Issue Type: Improvement
Components: Ozone Client
Reporter: Andrey Yarovoy
`BasicRootedOzoneClientAdapterImpl.readFile` (behind `FileSystem.open`) calls
`getBucket()`, which is an
`InfoBucket` RPC. For a link bucket it adds an `InfoVolume` and an `InfoBucket`
per hop. It then calls
`OzoneBucket.readFile`. Every `open` therefore costs at least 2 OM requests. On
read-heavy file system
workloads (Hive, Impala, Spark scans) `open` is one of the most frequent
metadata operations, so this is
the largest single `InfoBucket` source left after HDDS-15925 and HDDS-16760.
The fetch does one job: `OzoneFSUtils.validateBucketLayout`, which rejects
OBJECT_STORE. `readFile`
reads nothing else from the bucket.
### Why HDDS-15951's lookupFile check does not cover this
`RpcClient.readFile` uses `lookupFile` only for an OM older than
`OPTIMIZED_GET_KEY_INFO` (3). For every
current OM it sends **`GetKeyInfo`**, then checks `isFile()` on the client. Its
read-retry path
(`RpcClient.getKeyInfo`) also sends `GetKeyInfo`. So the OBJECT_STORE rejection
that HDDS-15951 added to
`lookupFile` is never reached from `open`.
### Why the rejection is opt-in
`GetKeyInfo` is the object store read RPC. It sits behind
`OzoneBucket.readKey`, `getKeyDetails`,
`headObject` and the S3 key lookups (`assumeS3Context=true`), which the S3
Gateway uses for GetObject and
HeadObject. `cli-shell`, `freon` and `cli-debug` call it as well. An
unconditional OBJECT_STORE rejection
would break all of them. As in HDDS-16760, the client asks for the check:
{code}
message GetKeyInfoRequest {
required KeyArgs keyArgs = 1;
optional bool assumeS3Context = 2;
// Set by file system clients: OM rejects the request with
// NOT_SUPPORTED_OPERATION if the resolved bucket layout is OBJECT_STORE.
optional bool requireFileSystemLayout = 3;
}
{code}
### Proposed change
*OM.*
* `OzoneManagerRequestHandler.getKeyInfo` copies the field into `OmKeyArgs`.
The `requireFileSystemLayout`
field added there by HDDS-16760 is reused, and the builder already survives
`ResolvedBucket.update`.
* `OmMetadataReader.getKeyInfo` already holds the link-resolved
`ResolvedBucket`. When the field is set,
it calls the existing `validateFileSystemLayout(bucket)` before the ACL check.
This is the same
placement as `listStatus` in HDDS-16760, so it adds no lookup.
*Client.*
* `RpcClient.readFile` sets the field on the `OmKeyArgs` it builds for
`GetKeyInfo`. The read-retry
`getKeyInfo` call also sets it, so a retried read is checked too.
* `OzoneManagerProtocolClientSideTranslatorPB.getKeyInfo` builds `KeyArgs`
through
`OmKeyArgs.toProtobuf()` but sets the request-level field explicitly. Do not
set it unconditionally:
`readKey` / `getKeyDetails` share this translator method.
* The adapter needs a way to ask for it, mirroring HDDS-16760's
`ListStatusLightOptions`. Options are a
`readFile` overload or an options object on `ClientProtocol`, or
`OzoneBucket.readFile` setting it
itself. `OzoneBucket.readFile` is a file-oriented API, so it could always set
it; decide on review.
* The adapter skips `getBucket()` when `proxy.getOmVersion() >=` a new
`OzoneManagerVersion` constant.
Place it after `LIST_STATUS_REJECTS_OBS(101)` and never below `ZDU(100)`; the
number is assigned at
merge. It maps `NOT_SUPPORTED_OPERATION` to `IllegalArgumentException`. Against
any older OM, including
one that reports ZDU, it keeps the current path.
* The `lookupFile` branch for OMs older than version 3 is unchanged, and such
OMs take the fallback anyway.
### Rejected alternative
`GetKeyInfoResponse` already returns `bucketLayout` (HDDS-16362), so the client
could check that instead
and need no new request field. Two problems:
* It only works when the key exists. A missing key on an OBJECT_STORE bucket
would then report
`FileNotFoundException` instead of today's `IllegalArgumentException`.
* The field was added without a version gate, so an older OM leaves it unset,
and the client cannot
tell "not OBJECT_STORE" from "not reported".
### Compatibility
| | Behavior |
|---|---|
| New client, new OM | 1 RPC (`GetKeyInfo`); OM rejects OBJECT_STORE |
| New client, older OM (incl. ZDU) | `getBucket()` + `GetKeyInfo`, as today |
| Old client / S3 Gateway / `readKey` / `getKeyDetails`, new OM | field absent
⇒ unchanged |
There is one new optional proto field, no new result code and no new
configuration.
## Testing
* Adapter (Mockito):
*`open` makes exactly one OM call, carrying the field.
*`NOT_SUPPORTED_OPERATION` maps to `IllegalArgumentException`; `KEY_NOT_FOUND`
/ `FILE_NOT_FOUND` /
`NOT_A_FILE` map to `FileNotFoundException`, as today.
* An older OM, including `ZDU`, falls back to `getBucket()`.
* `TestOMMetadataReader`:
* With the field set, `getKeyInfo` rejects OBJECT_STORE without reaching
`KeyManager` and serves FSO
and **LEGACY**.
* Without the field, it still serves OBJECT_STORE: the S3 Gateway case, and the
guard against anyone
making the check unconditional.
* The same holds with `assumeS3Context=true`.
* `TestOzoneManagerRequestHandler`: the field is forwarded into `OmKeyArgs`.
* Existing S3 and object-store read suites pass unchanged.
* `AbstractRootedOzoneFileSystemTest`: `open` on an OBJECT_STORE bucket fails
with
`IllegalArgumentException`. Do RPC counting in the adapter test, not with exact
OMMetrics deltas
(HDDS-16513).
* Benchmark `TestOfsOpenRpcBenchmark`, same shape as
`TestOfsListStatusRpcBenchmark`:
* 200 FSO buckets, open + close of a small file, single thread and 10 threads.
* n=3 per arm, built and run strictly one after the other.
* Invariant: exactly 1 OM RPC per `open` instead of 2. `open` alone, with no
data read, so DN reads do
not mask the OM saving.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]