Skip to content

HDDS-15852. Allow CopyObject to the same key when the metadata or tagging directive is REPLACE#10752

Open
rich7420 wants to merge 2 commits into
apache:masterfrom
rich7420:HDDS-15852
Open

HDDS-15852. Allow CopyObject to the same key when the metadata or tagging directive is REPLACE#10752
rich7420 wants to merge 2 commits into
apache:masterfrom
rich7420:HDDS-15852

Conversation

@rich7420

Copy link
Copy Markdown
Contributor

What changes were proposed in this pull request?

A CopyObject request whose source and destination are the same key was rejected with 400 InvalidRequest ("This copy request is illegal because it is trying to copy an object to it self ...") whenever no x-amz-storage-class header was present. This ignored the metadata and tagging directives.
AWS S3 permits a self-copy as long as at least one attribute is changed, including user metadata (x-amz-metadata-directive: REPLACE) or the tag set (x-amz-tagging-directive: REPLACE). The in-place metadata update (self-copy with MetadataDirective=REPLACE) is the canonical way to change an object's metadata.
The self-copy guard in ObjectEndpoint only accounted for the storage-class case. This change reads the metadata and tagging directives up front and only rejects the self-copy when neither directive is REPLACE (and the storage type is default). When either is REPLACE, the request falls through to the normal copy path, which replaces the metadata or tags in place. The storage-class-only self-copy behaviour is unchanged.

What is the link to the Apache JIRA?

https://issues.apache.org/jira/browse/HDDS-15852

How was this patch tested?

https://github.com/rich7420/ozone/actions/runs/29305530153

…ging directive is REPLACE

A self-copy (same source and destination key) was rejected with 400
InvalidRequest whenever no storage class was set, ignoring the metadata and
tagging directives. AWS permits a self-copy as long as at least one attribute
is changed, so gate the rejection on the metadata/tag directive not being
REPLACE and let REPLACE fall through to the normal copy path.
Copilot AI review requested due to automatic review settings July 14, 2026 05:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@adoroszlai
adoroszlai requested a review from peterxcli July 14, 2026 10:21

@chihsuan chihsuan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this, @rich7420. the metadata self-copy case looks good!

There are two areas where I may be missing some context, so I’m raising them here for discussion:

  1. Was the tag-only self-copy behavior verified against AWS? I found documentation for replacing tags as part of CopyObject, but not for using tag replacement alone to
    make a same-key copy legal. It is quite possible there is AWS behavior or testing behind this change that I have not found. If available, could you share the reproduction? The bucket encryption configuration would also be helpful because encryption can independently permit in-place copies.
  2. Would you mind extending the metadata integration test with a HeadObject check? Verifying that the new metadata exists and the old metadata is gone would make the
    end-to-end coverage stronger.

References:

// The object is still readable with its original content after the in-place copy.
ResponseBytes<GetObjectResponse> objectBytes = s3Client.getObjectAsBytes(
b -> b.bucket(bucketName).key(key));
assertEquals(content, objectBytes.asUtf8String());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also verify the resulting metadata through HeadObject here?

This test currently confirms that the self-copy succeeds and that the object content is preserved, but it would still pass if Ozone accepted the request without replacing the metadata. Since metadata replacement is the behavior this PR fixes, it would be useful to assert both that meta2=v2 is present and that meta1 is absent.

For example:

    HeadObjectResponse head = s3Client.headObject(
        b -> b.bucket(bucketName).key(key));
    assertEquals("v2", head.metadata().get("meta2"));
    assertFalse(head.metadata().containsKey("meta1"));

The unit test verifies the internal OzoneKeyDetails; this assertion would additionally cover the complete AWS SDK → S3 Gateway → OM → HeadObject path. Thanks!

@adoroszlai adoroszlai added the s3 S3 Gateway label Jul 15, 2026
@yandrey321

Copy link
Copy Markdown
Contributor

Do we have a performance benchmark for update metadata? Do we have a confirmation that s3g just do metadata update and it takes a constant time and does not depend on the object size?

…test

Per review, verify end-to-end that a metadata-REPLACE self-copy leaves the new
x-amz-meta entry and drops the old one, covering the AWS SDK -> S3 Gateway ->
OM -> HeadObject path (verified locally on a mini-cluster).
Copilot AI review requested due to automatic review settings July 16, 2026 01:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Gargi-jais11
Gargi-jais11 self-requested a review July 16, 2026 09:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

s3 S3 Gateway

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants