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 c149835b558 HDDS-15240. Support selecting volumes by StorageType when
creating containers (#10303)
c149835b558 is described below
commit c149835b558fa6d4dc9868074363ef661ca4d814
Author: XiChen <[email protected]>
AuthorDate: Sat May 23 14:27:03 2026 +0800
HDDS-15240. Support selecting volumes by StorageType when creating
containers (#10303)
---
.../container/common/interfaces/Container.java | 11 +++
.../common/interfaces/VolumeChoosingPolicy.java | 17 ++++
.../volume/AbstractStorageTypeChoosingPolicy.java | 53 ++++++++++++
.../volume/CapacityVolumeChoosingPolicy.java | 6 +-
.../volume/RoundRobinVolumeChoosingPolicy.java | 6 +-
.../container/keyvalue/KeyValueContainer.java | 16 +++-
.../TestStorageTypeVolumeChoosingPolicy.java | 94 ++++++++++++++++++++++
.../container/keyvalue/TestKeyValueContainer.java | 29 +++++++
8 files changed, 225 insertions(+), 7 deletions(-)
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/Container.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/Container.java
index d7f71e6e3b7..ddb7de4140b 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/Container.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/Container.java
@@ -24,6 +24,7 @@
import java.nio.file.Path;
import java.time.Instant;
import java.util.Map;
+import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
import
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.ContainerReplicaProto;
import
org.apache.hadoop.hdds.scm.container.common.helpers.StorageContainerException;
@@ -47,6 +48,16 @@ public interface Container<CONTAINERDATA extends
ContainerData> {
void create(VolumeSet volumeSet, VolumeChoosingPolicy volumeChoosingPolicy,
String scmId) throws StorageContainerException;
+ /**
+ * Creates a container and optionally constrains the destination volume to a
+ * specific storage type.
+ */
+ default void create(VolumeSet volumeSet,
+ VolumeChoosingPolicy volumeChoosingPolicy, String scmId,
+ StorageType storageType) throws StorageContainerException {
+ create(volumeSet, volumeChoosingPolicy, scmId);
+ }
+
/**
* Deletes the container.
*
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/VolumeChoosingPolicy.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/VolumeChoosingPolicy.java
index 72d05d38739..63d9dccc74b 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/VolumeChoosingPolicy.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/VolumeChoosingPolicy.java
@@ -19,6 +19,7 @@
import java.io.IOException;
import java.util.List;
+import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.annotation.InterfaceAudience;
import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
@@ -40,6 +41,22 @@ public interface VolumeChoosingPolicy {
* @return the chosen volume.
* @throws IOException when disks are unavailable or are full.
*/
+ @Deprecated
HddsVolume chooseVolume(List<HddsVolume> volumes, long maxContainerSize)
throws IOException;
+
+ /**
+ * Choose a volume to place a container, optionally constraining the choice
+ * to a specific storage type.
+ *
+ * @param volumes a list of available volumes.
+ * @param maxContainerSize the maximum size of the container for which a
+ * volume is sought.
+ * @param storageType the requested storage type, or {@code null} to allow
+ * the policy to choose from any volume.
+ * @return the chosen volume.
+ * @throws IOException when disks are unavailable or are full.
+ */
+ HddsVolume chooseVolume(List<HddsVolume> volumes,
+ long maxContainerSize, StorageType storageType) throws IOException;
}
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/AbstractStorageTypeChoosingPolicy.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/AbstractStorageTypeChoosingPolicy.java
new file mode 100644
index 00000000000..d73ab885e5f
--- /dev/null
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/AbstractStorageTypeChoosingPolicy.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ozone.container.common.volume;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.hadoop.fs.StorageType;
+import
org.apache.hadoop.ozone.container.common.interfaces.VolumeChoosingPolicy;
+
+/**
+ * Base volume choosing policy with optional storage-type filtering.
+ */
+public abstract class AbstractStorageTypeChoosingPolicy
+ implements VolumeChoosingPolicy {
+
+ @Override
+ @Deprecated
+ public HddsVolume chooseVolume(List<HddsVolume> volumes,
+ long maxContainerSize) throws IOException {
+ return chooseVolume(volumes, maxContainerSize, null);
+ }
+
+ @Override
+ public HddsVolume chooseVolume(List<HddsVolume> volumes,
+ long maxContainerSize, StorageType storageType) throws IOException {
+ List<HddsVolume> candidates = volumes;
+ if (storageType != null) {
+ candidates = volumes.stream()
+ .filter(volume -> volume.getStorageType() == storageType)
+ .collect(Collectors.toList());
+ }
+ return chooseVolumeInternal(candidates, maxContainerSize);
+ }
+
+ protected abstract HddsVolume chooseVolumeInternal(List<HddsVolume> volumes,
+ long maxContainerSize) throws IOException;
+}
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/CapacityVolumeChoosingPolicy.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/CapacityVolumeChoosingPolicy.java
index 08b64327b00..dfc360774dc 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/CapacityVolumeChoosingPolicy.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/CapacityVolumeChoosingPolicy.java
@@ -26,7 +26,6 @@
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
-import
org.apache.hadoop.ozone.container.common.interfaces.VolumeChoosingPolicy;
import org.apache.hadoop.util.DiskChecker.DiskOutOfSpaceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,7 +40,8 @@
* <p>
* Same algorithm as the SCMContainerPlacementCapacity.
*/
-public class CapacityVolumeChoosingPolicy implements VolumeChoosingPolicy {
+public class CapacityVolumeChoosingPolicy
+ extends AbstractStorageTypeChoosingPolicy {
private static final Logger LOG = LoggerFactory.getLogger(
CapacityVolumeChoosingPolicy.class);
@@ -58,7 +58,7 @@ public CapacityVolumeChoosingPolicy() {
}
@Override
- public HddsVolume chooseVolume(List<HddsVolume> volumes,
+ protected HddsVolume chooseVolumeInternal(List<HddsVolume> volumes,
long maxContainerSize) throws IOException {
// No volumes available to choose from
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/RoundRobinVolumeChoosingPolicy.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/RoundRobinVolumeChoosingPolicy.java
index ff6f5713001..2318b7d7311 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/RoundRobinVolumeChoosingPolicy.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/RoundRobinVolumeChoosingPolicy.java
@@ -24,7 +24,6 @@
import java.io.IOException;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
-import
org.apache.hadoop.ozone.container.common.interfaces.VolumeChoosingPolicy;
import org.apache.hadoop.util.DiskChecker.DiskOutOfSpaceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -33,7 +32,8 @@
* Choose volumes in round-robin order.
* The caller should synchronize access to the list of volumes.
*/
-public class RoundRobinVolumeChoosingPolicy implements VolumeChoosingPolicy {
+public class RoundRobinVolumeChoosingPolicy
+ extends AbstractStorageTypeChoosingPolicy {
private static final Logger LOG = LoggerFactory.getLogger(
RoundRobinVolumeChoosingPolicy.class);
@@ -53,7 +53,7 @@ public RoundRobinVolumeChoosingPolicy() {
}
@Override
- public HddsVolume chooseVolume(List<HddsVolume> volumes,
+ protected HddsVolume chooseVolumeInternal(List<HddsVolume> volumes,
long maxContainerSize) throws IOException {
// No volumes available to choose from
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java
index b8214882f12..727d7d14705 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java
@@ -56,6 +56,7 @@
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.fs.FileAlreadyExistsException;
import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.HddsUtils;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
@@ -146,8 +147,16 @@ public void setCheckChunksFilePath(boolean
bCheckChunksDirFilePath) {
}
@Override
+ @Deprecated
public void create(VolumeSet volumeSet, VolumeChoosingPolicy
volumeChoosingPolicy, String clusterId) throws StorageContainerException
{
+ create(volumeSet, volumeChoosingPolicy, clusterId, null);
+ }
+
+ @Override
+ public void create(VolumeSet volumeSet, VolumeChoosingPolicy
+ volumeChoosingPolicy, String clusterId, StorageType storageType)
+ throws StorageContainerException {
Objects.requireNonNull(volumeChoosingPolicy, "VolumeChoosingPolicy ==
null");
Objects.requireNonNull(volumeSet, "volumeSet == null");
Objects.requireNonNull(clusterId, "clusterId == null");
@@ -163,11 +172,16 @@ public void create(VolumeSet volumeSet,
VolumeChoosingPolicy
HddsVolume containerVolume;
String hddsVolumeDir;
try {
- containerVolume = volumeChoosingPolicy.chooseVolume(volumes,
maxSize);
+ // TODO Use the `chooseVolume` that supports `storageType`
+ containerVolume = storageType == null
+ ? volumeChoosingPolicy.chooseVolume(volumes, maxSize)
+ : volumeChoosingPolicy.chooseVolume(
+ volumes, maxSize, storageType);
hddsVolumeDir = containerVolume.getHddsRootDir().toString();
// Set volume before getContainerDBFile(), because we may need the
// volume to deduce the db file.
containerData.setVolume(containerVolume);
+ containerData.setStorageType(containerVolume.getStorageType());
// commit bytes have been reserved in
volumeChoosingPolicy#chooseVolume
containerData.setCommittedSpace(true);
} catch (DiskOutOfSpaceException ex) {
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestStorageTypeVolumeChoosingPolicy.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestStorageTypeVolumeChoosingPolicy.java
new file mode 100644
index 00000000000..72a58e48f97
--- /dev/null
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/volume/TestStorageTypeVolumeChoosingPolicy.java
@@ -0,0 +1,94 @@
+/*
+ * 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.ozone.container.common.volume;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
+import org.apache.hadoop.fs.StorageType;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.container.common.utils.StorageVolumeUtil;
+import org.apache.hadoop.util.DiskChecker.DiskOutOfSpaceException;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+/**
+ * Tests for storage-type-aware volume selection policies.
+ */
+public class TestStorageTypeVolumeChoosingPolicy {
+
+ private static final OzoneConfiguration CONF = new OzoneConfiguration();
+
+ @TempDir
+ private File folder;
+
+ private final String scmId = UUID.randomUUID().toString();
+ private final String datanodeId = UUID.randomUUID().toString();
+ private final List<HddsVolume> createdVolumes = new ArrayList<>();
+
+ @AfterEach
+ public void tearDown() {
+ createdVolumes.forEach(HddsVolume::shutdown);
+ }
+
+ @Test
+ public void testRoundRobinChoosesRequestedStorageType() throws Exception {
+ HddsVolume diskVolume = createVolume("disk", StorageType.DISK);
+ HddsVolume ssdVolume = createVolume("ssd", StorageType.SSD);
+
+ RoundRobinVolumeChoosingPolicy policy = new
RoundRobinVolumeChoosingPolicy();
+ HddsVolume chosen = policy.chooseVolume(
+ Arrays.asList(diskVolume, ssdVolume), 1L, StorageType.SSD);
+
+ assertSame(ssdVolume, chosen);
+ assertEquals(1L, ssdVolume.getCommittedBytes());
+ assertEquals(0L, diskVolume.getCommittedBytes());
+ }
+
+ @Test
+ public void testCapacityPolicyRejectsMissingStorageType() throws Exception {
+ HddsVolume diskVolume = createVolume("disk", StorageType.DISK);
+
+ CapacityVolumeChoosingPolicy policy = new CapacityVolumeChoosingPolicy();
+
+ assertThrows(DiskOutOfSpaceException.class,
+ () -> policy.chooseVolume(
+ Collections.singletonList(diskVolume), 1L, StorageType.SSD));
+ }
+
+ private HddsVolume createVolume(String name, StorageType storageType)
+ throws Exception {
+ HddsVolume volume = new HddsVolume.Builder(
+ new File(folder, name).getAbsolutePath())
+ .conf(CONF)
+ .datanodeUuid(datanodeId)
+ .storageType(storageType)
+ .build();
+ StorageVolumeUtil.checkVolume(volume, scmId, scmId, CONF, null, null);
+ createdVolumes.add(volume);
+ return volume;
+ }
+}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueContainer.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueContainer.java
index 9e66aaeb067..7c14200e6c8 100644
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueContainer.java
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueContainer.java
@@ -32,12 +32,14 @@
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.mockito.Mockito.anyList;
import static org.mockito.Mockito.anyLong;
+import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
@@ -63,6 +65,7 @@
import java.util.stream.Stream;
import org.apache.commons.io.FileUtils;
import org.apache.hadoop.conf.StorageUnit;
+import org.apache.hadoop.fs.StorageType;
import org.apache.hadoop.hdds.client.BlockID;
import org.apache.hadoop.hdds.conf.ConfigurationSource;
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
@@ -200,6 +203,32 @@ private void testCreateContainer() throws
StorageContainerException {
"DB does not exist");
}
+ @ContainerTestVersionInfo.ContainerTest
+ public void testCreateContainerWithStorageType(
+ ContainerTestVersionInfo versionInfo) throws Exception {
+ init(versionInfo);
+
+ HddsVolume ssdVolume = new HddsVolume.Builder(
+ new File(folder, "ssd-volume").getAbsolutePath())
+ .conf(CONF)
+ .datanodeUuid(datanodeId.toString())
+ .storageType(StorageType.SSD)
+ .build();
+ StorageVolumeUtil.checkVolume(ssdVolume, scmId, scmId, CONF, null, null);
+ hddsVolumes.add(ssdVolume);
+
+ when(volumeChoosingPolicy.chooseVolume(anyList(), anyLong(),
+ eq(StorageType.SSD))).thenReturn(ssdVolume);
+
+ keyValueContainer.create(volumeSet, volumeChoosingPolicy, scmId,
+ StorageType.SSD);
+
+ assertSame(ssdVolume, keyValueContainerData.getVolume());
+ assertEquals(StorageType.SSD, keyValueContainerData.getStorageType());
+ verify(volumeChoosingPolicy).chooseVolume(anyList(), anyLong(),
+ eq(StorageType.SSD));
+ }
+
/**
* Tests repair of containers affected by the bug reported in HDDS-6235.
*/
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]