Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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 @@ -55,10 +55,26 @@ public enum OzoneManagerVersion implements ComponentVersion {
private static final Map<Integer, OzoneManagerVersion> BY_PROTO_VALUE =
Arrays.stream(values())
.collect(toMap(OzoneManagerVersion::toProtoValue, identity()));

private static final long SUPPORTED_FEATURE_BITMAP = calculateVersionBitmap();
private final int version;
private final String description;

/**
* This is limited to 63 because the version bitmap is stored in a `long` type,
* which has 64 bits. One bit is reserved for each version number, starting from 0.
* Therefore, the highest representable version number is 63.
*/
public static final int MAX_SUPPORTED_VERSION = 63;

static {
for (OzoneManagerVersion version : OzoneManagerVersion.values()) {
if (version.toProtoValue() > MAX_SUPPORTED_VERSION) {
throw new IllegalStateException(
"Version " + version + " exceeds the maximum supported version: " + MAX_SUPPORTED_VERSION);
}
}
}

OzoneManagerVersion(int version, String description) {
this.version = version;
this.description = description;
Expand All @@ -82,4 +98,44 @@ private static OzoneManagerVersion latest() {
OzoneManagerVersion[] versions = OzoneManagerVersion.values();
return versions[versions.length - 2];
}

/**
* Checks if the given feature version is supported by the OM Service.
*
* @param omFeatureBitmap The feature bitmap from the remote OM.
* @param checkedFeature The feature to check.
* @return true if the feature is supported, false otherwise.
*/
public static boolean isOmFeatureSupported(long omFeatureBitmap, OzoneManagerVersion checkedFeature) {
if (checkedFeature.toProtoValue() < 0) {
return false;
}
return (omFeatureBitmap & (1L << checkedFeature .toProtoValue())) != 0;
}

/**
* Get the current bitmap representing supported features.
*
* @return The bitmap of supported features.
*/
public static long getSupportedFeatureBitmap() {
return SUPPORTED_FEATURE_BITMAP;
}

/**
* Calculate the version bitmap. Each bit position corresponds to a version.
* Example: Version 0 -> bit 0, Version 1 -> bit 1, etc.
* Note:
* - Uses a 64-bit `long`, supporting versions 0 to 63.
* - Versions beyond 63 are not supported.
*/
private static long calculateVersionBitmap() {
long bitmap = 0L;
for (OzoneManagerVersion version : values()) {
if (version.version >= 0) { // Ignore FUTURE_VERSION (-1)
bitmap |= (1L << version.version);
}
}
return bitmap;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.params.provider.Arguments.arguments;

/**
Expand Down Expand Up @@ -93,4 +95,26 @@ public void testAssignedProtoRepresentations(
}
assertEquals(values.length, ++startValue);
}

@ParameterizedTest
@MethodSource("values")
public void testSupportedFeatureBitmapIncludesAllVersions(
ComponentVersion[] values) {
if (values[0] instanceof OzoneManagerVersion) {
long expectedBitmap = 0L;
for (ComponentVersion version : values) {
int versionValue = version.toProtoValue();
if (versionValue >= 0) { // Ignore FUTURE_VERSION (-1)
assertTrue(OzoneManagerVersion.isOmFeatureSupported(
OzoneManagerVersion.getSupportedFeatureBitmap(), (OzoneManagerVersion) version));
expectedBitmap |= (1L << versionValue);
} else {
assertFalse(OzoneManagerVersion.isOmFeatureSupported(
OzoneManagerVersion.getSupportedFeatureBitmap(), (OzoneManagerVersion) version));
}
}
assertEquals(expectedBitmap, OzoneManagerVersion.getSupportedFeatureBitmap(),
"The SUPPORTED_FEATURE_BITMAP should correctly represent all supported features.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.apache.hadoop.io.retry.RetryPolicies;
import org.apache.hadoop.io.retry.RetryPolicy;
import org.apache.hadoop.ozone.OzoneManagerVersion;
import org.apache.hadoop.ozone.client.rpc.RpcClient;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
import org.apache.hadoop.ozone.om.helpers.OmMultipartCommitUploadPartInfo;
Expand Down Expand Up @@ -113,6 +114,7 @@ enum StreamAction {
private boolean atomicKeyCreation;
private ContainerClientMetrics clientMetrics;
private OzoneManagerVersion ozoneManagerVersion;
private long omSupportedFeatureBitmap;
private final Lock writeLock = new ReentrantLock();
private final Condition retryHandlingCondition = writeLock.newCondition();

Expand Down Expand Up @@ -191,6 +193,7 @@ public KeyOutputStream(Builder b) {
this.streamBufferArgs = b.getStreamBufferArgs();
this.clientMetrics = b.getClientMetrics();
this.ozoneManagerVersion = b.ozoneManagerVersion;
this.omSupportedFeatureBitmap = b.omSupportedFeatureBitmap;
}

/**
Expand Down Expand Up @@ -540,10 +543,11 @@ public void hsync() throws IOException {
throw new UnsupportedOperationException("The replication factor = "
+ replication.getRequiredNodes() + " <= 1");
}
if (ozoneManagerVersion.compareTo(OzoneManagerVersion.HBASE_SUPPORT) < 0) {
throw new UnsupportedOperationException("Hsync API requires OM version "
+ OzoneManagerVersion.HBASE_SUPPORT + " or later. Current OM version "
+ ozoneManagerVersion);
if (RpcClient.isOmFeatureSupported(
omSupportedFeatureBitmap, ozoneManagerVersion, OzoneManagerVersion.HBASE_SUPPORT)) {
throw new UnsupportedOperationException("Hsync API requires OM feature "
+ OzoneManagerVersion.HBASE_SUPPORT + ". Current OM feature "
+ omSupportedFeatureBitmap);
}
checkNotClosed();
final long hsyncPos = writeOffset;
Expand Down Expand Up @@ -707,6 +711,7 @@ public static class Builder {
private StreamBufferArgs streamBufferArgs;
private Supplier<ExecutorService> executorServiceSupplier;
private OzoneManagerVersion ozoneManagerVersion;
private long omSupportedFeatureBitmap;

public String getMultipartUploadID() {
return multipartUploadID;
Expand Down Expand Up @@ -834,6 +839,11 @@ public Builder setOmVersion(OzoneManagerVersion omVersion) {
return this;
}

public Builder setOmSupportedFeatureBitmap(long featureBitmap) {
omSupportedFeatureBitmap = featureBitmap;
return this;
}

public OzoneManagerVersion getOmVersion() {
return ozoneManagerVersion;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ public class RpcClient implements ClientProtocol {
private final ByteBufferPool byteBufferPool;
private final BlockInputStreamFactory blockInputStreamFactory;
private final OzoneManagerVersion omVersion;
private final long omSupportedFeatureBitmap;
private final MemoizedSupplier<ExecutorService> ecReconstructExecutor;
private final ContainerClientMetrics clientMetrics;
private final MemoizedSupplier<ExecutorService> writeExecutor;
Expand Down Expand Up @@ -272,6 +273,7 @@ public RpcClient(ConfigurationSource conf, String omServiceId)
dtService = omTransport.getDelegationTokenService();
ServiceInfoEx serviceInfoEx = ozoneManagerClient.getServiceInfo();
omVersion = getOmVersion(serviceInfoEx);
omSupportedFeatureBitmap = getOMSupportedFeatureBitmap(serviceInfoEx);
if (OzoneSecurityUtil.isSecurityEnabled(conf)) {
// If the client is authenticating using S3 style auth, all future
// requests serviced by this client will need S3 Auth set.
Expand Down Expand Up @@ -364,6 +366,20 @@ public static OzoneManagerVersion getOmVersion(ServiceInfoEx info) {
return version;
}

public static long getOMSupportedFeatureBitmap(ServiceInfoEx info) {
long omSupportedFeatureBitmap = 0;
for (ServiceInfo si : info.getServiceInfoList()) {
if (si.getNodeType() == HddsProtos.NodeType.OM) {
long current = si.getProtobuf().getSupportedFeatureBitmap();
if (current > 0) {
omSupportedFeatureBitmap = current;
}
}
}
LOG.trace("Ozone Manager Supported Feature Bitmap is {}", omSupportedFeatureBitmap);
return omSupportedFeatureBitmap;
}

static boolean validateOmVersion(OzoneManagerVersion minimumVersion,
List<ServiceInfo> serviceInfoList) {
if (minimumVersion == OzoneManagerVersion.FUTURE_VERSION) {
Expand Down Expand Up @@ -625,6 +641,21 @@ public void createBucket(String volumeName, String bucketName)
BucketArgs.newBuilder().build());
}

public static boolean isOmFeatureSupported(long omSupportedFeatureBitmap, OzoneManagerVersion omVersion,
OzoneManagerVersion checkedFeature) {
if (omSupportedFeatureBitmap > 0) {
// For the OM which support the "FeatureBitmap"
return OzoneManagerVersion.isOmFeatureSupported(omSupportedFeatureBitmap, checkedFeature);
} else {
// For the old OM which not support "FeatureBitmap~", fallback to use omVersion
return omVersion.compareTo(checkedFeature) >= 0;
}
}

private boolean isOmFeatureSupported(OzoneManagerVersion checkedFeature) {
return isOmFeatureSupported(omSupportedFeatureBitmap, omVersion, checkedFeature);
}

@Override
public void createBucket(
String volumeName, String bucketName, BucketArgs bucketArgs)
Expand All @@ -634,8 +665,7 @@ public void createBucket(
Preconditions.checkNotNull(bucketArgs);
verifyCountsQuota(bucketArgs.getQuotaInNamespace());
verifySpaceQuota(bucketArgs.getQuotaInBytes());
if (omVersion
.compareTo(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT) < 0) {
if (!isOmFeatureSupported(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT)) {
if (bucketArgs.getDefaultReplicationConfig() != null &&
bucketArgs.getDefaultReplicationConfig().getType()
== ReplicationType.EC) {
Expand Down Expand Up @@ -1291,8 +1321,7 @@ public void setReplicationConfig(
verifyVolumeName(volumeName);
verifyBucketName(bucketName);
Preconditions.checkNotNull(replicationConfig);
if (omVersion
.compareTo(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT) < 0) {
if (!isOmFeatureSupported(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT)) {
if (replicationConfig.getReplicationType()
== HddsProtos.ReplicationType.EC) {
throw new IOException("Can not set the default replication of the"
Expand Down Expand Up @@ -1411,7 +1440,7 @@ public OzoneOutputStream createKey(
Map<String, String> metadata, Map<String, String> tags) throws IOException {
createKeyPreChecks(volumeName, bucketName, keyName, replicationConfig);

if (omVersion.compareTo(OzoneManagerVersion.OBJECT_TAG) < 0) {
if (!isOmFeatureSupported(OzoneManagerVersion.OBJECT_TAG)) {
if (tags != null && !tags.isEmpty()) {
throw new IOException("OzoneManager does not support object tags");
}
Expand Down Expand Up @@ -1446,7 +1475,7 @@ public OzoneOutputStream createKey(
public OzoneOutputStream rewriteKey(String volumeName, String bucketName, String keyName,
long size, long existingKeyGeneration, ReplicationConfig replicationConfig,
Map<String, String> metadata) throws IOException {
if (omVersion.compareTo(OzoneManagerVersion.ATOMIC_REWRITE_KEY) < 0) {
if (!isOmFeatureSupported(OzoneManagerVersion.ATOMIC_REWRITE_KEY)) {
throw new IOException("OzoneManager does not support atomic key rewrite.");
}

Expand Down Expand Up @@ -1481,8 +1510,7 @@ private void createKeyPreChecks(String volumeName, String bucketName, String key
HddsClientUtils.verifyKeyName(keyName);
}
HddsClientUtils.checkNotNull(keyName);
if (omVersion
.compareTo(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT) < 0) {
if (!isOmFeatureSupported(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT)) {
if (replicationConfig != null &&
replicationConfig.getReplicationType()
== HddsProtos.ReplicationType.EC) {
Expand Down Expand Up @@ -1519,7 +1547,7 @@ public OzoneDataStreamOutput createStreamKey(
}
HddsClientUtils.checkNotNull(keyName);

if (omVersion.compareTo(OzoneManagerVersion.OBJECT_TAG) < 0) {
if (!isOmFeatureSupported(OzoneManagerVersion.OBJECT_TAG)) {
if (tags != null && !tags.isEmpty()) {
throw new IOException("OzoneManager does not support object tags");
}
Expand Down Expand Up @@ -1740,7 +1768,7 @@ public List<OzoneKey> listKeys(String volumeName, String bucketName,
int maxListResult)
throws IOException {

if (omVersion.compareTo(OzoneManagerVersion.LIGHTWEIGHT_LIST_KEYS) >= 0) {
if (isOmFeatureSupported(OzoneManagerVersion.LIGHTWEIGHT_LIST_KEYS)) {
List<BasicOmKeyInfo> keys = ozoneManagerClient.listKeysLight(
volumeName, bucketName, prevKey, keyPrefix, maxListResult).getKeys();

Expand Down Expand Up @@ -1869,7 +1897,7 @@ private OmKeyInfo getKeyInfo(

private OmKeyInfo getKeyInfo(OmKeyArgs keyArgs) throws IOException {
final OmKeyInfo keyInfo;
if (omVersion.compareTo(OzoneManagerVersion.OPTIMIZED_GET_KEY_INFO) >= 0) {
if (isOmFeatureSupported(OzoneManagerVersion.OPTIMIZED_GET_KEY_INFO)) {
keyInfo = ozoneManagerClient.getKeyInfo(keyArgs, false)
.getKeyInfo();
} else {
Expand Down Expand Up @@ -1934,8 +1962,7 @@ public OmMultipartInfo initiateMultipartUpload(String volumeName,
verifyBucketName(bucketName);
HddsClientUtils.checkNotNull(keyName);
String ownerName = getRealUserInfo().getShortUserName();
if (omVersion
.compareTo(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT) < 0) {
if (!isOmFeatureSupported(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT)) {
if (replicationConfig != null && replicationConfig.getReplicationType()
== HddsProtos.ReplicationType.EC) {
throw new IOException("Can not set the replication of the file to"
Expand All @@ -1944,7 +1971,7 @@ public OmMultipartInfo initiateMultipartUpload(String volumeName,
}
}

if (omVersion.compareTo(OzoneManagerVersion.OBJECT_TAG) < 0) {
if (!isOmFeatureSupported(OzoneManagerVersion.OBJECT_TAG)) {
if (tags != null && !tags.isEmpty()) {
throw new IOException("OzoneManager does not support object tags");
}
Expand Down Expand Up @@ -2186,7 +2213,7 @@ public OzoneInputStream readFile(String volumeName, String bucketName,
.setLatestVersionLocation(getLatestVersionLocation)
.build();
final OmKeyInfo keyInfo;
if (omVersion.compareTo(OzoneManagerVersion.OPTIMIZED_GET_KEY_INFO) >= 0) {
if (isOmFeatureSupported(OzoneManagerVersion.OPTIMIZED_GET_KEY_INFO)) {
keyInfo = ozoneManagerClient.getKeyInfo(keyArgs, false)
.getKeyInfo();
if (!keyInfo.isFile()) {
Expand Down Expand Up @@ -2234,8 +2261,7 @@ private OzoneInputStream getInputStreamWithRetryFunction(
public OzoneOutputStream createFile(String volumeName, String bucketName,
String keyName, long size, ReplicationConfig replicationConfig,
boolean overWrite, boolean recursive) throws IOException {
if (omVersion
.compareTo(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT) < 0) {
if (!isOmFeatureSupported(OzoneManagerVersion.ERASURE_CODED_STORAGE_SUPPORT)) {
if (replicationConfig.getReplicationType()
== HddsProtos.ReplicationType.EC) {
throw new IOException("Can not set the replication of the file to"
Expand Down Expand Up @@ -2316,7 +2342,7 @@ public List<OzoneFileStatusLight> listStatusLight(String volumeName,
String bucketName, String keyName, boolean recursive, String startKey,
long numEntries, boolean allowPartialPrefixes) throws IOException {
OmKeyArgs keyArgs = prepareOmKeyArgs(volumeName, bucketName, keyName);
if (omVersion.compareTo(OzoneManagerVersion.LIGHTWEIGHT_LIST_STATUS) >= 0) {
if (isOmFeatureSupported(OzoneManagerVersion.LIGHTWEIGHT_LIST_STATUS)) {
return ozoneManagerClient.listStatusLight(keyArgs, recursive, startKey,
numEntries, allowPartialPrefixes);
} else {
Expand Down Expand Up @@ -2562,7 +2588,8 @@ private KeyOutputStream.Builder createKeyOutputStream(
.setClientMetrics(clientMetrics)
.setExecutorServiceSupplier(writeExecutor)
.setStreamBufferArgs(streamBufferArgs)
.setOmVersion(omVersion);
.setOmVersion(omVersion)
.setOmSupportedFeatureBitmap(omSupportedFeatureBitmap);
}

@Override
Expand Down Expand Up @@ -2709,20 +2736,20 @@ public void setTimes(OzoneObj obj, String keyName, long mtime, long atime)
public LeaseKeyInfo recoverLease(String volumeName, String bucketName,
String keyName, boolean force)
throws IOException {
if (omVersion.compareTo(OzoneManagerVersion.HBASE_SUPPORT) < 0) {
throw new UnsupportedOperationException("Lease recovery API requires OM version "
+ OzoneManagerVersion.HBASE_SUPPORT + " or later. Current OM version "
+ omVersion);
if (!isOmFeatureSupported(OzoneManagerVersion.HBASE_SUPPORT)) {
throw new UnsupportedOperationException("Lease recovery API requires OM feature "
+ OzoneManagerVersion.HBASE_SUPPORT + ". Current OM support feature "
+ omSupportedFeatureBitmap);
}
return ozoneManagerClient.recoverLease(volumeName, bucketName, keyName, force);
}

@Override
public void recoverKey(OmKeyArgs args, long clientID) throws IOException {
if (omVersion.compareTo(OzoneManagerVersion.HBASE_SUPPORT) < 0) {
throw new UnsupportedOperationException("Lease recovery API requires OM version "
+ OzoneManagerVersion.HBASE_SUPPORT + " or later. Current OM version "
+ omVersion);
if (!isOmFeatureSupported(OzoneManagerVersion.HBASE_SUPPORT)) {
throw new UnsupportedOperationException("Lease recovery API requires OM feature "
+ OzoneManagerVersion.HBASE_SUPPORT + ". Current OM support feature "
+ omSupportedFeatureBitmap);
}
ozoneManagerClient.recoverKey(args, clientID);
}
Expand Down
Loading