Andrey Yarovoy created HDDS-16951:
-------------------------------------

             Summary: Remove the per-call InfoBucket from rooted-ofs rename on 
FSO buckets
                 Key: HDDS-16951
                 URL: https://issues.apache.org/jira/browse/HDDS-16951
             Project: Apache Ozone
          Issue Type: Improvement
          Components: Ozone Client
            Reporter: Andrey Yarovoy


`BasicRootedOzoneFileSystem.rename` calls `adapterImpl.getBucket(ofsSrc, 
false)`. That is an `InfoBucket`,
plus an `InfoVolume` and an `InfoBucket` per link hop. It then **branches on 
the layout**:

* **FSO**: `renameFSO` → one `RenameKey`. OM renames a file or a whole 
directory atomically. Total:
2 OM RPCs.
* **LEGACY**: two or three `getFileStatus` calls, a possible `listStatus`, then 
`RenameIterator`, which
issues another `getBucket()` and one `RenameKey` per key under the source.
* **OBJECT_STORE**: `getBucket()` throws `IllegalArgumentException` from 
`validateBucketLayout`.

So for the common case, an FSO bucket, half the RPCs of every `rename` exist 
only to learn the layout. Hive, Spark and MapReduce commit by renaming, so 
`rename` is one of the hottest file system write
operations.

This differs from the other Jiras under HDDS-16761. The fetch is not just a 
rejection check. Its result chooses *which algorithm* the client runs. So 
moving a check into OM is not enough. OM has to say "this is not FSO", and the 
client then has to fall back.

### Why it has to be opt-in

`RenameKey` is dual-use. `OMKeyRenameRequest` is registered for 
`BucketLayout.OBJECT_STORE` (that
registration also serves LEGACY), and these callers send it on any layout:
* `cli-shell`'s `RenameKeyHandler`;
* `TrashOzoneFileSystem`;
* `KeyLifecycleService` (non-OBJECT_STORE);
* the public `OzoneBucket.renameKey`.

On LEGACY a single `RenameKey` renames one key, not a directory tree. So OM 
cannot reject anything by default, and the client needs a request field:

{code}
message RenameKeyRequest {
required KeyArgs keyArgs = 1;
required string toKeyName = 2;
optional uint64 updateID = 3;
// Set by file system clients that rely on atomic directory rename: OM
// rejects the request with NOT_SUPPORTED_OPERATION unless the resolved
// bucket layout is FILE_SYSTEM_OPTIMIZED.
optional bool requireFileSystemOptimized = 4;
}
{code}

This is deliberately **not** `requireFileSystemLayout`, which only rejects 
OBJECT_STORE.
Here LEGACY must also be rejected, because a single `RenameKey` there does not 
implement the file system `rename`. The name says what it requires.

### Proposed change

*OM.* Check on the leader before Ratis, in `OMKeyRenameRequest.preExecute` / 
`OMKeyRenameRequestWithFSO.preExecute`
or right after `createClientRequest`. Use the link-resolved layout 
`BucketLayoutAwareOMKeyRequestFactory`
already read. When the field is set and the layout is not 
`FILE_SYSTEM_OPTIMIZED`, throw
`OMException(NOT_SUPPORTED_OPERATION)`. Neither rename class uses that code 
today, so the client can treat it as unambiguous. Do not put the check in 
`createRequest` itself, because that also runs at apply time.

*Client.* When `proxy.getOmVersion() >=` a new `OzoneManagerVersion` constant, 
`BasicRootedOzoneFileSystem.rename`
first sends `RenameKey` with the field set, with no `getBucket()` before it. 
Place the constant after
`LIST_STATUS_REJECTS_OBS(101)`, never below `ZDU(100)`; the number is assigned 
at merge.

* Success, or `KEY_ALREADY_EXISTS` / `KEY_RENAME_ERROR` / `KEY_NOT_FOUND`: same 
handling as today's
`renameFSO`.
* `NOT_SUPPORTED_OPERATION`: run today's code from `getBucket()` onward. 
OBJECT_STORE raises
`IllegalArgumentException` and LEGACY takes the iterating path, both exactly as 
today.
* `BUCKET_NOT_FOUND` / `VOLUME_NOT_FOUND`: same fallback, so the error a caller 
sees for a missing bucket
or an orphan link is the one `getBucket()` gives today.
* Against any older OM, including one that reports ZDU, keep today's path.

Cost per `rename`:
* FSO: 2 → 1 RPC.
* LEGACY: one extra failed `RenameKey`. LEGACY is rare for ofs, and its rename 
already costs many RPCs.
* OBJECT_STORE: one extra failed RPC before the same exception.

`adapterImpl.rename(OzoneBucket, …)` needs a variant that does not take a 
fetched bucket. It can build
the handle locally with `OzoneBucket.newBuilder(...)`, or call 
`ClientProtocol.renameKey` with the new
options.

### Compatibility

| | Behavior |
|---|---|
| New client, new OM, FSO | 1 RPC |
| New client, new OM, LEGACY / OBJECT_STORE | failed `RenameKey`, then today's 
path |
| New client, older OM (incl. ZDU) | as today |
| Old client / shell / trash / lifecycle / `OzoneBucket.renameKey`, new OM | 
field absent ⇒ unchanged |

There is one new optional proto field, no new result code and no new 
configuration.

Points for review:
* The field's semantics are FSO-only, and they differ from the other HDDS-16761 
fields. If reviewers
prefer one shape across Jiras, an enum `requiredBucketLayout` (FILE_SYSTEM | 
FILE_SYSTEM_OPTIMIZED) is
the alternative. Decide together with the delete Jira.
* The BUCKET/READ ACL check from `getBucketDetails` is dropped on the FSO path. 
`RenameKey` keeps its own
key ACL checks.
* The audit log shows a failed `RENAME_KEY` before `INFO_BUCKET` on LEGACY / 
OBJECT_STORE.

## Testing

* `BasicRootedOzoneFileSystem` / adapter (Mockito):
* FSO: exactly one `RenameKey` with the field set and no `getBucket()`.
*`NOT_SUPPORTED_OPERATION` on a LEGACY bucket takes the iterating path.
*`NOT_SUPPORTED_OPERATION` on an OBJECT_STORE bucket raises 
`IllegalArgumentException`.
* The `KEY_*` codes give `false` as today.
* An older OM, including one at `ZDU`, falls back.
* OM request tests:
* With the field set, FSO succeeds, and **both LEGACY and OBJECT_STORE** get 
`NOT_SUPPORTED_OPERATION`
before Ratis.
* Without the field, LEGACY and OBJECT_STORE succeed, guarding the shell, trash 
and lifecycle callers.
* A link to an FSO bucket succeeds.
* `AbstractRootedOzoneFileSystemTest` (run as `TestOFS` and `TestOFSWithFSO`): 
the existing rename suite
passes unchanged on both layouts. That includes rename into an existing 
directory, rename onto itself,
and rename across buckets (rejected client-side before any RPC). Count RPCs in 
the adapter test, not
with OMMetrics deltas (HDDS-16513).
* Benchmark `TestOfsRenameRpcBenchmark`, same shape as 
`TestOfsListStatusRpcBenchmark`:
* 200 FSO buckets, renaming one file back and forth, single-threaded and 10 
threads.
* n=3 per arm, built and run strictly one after the other.
* Invariant: exactly 1 OM RPC per FSO `rename`, from 2.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

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

Reply via email to