Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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 @@ -62,6 +62,7 @@
import java.util.NoSuchElementException;
import java.util.stream.Collectors;

import static org.apache.hadoop.ozone.OzoneConsts.ETAG;
import static org.apache.hadoop.ozone.OzoneConsts.QUOTA_RESET;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FILE_NOT_FOUND;
Expand Down Expand Up @@ -1276,25 +1277,33 @@ protected void initDelimiterKeyPrefix() {
protected List<OzoneKey> buildKeysWithKeyPrefix(
List<OzoneFileStatusLight> statuses) {
return statuses.stream()
.map(status -> {
BasicOmKeyInfo keyInfo = status.getKeyInfo();
String keyName = keyInfo.getKeyName();
if (status.isDirectory()) {
// add trailing slash to represent directory
keyName = OzoneFSUtils.addTrailingSlashIfNeeded(keyName);
}
return new OzoneKey(keyInfo.getVolumeName(),
keyInfo.getBucketName(), keyName,
keyInfo.getDataSize(), keyInfo.getCreationTime(),
keyInfo.getModificationTime(),
keyInfo.getReplicationConfig(), keyInfo.isFile());
})
.map(OzoneBucket::toOzoneKey)
.filter(key -> StringUtils.startsWith(key.getName(), getKeyPrefix()))
.collect(Collectors.toList());
}

}

private static OzoneKey toOzoneKey(OzoneFileStatusLight status) {
BasicOmKeyInfo keyInfo = status.getKeyInfo();
String keyName = keyInfo.getKeyName();
final Map<String, String> metadata;
if (status.isDirectory()) {
// add trailing slash to represent directory
keyName = OzoneFSUtils.addTrailingSlashIfNeeded(keyName);
metadata = Collections.emptyMap();
} else {
metadata = Collections.singletonMap(ETAG, keyInfo.getETag());
}
return new OzoneKey(keyInfo.getVolumeName(),
keyInfo.getBucketName(), keyName,
keyInfo.getDataSize(), keyInfo.getCreationTime(),
keyInfo.getModificationTime(),
keyInfo.getReplicationConfig(),
metadata,
keyInfo.isFile());
}


/**
* An Iterator to iterate over {@link OzoneKey} list.
Expand Down Expand Up @@ -1662,21 +1671,7 @@ private boolean getChildrenKeys(String keyPrefix, String startKey,
for (int indx = 0; indx < statuses.size(); indx++) {
OzoneFileStatusLight status = statuses.get(indx);
BasicOmKeyInfo keyInfo = status.getKeyInfo();
String keyName = keyInfo.getKeyName();

OzoneKey ozoneKey;
// Add dir to the dirList
if (status.isDirectory()) {
// add trailing slash to represent directory
keyName = OzoneFSUtils.addTrailingSlashIfNeeded(keyName);
}
ozoneKey = new OzoneKey(keyInfo.getVolumeName(),
keyInfo.getBucketName(), keyName,
keyInfo.getDataSize(), keyInfo.getCreationTime(),
keyInfo.getModificationTime(),
keyInfo.getReplicationConfig(),
keyInfo.isFile());

OzoneKey ozoneKey = toOzoneKey(status);
keysResultList.add(ozoneKey);

if (status.isDirectory()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.BasicKeyInfo;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ListKeysRequest;

import static org.apache.hadoop.ozone.OzoneConsts.ETAG;

/**
* Lightweight OmKeyInfo class.
*/
Expand All @@ -38,6 +40,7 @@ public final class BasicOmKeyInfo {
private final long modificationTime;
private final ReplicationConfig replicationConfig;
private final boolean isFile;
private final String eTag;

private BasicOmKeyInfo(Builder b) {
this.volumeName = b.volumeName;
Expand All @@ -48,6 +51,7 @@ private BasicOmKeyInfo(Builder b) {
this.modificationTime = b.modificationTime;
this.replicationConfig = b.replicationConfig;
this.isFile = b.isFile;
this.eTag = b.eTag;
}

private BasicOmKeyInfo(OmKeyInfo b) {
Expand All @@ -59,6 +63,7 @@ private BasicOmKeyInfo(OmKeyInfo b) {
this.modificationTime = b.getModificationTime();
this.replicationConfig = b.getReplicationConfig();
this.isFile = b.isFile();
this.eTag = b.getMetadata().get(ETAG);
}

public String getVolumeName() {
Expand Down Expand Up @@ -93,6 +98,10 @@ public boolean isFile() {
return isFile;
}

public String getETag() {
return eTag;
}

/**
* Builder of BasicOmKeyInfo.
*/
Expand All @@ -105,6 +114,7 @@ public static class Builder {
private long modificationTime;
private ReplicationConfig replicationConfig;
private boolean isFile;
private String eTag;

public Builder setVolumeName(String volumeName) {
this.volumeName = volumeName;
Expand Down Expand Up @@ -146,6 +156,11 @@ public Builder setIsFile(boolean isFile) {
return this;
}

public Builder setETag(String etag) {
this.eTag = etag;
return this;
}

public BasicOmKeyInfo build() {
return new BasicOmKeyInfo(this);
}
Expand All @@ -164,6 +179,9 @@ public BasicKeyInfo getProtobuf() {
} else {
builder.setFactor(ReplicationConfig.getLegacyFactor(replicationConfig));
}
if (eTag != null) {
builder.setETag(eTag);
}

return builder.build();
}
Expand All @@ -188,6 +206,7 @@ public static BasicOmKeyInfo getFromProtobuf(BasicKeyInfo basicKeyInfo,
basicKeyInfo.getType(),
basicKeyInfo.getFactor(),
basicKeyInfo.getEcReplicationConfig()))
.setETag(basicKeyInfo.getETag())
.setIsFile(!keyName.endsWith("/"));

return builder.build();
Expand All @@ -212,6 +231,7 @@ public static BasicOmKeyInfo getFromProtobuf(String volumeName,
basicKeyInfo.getType(),
basicKeyInfo.getFactor(),
basicKeyInfo.getEcReplicationConfig()))
.setETag(basicKeyInfo.getETag())
.setIsFile(!keyName.endsWith("/"));

return builder.build();
Expand All @@ -232,6 +252,7 @@ public boolean equals(Object o) {
creationTime == basicOmKeyInfo.creationTime &&
modificationTime == basicOmKeyInfo.modificationTime &&
replicationConfig.equals(basicOmKeyInfo.replicationConfig) &&
Objects.equals(eTag, basicOmKeyInfo.eTag) &&
isFile == basicOmKeyInfo.isFile;
}

Expand Down
4 changes: 2 additions & 2 deletions hadoop-ozone/dist/src/main/compose/common/s3a-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ EOF

# Some tests are skipped due to known issues.
# - ITestS3AContractDistCp: HDDS-10616
# - ITestS3AContractEtag, ITestS3AContractRename: HDDS-10615
# - ITestS3AContractGetFileStatusV1List: HDDS-10617
# - ITestS3AContractMkdir: HDDS-10572
# - ITestS3AContractRename: HDDS-10665
mvn -B -V --fail-never --no-transfer-progress \
-Dtest='ITestS3AContract*, !ITestS3AContractDistCp, !ITestS3AContractEtag, !ITestS3AContractGetFileStatusV1List, !ITestS3AContractMkdir, !ITestS3AContractRename' \
-Dtest='ITestS3AContract*, !ITestS3AContractDistCp, !ITestS3AContractGetFileStatusV1List, !ITestS3AContractMkdir, !ITestS3AContractRename' \
clean test

local target="${RESULT_DIR}/junit/${bucket}/target"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1117,6 +1117,7 @@ message BasicKeyInfo {
optional hadoop.hdds.ReplicationType type = 5;
optional hadoop.hdds.ReplicationFactor factor = 6;
optional hadoop.hdds.ECReplicationConfig ecReplicationConfig = 7;
optional string eTag = 8;
}

message DirectoryInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.UserInfo;

import static org.apache.hadoop.ozone.OzoneConsts.ETAG;

/**
* Interface for OM Requests to convert to audit objects.
*/
Expand Down Expand Up @@ -80,6 +82,11 @@ default Map<String, String> buildKeyArgsAuditMap(KeyArgs keyArgs) {
auditMap.put(OzoneConsts.REPLICATION_CONFIG,
ECReplicationConfig.toString(keyArgs.getEcReplicationConfig()));
}
for (HddsProtos.KeyValue item : keyArgs.getMetadataList()) {
if (ETAG.equals(item.getKey())) {
auditMap.put(ETAG, item.getValue());
}
}
return auditMap;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import java.util.List;
import java.util.Set;

import static org.apache.hadoop.ozone.OzoneConsts.ETAG;
import static org.apache.hadoop.ozone.audit.AuditLogger.PerformanceStringBuilder;
import static org.apache.hadoop.ozone.OzoneAcl.AclScope.ACCESS;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
Expand Down Expand Up @@ -709,7 +710,10 @@ private void addKey(ListObjectResponse response, OzoneKey next) {
keyMetadata.setKey(EncodingTypeObject.createNullable(next.getName(),
response.getEncodingType()));
keyMetadata.setSize(next.getDataSize());
keyMetadata.setETag("" + next.getModificationTime());
String eTag = next.getMetadata().get(ETAG);
if (eTag != null) {
keyMetadata.setETag(eTag);
Copy link
Contributor

@ivandika3 ivandika3 Apr 13, 2024

Choose a reason for hiding this comment

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

Shall we standardize so that the ETag returned needs to be surrounded by wrap in quotes? Similar to CopyObjectResponse?

From https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html

However, it seems that the S3A pass even without the quotes. From what I briefly saw from AbstractContractEtagTest, the test does not assert the quotations of the ETag so it will pass regardless of the quotations.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the AWS page it is interesting that both Key and ETag are defined as string, but only that latter has quotes as part of the value.

Copy link
Contributor

Choose a reason for hiding this comment

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

From what I understand the ETag is specified by RFC to always be surrounded by double quotes.

Ref: aws/aws-sdk-go-v2#1696

@vtutrinov Could you help confirm this?

Copy link
Contributor

Choose a reason for hiding this comment

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

@ivandika3 sure thing, the RFC (https://datatracker.ietf.org/doc/html/rfc7232#section-2.3) says that the ETag header value is a quoted string

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for the pointers. Updated to wrap in quotes.

}
if (next.getReplicationType().toString().equals(ReplicationType
.STAND_ALONE.toString())) {
keyMetadata.setStorageClass(S3StorageType.REDUCED_REDUNDANCY.toString());
Expand Down