Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
afa8b6c
Recognizes expectedDataGeneration = -1L as a sentinel for "create if …
peterxcli Nov 20, 2025
7868a86
correct the new result code position
peterxcli Nov 24, 2025
d630699
Merge remote-tracking branch 'upstream/master' into HDDS-13963-atomic…
peterxcli Nov 26, 2025
f7ad505
Merge remote-tracking branch 'upstream/master' into HDDS-13963-atomic…
peterxcli Dec 3, 2025
2fdb6de
Merge remote-tracking branch 'upstream/master' into HDDS-13963-atomic…
peterxcli Dec 3, 2025
da492ce
HDDS-14070. Update key generation mismatch handling in Ozone RPC clie…
peterxcli Dec 3, 2025
0d4dfb0
Introduce EXPECTED_GEN_CREATE_IF_NOT_EXISTS constant
peterxcli Dec 3, 2025
f238ade
Merge remote-tracking branch 'upstream/master' into HDDS-13963-atomic…
peterxcli Dec 25, 2025
4e9665c
revert the new KEY_GENERATION_MISMATCH error code
peterxcli Jan 2, 2026
b5249f1
Add tests for atomic key creation and rewriting with expected generat…
peterxcli Jan 2, 2026
817e33f
Recognizes expectedDataGeneration = -1L as a sentinel for "create if …
peterxcli Nov 20, 2025
021747b
correct the new result code position
peterxcli Nov 24, 2025
0fd6730
HDDS-14070. Update key generation mismatch handling in Ozone RPC clie…
peterxcli Dec 3, 2025
c64beca
Introduce EXPECTED_GEN_CREATE_IF_NOT_EXISTS constant
peterxcli Dec 3, 2025
6b33766
revert the new KEY_GENERATION_MISMATCH error code
peterxcli Jan 2, 2026
83ef2ea
Add tests for atomic key creation and rewriting with expected generat…
peterxcli Jan 2, 2026
6c8a08e
Implement S3 conditional write support
peterxcli Feb 24, 2026
57d7788
Add aws kit tests for S3 conditional object put
peterxcli Mar 12, 2026
6d85ee1
Add tests for S3 object put with conditional headers
peterxcli Mar 25, 2026
c15cd6a
Merge branch 'master' into HDDS-13919-conditional-writes
peterxcli Mar 25, 2026
88aa08e
Merge branch 'master' into HDDS-13963-atomic-create-if-not-exists
peterxcli Mar 25, 2026
a1898c0
Add ATOMIC_CREATE_IF_NOT_EXISTS version gate
peterxcli Mar 25, 2026
e5f5e3d
suggestion
peterxcli Mar 25, 2026
86489b6
fix pmd
peterxcli Mar 25, 2026
9081e96
Merge branch 'HDDS-13963-atomic-create-if-not-exists' into HDDS-13919…
peterxcli Mar 25, 2026
d6395a9
fix pmd
peterxcli Mar 25, 2026
c10fb9e
fix new smoke test
peterxcli Mar 25, 2026
020ad2d
Merge remote-tracking branch 'upstream/master' into HDDS-13919-condit…
peterxcli Mar 26, 2026
eea244a
fix test
peterxcli Mar 27, 2026
83da905
Merge remote-tracking branch 'upstream/master' into HDDS-13919-condit…
peterxcli Mar 27, 2026
5764a70
copilot suggestion
peterxcli Mar 31, 2026
e9a45cf
Use a unified builder to refactor create, rewrite, createIfNotExists …
peterxcli Mar 31, 2026
e455b88
enhance check in robot test and s3 test
peterxcli Mar 31, 2026
b496634
allow streaming key to use conditional put request
peterxcli Apr 1, 2026
d929ed9
handle * etag matching
peterxcli Apr 1, 2026
d5d74c9
set error message when validating the conditional request
peterxcli Apr 1, 2026
77aa2e6
use standard sdk request builder to build conditional request in v2 s…
peterxcli Apr 1, 2026
2ed823d
add conditional put endpoints for streaming
peterxcli Apr 1, 2026
3a5e880
checkstyle
peterxcli Apr 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,44 @@ public OzoneOutputStream rewriteKey(String keyName, long size, long existingKeyG
return proxy.rewriteKey(volumeName, name, keyName, size, existingKeyGeneration, replicationConfig, metadata);
}

/**
* Creates a key only if it does not exist (S3 If-None-Match: * semantics).
*
* @param keyName Name of the key
* @param size Size of the data
* @param replicationConfig Replication configuration
* @param metadata custom key value metadata
* @param tags Tags used for S3 object tags
* @return OzoneOutputStream to which the data has to be written.
* @throws IOException
*/
public OzoneOutputStream createKeyIfNotExists(String keyName, long size,
ReplicationConfig replicationConfig, Map<String, String> metadata,
Map<String, String> tags) throws IOException {
return proxy.createKeyIfNotExists(volumeName, name, keyName, size,
replicationConfig, metadata, tags);
}

/**
* Rewrites a key only if its ETag matches (S3 If-Match semantics).
*
* @param keyName Name of the key
* @param size Size of the data
* @param expectedETag The ETag value the existing key must have
* @param replicationConfig Replication configuration
* @param metadata custom key value metadata
* @param tags Tags used for S3 object tags
* @return OzoneOutputStream to which the data has to be written.
* @throws IOException
*/
public OzoneOutputStream rewriteKeyIfMatch(String keyName, long size,
String expectedETag, ReplicationConfig replicationConfig,
Map<String, String> metadata, Map<String, String> tags)
throws IOException {
return proxy.rewriteKeyIfMatch(volumeName, name, keyName, size,
expectedETag, replicationConfig, metadata, tags);
}

/**
* Creates a new key in the bucket, with default replication type RATIS and
* with replication factor THREE.
Expand Down Expand Up @@ -575,6 +613,52 @@ public OzoneDataStreamOutput createStreamKey(String key, long size,
replicationConfig, keyMetadata, tags);
}

/**
* Creates a key with datastream only if it does not exist already
* (S3 If-None-Match: * semantics).
*
* @param key Name of the key to be created.
* @param size Size of the data the key will point to.
* @param replicationConfig Replication configuration.
* @param keyMetadata Custom key metadata.
* @param tags Tags used for S3 object tags
* @return OzoneDataStreamOutput to which the data has to be written.
* @throws IOException
*/
public OzoneDataStreamOutput createStreamKeyIfNotExists(String key, long size,
ReplicationConfig replicationConfig, Map<String, String> keyMetadata,
Map<String, String> tags) throws IOException {
if (replicationConfig == null) {
replicationConfig = defaultReplication;
}
return proxy.createStreamKeyIfNotExists(volumeName, name, key, size,
replicationConfig, keyMetadata, tags);
}

/**
* Rewrites a key with datastream only if its ETag matches
* (S3 If-Match semantics).
*
* @param key Name of the key to be rewritten.
* @param size Size of the data the key will point to.
* @param expectedETag The ETag value the existing key must have.
* @param replicationConfig Replication configuration.
* @param keyMetadata Custom key metadata.
* @param tags Tags used for S3 object tags
* @return OzoneDataStreamOutput to which the data has to be written.
* @throws IOException
*/
public OzoneDataStreamOutput rewriteStreamKeyIfMatch(String key, long size,
String expectedETag, ReplicationConfig replicationConfig,
Map<String, String> keyMetadata, Map<String, String> tags)
throws IOException {
if (replicationConfig == null) {
replicationConfig = defaultReplication;
}
return proxy.rewriteStreamKeyIfMatch(volumeName, name, key, size,
expectedETag, replicationConfig, keyMetadata, tags);
}

/**
* Reads an existing key from the bucket.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Map;
import org.apache.hadoop.fs.FileEncryptionInfo;
import org.apache.hadoop.hdds.client.ReplicationConfig;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.client.io.OzoneInputStream;
import org.apache.ratis.util.function.CheckedSupplier;

Expand Down Expand Up @@ -107,4 +108,19 @@ public Long getGeneration() {
public OzoneInputStream getContent() throws IOException {
return this.contentSupplier.get();
}

public boolean hasEtag() {
return getMetadata().containsKey(OzoneConsts.ETAG);
}

public boolean isEtagEquals(String matchingETag) {
String currentETag = getMetadata().get(OzoneConsts.ETAG);
if (currentETag == null) {
return false;
}
if (matchingETag.equals("*")) {
return true;
}
return currentETag.equals(matchingETag);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,44 @@ OzoneOutputStream rewriteKey(String volumeName, String bucketName, String keyNam
long size, long existingKeyGeneration, ReplicationConfig replicationConfig,
Map<String, String> metadata) throws IOException;

/**
* Creates a key only if it does not exist (S3 If-None-Match: * semantics).
*
* @param volumeName Name of the Volume
* @param bucketName Name of the Bucket
* @param keyName Name of the Key
* @param size Size of the data
* @param replicationConfig The replication configuration
* @param metadata custom key value metadata
* @param tags Tags used for S3 object tags
* @return {@link OzoneOutputStream}
* @throws OMException with KEY_ALREADY_EXISTS if key exists
*/
OzoneOutputStream createKeyIfNotExists(String volumeName, String bucketName,
String keyName, long size, ReplicationConfig replicationConfig,
Map<String, String> metadata, Map<String, String> tags)
throws IOException;

/**
* Rewrites a key only if its ETag matches (S3 If-Match semantics).
*
* @param volumeName Name of the Volume
* @param bucketName Name of the Bucket
* @param keyName Name of the Key
* @param size Size of the data
* @param expectedETag The ETag value the existing key must have
* @param replicationConfig The replication configuration
* @param metadata custom key value metadata
* @param tags Tags used for S3 object tags
* @return {@link OzoneOutputStream}
* @throws OMException with ETAG_MISMATCH, ETAG_NOT_AVAILABLE, or KEY_NOT_FOUND
*/
@SuppressWarnings("checkstyle:parameternumber")
OzoneOutputStream rewriteKeyIfMatch(String volumeName, String bucketName,
String keyName, long size, String expectedETag,
ReplicationConfig replicationConfig, Map<String, String> metadata,
Map<String, String> tags) throws IOException;

/**
* Writes a key in an existing bucket.
* @param volumeName Name of the Volume
Expand Down Expand Up @@ -426,6 +464,46 @@ OzoneDataStreamOutput createStreamKey(String volumeName, String bucketName,
Map<String, String> metadata, Map<String, String> tags)
throws IOException;

/**
* Writes a key in an existing bucket only if it does not already exist
* (S3 If-None-Match: * semantics).
*
* @param volumeName Name of the Volume
* @param bucketName Name of the Bucket
* @param keyName Name of the Key
* @param size Size of the data
* @param replicationConfig The replication configuration
* @param metadata custom key value metadata
* @param tags Tags used for S3 object tags
* @return {@link OzoneDataStreamOutput}
* @throws OMException with KEY_ALREADY_EXISTS if key exists
*/
OzoneDataStreamOutput createStreamKeyIfNotExists(String volumeName,
String bucketName, String keyName, long size,
ReplicationConfig replicationConfig, Map<String, String> metadata,
Map<String, String> tags) throws IOException;

/**
* Writes a key in an existing bucket only if its ETag matches
* (S3 If-Match semantics).
*
* @param volumeName Name of the Volume
* @param bucketName Name of the Bucket
* @param keyName Name of the Key
* @param size Size of the data
* @param expectedETag The ETag value the existing key must have
* @param replicationConfig The replication configuration
* @param metadata custom key value metadata
* @param tags Tags used for S3 object tags
* @return {@link OzoneDataStreamOutput}
* @throws OMException with ETAG_MISMATCH, ETAG_NOT_AVAILABLE, or KEY_NOT_FOUND
*/
@SuppressWarnings("checkstyle:parameternumber")
OzoneDataStreamOutput rewriteStreamKeyIfMatch(String volumeName,
String bucketName, String keyName, long size, String expectedETag,
ReplicationConfig replicationConfig, Map<String, String> metadata,
Map<String, String> tags) throws IOException;

/**
* Reads a key from an existing bucket.
* @param volumeName Name of the Volume
Expand Down
Loading