This is an automated email from the ASF dual-hosted git repository.
ivandika3 pushed a commit to branch HDDS-11233
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-11233 by this push:
new dd50a071106 HDDS-15409. SCM Pipeline Add SupportedStorageTier Field
(#10573)
dd50a071106 is described below
commit dd50a0711063bd6df411b67abea2fa9e037670d8
Author: XiChen <[email protected]>
AuthorDate: Mon Jul 13 09:21:07 2026 +0800
HDDS-15409. SCM Pipeline Add SupportedStorageTier Field (#10573)
---
.../org/apache/hadoop/hdds/client/StorageTier.java | 7 +
.../apache/hadoop/hdds/client/StorageTierUtil.java | 43 +++---
.../apache/hadoop/hdds/scm/pipeline/Pipeline.java | 44 ++++++
.../hadoop/hdds/client/StorageTierUtilTest.java | 151 +++++++++++++++++++++
.../common/impl/StorageLocationReport.java | 25 ----
.../interface-client/src/main/proto/hdds.proto | 1 +
.../org/apache/hadoop/hdds/scm/node/NodeUtils.java | 75 ++++++++++
.../hdds/scm/pipeline/ECPipelineProvider.java | 26 ++--
.../hadoop/hdds/scm/pipeline/PipelineFactory.java | 5 +-
.../hadoop/hdds/scm/pipeline/PipelineManager.java | 6 +-
.../hdds/scm/pipeline/PipelineManagerImpl.java | 8 +-
.../hdds/scm/pipeline/PipelinePlacementPolicy.java | 26 +++-
.../hadoop/hdds/scm/pipeline/PipelineProvider.java | 6 +-
.../hdds/scm/pipeline/RatisPipelineProvider.java | 47 +++++--
.../hdds/scm/pipeline/SimplePipelineProvider.java | 34 ++++-
.../hadoop/hdds/scm/container/MockNodeManager.java | 16 ++-
.../hadoop/hdds/scm/node/TestSCMNodeManager.java | 2 +-
.../hdds/scm/pipeline/MockPipelineManager.java | 7 +-
.../scm/pipeline/MockRatisPipelineProvider.java | 6 +-
.../hdds/scm/pipeline/TestECPipelineProvider.java | 15 ++
.../hdds/scm/pipeline/TestPipelineManagerImpl.java | 78 ++++++++++-
.../scm/pipeline/TestPipelinePlacementPolicy.java | 20 ++-
.../scm/pipeline/TestRatisPipelineProvider.java | 138 ++++++++++++++++---
.../scm/pipeline/TestSimplePipelineProvider.java | 69 +++++++++-
.../hadoop/hdds/protocol/StorageTierTest.java | 3 +-
.../hadoop/hdds/scm/pipeline/TestSCMRestart.java | 4 +
.../apache/hadoop/ozone/om/TestKeyManagerImpl.java | 3 +-
.../ozone/recon/scm/ReconPipelineFactory.java | 2 +-
28 files changed, 736 insertions(+), 131 deletions(-)
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/StorageTier.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/StorageTier.java
index 1e5c40dfe64..24b783f1b14 100644
---
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/StorageTier.java
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/StorageTier.java
@@ -104,6 +104,13 @@ public boolean isUniform() {
return isUniform;
}
+ public StorageType getUniformStorageType() {
+ if (!isUniform()) {
+ throw new IllegalArgumentException("Uniform storage type is not
supported");
+ }
+ return storageTypes.get(0);
+ }
+
/**
* Maps a StorageTier to its corresponding StorageType based on replication
type.
*
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/StorageTierUtil.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/StorageTierUtil.java
index d68c71a31da..f7ff2afe2b7 100644
---
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/StorageTierUtil.java
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/client/StorageTierUtil.java
@@ -17,7 +17,9 @@
package org.apache.hadoop.hdds.client;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.scm.exceptions.SCMException;
@@ -45,22 +47,31 @@ public static void validateNotEmpty(StorageTier
storageTier) throws SCMException
}
}
- /**
- * Returns the StorageType for uniform StorageTier.
- *
- * @param storageTier the StorageTier to get StorageType from
- * @return The uniform StorageTier corresponding StorageType
- * @throws SCMException if the StorageTier is non-uniform or the EMPTY
StorageTier
- */
- public static StorageType getStorageTypeForUniformStorageTier(StorageTier
storageTier, ReplicationConfig config)
- throws SCMException {
- validateNotEmpty(storageTier);
- List<StorageType> storageTypes =
storageTier.getStorageTypes(config.getRequiredNodes());
- if (storageTier.isUniform()) {
- return storageTypes.get(0);
- } else {
- throw new SCMException("Unsupported non-uniform storage tier " +
storageTier,
- SCMException.ResultCodes.UNSUPPORTED_NON_UNIFORM_STORAGE_TIER);
+ public static List<StorageTier> findSupportedStorageTiers(
+ List<Set<StorageType>> dnStorageTypes) {
+ List<StorageTier> supportedStorageTiers = new ArrayList<>();
+ if (dnStorageTypes.isEmpty()) {
+ return supportedStorageTiers;
+ }
+ // We only support uniform storage tiers currently
+ for (StorageTier storageTier : StorageTier.values()) {
+ if (storageTier.equals(StorageTier.EMPTY)) {
+ continue;
+ }
+ if (!storageTier.isUniform()) {
+ throw new UnsupportedOperationException(storageTier + " is not a
uniform storage tier");
+ }
+ boolean supportedTier = true;
+ for (Set<StorageType> dnStorageType : dnStorageTypes) {
+ if (!dnStorageType.contains(storageTier.getUniformStorageType())) {
+ supportedTier = false;
+ break;
+ }
+ }
+ if (supportedTier) {
+ supportedStorageTiers.add(storageTier);
+ }
}
+ return supportedStorageTiers;
}
}
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/pipeline/Pipeline.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/pipeline/Pipeline.java
index d168fdc5a4d..1b40cf2f5b3 100644
---
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/pipeline/Pipeline.java
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/scm/pipeline/Pipeline.java
@@ -33,6 +33,8 @@
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
@@ -42,6 +44,7 @@
import org.apache.hadoop.hdds.client.ReplicatedReplicationConfig;
import org.apache.hadoop.hdds.client.ReplicationConfig;
import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
+import org.apache.hadoop.hdds.client.StorageTier;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.DatanodeID;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
@@ -87,6 +90,10 @@ public final class Pipeline {
// suggested leader id with high priority
private final DatanodeID suggestedLeaderId;
+ private final StorageTier supportedStorageTier;
+
+ private final ReadWriteLock lock;
+
private final Instant stateEnterTime;
/**
@@ -114,6 +121,8 @@ private Pipeline(Builder b) {
replicaIndexes = b.replicaIndexes;
creationTimestamp = b.creationTimestamp != null ? b.creationTimestamp :
Instant.now();
stateEnterTime = Instant.now();
+ supportedStorageTier = b.supportedStorageTier;
+ lock = new ReentrantReadWriteLock();
}
public static Codec<Pipeline> getCodec() {
@@ -170,6 +179,20 @@ public DatanodeID getSuggestedLeaderId() {
return suggestedLeaderId;
}
+ /**
+ * Return the Pipeline supported StorageTier.
+ *
+ * @return Supported StorageTier
+ */
+ public StorageTier getSupportedStorageTier() {
+ lock.readLock().lock();
+ try {
+ return supportedStorageTier;
+ } finally {
+ lock.readLock().unlock();
+ }
+ }
+
/**
* Set the creation timestamp. Only for protobuf now.
*/
@@ -399,6 +422,12 @@ public HddsProtos.Pipeline getProtobufMessage(int
clientVersion, Set<DatanodeDet
builder.setSuggestedLeaderDatanodeID(suggestedLeaderId.toProto());
}
+ // To simplify Pipeline management, we currently only support Pipelines
with a single StorageTier.
+ // However, to facilitate future expansion, StorageTier is still defined
using `repeat` in the proto file.
+ if (supportedStorageTier != null) {
+ builder.addSupportedStorageTier(supportedStorageTier.toProto());
+ }
+
// To save the message size on wire, only transfer the node order based on
// network topology
if (!nodesInOrder.isEmpty()) {
@@ -488,6 +517,12 @@ public static Builder toBuilder(HddsProtos.Pipeline
pipeline) {
HddsProtos.UUID uuid = pipeline.getSuggestedLeaderID();
suggestedLeaderId = DatanodeID.of(uuid);
}
+ StorageTier supportedStorageTier = null;
+ // To simplify Pipeline management, we currently only support Pipelines
with a single StorageTier.
+ // However, to facilitate future expansion, StorageTier is still defined
using `repeat` in the proto file.
+ for (HddsProtos.StorageTierProto storageTierProto :
pipeline.getSupportedStorageTierList()) {
+ supportedStorageTier = StorageTier.fromProto(storageTierProto);
+ }
final ReplicationConfig config = ReplicationConfig
.fromProto(pipeline.getType(), pipeline.getFactor(),
@@ -501,6 +536,7 @@ public static Builder toBuilder(HddsProtos.Pipeline
pipeline) {
.setLeaderId(leaderId)
.setSuggestedLeaderId(suggestedLeaderId)
.setNodeOrder(pipeline.getMemberOrdersList())
+ .setSupportedStorageTier(supportedStorageTier)
.setCreateTimestamp(pipeline.getCreationTimeStamp());
}
@@ -548,6 +584,7 @@ public String toString() {
b.append(']')
.append(", ReplicationConfig: ").append(replicationConfig)
.append(", State:").append(getPipelineState())
+ .append(", SupportStorageTier:").append(getSupportedStorageTier())
.append(", leaderId:").append(leaderId != null ? leaderId.toString() :
"")
.append(",
CreationTimestamp").append(getCreationTimestamp().atZone(ZoneId.systemDefault()))
.append('}');
@@ -572,6 +609,7 @@ public static final class Builder {
private Instant creationTimestamp = null;
private DatanodeID suggestedLeaderId = null;
private Map<DatanodeDetails, Integer> replicaIndexes = ImmutableMap.of();
+ private StorageTier supportedStorageTier;
private Builder() { }
@@ -594,6 +632,7 @@ private Builder(Pipeline pipeline) {
}
replicaIndexes = b.build();
}
+ this.supportedStorageTier = pipeline.getSupportedStorageTier();
}
public Builder setId(DatanodeID datanodeID) {
@@ -676,6 +715,11 @@ public Builder setReplicaIndexes(Map<DatanodeDetails,
Integer> indexes) {
return this;
}
+ public Builder setSupportedStorageTier(StorageTier supportedStorageTier) {
+ this.supportedStorageTier = supportedStorageTier;
+ return this;
+ }
+
public Pipeline build() {
Objects.requireNonNull(id, "id == null");
Objects.requireNonNull(replicationConfig, "replicationConfig == null");
diff --git
a/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/client/StorageTierUtilTest.java
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/client/StorageTierUtilTest.java
new file mode 100644
index 00000000000..f443d72f390
--- /dev/null
+++
b/hadoop-hdds/common/src/test/java/org/apache/hadoop/hdds/client/StorageTierUtilTest.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hdds.client;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.hadoop.fs.StorageType;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Provides {@link StorageTierUtil} factory methods for testing.
+ */
+class StorageTierUtilTest {
+ @Test
+ void testFindSupportedStorageTiers() {
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.SSD),
+ setOf(StorageType.SSD),
+ setOf(StorageType.SSD)),
+ 1, setOf(StorageTier.SSD));
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.SSD, StorageType.DISK),
+ setOf(StorageType.SSD, StorageType.DISK),
+ setOf(StorageType.SSD)),
+ 1, setOf(StorageTier.SSD));
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.SSD, StorageType.DISK),
+ setOf(StorageType.SSD, StorageType.DISK),
+ setOf(StorageType.SSD, StorageType.DISK)),
+ 2, setOf(StorageTier.SSD, StorageTier.DISK));
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.SSD, StorageType.DISK, StorageType.ARCHIVE),
+ setOf(StorageType.SSD, StorageType.DISK),
+ setOf(StorageType.SSD, StorageType.DISK)),
+ 2, setOf(StorageTier.SSD, StorageTier.DISK));
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.SSD, StorageType.DISK, StorageType.ARCHIVE),
+ setOf(StorageType.SSD, StorageType.DISK, StorageType.ARCHIVE),
+ setOf(StorageType.SSD, StorageType.DISK, StorageType.ARCHIVE)),
+ 3, setOf(StorageTier.SSD, StorageTier.DISK, StorageTier.ARCHIVE));
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.SSD, StorageType.DISK)),
+ 2, setOf(StorageTier.SSD, StorageTier.DISK));
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.SSD)),
+ 1, setOf(StorageTier.SSD));
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.DISK)),
+ 1, setOf(StorageTier.DISK));
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.ARCHIVE)),
+ 1, setOf(StorageTier.ARCHIVE));
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.SSD, StorageType.DISK),
+ setOf(StorageType.SSD, StorageType.DISK),
+ setOf(StorageType.SSD, StorageType.DISK),
+ setOf(StorageType.SSD, StorageType.DISK),
+ setOf(StorageType.SSD, StorageType.DISK)),
+ 2, setOf(StorageTier.SSD, StorageTier.DISK));
+ }
+
+ @Test
+ void testFindInvalidStorageTiers() {
+ assertStorageTiers(createDnStorageTypes(), 0, new HashSet<>());
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.DISK),
+ setOf(StorageType.SSD),
+ setOf(StorageType.SSD)),
+ 0, new HashSet<>());
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.DISK),
+ setOf(StorageType.DISK),
+ setOf(StorageType.SSD)),
+ 0, new HashSet<>());
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.ARCHIVE),
+ setOf(StorageType.DISK),
+ setOf(StorageType.SSD)),
+ 0, new HashSet<>());
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.RAM_DISK),
+ setOf(StorageType.SSD),
+ setOf(StorageType.SSD)),
+ 0, new HashSet<>());
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.RAM_DISK),
+ setOf(StorageType.RAM_DISK),
+ setOf(StorageType.RAM_DISK)),
+ 0, new HashSet<>());
+
+ assertStorageTiers(createDnStorageTypes(
+ setOf(StorageType.PROVIDED),
+ setOf(StorageType.PROVIDED),
+ setOf(StorageType.PROVIDED)),
+ 0, new HashSet<>());
+ }
+
+ private void assertStorageTiers(List<Set<StorageType>> dnStorageTypes,
+ int expectedSize, Set<StorageTier> expectedTiers) {
+ List<StorageTier> supportedTiers =
+ StorageTierUtil.findSupportedStorageTiers(dnStorageTypes);
+ HashSet<StorageTier> tiers = new HashSet<>(supportedTiers);
+ assertEquals(expectedSize, tiers.size());
+ assertEquals(expectedTiers, tiers);
+ }
+
+ private List<Set<StorageType>> createDnStorageTypes(Set<StorageType>...
storageSets) {
+ return Arrays.asList(storageSets);
+ }
+
+ private Set<StorageType> setOf(StorageType... types) {
+ return new HashSet<>(Arrays.asList(types));
+ }
+
+ private Set<StorageTier> setOf(StorageTier... tiers) {
+ return new HashSet<>(Arrays.asList(tiers));
+ }
+}
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/StorageLocationReport.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/StorageLocationReport.java
index 75c2f973222..5bfcc78e9e6 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/StorageLocationReport.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/StorageLocationReport.java
@@ -132,31 +132,6 @@ public long getFsAvailable() {
return fsAvailable;
}
- public static StorageType getStorageType(StorageTypeProto proto) throws
- IllegalArgumentException {
- StorageType storageType;
- switch (proto) {
- case SSD:
- storageType = StorageType.SSD;
- break;
- case DISK:
- storageType = StorageType.DISK;
- break;
- case ARCHIVE:
- storageType = StorageType.ARCHIVE;
- break;
- case PROVIDED:
- storageType = StorageType.PROVIDED;
- break;
- case RAM_DISK:
- storageType = StorageType.RAM_DISK;
- break;
- default:
- throw new IllegalArgumentException("Illegal Storage Type specified: " +
proto);
- }
- return storageType;
- }
-
/**
* Returns the StorageReportProto protoBuf message for the Storage Location
* report.
diff --git a/hadoop-hdds/interface-client/src/main/proto/hdds.proto
b/hadoop-hdds/interface-client/src/main/proto/hdds.proto
index 5b7399215d8..81b1e89089e 100644
--- a/hadoop-hdds/interface-client/src/main/proto/hdds.proto
+++ b/hadoop-hdds/interface-client/src/main/proto/hdds.proto
@@ -143,6 +143,7 @@ message Pipeline {
optional DatanodeIDProto leaderDatanodeID = 101;
optional DatanodeIDProto suggestedLeaderDatanodeID = 102;
+ repeated StorageTierProto supportedStorageTier = 103;
}
message KeyValue {
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/NodeUtils.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/NodeUtils.java
new file mode 100644
index 00000000000..f42a6e0f5a7
--- /dev/null
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/node/NodeUtils.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.hdds.scm.node;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.hadoop.fs.StorageType;
+import org.apache.hadoop.hdds.client.StorageTier;
+import org.apache.hadoop.hdds.client.StorageTierUtil;
+import org.apache.hadoop.hdds.client.StorageTypeUtils;
+import org.apache.hadoop.hdds.protocol.DatanodeDetails;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.StorageTypeProto;
+import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.StorageReportProto;
+
+/**
+ * Util class for Node operations.
+ */
+public final class NodeUtils {
+
+ private NodeUtils() {
+ }
+
+ public static List<StorageTier> getDatanodesStorageTypes(
+ List<DatanodeDetails> dns, NodeManager nodeManager) {
+ List<Set<StorageType>> dnStorageTypes = new ArrayList<>();
+ for (DatanodeDetails dn : dns) {
+ DatanodeInfo datanodeInfo = nodeManager.getDatanodeInfo(dn);
+ if (datanodeInfo == null) {
+ throw new IllegalStateException("Cannot get Datanode : " +
dn.getUuidString() + " Info");
+ }
+ dnStorageTypes.add(getDatanodeStorageTypes(datanodeInfo));
+ }
+ return StorageTierUtil.findSupportedStorageTiers(dnStorageTypes);
+ }
+
+ public static Set<StorageType> getDatanodeStorageTypes(
+ DatanodeInfo datanodeInfo) {
+ List<StorageReportProto> storageReportProtos =
+ datanodeInfo.getStorageReports();
+ if (storageReportProtos == null || storageReportProtos.isEmpty()) {
+ return Collections.emptySet();
+ }
+
+ Set<StorageType> uniqueStorageTypes = new HashSet<>();
+ for (StorageReportProto storageReportProto : storageReportProtos) {
+ uniqueStorageTypes.add(StorageTypeUtils.getFromProtobuf((
+ storageReportProto.getStorageType())));
+ }
+ return uniqueStorageTypes;
+ }
+
+ public static StorageTypeProto getStorageTypeFromStorageReportProto(
+ StorageReportProto storageReportProto) {
+ return storageReportProto.hasStorageType()
+ ? storageReportProto.getStorageType() : StorageTypeProto.DISK;
+ }
+}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/ECPipelineProvider.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/ECPipelineProvider.java
index 6b55f23d30c..9376d861ab4 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/ECPipelineProvider.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/ECPipelineProvider.java
@@ -28,15 +28,16 @@
import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.client.ECReplicationConfig;
import org.apache.hadoop.hdds.client.StorageTier;
-import org.apache.hadoop.hdds.client.StorageTierUtil;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
import org.apache.hadoop.hdds.conf.StorageUnit;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.scm.PlacementPolicy;
import org.apache.hadoop.hdds.scm.ScmConfigKeys;
import org.apache.hadoop.hdds.scm.container.ContainerReplica;
+import org.apache.hadoop.hdds.scm.exceptions.SCMException;
import org.apache.hadoop.hdds.scm.node.NodeManager;
import org.apache.hadoop.hdds.scm.node.NodeStatus;
+import org.apache.hadoop.hdds.scm.node.NodeUtils;
import org.apache.hadoop.hdds.scm.node.states.NodeNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -90,25 +91,30 @@ protected Pipeline create(ECReplicationConfig
replicationConfig,
List<DatanodeDetails> excludedNodes, List<DatanodeDetails> favoredNodes,
StorageTier storageTier)
throws IOException {
- StorageType storageType =
StorageTierUtil.getStorageTypeForUniformStorageTier(storageTier,
replicationConfig);
+ StorageType storageType = storageTier.getUniformStorageType();
List<DatanodeDetails> dns = placementPolicy
.chooseDatanodes(excludedNodes, favoredNodes,
replicationConfig.getRequiredNodes(), 0, this.containerSizeBytes,
storageType);
- return create(replicationConfig, dns);
+ return create(replicationConfig, dns, storageTier);
}
@Override
protected Pipeline create(ECReplicationConfig replicationConfig,
- List<DatanodeDetails> nodes) {
-
+ List<DatanodeDetails> nodes, StorageTier storageTier) throws IOException
{
+ List<StorageTier> storageTiers = NodeUtils.getDatanodesStorageTypes(nodes,
getNodeManager());
+ if (!storageTiers.contains(storageTier)) {
+ throw new SCMException(String.format("Cannot create pipeline for "
+ + "StorageTier %s replicationConfig: %s",
+ storageTier, replicationConfig),
+ SCMException.ResultCodes.FAILED_TO_FIND_SUITABLE_NODE);
+ }
Map<DatanodeDetails, Integer> dnIndexes = new HashMap<>();
int ecIndex = 1;
for (DatanodeDetails dn : nodes) {
dnIndexes.put(dn, ecIndex);
ecIndex++;
}
-
- return createPipelineInternal(replicationConfig, nodes, dnIndexes);
+ return createPipelineInternal(replicationConfig, nodes, dnIndexes,
storageTier);
}
@Override
@@ -135,17 +141,19 @@ public Pipeline createForRead(
dns.sort(Comparator.comparing(nodeStatusMap::get,
CREATE_FOR_READ_COMPARATOR));
- return createPipelineInternal(replicationConfig, dns, map);
+ // Read Pipelines do not require storage tiers, so the calculation of
storage tiers can be omitted.
+ return createPipelineInternal(replicationConfig, dns, map, null);
}
private Pipeline createPipelineInternal(ECReplicationConfig repConfig,
- List<DatanodeDetails> dns, Map<DatanodeDetails, Integer> indexes) {
+ List<DatanodeDetails> dns, Map<DatanodeDetails, Integer> indexes,
StorageTier storageTier) {
return Pipeline.newBuilder()
.setId(PipelineID.randomId())
.setState(Pipeline.PipelineState.ALLOCATED)
.setReplicationConfig(repConfig)
.setNodes(dns)
.setReplicaIndexes(indexes)
+ .setSupportedStorageTier(storageTier)
.build();
}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineFactory.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineFactory.java
index 9da5bac2f28..2268309012b 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineFactory.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineFactory.java
@@ -108,10 +108,9 @@ private void checkPipeline(Pipeline pipeline) throws
IOException {
}
public Pipeline create(ReplicationConfig replicationConfig,
- List<DatanodeDetails> nodes
- ) {
+ List<DatanodeDetails> nodes, StorageTier storageTier) throws IOException
{
return providers.get(replicationConfig.getReplicationType())
- .create(replicationConfig, nodes);
+ .create(replicationConfig, nodes, storageTier);
}
public Pipeline createForRead(ReplicationConfig replicationConfig,
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManager.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManager.java
index 739b0c058ec..db8e23c9bf0 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManager.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManager.java
@@ -24,6 +24,7 @@
import java.util.NavigableSet;
import java.util.Set;
import org.apache.hadoop.hdds.client.ReplicationConfig;
+import org.apache.hadoop.hdds.client.StorageTier;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.scm.container.ContainerID;
import org.apache.hadoop.hdds.scm.container.ContainerReplica;
@@ -53,8 +54,9 @@ Pipeline buildECPipeline(ReplicationConfig replicationConfig,
Pipeline createPipeline(
ReplicationConfig replicationConfig,
- List<DatanodeDetails> nodes
- );
+ List<DatanodeDetails> nodes,
+ StorageTier storageTier
+ ) throws IOException;
Pipeline createPipelineForRead(
ReplicationConfig replicationConfig, Set<ContainerReplica> replicas);
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManagerImpl.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManagerImpl.java
index c4375e3f20e..c616edfcd3b 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManagerImpl.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineManagerImpl.java
@@ -39,6 +39,7 @@
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
import org.apache.hadoop.hdds.client.ReplicationConfig;
import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
+import org.apache.hadoop.hdds.client.StorageTier;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
@@ -317,11 +318,12 @@ private boolean factorOne(ReplicationConfig
replicationConfig) {
@Override
public Pipeline createPipeline(
ReplicationConfig replicationConfig,
- List<DatanodeDetails> nodes
- ) {
+ List<DatanodeDetails> nodes,
+ StorageTier storageTier
+ ) throws IOException {
// This will mostly be used to create dummy pipeline for SimplePipelines.
// We don't update the metrics for SimplePipelines.
- return pipelineFactory.create(replicationConfig, nodes);
+ return pipelineFactory.create(replicationConfig, nodes, storageTier);
}
@Override
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelinePlacementPolicy.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelinePlacementPolicy.java
index e2f880121fc..8dbdafea23b 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelinePlacementPolicy.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelinePlacementPolicy.java
@@ -85,7 +85,8 @@ public PipelinePlacementPolicy(final NodeManager nodeManager,
static int currentRatisThreePipelineCount(
NodeManager nodeManager,
PipelineStateManager stateManager,
- DatanodeDetails datanodeDetails) {
+ DatanodeDetails datanodeDetails,
+ StorageType storageType) {
// Safe to cast collection's size to int
return (int) nodeManager.getPipelines(datanodeDetails).stream()
.map(id -> {
@@ -97,15 +98,15 @@ static int currentRatisThreePipelineCount(
return null;
}
})
- .filter(PipelinePlacementPolicy::isNonClosedRatisThreePipeline)
+ .filter(p -> isNonClosedRatisThreePipeline(p, storageType))
.count();
}
/** Filter the given datanodes within its pipeline limit. */
- List<DatanodeDetails> filterPipelineLimit(Iterable<DatanodeDetails>
datanodes) {
+ List<DatanodeDetails> filterPipelineLimit(Iterable<DatanodeDetails>
datanodes, StorageType storageType) {
final SortedList<DatanodeDetails> sorted = new
SortedList<>(DatanodeDetails.class);
for (DatanodeDetails d : datanodes) {
- final int count = currentRatisThreePipelineCount(nodeManager,
stateManager, d);
+ final int count = currentRatisThreePipelineCount(nodeManager,
stateManager, d, storageType);
if (count < nodeManager.pipelineLimit(d)) {
sorted.add(d, count);
}
@@ -113,10 +114,21 @@ List<DatanodeDetails>
filterPipelineLimit(Iterable<DatanodeDetails> datanodes) {
return sorted;
}
- private static boolean isNonClosedRatisThreePipeline(Pipeline p) {
+ private static boolean isNonClosedRatisThreePipeline(Pipeline p, StorageType
storageType) {
+ boolean matchedTier = false;
+ if (storageType != null) {
+ try {
+ // TODO: Do we need to return true if getSupportedStorageTier() is
empty
+ // otherwise this might cause more pipelines to be created than
necessary
+ matchedTier =
p.getSupportedStorageTier().getUniformStorageType().equals(storageType);
+ } catch (IllegalArgumentException e) {
+ LOG.debug("Cannot convert pipeline storage tier {} to storage type.",
p.getSupportedStorageTier(), e);
+ return false;
+ }
+ }
return p != null && p.getReplicationConfig()
.equals(RatisReplicationConfig.getInstance(ReplicationFactor.THREE))
- && !p.isClosed();
+ && !p.isClosed() && matchedTier;
}
@Override
@@ -182,7 +194,7 @@ List<DatanodeDetails> filterViableNodes(
// filter nodes that meet the size and pipeline engagement criteria.
// Pipeline placement doesn't take node space left into account.
// Sort the DNs by pipeline load.
- final List<DatanodeDetails> healthyList =
filterPipelineLimit(healthyNodes);
+ final List<DatanodeDetails> healthyList =
filterPipelineLimit(healthyNodes, storageType);
if (healthyList.size() < nodesRequired) {
if (LOG.isDebugEnabled()) {
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineProvider.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineProvider.java
index 0a02cb5fd3b..dca15ca5637 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineProvider.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/PipelineProvider.java
@@ -74,8 +74,8 @@ protected abstract Pipeline create(REPLICATION_CONFIG
replicationConfig,
protected abstract Pipeline create(
REPLICATION_CONFIG replicationConfig,
- List<DatanodeDetails> nodes
- );
+ List<DatanodeDetails> nodes,
+ StorageTier storageTier) throws IOException;
protected abstract Pipeline createForRead(
REPLICATION_CONFIG replicationConfig,
@@ -89,7 +89,7 @@ List<DatanodeDetails> pickNodesNotUsed(REPLICATION_CONFIG
replicationConfig,
long dataSizeRequired, StorageTier
storageTier)
throws SCMException {
StorageTierUtil.validateNotEmpty(storageTier);
- StorageType storageType =
StorageTierUtil.getStorageTypeForUniformStorageTier(storageTier,
replicationConfig);
+ StorageType storageType = storageTier.getUniformStorageType();
int nodesRequired = replicationConfig.getRequiredNodes();
List<DatanodeDetails> healthyDNs = pickAllNodesNotUsed(replicationConfig);
List<DatanodeDetails> healthyDNsWithSpace = healthyDNs.stream()
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/RatisPipelineProvider.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/RatisPipelineProvider.java
index 9b763e6d5c2..5d5ad3111ce 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/RatisPipelineProvider.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/RatisPipelineProvider.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.hdds.scm.pipeline;
import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@@ -40,6 +41,7 @@
import org.apache.hadoop.hdds.scm.ha.SCMContext;
import org.apache.hadoop.hdds.scm.node.NodeManager;
import org.apache.hadoop.hdds.scm.node.NodeStatus;
+import org.apache.hadoop.hdds.scm.node.NodeUtils;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline.PipelineState;
import
org.apache.hadoop.hdds.scm.pipeline.leader.choose.algorithms.LeaderChoosePolicy;
import
org.apache.hadoop.hdds.scm.pipeline.leader.choose.algorithms.LeaderChoosePolicyFactory;
@@ -154,8 +156,8 @@ public synchronized Pipeline create(RatisReplicationConfig
replicationConfig,
: String.format(": %d", pipelineNumberLimit);
throw new SCMException(
- String.format("Cannot create pipeline as it would exceed the limit
%s replicationConfig: %s",
- limitInfo, replicationConfig),
+ String.format("Cannot create pipeline for StorageTier %s as it would
exceed the limit %s " +
+ "replicationConfig: %s", storageTier, limitInfo,
replicationConfig),
SCMException.ResultCodes.FAILED_TO_FIND_SUITABLE_NODE
);
}
@@ -169,8 +171,8 @@ public synchronized Pipeline create(RatisReplicationConfig
replicationConfig,
break;
case THREE:
StorageTierUtil.validateNotEmpty(storageTier);
- StorageType storageType =
StorageTierUtil.getStorageTypeForUniformStorageTier(storageTier,
replicationConfig);
- List<DatanodeDetails> excludeDueToEngagement =
filterPipelineEngagement();
+ StorageType storageType = storageTier.getUniformStorageType();
+ List<DatanodeDetails> excludeDueToEngagement =
filterPipelineEngagement(storageTier);
if (!excludeDueToEngagement.isEmpty()) {
if (excludedNodes.isEmpty()) {
excludedNodes = excludeDueToEngagement;
@@ -188,6 +190,12 @@ public synchronized Pipeline create(RatisReplicationConfig
replicationConfig,
DatanodeDetails suggestedLeader = leaderChoosePolicy.chooseLeader(dns);
+ List<StorageTier> storageTiers = NodeUtils.getDatanodesStorageTypes(dns,
getNodeManager());
+ if (!storageTiers.contains(storageTier)) {
+ throw new SCMException(String.format("Cannot create pipeline for
StorageTier %s replicationConfig: %s",
+ storageTier, replicationConfig),
SCMException.ResultCodes.FAILED_TO_FIND_SUITABLE_NODE);
+ }
+ Preconditions.checkArgument(storageTiers.contains(storageTier));
Pipeline pipeline = Pipeline.newBuilder()
.setId(PipelineID.randomId())
.setState(PipelineState.ALLOCATED)
@@ -195,6 +203,7 @@ public synchronized Pipeline create(RatisReplicationConfig
replicationConfig,
.setNodes(dns)
.setSuggestedLeaderId(
suggestedLeader != null ? suggestedLeader.getID() : null)
+ .setSupportedStorageTier(storageTier)
.build();
// Send command to datanodes to create pipeline
@@ -207,8 +216,8 @@ public synchronized Pipeline create(RatisReplicationConfig
replicationConfig,
createCommand.setTerm(scmContext.getTermOfLeader());
dns.forEach(node -> {
- LOG.info("Sending CreatePipelineCommand for pipeline:{} to datanode:{}",
- pipeline.getId(), node);
+ LOG.info("Sending CreatePipelineCommand for pipeline:{} to datanode:{}
storageTier:{}",
+ pipeline.getId(), node, storageTier);
eventPublisher.fireEvent(SCMEvents.DATANODE_COMMAND,
new CommandForDatanode<>(node, createCommand));
});
@@ -218,12 +227,25 @@ public synchronized Pipeline
create(RatisReplicationConfig replicationConfig,
@Override
public Pipeline create(RatisReplicationConfig replicationConfig,
- List<DatanodeDetails> nodes) {
+ List<DatanodeDetails> nodes, StorageTier storageTier) throws IOException
{
+ List<StorageTier> storageTiers = NodeUtils.getDatanodesStorageTypes(nodes,
getNodeManager());
+ if (!storageTiers.contains(storageTier)) {
+ throw new SCMException(String.format("Cannot create pipeline for "
+ + "StorageTier %s replicationConfig: %s",
+ storageTier, replicationConfig),
+ SCMException.ResultCodes.FAILED_TO_FIND_SUITABLE_NODE);
+ }
+ return createPipelineInternal(replicationConfig, nodes, storageTier);
+ }
+
+ private Pipeline createPipelineInternal(RatisReplicationConfig
replicationConfig,
+ List<DatanodeDetails> nodes, StorageTier storageTier) {
return Pipeline.newBuilder()
.setId(PipelineID.randomId())
.setState(PipelineState.ALLOCATED)
.setReplicationConfig(replicationConfig)
.setNodes(nodes)
+ .setSupportedStorageTier(storageTier)
.build();
}
@@ -231,19 +253,22 @@ public Pipeline create(RatisReplicationConfig
replicationConfig,
public Pipeline createForRead(
RatisReplicationConfig replicationConfig,
Set<ContainerReplica> replicas) {
- return create(replicationConfig, replicas
+ // Read Pipelines do not require storage tiers, so the calculation of
storage tiers can be omitted.
+ return createPipelineInternal(replicationConfig, replicas
.stream()
.map(ContainerReplica::getDatanodeDetails)
- .collect(Collectors.toList()));
+ .collect(Collectors.toList()), null);
}
- private List<DatanodeDetails> filterPipelineEngagement() {
+ private List<DatanodeDetails> filterPipelineEngagement(StorageTier
storageTier) {
final NodeManager nodeManager = getNodeManager();
final PipelineStateManager stateManager = getPipelineStateManager();
final List<DatanodeDetails> healthyNodes =
nodeManager.getNodes(NodeStatus.inServiceHealthy());
final List<DatanodeDetails> excluded = new ArrayList<>();
+ final StorageType storageType = storageTier.getUniformStorageType();
for (DatanodeDetails d : healthyNodes) {
- final int count =
PipelinePlacementPolicy.currentRatisThreePipelineCount(nodeManager,
stateManager, d);
+ final int count = PipelinePlacementPolicy.currentRatisThreePipelineCount(
+ nodeManager, stateManager, d, storageType);
if (count >= nodeManager.pipelineLimit(d)) {
excluded.add(d);
}
diff --git
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/SimplePipelineProvider.java
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/SimplePipelineProvider.java
index 62102938937..411679010b5 100644
---
a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/SimplePipelineProvider.java
+++
b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/pipeline/SimplePipelineProvider.java
@@ -29,8 +29,10 @@
import org.apache.hadoop.hdds.client.StorageTypeUtils;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.scm.container.ContainerReplica;
+import org.apache.hadoop.hdds.scm.exceptions.SCMException;
import org.apache.hadoop.hdds.scm.node.DatanodeInfo;
import org.apache.hadoop.hdds.scm.node.NodeManager;
+import org.apache.hadoop.hdds.scm.node.NodeUtils;
import org.apache.hadoop.hdds.scm.pipeline.Pipeline.PipelineState;
/**
@@ -56,7 +58,7 @@ public Pipeline create(StandaloneReplicationConfig
replicationConfig, StorageTie
public Pipeline create(StandaloneReplicationConfig replicationConfig,
List<DatanodeDetails> excludedNodes, List<DatanodeDetails> favoredNodes,
StorageTier storageTier)
throws IOException {
- StorageType storageType =
StorageTierUtil.getStorageTypeForUniformStorageTier(storageTier,
replicationConfig);
+ StorageType storageType = storageTier.getUniformStorageType();
List<DatanodeDetails> dns = pickNodesNotUsed(replicationConfig);
dns = dns.stream().filter(dn ->
((DatanodeInfo) dn).getStorageReports().stream()
@@ -73,33 +75,53 @@ public Pipeline create(StandaloneReplicationConfig
replicationConfig,
}
Collections.shuffle(dns);
+ List<StorageTier> storageTiers = NodeUtils.getDatanodesStorageTypes(dns,
getNodeManager());
+ if (!storageTiers.contains(storageTier)) {
+ throw new SCMException(String.format("Cannot create pipeline for
StorageTier %s replicationConfig: %s",
+ storageTier, replicationConfig),
SCMException.ResultCodes.FAILED_TO_FIND_SUITABLE_NODE);
+ }
return Pipeline.newBuilder()
.setId(PipelineID.randomId())
.setState(PipelineState.OPEN)
.setReplicationConfig(replicationConfig)
.setNodes(dns.subList(0,
replicationConfig.getReplicationFactor().getNumber()))
+ .setSupportedStorageTier(storageTier)
.build();
}
- @Override
- public Pipeline create(StandaloneReplicationConfig replicationConfig,
- List<DatanodeDetails> nodes) {
+ private Pipeline createPipelineInternal(StandaloneReplicationConfig
replicationConfig,
+ List<DatanodeDetails> nodes, StorageTier storageTier) {
return Pipeline.newBuilder()
.setId(PipelineID.randomId())
.setState(PipelineState.OPEN)
.setReplicationConfig(replicationConfig)
.setNodes(nodes)
+ .setSupportedStorageTier(storageTier)
.build();
}
+ @Override
+ public Pipeline create(StandaloneReplicationConfig replicationConfig,
+ List<DatanodeDetails> nodes, StorageTier storageTier) throws IOException
{
+ List<StorageTier> storageTiers = NodeUtils.getDatanodesStorageTypes(nodes,
getNodeManager());
+ if (!storageTiers.contains(storageTier)) {
+ throw new SCMException(String.format("Cannot create pipeline for "
+ + "StorageTier %s replicationConfig: %s",
+ storageTier, replicationConfig),
+ SCMException.ResultCodes.FAILED_TO_FIND_SUITABLE_NODE);
+ }
+ return createPipelineInternal(replicationConfig, nodes, storageTier);
+ }
+
@Override
public Pipeline createForRead(StandaloneReplicationConfig replicationConfig,
Set<ContainerReplica> replicas) {
- return create(replicationConfig, replicas
+ // Read Pipelines do not require storage tiers, so the calculation of
storage tiers can be omitted.
+ return createPipelineInternal(replicationConfig, replicas
.stream()
.map(ContainerReplica::getDatanodeDetails)
- .collect(Collectors.toList()));
+ .collect(Collectors.toList()), null);
}
@Override
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/MockNodeManager.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/MockNodeManager.java
index 096720afaca..11e24a24913 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/MockNodeManager.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/container/MockNodeManager.java
@@ -38,6 +38,7 @@
import java.util.concurrent.ConcurrentMap;
import java.util.stream.Collectors;
import org.apache.hadoop.fs.StorageType;
+import org.apache.hadoop.hdds.client.StorageTypeUtils;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.DatanodeID;
@@ -120,6 +121,8 @@ public class MockNodeManager implements NodeManager {
private final OzoneConfiguration conf = new OzoneConfiguration();
private StorageType storageType = null;
+ private Map<DatanodeID, StorageType> nodeStorageTypeMap = new HashMap<>();
+
{
this.healthyNodes = new LinkedList<>();
this.staleNodes = new LinkedList<>();
@@ -289,10 +292,12 @@ public List<DatanodeDetails> getNodes(
long capacity = nodeMetricMap.get(dd).getCapacity().get();
long used = nodeMetricMap.get(dd).getScmUsed().get();
long remaining = nodeMetricMap.get(dd).getRemaining().get();
+ StorageType nodeStorageType = nodeStorageTypeMap.get(dd.getID()) !=
null ?
+ nodeStorageTypeMap.get(dd.getID()) : storageType;
StorageReportProto storage1 = HddsTestUtils.createStorageReport(
di.getID(), "/data1-" + di.getID(),
capacity, used, remaining,
- storageType == null ? null : getStorageTypeProto(storageType));
+ nodeStorageType == null ? null :
getStorageTypeProto(nodeStorageType));
MetadataStorageReportProto metaStorage1 =
HddsTestUtils.createMetadataStorageReport(
"/metadata1-" + di.getID(), capacity, used, remaining, null);
@@ -457,9 +462,12 @@ public DatanodeInfo getDatanodeInfo(DatanodeDetails dd) {
long capacity = nodeMetricMap.get(dd).getCapacity().get();
long used = nodeMetricMap.get(dd).getScmUsed().get();
long remaining = nodeMetricMap.get(dd).getRemaining().get();
+ StorageType nodeStorageType = nodeStorageTypeMap.get(dd.getID()) != null ?
+ nodeStorageTypeMap.get(dd.getID()) : storageType;
StorageReportProto storage1 = HddsTestUtils.createStorageReport(
di.getID(), "/data1-" + di.getUuidString(),
- capacity, used, remaining, null);
+ capacity, used, remaining,
+ nodeStorageType == null ? null :
StorageTypeUtils.getStorageTypeProto(nodeStorageType));
MetadataStorageReportProto metaStorage1 =
HddsTestUtils.createMetadataStorageReport(
"/metadata1-" + di.getUuidString(), capacity, used,
@@ -1046,4 +1054,8 @@ public void setCurrentState(long currentState) {
}
}
+
+ public void setStorageTypeForNode(DatanodeID uuid, StorageType st) {
+ this.nodeStorageTypeMap.put(uuid, st);
+ }
}
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
index 59a4938e8d7..3515f83083d 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/node/TestSCMNodeManager.java
@@ -480,7 +480,7 @@ private void
assertPipelineCreationFailsWithExceedingLimit(int limit) {
() -> scm.getPipelineManager().createPipeline(config),
"3 nodes should not have been found for a pipeline.");
assertThat(ex.getMessage())
- .contains("Cannot create pipeline as it would exceed the limit per
datanode: " + limit);
+ .contains("Cannot create pipeline for StorageTier DISK as it would
exceed the limit per datanode: " + limit);
}
private void assertPipelines(HddsProtos.ReplicationFactor factor,
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockPipelineManager.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockPipelineManager.java
index 69b1e24dfe3..62fd716656e 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockPipelineManager.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockPipelineManager.java
@@ -30,6 +30,7 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.hadoop.hdds.client.ReplicationConfig;
+import org.apache.hadoop.hdds.client.StorageTier;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
@@ -83,7 +84,8 @@ public Pipeline createPipeline(ReplicationConfig
replicationConfig,
pipeline = createPipeline(replicationConfig,
ImmutableList.of(MockDatanodeDetails.randomDatanodeDetails(),
MockDatanodeDetails.randomDatanodeDetails(),
- MockDatanodeDetails.randomDatanodeDetails()));
+ MockDatanodeDetails.randomDatanodeDetails()),
+ StorageTier.getDefaultTier());
}
stateManager.addPipeline(pipeline.getProtobufMessage(
@@ -116,11 +118,12 @@ public void addEcPipeline(Pipeline pipeline)
@Override
public Pipeline createPipeline(final ReplicationConfig replicationConfig,
- final List<DatanodeDetails> nodes) {
+ final List<DatanodeDetails> nodes, StorageTier storageTier) {
return Pipeline.newBuilder()
.setId(PipelineID.randomId())
.setReplicationConfig(replicationConfig)
.setNodes(nodes)
+ .setSupportedStorageTier(storageTier)
.setState(Pipeline.PipelineState.OPEN)
.build();
}
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockRatisPipelineProvider.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockRatisPipelineProvider.java
index 4ad8ee4a302..fbca53d4818 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockRatisPipelineProvider.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/MockRatisPipelineProvider.java
@@ -79,6 +79,7 @@ public Pipeline create(RatisReplicationConfig
replicationConfig, StorageTier sto
.fromProtoTypeAndFactor(initialPipeline.getType(),
replicationConfig.getReplicationFactor()))
.setNodes(initialPipeline.getNodes())
+ .setSupportedStorageTier(initialPipeline.getSupportedStorageTier())
.build();
return pipeline;
}
@@ -94,12 +95,15 @@ public static void markPipelineHealthy(Pipeline pipeline)
@Override
public Pipeline create(RatisReplicationConfig replicationConfig,
- List<DatanodeDetails> nodes) {
+ List<DatanodeDetails> nodes, StorageTier storageTier)
+ throws IOException {
return Pipeline.newBuilder()
.setId(PipelineID.randomId())
.setState(Pipeline.PipelineState.OPEN)
.setReplicationConfig(replicationConfig)
.setNodes(nodes)
+ .setSupportedStorageTier(storageTier)
.build();
}
+
}
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestECPipelineProvider.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestECPipelineProvider.java
index 92a28c99d46..0657282ca74 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestECPipelineProvider.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestECPipelineProvider.java
@@ -37,6 +37,7 @@
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -50,10 +51,12 @@
import org.apache.hadoop.hdds.protocol.DatanodeID;
import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos;
+import org.apache.hadoop.hdds.scm.HddsTestUtils;
import org.apache.hadoop.hdds.scm.PlacementPolicy;
import org.apache.hadoop.hdds.scm.ScmConfigKeys;
import org.apache.hadoop.hdds.scm.container.ContainerID;
import org.apache.hadoop.hdds.scm.container.ContainerReplica;
+import org.apache.hadoop.hdds.scm.node.DatanodeInfo;
import org.apache.hadoop.hdds.scm.node.NodeManager;
import org.apache.hadoop.hdds.scm.node.NodeStatus;
import org.apache.hadoop.hdds.scm.node.states.NodeNotFoundException;
@@ -95,6 +98,8 @@ public void setup() throws IOException, NodeNotFoundException
{
when(nodeManager.getNodeStatus(any()))
.thenReturn(NodeStatus.inServiceHealthy());
+ when(nodeManager.getDatanodeInfo(any()))
+ .thenAnswer(invocation ->
createDatanodeInfo(invocation.getArgument(0)));
}
@Test
@@ -223,4 +228,14 @@ private Set<ContainerReplica> createContainerReplicas(int
number) {
return replicas;
}
+ private DatanodeInfo createDatanodeInfo(DatanodeDetails dn) {
+ DatanodeInfo datanodeInfo = new DatanodeInfo(dn,
+ NodeStatus.inServiceHealthy(), null,
+ HddsTestUtils.ROLL_INTERVAL_MS_DEFAULT);
+ datanodeInfo.updateStorageReports(Collections.singletonList(
+ HddsTestUtils.createStorageReport(dn.getID(),
+ "/data-" + dn.getUuidString(), 100)));
+ return datanodeInfo;
+ }
+
}
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java
index 4e53f6d629a..2e453e5c7d2 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelineManagerImpl.java
@@ -63,10 +63,12 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.client.ECReplicationConfig;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
import org.apache.hadoop.hdds.client.ReplicationConfig;
import org.apache.hadoop.hdds.client.ReplicationType;
+import org.apache.hadoop.hdds.client.StorageTier;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.DatanodeID;
@@ -163,6 +165,18 @@ public void cleanup() throws Exception {
}
}
+ private PipelineManagerImpl createPipelineManager(NodeManager manager,
boolean isLeader)
+ throws IOException {
+ return PipelineManagerImpl.newPipelineManager(conf,
+ SCMHAManagerStub.getInstance(isLeader),
+ manager,
+ SCMDBDefinition.PIPELINES.getTable(dbStore),
+ new EventQueue(),
+ scmContext,
+ serviceManager,
+ testClock);
+ }
+
private PipelineManagerImpl createPipelineManager(boolean isLeader)
throws IOException {
return PipelineManagerImpl.newPipelineManager(conf,
@@ -377,7 +391,7 @@ public void testPipelineReport() throws Exception {
// get pipeline report from each dn in the pipeline
PipelineReportHandler pipelineReportHandler =
new PipelineReportHandler(scmSafeModeManager, pipelineManager,
- SCMContext.emptyContext(), conf);
+ scmContext, conf);
nodes.subList(0, 2).forEach(dn -> sendPipelineReport(dn, pipeline,
pipelineReportHandler, false));
sendPipelineReport(nodes.get(nodes.size() - 1), pipeline,
@@ -405,6 +419,60 @@ public void testPipelineReport() throws Exception {
}
}
+ @Test
+ public void testPipelineReportDoesNotUpdateSupportedStorageTier() throws
Exception {
+ // Set Env
+ int nodeCount = 3;
+ MockNodeManager localNodeManager = new MockNodeManager(true, nodeCount,
StorageType.DISK);
+ SCMContext localScmContext = spy(SCMContext.emptyContext());
+ StorageContainerManager localScm = mock(StorageContainerManager.class);
+ when(localScm.getScmNodeManager()).thenReturn(localNodeManager);
+ when(localScmContext.getScm()).thenReturn(localScm);
+
+ PipelineManagerImpl pipelineManager =
createPipelineManager(localNodeManager, true);
+ SCMSafeModeManager scmSafeModeManager = new SCMSafeModeManager(conf,
+ localNodeManager, pipelineManager, mock(ContainerManager.class),
+ serviceManager, new EventQueue(), scmContext);
+ List<DatanodeDetails> nodes =
localNodeManager.getNodes(NodeStatus.inServiceHealthy());
+ assertEquals(nodeCount, nodes.size());
+ Pipeline pipeline = pipelineManager.createPipeline(RatisReplicationConfig
+ .getInstance(ReplicationFactor.THREE));
+ assertEquals(StorageTier.DISK, pipeline.getSupportedStorageTier());
+
+ assertFalse(pipelineManager.getPipeline(pipeline.getId()).isHealthy());
+ PipelineReportHandler pipelineReportHandler = new PipelineReportHandler(
+ scmSafeModeManager, pipelineManager, localScmContext, conf);
+ nodes.subList(0, 2).forEach(dn -> sendPipelineReport(dn, pipeline,
+ pipelineReportHandler, false));
+ sendPipelineReport(nodes.get(nodes.size() - 1), pipeline,
+ pipelineReportHandler, true);
+
+ // All the Datanode Volume StorageType is DISK so the Pipeline StorageTier
will be StorageTier.DISK
+ assertTrue(pipelineManager.getPipeline(pipeline.getId()).isHealthy());
+ assertTrue(pipelineManager.getPipeline(pipeline.getId()).isOpen());
+ assertEquals(StorageTier.DISK, pipeline.getSupportedStorageTier());
+
+ // Only the first Datanode updated its NodeReport to SSD,
+ // but the Pipeline supportedStorageTier keeps the StorageTier selected at
creation.
+ localNodeManager.setStorageTypeForNode(nodes.get(0).getID(),
StorageType.SSD);
+ sendPipelineReport(nodes.get(0), pipeline, pipelineReportHandler, false);
+ assertEquals(StorageTier.DISK,
pipelineManager.getPipeline(pipeline.getId()).getSupportedStorageTier());
+
+ // The first and second Datanode updated its NodeReport to SSD
+ localNodeManager.setStorageTypeForNode(nodes.get(1).getID(),
StorageType.SSD);
+ sendPipelineReport(nodes.get(1), pipeline, pipelineReportHandler, false);
+ assertEquals(StorageTier.DISK,
pipelineManager.getPipeline(pipeline.getId()).getSupportedStorageTier());
+
+ // The first and second Datanode updated its NodeReport to SSD
+ localNodeManager.setStorageTypeForNode(nodes.get(2).getID(),
StorageType.SSD);
+ sendPipelineReport(nodes.get(2), pipeline, pipelineReportHandler, true);
+ assertEquals(StorageTier.DISK,
pipelineManager.getPipeline(pipeline.getId()).getSupportedStorageTier());
+
+ // close the pipeline and clean up
+ pipelineManager.closePipeline(pipeline.getId());
+ pipelineManager.close();
+ }
+
@Test
public void testPipelineCreationFailedMetric() throws Exception {
PipelineManagerImpl pipelineManager = createPipelineManager(true);
@@ -478,7 +546,7 @@ public void testPipelineOpenOnlyWhenLeaderReported() throws
Exception {
serviceManager, new EventQueue(), scmContext);
PipelineReportHandler pipelineReportHandler =
new PipelineReportHandler(scmSafeModeManager, pipelineManager,
- SCMContext.emptyContext(), conf);
+ scmContext, conf);
// Report pipelines with leaders
List<DatanodeDetails> nodes = pipeline.getNodes();
@@ -855,7 +923,7 @@ public void testWaitForAllocatedPipeline() throws
IOException {
= new HealthyPipelineChoosePolicy();
ContainerManager containerManager
= mock(ContainerManager.class);
-
+
WritableContainerProvider<ReplicationConfig> provider;
String owner = "TEST";
Pipeline allocatedPipeline;
@@ -876,7 +944,7 @@ public void testWaitForAllocatedPipeline() throws
IOException {
ContainerInfo container = HddsTestUtils.
getContainer(HddsProtos.LifeCycleState.OPEN,
allocatedPipeline.getId());
-
+
pipelineManager.addContainerToPipeline(
allocatedPipeline.getId(), container.containerID());
doReturn(container).when(containerManager).getMatchingContainer(anyLong(),
@@ -902,7 +970,7 @@ public void testWaitForAllocatedPipeline() throws
IOException {
return call.callRealMethod();
}).when(pipelineManagerSpy).waitOnePipelineReady(any(), anyLong());
-
+
ContainerInfo c = provider.getContainer(1, repConfig,
owner, new ExcludeList());
assertEquals(c, container, "Expected container was returned");
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelinePlacementPolicy.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelinePlacementPolicy.java
index 53c9f92d0b7..07e367b172f 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelinePlacementPolicy.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestPipelinePlacementPolicy.java
@@ -47,6 +47,7 @@
import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
import org.apache.hadoop.hdds.client.ReplicationConfig;
+import org.apache.hadoop.hdds.client.StorageTier;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.conf.StorageUnit;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
@@ -114,11 +115,13 @@ public class TestPipelinePlacementPolicy {
private List<DatanodeDetails> nodesWithOutRackAwareness = new ArrayList<>();
private List<DatanodeDetails> nodesWithRackAwareness = new ArrayList<>();
- private final StorageType storageType = StorageType.DEFAULT;
+ private final StorageTier storageTier = StorageTier.DISK;
+ private StorageType storageType = StorageType.DEFAULT;
@BeforeEach
public void init() throws Exception {
cluster = initTopology();
+ storageType = storageTier.getUniformStorageType();
// start with nodes with rack awareness.
nodeManager = new MockNodeManager(cluster, getNodesWithRackAwareness(),
false, PIPELINE_PLACEMENT_MAX_NODES_COUNT, storageType);
@@ -290,6 +293,7 @@ public void testPickLowestLoadAnchor() throws IOException,
TimeoutException {
.setState(Pipeline.PipelineState.ALLOCATED)
.setReplicationConfig(RatisReplicationConfig.getInstance(
ReplicationFactor.THREE))
+ .setSupportedStorageTier(storageTier)
.setNodes(nodes)
.build();
HddsProtos.Pipeline pipelineProto = pipeline.getProtobufMessage(
@@ -647,6 +651,7 @@ private void insertHeavyNodesIntoNodeManager(
.setReplicationConfig(ReplicationConfig
.fromProtoTypeAndFactor(RATIS, THREE))
.setNodes(dnList)
+ .setSupportedStorageTier(storageTier)
.build();
pipelineProto = pipeline.getProtobufMessage(
@@ -674,7 +679,7 @@ public void testCurrentRatisThreePipelineCount()
pipelineCount
= placementPolicy.currentRatisThreePipelineCount(nodeManager,
- stateManager, healthyNodes.get(0));
+ stateManager, healthyNodes.get(0), StorageType.DEFAULT);
assertEquals(pipelineCount, 0);
// Check datanode with one RATIS/ONE pipeline
@@ -684,7 +689,7 @@ public void testCurrentRatisThreePipelineCount()
pipelineCount
= placementPolicy.currentRatisThreePipelineCount(nodeManager,
- stateManager, healthyNodes.get(1));
+ stateManager, healthyNodes.get(1), StorageType.DEFAULT);
assertEquals(pipelineCount, 0);
// Check datanode with one RATIS/THREE pipeline
@@ -696,7 +701,7 @@ public void testCurrentRatisThreePipelineCount()
pipelineCount
= placementPolicy.currentRatisThreePipelineCount(nodeManager,
- stateManager, healthyNodes.get(2));
+ stateManager, healthyNodes.get(2), StorageType.DEFAULT);
assertEquals(pipelineCount, 1);
// Check datanode with one RATIS/ONE and one STANDALONE/ONE pipeline
@@ -706,7 +711,7 @@ public void testCurrentRatisThreePipelineCount()
pipelineCount
= placementPolicy.currentRatisThreePipelineCount(nodeManager,
- stateManager, healthyNodes.get(1));
+ stateManager, healthyNodes.get(1), StorageType.DEFAULT);
assertEquals(pipelineCount, 0);
// Check datanode with one RATIS/ONE and one STANDALONE/ONE pipeline and
@@ -720,7 +725,7 @@ public void testCurrentRatisThreePipelineCount()
pipelineCount
= placementPolicy.currentRatisThreePipelineCount(nodeManager,
- stateManager, healthyNodes.get(1));
+ stateManager, healthyNodes.get(1), StorageType.DEFAULT);
assertEquals(pipelineCount, 2);
}
@@ -767,7 +772,7 @@ public void
testPipelinePlacementPolicyDefaultLimitFiltersNodeAtLimit()
createPipelineWithReplicationConfig(p2Dns, RATIS, THREE);
assertEquals(2, PipelinePlacementPolicy.currentRatisThreePipelineCount(
- localNodeManager, localStateManager, target));
+ localNodeManager, localStateManager, target, storageType));
// 3) Verifies node is filtered out when choosing nodes for new pipeline
int nodesRequired = HddsProtos.ReplicationFactor.THREE.getNumber();
@@ -790,6 +795,7 @@ private void
createPipelineWithReplicationConfig(List<DatanodeDetails> dnList,
.setReplicationConfig(ReplicationConfig
.fromProtoTypeAndFactor(replicationType, replicationFactor))
.setNodes(dnList)
+ .setSupportedStorageTier(storageTier)
.build();
HddsProtos.Pipeline pipelineProto = pipeline.getProtobufMessage(
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestRatisPipelineProvider.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestRatisPipelineProvider.java
index af965a44f30..78e0fc4075b 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestRatisPipelineProvider.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestRatisPipelineProvider.java
@@ -18,10 +18,12 @@
package org.apache.hadoop.hdds.scm.pipeline;
import static org.apache.commons.collections4.CollectionUtils.intersection;
+import static
org.apache.hadoop.hdds.client.StorageTypeUtils.getStorageTypeProto;
import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_DATANODE_PIPELINE_LIMIT;
import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_DATANODE_RATIS_VOLUME_FREE_SPACE_MIN;
import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_CONTAINER_SIZE;
import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_PIPELINE_PLACEMENT_IMPL_KEY;
+import static
org.apache.hadoop.hdds.scm.ScmConfigKeys.OZONE_SCM_RATIS_PIPELINE_LIMIT;
import static
org.apache.hadoop.hdds.scm.exceptions.SCMException.ResultCodes.CANNOT_CREATE_PIPELINE_FOR_EMPTY_TIER;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -29,6 +31,9 @@
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
import java.io.File;
import java.io.IOException;
@@ -48,23 +53,29 @@
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.DatanodeID;
-import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor;
import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos;
+import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.MetadataStorageReportProto;
+import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.StorageReportProto;
+import org.apache.hadoop.hdds.scm.HddsTestUtils;
import org.apache.hadoop.hdds.scm.ScmConfigKeys;
import org.apache.hadoop.hdds.scm.container.ContainerID;
import org.apache.hadoop.hdds.scm.container.ContainerReplica;
import org.apache.hadoop.hdds.scm.container.MockNodeManager;
import
org.apache.hadoop.hdds.scm.container.placement.algorithms.SCMContainerPlacementRackScatter;
import org.apache.hadoop.hdds.scm.exceptions.SCMException;
+import org.apache.hadoop.hdds.scm.ha.SCMContext;
import org.apache.hadoop.hdds.scm.ha.SCMHAManager;
import org.apache.hadoop.hdds.scm.ha.SCMHAManagerStub;
import org.apache.hadoop.hdds.scm.metadata.SCMDBDefinition;
+import org.apache.hadoop.hdds.scm.node.DatanodeInfo;
import org.apache.hadoop.hdds.scm.node.NodeStatus;
+import org.apache.hadoop.hdds.server.events.EventQueue;
import org.apache.hadoop.hdds.utils.db.DBStore;
import org.apache.hadoop.hdds.utils.db.DBStoreBuilder;
import org.apache.hadoop.ozone.ClientVersion;
+import org.apache.hadoop.ozone.container.upgrade.UpgradeUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Test;
@@ -88,6 +99,7 @@ public class TestRatisPipelineProvider {
private File testDir;
private DBStore dbStore;
private int nodeCount = 10;
+ private List<DatanodeDetails> datanodeList;
public void init(int maxPipelinePerNode, StorageTier storageTier) throws
Exception {
init(maxPipelinePerNode, new OzoneConfiguration(), storageTier);
@@ -102,11 +114,12 @@ public void init(int maxPipelinePerNode,
OzoneConfiguration conf, File dir,
StorageTier storageTier) throws Exception {
assertTrue(storageTier.isUniform(), "Only support uniform StorageTier");
assertFalse(storageTier.equals(StorageTier.EMPTY), "not support the EMPTY
StorageTier");
- StorageType storageType = storageTier.getStorageTypes(
-
RatisReplicationConfig.getInstance(ReplicationFactor.ONE).getRequiredNodes()).get(0);
+ StorageType storageType = storageTier.
+ getStorageTypes(ReplicationFactor.ONE.getNumber()).get(0);
conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, dir.getAbsolutePath());
dbStore = DBStoreBuilder.createDBStore(conf, SCMDBDefinition.get());
nodeManager = new MockNodeManager(true, nodeCount, storageType);
+ datanodeList = nodeManager.getNodes(NodeStatus.inServiceHealthy());
nodeManager.setNumPipelinePerDatanode(maxPipelinePerNode);
SCMHAManager scmhaManager = SCMHAManagerStub.getInstance(true);
conf.setInt(OZONE_DATANODE_PIPELINE_LIMIT,
@@ -132,11 +145,12 @@ void cleanup() throws Exception {
private static void assertPipelineProperties(
Pipeline pipeline, HddsProtos.ReplicationFactor expectedFactor,
HddsProtos.ReplicationType expectedReplicationType,
- Pipeline.PipelineState expectedState) {
+ Pipeline.PipelineState expectedState, StorageTier expectedStorageTier) {
assertEquals(expectedState, pipeline.getPipelineState());
assertEquals(expectedReplicationType, pipeline.getType());
assertEquals(expectedFactor.getNumber(),
pipeline.getReplicationConfig().getRequiredNodes());
assertEquals(expectedFactor.getNumber(), pipeline.getNodes().size());
+ assertEquals(expectedStorageTier, pipeline.getSupportedStorageTier());
}
private void createPipelineAndAssertions(
@@ -145,7 +159,7 @@ private void createPipelineAndAssertions(
Pipeline pipeline = provider.create(RatisReplicationConfig
.getInstance(factor), storageTier);
assertPipelineProperties(pipeline, factor, REPLICATION_TYPE,
- Pipeline.PipelineState.ALLOCATED);
+ Pipeline.PipelineState.ALLOCATED, storageTier);
HddsProtos.Pipeline pipelineProto = pipeline.getProtobufMessage(
ClientVersion.CURRENT_VERSION);
stateManager.addPipeline(pipelineProto);
@@ -156,7 +170,7 @@ private void createPipelineAndAssertions(
HddsProtos.Pipeline pipelineProto1 = pipeline1.getProtobufMessage(
ClientVersion.CURRENT_VERSION);
assertPipelineProperties(pipeline1, factor, REPLICATION_TYPE,
- Pipeline.PipelineState.ALLOCATED);
+ Pipeline.PipelineState.ALLOCATED, storageTier);
// New pipeline should not overlap with the previous created pipeline
assertThat(intersection(pipeline.getNodes(), pipeline1.getNodes()).size())
.isLessThan(factor.getNumber());
@@ -181,10 +195,67 @@ public void testCreatePipelineWithFactorOne(StorageTier
storageTier) throws Exce
createPipelineAndAssertions(HddsProtos.ReplicationFactor.ONE, storageTier);
}
+ @Test
+ public void testPipelineEngagementLimitIsStorageTierAware() throws Exception
{
+ init(1, StorageTier.DISK);
+ List<DatanodeDetails> diskAndSsdNodes = datanodeList.stream()
+ .map(TestRatisPipelineProvider::datanodeInfoWithDiskAndSsd)
+ .collect(Collectors.toList());
+ MockNodeManager nodeManagerSpy = spy(nodeManager);
+ doAnswer(invocation -> diskAndSsdNodes)
+ .when(nodeManagerSpy).getNodes(any(NodeStatus.class));
+ doAnswer(invocation ->
datanodeInfoWithDiskAndSsd(invocation.getArgument(0)))
+ .when(nodeManagerSpy).getDatanodeInfo(any(DatanodeDetails.class));
+ RatisPipelineProvider localProvider = new RatisPipelineProvider(
+ nodeManagerSpy, stateManager, new OzoneConfiguration(), new
EventQueue(), SCMContext.emptyContext());
+ for (int i = 0; i < 2; i++) {
+ addPipeline(diskAndSsdNodes.subList(i * 3, i * 3 + 3),
+ Pipeline.PipelineState.OPEN,
+ RatisReplicationConfig.getInstance(ReplicationFactor.THREE),
+ StorageTier.DISK);
+ }
+
+ Pipeline pipeline = localProvider.create(
+ RatisReplicationConfig.getInstance(ReplicationFactor.THREE),
StorageTier.SSD);
+
+ assertPipelineProperties(pipeline, ReplicationFactor.THREE,
+ REPLICATION_TYPE, Pipeline.PipelineState.ALLOCATED, StorageTier.SSD);
+ }
+
+ @Test
+ public void testGlobalPipelineNumberLimitIsNotStorageTierAware() throws
Exception {
+ OzoneConfiguration pipelineLimitConf = new OzoneConfiguration();
+ pipelineLimitConf.setInt(OZONE_SCM_RATIS_PIPELINE_LIMIT, 1);
+ init(0, pipelineLimitConf, StorageTier.DISK);
+ List<DatanodeDetails> diskAndSsdNodes = datanodeList.stream()
+ .map(TestRatisPipelineProvider::datanodeInfoWithDiskAndSsd)
+ .collect(Collectors.toList());
+ MockNodeManager nodeManagerSpy = spy(nodeManager);
+ doAnswer(invocation -> diskAndSsdNodes)
+ .when(nodeManagerSpy).getNodes(any(NodeStatus.class));
+ doAnswer(invocation ->
datanodeInfoWithDiskAndSsd(invocation.getArgument(0)))
+ .when(nodeManagerSpy).getDatanodeInfo(any(DatanodeDetails.class));
+ RatisPipelineProvider localProvider = new RatisPipelineProvider(
+ nodeManagerSpy, stateManager, pipelineLimitConf, new EventQueue(),
+ SCMContext.emptyContext());
+ for (int i = 0; i < 2; i++) {
+ addPipeline(diskAndSsdNodes.subList(i * 3, i * 3 + 3),
+ Pipeline.PipelineState.OPEN,
+ RatisReplicationConfig.getInstance(ReplicationFactor.THREE),
+ StorageTier.DISK);
+ }
+
+ SCMException exception = assertThrows(SCMException.class, () ->
+ localProvider.create(
+ RatisReplicationConfig.getInstance(ReplicationFactor.THREE),
StorageTier.SSD));
+
+ assertThat(exception.getMessage()).contains("would exceed the limit");
+ }
+
private List<DatanodeDetails> createListOfNodes(int count) {
List<DatanodeDetails> nodes = new ArrayList<>();
for (int i = 0; i < count; i++) {
- nodes.add(MockDatanodeDetails.randomDatanodeDetails());
+ nodes.add(datanodeList.get(i));
}
return nodes;
}
@@ -197,7 +268,7 @@ public void testCreatePipelineWithFactor(StorageTier
storageTier) throws Excepti
Pipeline pipeline = provider.create(RatisReplicationConfig
.getInstance(factor), storageTier);
assertPipelineProperties(pipeline, factor, REPLICATION_TYPE,
- Pipeline.PipelineState.ALLOCATED);
+ Pipeline.PipelineState.ALLOCATED, storageTier);
HddsProtos.Pipeline pipelineProto = pipeline.getProtobufMessage(
ClientVersion.CURRENT_VERSION);
stateManager.addPipeline(pipelineProto);
@@ -206,7 +277,7 @@ public void testCreatePipelineWithFactor(StorageTier
storageTier) throws Excepti
Pipeline pipeline1 = provider.create(RatisReplicationConfig
.getInstance(factor), storageTier);
assertPipelineProperties(pipeline1, factor, REPLICATION_TYPE,
- Pipeline.PipelineState.ALLOCATED);
+ Pipeline.PipelineState.ALLOCATED, storageTier);
HddsProtos.Pipeline pipelineProto1 = pipeline1.getProtobufMessage(
ClientVersion.CURRENT_VERSION);
stateManager.addPipeline(pipelineProto1);
@@ -221,15 +292,17 @@ public void testCreatePipelineWithNodes() throws
Exception {
HddsProtos.ReplicationFactor factor = HddsProtos.ReplicationFactor.THREE;
Pipeline pipeline =
provider.create(RatisReplicationConfig.getInstance(factor),
- createListOfNodes(factor.getNumber()));
+ createListOfNodes(factor.getNumber()),
+ StorageTier.getDefaultTier());
assertPipelineProperties(pipeline, factor, REPLICATION_TYPE,
- Pipeline.PipelineState.OPEN);
+ Pipeline.PipelineState.OPEN, StorageTier.getDefaultTier());
factor = HddsProtos.ReplicationFactor.ONE;
pipeline = provider.create(RatisReplicationConfig.getInstance(factor),
- createListOfNodes(factor.getNumber()));
+ createListOfNodes(factor.getNumber()),
+ StorageTier.getDefaultTier());
assertPipelineProperties(pipeline, factor, REPLICATION_TYPE,
- Pipeline.PipelineState.OPEN);
+ Pipeline.PipelineState.OPEN, StorageTier.getDefaultTier());
}
@Test
@@ -243,13 +316,12 @@ public void
testCreateFactorTHREEPipelineWithSameDatanodes()
Pipeline pipeline1 = provider.create(
RatisReplicationConfig.getInstance(ReplicationFactor.THREE),
- healthyNodes);
+ healthyNodes, StorageTier.getDefaultTier());
Pipeline pipeline2 = provider.create(
RatisReplicationConfig.getInstance(ReplicationFactor.THREE),
- healthyNodes);
+ healthyNodes, StorageTier.getDefaultTier());
Pipeline pipeline3 = provider.createForRead(
- RatisReplicationConfig.getInstance(ReplicationFactor.THREE),
- replicas);
+ RatisReplicationConfig.getInstance(ReplicationFactor.THREE), replicas);
assertEquals(pipeline1.getNodeSet(), pipeline2.getNodeSet());
assertEquals(pipeline2.getNodeSet(), pipeline3.getNodeSet());
@@ -274,21 +346,21 @@ public void testCreatePipelinesDnExclude(StorageTier
storageTier) throws Excepti
for (int i = 0; i < maxPipelinePerNode; i++) {
// Saturate pipeline counts on all the 1st 3 DNs.
addPipeline(dns, Pipeline.PipelineState.OPEN,
- RatisReplicationConfig.getInstance(factor));
+ RatisReplicationConfig.getInstance(factor), storageTier);
}
Set<DatanodeDetails> membersOfOpenPipelines = new HashSet<>(dns);
// Use up next 3 DNs for a closed pipeline.
dns = healthyNodes.subList(3, 6);
addPipeline(dns, Pipeline.PipelineState.CLOSED,
- RatisReplicationConfig.getInstance(factor));
+ RatisReplicationConfig.getInstance(factor), storageTier);
Set<DatanodeDetails> membersOfClosedPipelines = new HashSet<>(dns);
// only 2 healthy DNs left that are not part of any pipeline
Pipeline pipeline = provider.create(
RatisReplicationConfig.getInstance(factor), storageTier);
assertPipelineProperties(pipeline, factor, REPLICATION_TYPE,
- Pipeline.PipelineState.ALLOCATED);
+ Pipeline.PipelineState.ALLOCATED, storageTier);
HddsProtos.Pipeline pipelineProto = pipeline.getProtobufMessage(
ClientVersion.CURRENT_VERSION);
nodeManager.addPipeline(pipeline);
@@ -459,7 +531,8 @@ public void
testCreatePipelineThrowErrorWithDataNodeLimit(int limit, int pipelin
// Validate exception message.
String expectedError = String.format(
- "Cannot create pipeline as it would exceed the limit per datanode: %d
replicationConfig: RATIS/THREE", limit);
+ "Cannot create pipeline for StorageTier DISK as it would exceed the
limit per" +
+ " datanode: %d replicationConfig: RATIS/THREE", limit);
assertEquals(expectedError, exception.getMessage());
}
@@ -480,13 +553,14 @@ public void testCreatePipelinesInEmptyTier() throws
Exception {
private void addPipeline(
List<DatanodeDetails> dns,
- Pipeline.PipelineState open, ReplicationConfig replicationConfig)
+ Pipeline.PipelineState open, ReplicationConfig replicationConfig,
StorageTier storageTier)
throws IOException, TimeoutException {
Pipeline openPipeline = Pipeline.newBuilder()
.setReplicationConfig(replicationConfig)
.setNodes(dns)
.setState(open)
.setId(PipelineID.randomId())
+ .setSupportedStorageTier(storageTier)
.build();
HddsProtos.Pipeline pipelineProto = openPipeline.getProtobufMessage(
ClientVersion.CURRENT_VERSION);
@@ -522,4 +596,24 @@ static Stream<StorageTier> storageTiers() {
StorageTier.ARCHIVE
);
}
+
+ private static DatanodeInfo datanodeInfoWithDiskAndSsd(DatanodeDetails dn) {
+ DatanodeInfo datanodeInfo = new DatanodeInfo(
+ dn, NodeStatus.inServiceHealthy(),
UpgradeUtils.defaultLayoutVersionProto(),
+ HddsTestUtils.ROLL_INTERVAL_MS_DEFAULT);
+ List<StorageReportProto> storageReports = new ArrayList<>();
+ long capacity = 10L * 1024 * 1024 * 1024;
+ storageReports.add(HddsTestUtils.createStorageReport(
+ dn.getID(), "/disk-" + dn.getUuidString(),
+ capacity, 0L, capacity, getStorageTypeProto(StorageType.DISK)));
+ storageReports.add(HddsTestUtils.createStorageReport(
+ dn.getID(), "/ssd-" + dn.getUuidString(),
+ capacity, 0L, capacity, getStorageTypeProto(StorageType.SSD)));
+ MetadataStorageReportProto metadataReport =
HddsTestUtils.createMetadataStorageReport(
+ "/metadata-" + dn.getUuidString(), capacity, 0L, capacity, null);
+ datanodeInfo.updateStorageReports(storageReports);
+
datanodeInfo.updateMetaDataStorageReports(Collections.singletonList(metadataReport));
+ return datanodeInfo;
+ }
+
}
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestSimplePipelineProvider.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestSimplePipelineProvider.java
index 42aa1943aa7..3326c09d5cd 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestSimplePipelineProvider.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestSimplePipelineProvider.java
@@ -22,30 +22,41 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
import java.io.File;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.HddsConfigKeys;
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
+import org.apache.hadoop.hdds.client.ReplicationConfig;
import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
import org.apache.hadoop.hdds.client.StorageTier;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.MockDatanodeDetails;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos;
+import org.apache.hadoop.hdds.protocol.proto.HddsProtos.StorageTypeProto;
+import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.StorageReportProto;
+import org.apache.hadoop.hdds.scm.HddsTestUtils;
import org.apache.hadoop.hdds.scm.container.MockNodeManager;
import org.apache.hadoop.hdds.scm.exceptions.SCMException;
import org.apache.hadoop.hdds.scm.ha.SCMHAManager;
import org.apache.hadoop.hdds.scm.ha.SCMHAManagerStub;
import org.apache.hadoop.hdds.scm.metadata.SCMDBDefinition;
+import org.apache.hadoop.hdds.scm.node.DatanodeInfo;
import org.apache.hadoop.hdds.scm.node.NodeManager;
+import org.apache.hadoop.hdds.scm.node.NodeStatus;
import org.apache.hadoop.hdds.utils.db.DBStore;
import org.apache.hadoop.hdds.utils.db.DBStoreBuilder;
import org.apache.hadoop.ozone.ClientVersion;
import org.apache.hadoop.ozone.container.common.SCMTestUtils;
+import org.apache.hadoop.ozone.container.upgrade.UpgradeUtils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -63,6 +74,7 @@ public class TestSimplePipelineProvider {
@TempDir
private File testDir;
private DBStore dbStore;
+ private List<DatanodeDetails> datanodeList;
@BeforeEach
public void startup() throws Exception {
@@ -78,6 +90,7 @@ public void init(StorageTier storageTier) throws Exception {
StorageType storageType = storageTier.getStorageTypes(
RatisReplicationConfig.getInstance(HddsProtos.ReplicationFactor.ONE).getRequiredNodes()).get(0);
NodeManager nodeManager = new MockNodeManager(true, 10, storageType);
+ datanodeList = nodeManager.getNodes(NodeStatus.inServiceHealthy());
SCMHAManager scmhaManager = SCMHAManagerStub.getInstance(true);
stateManager = PipelineStateManagerImpl.newBuilder()
.setPipelineStore(SCMDBDefinition.PIPELINES.getTable(dbStore))
@@ -109,6 +122,7 @@ public void testCreatePipelineWithFactor(StorageTier
storageTier) throws Excepti
assertEquals(pipeline.getReplicationConfig().getRequiredNodes(),
factor.getNumber());
assertEquals(pipeline.getPipelineState(), Pipeline.PipelineState.OPEN);
assertEquals(pipeline.getNodes().size(), factor.getNumber());
+ assertEquals(storageTier, pipeline.getSupportedStorageTier());
factor = HddsProtos.ReplicationFactor.ONE;
Pipeline pipeline1 =
@@ -122,12 +136,13 @@ public void testCreatePipelineWithFactor(StorageTier
storageTier) throws Excepti
.getReplicationFactor(), factor);
assertEquals(pipeline1.getPipelineState(), Pipeline.PipelineState.OPEN);
assertEquals(pipeline1.getNodes().size(), factor.getNumber());
+ assertEquals(storageTier, pipeline1.getSupportedStorageTier());
}
private List<DatanodeDetails> createListOfNodes(int nodeCount) {
List<DatanodeDetails> nodes = new ArrayList<>();
for (int i = 0; i < nodeCount; i++) {
- nodes.add(MockDatanodeDetails.randomDatanodeDetails());
+ nodes.add(datanodeList.get(i));
}
return nodes;
}
@@ -139,7 +154,8 @@ public void testCreatePipelineWithNodes()
HddsProtos.ReplicationFactor factor = HddsProtos.ReplicationFactor.THREE;
Pipeline pipeline =
provider.create(StandaloneReplicationConfig.getInstance(factor),
- createListOfNodes(factor.getNumber()));
+ createListOfNodes(factor.getNumber()),
+ StorageTier.getDefaultTier());
assertEquals(pipeline.getType(),
HddsProtos.ReplicationType.STAND_ALONE);
assertEquals(
@@ -147,16 +163,63 @@ public void testCreatePipelineWithNodes()
.getReplicationFactor(), factor);
assertEquals(pipeline.getPipelineState(), Pipeline.PipelineState.OPEN);
assertEquals(pipeline.getNodes().size(), factor.getNumber());
+ assertEquals(StorageTier.getDefaultTier(),
pipeline.getSupportedStorageTier());
factor = HddsProtos.ReplicationFactor.ONE;
pipeline = provider.create(StandaloneReplicationConfig.getInstance(factor),
- createListOfNodes(factor.getNumber()));
+ createListOfNodes(factor.getNumber()),
+ StorageTier.getDefaultTier());
assertEquals(pipeline.getType(), HddsProtos.ReplicationType.STAND_ALONE);
assertEquals(
((StandaloneReplicationConfig) pipeline.getReplicationConfig())
.getReplicationFactor(), factor);
assertEquals(pipeline.getPipelineState(), Pipeline.PipelineState.OPEN);
assertEquals(pipeline.getNodes().size(), factor.getNumber());
+ assertEquals(StorageTier.getDefaultTier(),
pipeline.getSupportedStorageTier());
+ }
+
+ @Test
+ public void testCreatedPipelineOnlySupportsRequestedStorageTier()
+ throws Exception {
+ NodeManager nodeManager = mock(NodeManager.class);
+ PipelineStateManager pipelineStateManager =
mock(PipelineStateManager.class);
+ List<DatanodeDetails> nodes = new ArrayList<>();
+ for (int i = 0; i < HddsProtos.ReplicationFactor.THREE.getNumber(); i++) {
+ nodes.add(createDatanodeInfoWithStorageReports(
+ StorageTypeProto.DISK, StorageTypeProto.SSD));
+ }
+ when(nodeManager.getNodes(NodeStatus.inServiceHealthy()))
+ .thenReturn(nodes);
+ when(nodeManager.getDatanodeInfo(any()))
+ .thenAnswer(invocation -> invocation.getArgument(0));
+ when(pipelineStateManager.getPipelines(
+ any(ReplicationConfig.class)))
+ .thenReturn(Collections.emptyList());
+
+ PipelineProvider pipelineProvider =
+ new SimplePipelineProvider(nodeManager, pipelineStateManager);
+ Pipeline pipeline =
pipelineProvider.create(StandaloneReplicationConfig.getInstance(
+ HddsProtos.ReplicationFactor.THREE), StorageTier.DISK);
+
+ assertEquals(StorageTier.DISK, pipeline.getSupportedStorageTier());
+ }
+
+ private DatanodeInfo createDatanodeInfoWithStorageReports(
+ HddsProtos.StorageTypeProto... storageTypes) {
+ DatanodeInfo datanodeInfo = new DatanodeInfo(
+ MockDatanodeDetails.randomDatanodeDetails(),
+ NodeStatus.inServiceHealthy(),
UpgradeUtils.defaultLayoutVersionProto(),
+ HddsTestUtils.ROLL_INTERVAL_MS_DEFAULT);
+ List<StorageReportProto> storageReports = new ArrayList<>();
+ for (HddsProtos.StorageTypeProto storageType : storageTypes) {
+ storageReports.add(StorageReportProto.newBuilder()
+ .setStorageUuid(datanodeInfo.getUuidString() + "-" + storageType)
+ .setStorageLocation("/data-" + storageType)
+ .setStorageType(storageType)
+ .build());
+ }
+ datanodeInfo.updateStorageReports(storageReports);
+ return datanodeInfo;
}
@Test
diff --git
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/hdds/protocol/StorageTierTest.java
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/hdds/protocol/StorageTierTest.java
index 0630dd45cd3..af978dfef36 100644
---
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/hdds/protocol/StorageTierTest.java
+++
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/hdds/protocol/StorageTierTest.java
@@ -59,7 +59,8 @@ void testGetStorageTypesWithReplicationConfig() {
}
for (ReplicationConfig replicationConfig : Arrays.asList(ratisOne,
ratisThree,
standaloneOne, standaloneThree)) {
- List<StorageType> storageTypes =
tier.getStorageTypes(replicationConfig.getRequiredNodes());
+ List<StorageType> storageTypes = tier.getStorageTypes(
+ replicationConfig.getRequiredNodes());
if (tier.equals(StorageTier.EMPTY)) {
assertEquals(0, storageTypes.size());
} else {
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestSCMRestart.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestSCMRestart.java
index 431e8857490..5375206bab7 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestSCMRestart.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/pipeline/TestSCMRestart.java
@@ -104,6 +104,10 @@ public void testPipelineWithScmRestart()
assertNotSame(ratisPipeline2AfterRestart, ratisPipeline2);
assertEquals(ratisPipeline1AfterRestart, ratisPipeline1);
assertEquals(ratisPipeline2AfterRestart, ratisPipeline2);
+ assertEquals(ratisPipeline1AfterRestart.getSupportedStorageTier(),
+ ratisPipeline1.getSupportedStorageTier());
+ assertEquals(ratisPipeline2AfterRestart.getSupportedStorageTier(),
+ ratisPipeline2.getSupportedStorageTier());
// Try creating a new container, it should be from the same pipeline
// as was before restart
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestKeyManagerImpl.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestKeyManagerImpl.java
index dcdb3828ae6..fa1846d30c5 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestKeyManagerImpl.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestKeyManagerImpl.java
@@ -82,6 +82,7 @@
import org.apache.hadoop.hdds.client.RatisReplicationConfig;
import org.apache.hadoop.hdds.client.ReplicationConfig;
import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
+import org.apache.hadoop.hdds.client.StorageTier;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.protocol.DatanodeDetails;
import org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor;
@@ -821,7 +822,7 @@ private static void createKeyWithPipeline(OmKeyArgs
keyArgs) throws IOException
assumeFalse(nodeList.get(0).equals(nodeList.get(2)));
// create a pipeline using 3 datanodes
Pipeline pipeline = scm.getPipelineManager().createPipeline(
- RatisReplicationConfig.getInstance(ReplicationFactor.THREE), nodeList);
+ RatisReplicationConfig.getInstance(ReplicationFactor.THREE), nodeList,
StorageTier.getDefaultTier());
List<OmKeyLocationInfo> locationInfoList = new ArrayList<>();
List<OmKeyLocationInfo> locationList =
keySession.getKeyInfo().getLatestVersionLocations().getLocationList();
diff --git
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconPipelineFactory.java
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconPipelineFactory.java
index 55fee8f8653..f8063a3a3a2 100644
---
a/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconPipelineFactory.java
+++
b/hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/scm/ReconPipelineFactory.java
@@ -64,7 +64,7 @@ public Pipeline create(ReplicationConfig config,
@Override
public Pipeline create(ReplicationConfig config,
- List<DatanodeDetails> nodes) {
+ List<DatanodeDetails> nodes, StorageTier
storageTier) {
throw new UnsupportedOperationException(
"Trying to create pipeline in Recon, which is prohibited!");
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]