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

   ## What changes were proposed in this pull request?
   
   S3 `CopyObject` with the same source and destination key plus 
`x-amz-metadata-directive: REPLACE` is the mechanism AWS documents for updating 
an object's metadata in place. Today the S3 Gateway serves it by streaming 
every byte of the object from the datanodes through the gateway and writing a 
brand new key (`ObjectEndpoint#copyObject`), which is pure waste for a 
metadata-only change. This PR turns that request into a metadata-only update in 
the Ozone Manager.
   
   **New OM write request `SetObjectMetadata`** (`S3SetObjectMetadataRequest` 
plus an FSO variant) replaces the custom metadata and the tag set of an 
existing key under `BUCKET_LOCK`:
   
   * System-managed metadata entries (`ETag`, GDPR flag/secret/algorithm, 
`hsyncClientId`) are always carried over from the existing key server-side, so 
a metadata update can never corrupt the stored content ETag or make a GDPR key 
unreadable. The S3 Gateway is never trusted to filter these. ETag preservation 
is required by AWS semantics: the ETag reflects only changes to the object's 
contents, not its metadata.
   * `keyLocationVersions`, `dataSize`, replication config and 
`FileEncryptionInfo` are untouched.
   * `modificationTime` is updated (stamped in `preExecute`) because AWS 
`CopyObject` updates `LastModified`. This deliberately differs from 
`PutObjectTagging`, which keeps the modification time.
   * Tags are replaced in the same atomic request, so `x-amz-tagging-directive` 
keeps working for self-copies.
   
   **Proto / plumbing.** New `SetObjectMetadata` cmdType with request and 
response messages; metadata and tags travel in the existing `KeyArgs` fields. 
Classified as a write in `OmUtils`, registered in 
`BucketLayoutAwareOMKeyRequestFactory` and `OzoneManagerRatisUtils`, with a new 
`OMAction` audit value and OM metrics.
   
   **Version gating.** New `OzoneManagerVersion.SET_OBJECT_METADATA` checked 
client-side in `RpcClient`, and a new `OMLayoutFeature.SET_OBJECT_METADATA` 
with `@DisallowedUntilLayoutVersion` on `preExecute` so a pre-finalized cluster 
rejects the new cmdType. There is no on-disk schema change.
   
   **Client API.** `OzoneBucket#setObjectMetadata` through `ClientProtocol`, 
`RpcClient` and `OzoneManagerProtocolClientSideTranslatorPB`.
   
   **S3 Gateway.** In `ObjectEndpoint#copyObject`, a self-copy with directive 
`REPLACE` — after the copy-source preconditions are evaluated, when the storage 
class does not imply a replication change and no write preconditions are 
present — calls `setObjectMetadata` and returns the stored ETag with the new 
`LastModified`. When the OM does not support the API (older OM, pre-finalized 
cluster, or an FSO directory) it falls back silently to the existing byte-copy 
path, so mixed-version clusters keep working.
   
   ### Why a new cmdType instead of extending PutObjectTagging
   
   Any OM from version 9 onwards already accepts `PutObjectTagging`, and 
`metadata` is an existing field of `KeyArgs`, not an unknown one. An old OM 
receiving a tagging request that carried metadata would therefore replace the 
tag set, silently ignore the metadata and return `OK` — telling the client the 
metadata update succeeded when it had not happened. A distinct cmdType makes an 
old OM reject the request cleanly, which is exactly what the gateway's fallback 
keys off. Reusing the message would also require an explicit `replaceMetadata` 
flag, because "clear all metadata" and "leave metadata alone" are both the 
empty repeated field.
   
   ### Included refactor
   
   The third commit (`HDDS-16318. Deduplicate in-place key update requests and 
responses`) extracts the duplication this feature would otherwise have added 
to. `PutObjectTagging`, `DeleteObjectTagging` and `SetObjectMetadata` were 
near-verbatim copies of one request skeleton in both bucket layouts — 
`S3DeleteObjectTaggingRequest` differed from its Put sibling in eight 
substantive lines — backed by six byte-identical response classes. A shared 
`OMKeyInfoUpdateRequest` base now owns the lock / validate / mutate / cache / 
audit skeleton and both layout resolutions, and a shared 
`OMKeyInfoUpdateResponse(WithFSO)` replaces the six response classes, following 
the pattern `S3BucketTaggingRequestBase` already established for bucket 
tagging. Net 907 lines removed.
   
   That commit also normalizes two inconsistencies the duplication had let 
drift, in both cases to the object-store behaviour: the FSO tagging variants 
never called `markForAudit` (so `PutObjectTagging` and `DeleteObjectTagging` on 
an FSO bucket produced no audit record), and they logged client request 
failures without the `OMClientRequestUtils.shouldLogClientRequestFailure` 
guard. `OMKeySetTimesResponse` looks like more of the same but is genuinely 
different — it also updates FSO directories and declares `DIRECTORY_TABLE` 
cleanup — so it is left alone.
   
   The commit is self-contained and touches no proto, no client API and no S3G 
code, so it can be split into its own Jira and PR if reviewers prefer.
   
   ### Measured effect
   
   S3 Gateway side only, driven through the real `ObjectEndpoint` against the 
in-memory client stub, self-copy with metadata directive `REPLACE`, median of 
15 iterations with ABBA ordering (Apple M4, JDK 21). The "before" arm is 
produced by making the OM reject `SetObjectMetadata`, which is exactly the 
fallback path this PR adds:
   
   | object size | full copy (today) | metadata only | speedup |
   |---|---|---|---|
   | 1 MiB | 2.36 ms | 0.51 ms | 4.6x |
   | 8 MiB | 12.23 ms | 0.35 ms | 34.9x |
   | 32 MiB | 44.79 ms | 0.35 ms | 128.9x |
   | 64 MiB | 89.81 ms | 0.37 ms | 244.9x |
   
   The current cost is linear in object size, roughly 1.4 ms of gateway CPU per 
MiB; the metadata-only update is constant at about 0.35 ms. Each measurement 
was probed to confirm which path it actually took (the "before" arm issued 15 
`createKey` calls and no `setObjectMetadata`, the "after" arm the reverse), so 
neither arm silently collapsed into the other.
   
   These numbers are a lower bound rather than cluster numbers: the harness has 
no datanode I/O, no replication and no RPC. On a real cluster the same 
operation additionally stops reading N bytes from datanodes and writing N x 
replication bytes back, so a 64 MiB self-copy also avoids roughly 192 MiB of 
replicated writes.
   
   ## What is the link to the Apache JIRA
   
   https://issues.apache.org/jira/browse/HDDS-16318
   
   Related: HDDS-569 proposed a metadata-only copy in 2018.
   
   ## How was this patch tested?
   
   * New OM request unit tests for both layouts 
(`TestS3SetObjectMetadataRequest`, `TestS3SetObjectMetadataRequestWithFSO`): 
metadata replaced, reserved system keys preserved even when the request tries 
to override them, modification time updated, update ID set, and FSO directories 
rejected.
   * New `TestOMKeyInfoUpdateResponse(WithFSO)` covering the shared response 
for both layouts, replacing the six deleted response test classes.
   * All existing tagging request tests pass unchanged against the refactored 
classes (`TestS3PutObjectTaggingRequest(WithFSO)`, 
`TestS3DeleteObjectTaggingRequest(WithFSO)`), together with 
`TestBucketLayoutAwareOMKeyFactory`, which reflectively instantiates every 
registered request class in all three bucket layouts, and 
`TestCleanupTableInfo`, which reflects over the whole response package.
   * s3gateway `TestObjectPut` (50 tests), including three new ones: the 
self-copy is served as a metadata-only update with no key rewrite and the ETag 
preserved; tags survive the update under the default `COPY` tagging directive; 
and the copy falls back to the byte-copy path when the OM rejects the API, 
covering the mixed-version case.
   * `AbstractS3SDKV2Tests#testCopyObjectToSelfWithMetadataReplace` exercises 
the path end to end through the real AWS SDK v2 client, strengthened here to 
assert the ETag is preserved.
   * New robot test case in `objectcopy.robot` asserting the metadata is 
replaced in place and the object content is unchanged.
   * `checkstyle.sh` and `rat.sh` are clean.
   
   Generated-by: Claude Code (claude-fable-5)
   


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