Skip to content

Enabling Support for Conditional Single-Part Upload [AWS S3] #18092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

x-INFiN1TY-x
Copy link

@x-INFiN1TY-x x-INFiN1TY-x commented Apr 28, 2025

Enable Conditional Single-Part Uploads via executeSingleUploadConditionally

Introduce a condition-aware single-part upload method to S3BlobStore, leveraging ConditionalWriteOptions for “If-Match” and “If-None-Match” semantics and returning structured ConditionalWriteResponse results.

Method Location Purpose
executeSingleUploadConditionally S3BlobStore Conditional single-part S3 upload

Summary of Changes

  • Add executeSingleUploadConditionally(...) to S3BlobStore

  • Introduce ConditionalWriteOptions to model “If-Match” and “If-None-Match” conditions

  • Return a ConditionalWriteResponse.success(etag) on success

  • Translate HTTP 412 (precondition failed) into OpenSearchException("stale_primary_shard")

  • Wrap other S3/SDK errors in IOException and propagate via listener.onFailure(...)

  • Enforce blob size limits (≤ 5 GB and ≤ buffer size) before making any S3 requests

  • Apply custom metadata and server-side encryption (AES256 or KMS) settings consistently


Core Workflow

  1. Validate Blob Size

    • If blobSize > 5 GB or blobSize > bufferSize, throw IllegalArgumentException.

  2. Build and Send PutObjectRequest

    • Set bucket, key, contentLength, storageClass, acl, and metrics.

    • Apply conditional headers from ConditionalWriteOptions (If-Match or If-None-Match).

    • Attach metadata and configure encryption (AES256 or KMS).

    • Upload via putObject(...).

  3. Handle Response

    • If response.eTag() is non-null, return ConditionalWriteResponse.success(etag).

    • If response.eTag() is null, throw IOException and invoke listener.onFailure(...).

  4. Error Handling

    • HTTP 412 → listener receives OpenSearchException("stale_primary_shard"), then throw IOException to abort.

    • Other S3Exception/SdkException → wrap in IOException, invoke listener.onFailure(...), and rethrow.


Test Coverage Highlights

  • testExecuteSingleUploadConditionallyPreconditionFailed: ETag mismatch (HTTP 412) → OpenSearchException("stale_primary_shard").

  • testExecuteSingleUploadConditionallyS3Exception: S3 error (e.g., HTTP 403) → IOException.

  • testExecuteSingleUploadConditionallySuccess: Successful upload with metadata, AES256/KMS, and correct ETag response.

  • testExecuteSingleUploadConditionallySdkException: AWS SDK failure → IOException.

  • testExecuteSingleUploadConditionallyWithNullETag: Null ETag → IOException.

  • testExecuteSingleUploadConditionallyNullOrEmptyInput: Zero-length blob or empty ETag handling.


Related Issues


Developer Checklist

  • Add executeSingleUploadConditionally(...) to S3BlobStore

  • Introduce ConditionalWriteOptions / ConditionalWriteResponse

  • Validate size limits before request

  • Apply conditional headers correctly

  • Configure metadata and encryption settings

  • Map HTTP 412 to OpenSearchException("stale_primary_shard") + abort

  • Wrap other exceptions in IOException

  • Expand tests for conditional and boundary scenarios

  • Sign off commits per DCO

By submitting this PR, I confirm that my contribution is made under the terms of the Apache 2.0 license.

# Enable Conditional Single-Part Uploads via `executeSingleUploadConditionally` (#XXXX)

At a Glance:
Introduce a condition-aware single-part upload method to S3BlobStore, leveraging ConditionalWriteOptions for “If-Match” and “If-None-Match” semantics and returning structured ConditionalWriteResponse results.

Method Location Purpose
executeSingleUploadConditionally S3BlobStore Conditional single-part S3 upload

Summary of Changes

  • Add executeSingleUploadConditionally(...) to S3BlobStore
  • Introduce ConditionalWriteOptions to model “If-Match” and “If-None-Match” conditions
  • Return a ConditionalWriteResponse.success(etag) on success
  • Translate HTTP 412 (precondition failed) into OpenSearchException("stale_primary_shard")
  • Wrap other S3/SDK errors in IOException and propagate via listener.onFailure(...)
  • Enforce blob size limits (≤ 5 GB and ≤ buffer size) before making any S3 requests
  • Apply custom metadata and server-side encryption (AES256 or KMS) settings consistently

Core Workflow

  1. Validate Blob Size

    • If blobSize > 5 GB or blobSize > bufferSize, throw IllegalArgumentException.
  2. Build and Send PutObjectRequest

    • Set bucket, key, contentLength, storageClass, acl, and metrics.
    • Apply conditional headers from ConditionalWriteOptions (If-Match or If-None-Match).
    • Attach metadata and configure encryption (AES256 or KMS).
    • Upload via putObject(...).
  3. Handle Response

    • If response.eTag() is non-null, return ConditionalWriteResponse.success(etag).
    • If response.eTag() is null, throw IOException and invoke listener.onFailure(...).
  4. Error Handling

    • HTTP 412 → listener receives OpenSearchException("stale_primary_shard"), then throw IOException to abort.
    • Other S3Exception/SdkException → wrap in IOException, invoke listener.onFailure(...), and rethrow.

Test Coverage

  • testExecuteSingleUploadConditionallyPreconditionFailed: ETag mismatch (HTTP 412) → OpenSearchException("stale_primary_shard").
  • testExecuteSingleUploadConditionallyS3Exception: S3 error (e.g., HTTP 403) → IOException.
  • testExecuteSingleUploadConditionallySuccess: Successful upload with metadata, AES256/KMS, and correct ETag response.
  • testExecuteSingleUploadConditionallySdkException: AWS SDK failure → IOException.
  • testExecuteSingleUploadConditionallyWithNullETag: Null ETag → IOException.
  • testExecuteSingleUploadConditionallyNullOrEmptyInput: Zero-length blob or empty ETag handling.

Related Issue

Concerned RFC : RFC #17763
Parent Meta Issue : Meta #17859

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Editor _ Mermaid Chart-2025-06-02-102533

@x-INFiN1TY-x x-INFiN1TY-x changed the title Pr branch conditional single upload Support Conditional Writes for Single-Part S3 Uploads Apr 28, 2025
Copy link
Contributor

❌ Gradle check result for f1c411e: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@x-INFiN1TY-x
Copy link
Author

Flaky Test : : #14509

  • "testRecoverWhileUnderLoadAllocateReplicasRelocatePrimariesTest {p0={"cluster.indices.replication.strategy":"DOCUMENT"}} – org.opensearch.recovery.RecoveryWhileUnderLoadIT"

Copy link
Contributor

✅ Gradle check result for 3951775: SUCCESS

Copy link

codecov bot commented Apr 28, 2025

Codecov Report

Attention: Patch coverage is 82.14286% with 15 lines in your changes missing coverage. Please review.

Project coverage is 72.64%. Comparing base (d52cefa) to head (9a429f2).

Files with missing lines Patch % Lines
.../opensearch/common/blobstore/ConditionalWrite.java 71.79% 11 Missing ⚠️
...rg/opensearch/repositories/s3/S3BlobContainer.java 91.11% 2 Missing and 2 partials ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #18092      +/-   ##
============================================
- Coverage     72.74%   72.64%   -0.10%     
+ Complexity    67767    67688      -79     
============================================
  Files          5497     5498       +1     
  Lines        311815   311899      +84     
  Branches      45261    45268       +7     
============================================
- Hits         226822   226588     -234     
- Misses        66504    66829     +325     
+ Partials      18489    18482       -7     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@x-INFiN1TY-x x-INFiN1TY-x changed the title Support Conditional Writes for Single-Part S3 Uploads Enabling Support for Conditional Single-Part Upload [AWS S3] Apr 28, 2025
@opensearch-trigger-bot
Copy link
Contributor

This PR is stalled because it has been open for 30 days with no activity.

@opensearch-trigger-bot opensearch-trigger-bot bot added stalled Issues that have stalled and removed stalled Issues that have stalled labels May 29, 2025
@x-INFiN1TY-x x-INFiN1TY-x requested a review from a team as a code owner May 31, 2025 13:25
Copy link
Contributor

❌ Gradle check result for 109a7cf: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

@x-INFiN1TY-x x-INFiN1TY-x marked this pull request as draft May 31, 2025 13:52
tqranjan added 2 commits May 31, 2025 19:33
	plugins/repository-s3/src/main/java/org/opensearch/repositories/s3/S3BlobContainer.java
	plugins/repository-s3/src/test/java/org/opensearch/repositories/s3/S3BlobStoreContainerTests.java
@x-INFiN1TY-x x-INFiN1TY-x force-pushed the pr-branch-conditionalSingleUpload branch from 9ef21e3 to 9a429f2 Compare May 31, 2025 14:18
Copy link
Contributor

✅ Gradle check result for 9a429f2: SUCCESS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants