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]

Reply via email to