This is an automated email from the ASF dual-hosted git repository.

chungen0126 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 93069b8a9ec HDDS-15239. Support persist StorageType on Datanode 
Container YAML (#10246)
93069b8a9ec is described below

commit 93069b8a9ecfe6b3e6e28c8e43feb86454dacdd0
Author: XiChen <[email protected]>
AuthorDate: Mon May 18 21:57:58 2026 +0800

    HDDS-15239. Support persist StorageType on Datanode Container YAML (#10246)
---
 .../java/org/apache/hadoop/ozone/OzoneConsts.java  |  1 +
 .../container/common/helpers/ContainerUtils.java   | 11 +---
 .../ozone/container/common/impl/ContainerData.java | 32 +++++++--
 .../container/common/impl/ContainerDataYaml.java   | 40 +++++++-----
 .../common/impl/StorageLocationReport.java         | 32 +++++----
 .../common/report/NodeReportPublisher.java         |  2 +-
 .../container/common/report/ReportPublisher.java   |  2 +-
 .../ozone/container/ozoneimpl/OzoneContainer.java  |  2 +-
 .../common/TestKeyValueContainerData.java          |  6 +-
 .../TestSchemaOneBackwardsCompatibility.java       |  7 +-
 .../common/impl/TestContainerDataYaml.java         | 75 ++++++++++++++++++++--
 11 files changed, 154 insertions(+), 56 deletions(-)

diff --git 
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java 
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java
index 151022823a1..2656668309a 100644
--- a/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java
+++ b/hadoop-hdds/common/src/main/java/org/apache/hadoop/ozone/OzoneConsts.java
@@ -243,6 +243,7 @@ public final class OzoneConsts {
   public static final String ORIGIN_NODE_ID = "originNodeId";
   public static final String SCHEMA_VERSION = "schemaVersion";
   public static final String REPLICA_INDEX = "replicaIndex";
+  public static final String CONTAINER_STORAGE_TYPE = "storageType";
 
   // Supported .container datanode schema versions.
   // Since containers in older schema versions are currently not reformatted to
diff --git 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/helpers/ContainerUtils.java
 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/helpers/ContainerUtils.java
index 7d16546fb69..dde4588806f 100644
--- 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/helpers/ContainerUtils.java
+++ 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/helpers/ContainerUtils.java
@@ -54,14 +54,12 @@
 import org.apache.hadoop.hdds.utils.HddsServerUtil;
 import org.apache.hadoop.ozone.OzoneConsts;
 import org.apache.hadoop.ozone.container.common.impl.ContainerData;
-import org.apache.hadoop.ozone.container.common.impl.ContainerDataYaml;
 import org.apache.hadoop.ozone.container.common.impl.ContainerSet;
 import org.apache.hadoop.ozone.container.common.utils.StorageVolumeUtil;
 import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
 import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.yaml.snakeyaml.Yaml;
 
 /**
  * A mix of helper functions for containers.
@@ -247,11 +245,8 @@ public static void 
verifyContainerFileChecksum(ContainerData containerData,
     if (enabled) {
       String storedChecksum = containerData.getContainerFileChecksum();
 
-      Yaml yaml = ContainerDataYaml.getYamlForContainerType(
-          containerData.getContainerType(),
-          containerData instanceof KeyValueContainerData &&
-              ((KeyValueContainerData)containerData).getReplicaIndex() > 0);
-      containerData.computeAndSetContainerFileChecksum(yaml);
+      // Compute checksum (storageTypeis automatically excluded for rollback 
compatibility)
+      containerData.computeAndSetContainerFileChecksum();
       String computedChecksum = containerData.getContainerFileChecksum();
 
       if (storedChecksum == null || !storedChecksum.equals(computedChecksum)) {
@@ -375,7 +370,7 @@ public static void assertSpaceAvailability(long 
containerId, HddsVolume volume,
           + currentUsage + ", minimum free space spared="  + spared, 
DISK_OUT_OF_SPACE);
     }
   }
-  
+
   public static long getPendingDeletionBytes(ContainerData containerData) {
     if (containerData.getContainerType()
         .equals(ContainerProtos.ContainerType.KeyValueContainer)) {
diff --git 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/ContainerData.java
 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/ContainerData.java
index 31b890fdbd3..5e6bba1189a 100644
--- 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/ContainerData.java
+++ 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/ContainerData.java
@@ -43,12 +43,14 @@
 import java.util.Optional;
 import java.util.TreeMap;
 import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.hadoop.fs.StorageType;
 import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
 import 
org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerDataProto;
 import 
org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerType;
 import 
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.ContainerReplicaProto;
 import org.apache.hadoop.ozone.container.common.helpers.ContainerUtils;
 import org.apache.hadoop.ozone.container.common.volume.HddsVolume;
+import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
 import org.apache.ratis.util.Preconditions;
 import org.yaml.snakeyaml.Yaml;
 
@@ -114,6 +116,7 @@ public abstract class ContainerData {
   public static final Charset CHARSET_ENCODING = StandardCharsets.UTF_8;
   public static final String ZERO_CHECKSUM = new String(new byte[64],
       CHARSET_ENCODING);
+  private StorageType storageType;
 
   // Common Fields need to be stored in .container file.
   protected static final List<String> YAML_FIELDS =
@@ -162,6 +165,7 @@ protected ContainerData(ContainerData source) {
         source.getLayoutVersion(), source.getMaxSize(),
         source.getOriginPipelineId(), source.getOriginNodeId());
     replicaIndex = source.getReplicaIndex();
+    storageType = source.getStorageType();
   }
 
   /**
@@ -284,6 +288,14 @@ public Map<String, String> getMetadata() {
     return Collections.unmodifiableMap(this.metadata);
   }
 
+  public void setStorageType(StorageType type) {
+    storageType = type;
+  }
+
+  public StorageType getStorageType() {
+    return storageType;
+  }
+
   /**
    * Set metadata.
    * We should hold the container lock before updating the metadata as this
@@ -516,22 +528,32 @@ public String getOriginNodeId() {
   }
 
   /**
-   * Compute the checksum for ContainerData using the specified Yaml (based
-   * on ContainerType) and set the checksum.
+   * Compute the checksum for ContainerData and set the checksum.
    *
    * Checksum of ContainerData is calculated by setting the
    * {@link ContainerData#checksum} field to a 64-byte array with all 0's -
    * {@link ContainerData#ZERO_CHECKSUM}. After the checksum is calculated,
    * the checksum field is updated with this value.
    *
-   * @param yaml Yaml for ContainerType to get the ContainerData as Yaml String
    * @throws IOException
    */
-  public void computeAndSetContainerFileChecksum(Yaml yaml) throws IOException 
{
+  public void computeAndSetContainerFileChecksum() throws IOException {
     // Set checksum to dummy value - 0 byte array, to calculate the checksum
     // of rest of the data.
     this.checksum = ZERO_CHECKSUM;
 
+    // Create Yaml for checksum calculation that excludes storageType for 
backward compatibility
+    boolean withReplicaIndex = this instanceof KeyValueContainerData &&
+        ((KeyValueContainerData) this).getReplicaIndex() > 0;
+    // IMPORTANT: Pass null for storageType to ensure rollback compatibility.
+    // Ozone calculates checksum by reading the YAML file into a Java object, 
then converting
+    // it back to YAML string (not directly using the YAML file content).
+    // If storageType participates in checksum calculation, when rolling back 
to older versions that don't
+    // support storageType, they would recalculate checksum without 
storageType field
+    // (as it's unknown to them), causing checksum mismatch and validation 
failure.
+    Yaml yaml = ContainerDataYaml.getYamlForContainerType(
+        this.containerType, withReplicaIndex, null);
+
     // Dump yaml data into a string to compute its checksum
     String containerDataYamlStr = yaml.dump(this);
 
@@ -588,7 +610,7 @@ public boolean needsDataChecksum() {
    * - writeCount += 1 (one operation)
    * - usedSpace/committedBytes NOT updated here (delta handled separately)
    * - blockBytes NOT updated here (delta=4 handled by incrementBlockBytes)
-   * 
+   *
    * @param bytesWritten Number of bytes in the I/O operation
    * @param overwrite Whether this is an overwrite operation
    */
diff --git 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/ContainerDataYaml.java
 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/ContainerDataYaml.java
index e667161559a..24201daa7e7 100644
--- 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/ContainerDataYaml.java
+++ 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/impl/ContainerDataYaml.java
@@ -17,6 +17,7 @@
 
 package org.apache.hadoop.ozone.container.common.impl;
 
+import static org.apache.hadoop.ozone.OzoneConsts.CONTAINER_STORAGE_TYPE;
 import static org.apache.hadoop.ozone.OzoneConsts.REPLICA_INDEX;
 import static 
org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData.KEYVALUE_YAML_TAG;
 
@@ -31,6 +32,8 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeSet;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.fs.StorageType;
 import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
 import 
org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerType;
 import 
org.apache.hadoop.hdds.scm.container.common.helpers.StorageContainerException;
@@ -70,12 +73,18 @@ private ContainerDataYaml() {
   /**
    * Creates a .container file in yaml format.
    */
-  public static void createContainerFile(ContainerData containerData, File 
containerFile) throws IOException {
-    // Create Yaml for given container type
-    final Yaml yaml = 
getYamlForContainerType(containerData.getContainerType(), 
containerData.getReplicaIndex() > 0);
+  public static void createContainerFile(ContainerData containerData,
+      File containerFile) throws IOException {
+    boolean withReplicaIndex =
+        containerData instanceof KeyValueContainerData
+            && ((KeyValueContainerData) containerData).getReplicaIndex() > 0;
+    StorageType storageType =
+        containerData instanceof KeyValueContainerData
+            ? containerData.getStorageType() : null;
+    Yaml yaml = getYamlForContainerType(containerData.getContainerType(),
+        withReplicaIndex, storageType);
     // Compute Checksum and update ContainerData
-    containerData.computeAndSetContainerFileChecksum(yaml);
-
+    containerData.computeAndSetContainerFileChecksum();
     // Write the ContainerData with checksum to Yaml file.
     YamlUtils.dump(yaml, containerData, containerFile, LOG);
   }
@@ -145,17 +154,8 @@ public static ContainerData readContainer(InputStream 
input)
     return containerData;
   }
 
-  /**
-   * Given a ContainerType this method returns a Yaml representation of
-   * the container properties.
-   *
-   * @param containerType    type of container
-   * @param withReplicaIndex in the container yaml
-   * @return Yamal representation of container properties
-   * @throws StorageContainerException if the type is unrecognized
-   */
   public static Yaml getYamlForContainerType(ContainerType containerType,
-      boolean withReplicaIndex)
+      boolean withReplicaIndex, StorageType storageType)
       throws StorageContainerException {
     PropertyUtils propertyUtils = new PropertyUtils();
     propertyUtils.setBeanAccess(BeanAccess.FIELD);
@@ -168,6 +168,10 @@ public static Yaml getYamlForContainerType(ContainerType 
containerType,
         yamlFields = new ArrayList<>(yamlFields);
         yamlFields.add(REPLICA_INDEX);
       }
+      if (storageType != null) {
+        yamlFields = new ArrayList<>(yamlFields);
+        yamlFields.add(CONTAINER_STORAGE_TYPE);
+      }
       Representer representer = new ContainerDataRepresenter(yamlFields);
       representer.setPropertyUtils(propertyUtils);
       representer.addClassTag(
@@ -284,6 +288,12 @@ public Object construct(Node node) {
           kvData.setReplicaIndex(
               ((Long) replicaIndex).intValue());
         }
+        String storageTypeString = (String) nodes.get(CONTAINER_STORAGE_TYPE);
+        StorageType storageType = StringUtils.isEmpty(storageTypeString) ?
+            null : StorageType.valueOf(storageTypeString);
+        if (storageType != null) {
+          kvData.setStorageType(storageType);
+        }
         return kvData;
       }
     }
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 34643cc6161..a32cdce53a1 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
@@ -20,6 +20,7 @@
 import java.io.IOException;
 import net.jcip.annotations.Immutable;
 import org.apache.hadoop.fs.StorageType;
+import org.apache.hadoop.hdds.conf.ConfigurationSource;
 import org.apache.hadoop.hdds.protocol.proto.HddsProtos.StorageTypeProto;
 import 
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.MetadataStorageReportProto;
 import 
org.apache.hadoop.hdds.protocol.proto.StorageContainerDatanodeProtocolProtos.StorageReportProto;
@@ -114,12 +115,12 @@ public StorageType getStorageType() {
     return storageType;
   }
 
-  private StorageTypeProto getStorageTypeProto() throws IOException {
+  private StorageTypeProto getStorageTypeProto() throws 
IllegalArgumentException {
     return getStorageTypeProto(getStorageType());
   }
 
   public static StorageTypeProto getStorageTypeProto(StorageType type)
-      throws IOException {
+      throws IllegalArgumentException {
     StorageTypeProto storageTypeProto;
     switch (type) {
     case SSD:
@@ -138,12 +139,12 @@ public static StorageTypeProto 
getStorageTypeProto(StorageType type)
       storageTypeProto = StorageTypeProto.RAM_DISK;
       break;
     default:
-      throw new IOException("Illegal Storage Type specified");
+      throw new IllegalArgumentException("Illegal Storage Type specified");
     }
     return storageTypeProto;
   }
 
-  public long getReserved() { 
+  public long getReserved() {
     return reserved;
   }
 
@@ -155,8 +156,8 @@ public long getFsAvailable() {
     return fsAvailable;
   }
 
-  private static StorageType getStorageType(StorageTypeProto proto) throws
-      IOException {
+  public static StorageType getStorageType(StorageTypeProto proto) throws
+      IllegalArgumentException {
     StorageType storageType;
     switch (proto) {
     case SSD:
@@ -175,7 +176,7 @@ private static StorageType getStorageType(StorageTypeProto 
proto) throws
       storageType = StorageType.RAM_DISK;
       break;
     default:
-      throw new IOException("Illegal Storage Type specified");
+      throw new IllegalArgumentException("Illegal Storage Type specified");
     }
     return storageType;
   }
@@ -184,9 +185,14 @@ private static StorageType getStorageType(StorageTypeProto 
proto) throws
    * Returns the StorageReportProto protoBuf message for the Storage Location
    * report.
    * @return StorageReportProto
-   * @throws IOException In case, the storage type specified is invalid.
+   * @throws IllegalArgumentException In case, the storage type specified is 
invalid.
    */
-  public StorageReportProto getProtoBufMessage() throws IOException {
+  public StorageReportProto getProtoBufMessage() throws 
IllegalArgumentException, IOException {
+    return getProtoBufMessage(null);
+  }
+
+  public StorageReportProto getProtoBufMessage(ConfigurationSource conf)
+      throws IOException {
     StorageReportProto.Builder srb = StorageReportProto.newBuilder();
     return srb.setStorageUuid(getId())
         .setCapacity(getCapacity())
@@ -207,10 +213,10 @@ public StorageReportProto getProtoBufMessage() throws 
IOException {
    * Returns the MetadataStorageReportProto protoBuf message for the
    * Storage Location report.
    * @return MetadataStorageReportProto
-   * @throws IOException In case, the storage type specified is invalid.
+   * @throws IllegalArgumentException In case, the storage type specified is 
invalid.
    */
   public MetadataStorageReportProto getMetadataProtoBufMessage()
-      throws IOException {
+      throws IllegalArgumentException {
     MetadataStorageReportProto.Builder srb =
         MetadataStorageReportProto.newBuilder();
     return srb.setCapacity(getCapacity())
@@ -226,11 +232,11 @@ public MetadataStorageReportProto 
getMetadataProtoBufMessage()
    * Returns the StorageLocationReport from the protoBuf message.
    * @param report SCMStorageReport
    * @return StorageLocationReport
-   * @throws IOException in case of invalid storage type
+   * @throws IllegalArgumentException in case of invalid storage type
    */
 
   public static StorageLocationReport getFromProtobuf(StorageReportProto 
report)
-      throws IOException {
+      throws IllegalArgumentException {
     StorageLocationReport.Builder builder = StorageLocationReport.newBuilder();
     builder.setId(report.getStorageUuid())
         .setStorageLocation(report.getStorageLocation());
diff --git 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/report/NodeReportPublisher.java
 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/report/NodeReportPublisher.java
index 3f6ba78e125..4ccd8538647 100644
--- 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/report/NodeReportPublisher.java
+++ 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/report/NodeReportPublisher.java
@@ -56,7 +56,7 @@ protected long getReportFrequency() {
   }
 
   @Override
-  protected NodeReportProto getReport() throws IOException {
+  protected NodeReportProto getReport() throws IOException, 
IllegalArgumentException {
     return getContext().getParent().getContainer().getNodeReport();
   }
 }
diff --git 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/report/ReportPublisher.java
 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/report/ReportPublisher.java
index 03fa43fa841..beda2cb8ca0 100644
--- 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/report/ReportPublisher.java
+++ 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/report/ReportPublisher.java
@@ -83,7 +83,7 @@ private void publishReport() {
       } else {
         context.refreshFullReport(report);
       }
-    } catch (IOException e) {
+    } catch (IOException | IllegalArgumentException e) {
       LOG.error("Exception while publishing report.", e);
     }
   }
diff --git 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OzoneContainer.java
 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OzoneContainer.java
index 27702064cf9..007b6ecba77 100644
--- 
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OzoneContainer.java
+++ 
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/OzoneContainer.java
@@ -677,7 +677,7 @@ public ContainerController getController() {
    * Returns node report of container storage usage.
    */
   public StorageContainerDatanodeProtocolProtos.NodeReportProto getNodeReport()
-          throws IOException {
+          throws IOException, IllegalArgumentException {
     StorageLocationReport[] reports = volumeSet.getStorageReport();
     StorageContainerDatanodeProtocolProtos.NodeReportProto.Builder nrb
             = StorageContainerDatanodeProtocolProtos.
diff --git 
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/TestKeyValueContainerData.java
 
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/TestKeyValueContainerData.java
index 2e54a12ef8f..68e682f87ca 100644
--- 
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/TestKeyValueContainerData.java
+++ 
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/TestKeyValueContainerData.java
@@ -25,6 +25,7 @@
 
 import java.util.UUID;
 import org.apache.hadoop.conf.StorageUnit;
+import org.apache.hadoop.fs.StorageType;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
 import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos;
 import org.apache.hadoop.ozone.container.common.impl.ContainerData;
@@ -94,8 +95,9 @@ public void testKeyValueData(ContainerTestVersionInfo 
versionInfo) {
     kvData.incrPendingDeletionBlocks(1, 256);
     kvData.setSchemaVersion(
         VersionedDatanodeFeatures.SchemaV3.chooseSchemaVersion(conf));
-    long expectedDataHash =  1234L;
+    long expectedDataHash = 1234L;
     kvData.setDataChecksum(expectedDataHash);
+    kvData.setStorageType(StorageType.SSD);
 
     assertEquals(state, kvData.getState());
     assertEquals(containerDBType, kvData.getContainerDBType());
@@ -110,12 +112,14 @@ public void testKeyValueData(ContainerTestVersionInfo 
versionInfo) {
     assertEquals(VersionedDatanodeFeatures.SchemaV3.chooseSchemaVersion(conf),
         kvData.getSchemaVersion());
     assertEquals(expectedDataHash, kvData.getDataChecksum());
+    assertEquals(StorageType.SSD, kvData.getStorageType());
 
     KeyValueContainerData newKvData = new KeyValueContainerData(kvData);
     assertEquals(kvData.getReplicaIndex(), newKvData.getReplicaIndex());
     assertEquals(0, newKvData.getNumPendingDeletionBlocks());
     assertEquals(0, newKvData.getDeleteTransactionId());
     assertEquals(kvData.getSchemaVersion(), newKvData.getSchemaVersion());
+    assertEquals(kvData.getStorageType(), newKvData.getStorageType());
   }
 
   @ContainerTestVersionInfo.ContainerTest
diff --git 
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/TestSchemaOneBackwardsCompatibility.java
 
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/TestSchemaOneBackwardsCompatibility.java
index a8723fc147c..b025803af7e 100644
--- 
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/TestSchemaOneBackwardsCompatibility.java
+++ 
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/TestSchemaOneBackwardsCompatibility.java
@@ -70,7 +70,6 @@
 import org.junit.jupiter.api.io.TempDir;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
-import org.yaml.snakeyaml.Yaml;
 
 /**
  * Tests processing of containers written with DB schema version 1,
@@ -597,10 +596,10 @@ private KeyValueContainerData newKvData() throws 
IOException {
 
     // Changing the paths above affects the checksum, so it was also removed
     // from the container file and calculated at run time.
-    Yaml yaml = ContainerDataYaml.getYamlForContainerType(
+    ContainerDataYaml.getYamlForContainerType(
             kvData.getContainerType(),
-        kvData.getReplicaIndex() > 0);
-    kvData.computeAndSetContainerFileChecksum(yaml);
+        kvData.getReplicaIndex() > 0, kvData.getStorageType());
+    kvData.computeAndSetContainerFileChecksum();
 
     KeyValueContainerUtil.parseKVContainerData(kvData, conf);
 
diff --git 
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/impl/TestContainerDataYaml.java
 
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/impl/TestContainerDataYaml.java
index 84a2672b3f9..ef77d276d8d 100644
--- 
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/impl/TestContainerDataYaml.java
+++ 
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/impl/TestContainerDataYaml.java
@@ -17,9 +17,11 @@
 
 package org.apache.hadoop.ozone.container.common.impl;
 
+import static org.apache.hadoop.ozone.OzoneConsts.CONTAINER_STORAGE_TYPE;
 import static 
org.apache.hadoop.ozone.container.common.impl.ContainerLayoutVersion.FILE_PER_CHUNK;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
@@ -32,6 +34,7 @@
 import org.apache.hadoop.conf.StorageUnit;
 import org.apache.hadoop.fs.FileSystemTestHelper;
 import org.apache.hadoop.fs.FileUtil;
+import org.apache.hadoop.fs.StorageType;
 import org.apache.hadoop.hdds.HddsConfigKeys;
 import org.apache.hadoop.hdds.conf.ConfigurationSource;
 import org.apache.hadoop.hdds.conf.OzoneConfiguration;
@@ -41,6 +44,8 @@
 import org.apache.hadoop.ozone.container.keyvalue.ContainerLayoutTestInfo;
 import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
 import org.apache.hadoop.ozone.container.upgrade.VersionedDatanodeFeatures;
+import org.junit.jupiter.api.Test;
+import org.yaml.snakeyaml.Yaml;
 
 /**
  * This class tests create/read .container files.
@@ -68,9 +73,10 @@ private void setLayoutVersion(ContainerLayoutVersion 
layoutVersion) {
    * Creates a .container file. cleanup() should be called at the end of the
    * test when container file is created.
    */
-  private File createContainerFile(long containerID, int replicaIndex)
+  private File createContainerFile(long containerID, int replicaIndex, 
StorageType storageType)
       throws IOException {
-    assertTrue(new File(testRoot).mkdirs());
+    File root = new File(testRoot);
+    assertTrue(root.mkdirs() || root.exists());
 
     String containerPath = containerID + ".container";
 
@@ -78,6 +84,7 @@ private File createContainerFile(long containerID, int 
replicaIndex)
         containerID, layoutVersion, MAXSIZE,
         UUID.randomUUID().toString(),
         UUID.randomUUID().toString());
+    keyValueContainerData.setStorageType(storageType);
     keyValueContainerData.setContainerDBType(CONTAINER_DB_TYPE);
     keyValueContainerData.setMetadataPath(testRoot);
     keyValueContainerData.setChunksPath(testRoot);
@@ -108,11 +115,12 @@ public void 
testCreateContainerFile(ContainerLayoutVersion layout)
     setLayoutVersion(layout);
     long containerID = testContainerID++;
 
-    File containerFile = createContainerFile(containerID, 7);
+    File containerFile = createContainerFile(containerID, 7, StorageType.SSD);
 
     // Read from .container file, and verify data.
     KeyValueContainerData kvData = (KeyValueContainerData) ContainerDataYaml
         .readContainerFile(containerFile);
+    assertEquals(StorageType.SSD, kvData.getStorageType());
     assertEquals(containerID, kvData.getContainerID());
     assertEquals(ContainerProtos.ContainerType.KeyValueContainer, kvData
         .getContainerType());
@@ -176,7 +184,7 @@ public void testCreateContainerFileWithoutReplicaIndex(
     setLayoutVersion(layout);
     long containerID = testContainerID++;
 
-    File containerFile = createContainerFile(containerID, 0);
+    File containerFile = createContainerFile(containerID, 0, null);
 
     final String content =
         FileUtils.readFileToString(containerFile, Charset.defaultCharset());
@@ -241,7 +249,7 @@ public void 
testChecksumInContainerFile(ContainerLayoutVersion layout) throws IO
     setLayoutVersion(layout);
     long containerID = testContainerID++;
 
-    File containerFile = createContainerFile(containerID, 0);
+    File containerFile = createContainerFile(containerID, 0, null);
 
     // Read from .container file, and verify data.
     KeyValueContainerData kvData = (KeyValueContainerData) 
ContainerDataYaml.readContainerFile(containerFile);
@@ -259,7 +267,7 @@ public void 
testDataChecksumNotInContainerFile(ContainerLayoutVersion layout) th
     setLayoutVersion(layout);
     long containerID = testContainerID++;
 
-    File containerFile = createContainerFile(containerID, 0);
+    File containerFile = createContainerFile(containerID, 0, null);
 
     // Read from .container file. The kvData object should not have a data 
hash because it was not persisted in this
     // file.
@@ -278,7 +286,7 @@ public void testChecksumInContainerFileWithReplicaIndex(
     setLayoutVersion(layout);
     long containerID = testContainerID++;
 
-    File containerFile = createContainerFile(containerID, 10);
+    File containerFile = createContainerFile(containerID, 10, null);
 
     // Read from .container file, and verify data.
     KeyValueContainerData kvData = (KeyValueContainerData) ContainerDataYaml
@@ -288,6 +296,44 @@ public void testChecksumInContainerFileWithReplicaIndex(
     cleanup();
   }
 
+  @Test
+  public void testChecksumCanBeVerifiedAfterRollbackWithStorageType()
+      throws IOException {
+    setLayoutVersion(FILE_PER_CHUNK);
+    long containerID = testContainerID++;
+
+    File containerFile = createContainerFile(containerID, 7, StorageType.SSD);
+
+    final String content =
+        FileUtils.readFileToString(containerFile, Charset.defaultCharset());
+    assertThat(content).contains(CONTAINER_STORAGE_TYPE);
+
+    KeyValueContainerData kvData = (KeyValueContainerData) ContainerDataYaml
+        .readContainerFile(containerFile);
+    String storedChecksum = kvData.getContainerFileChecksum();
+
+    assertEquals(computeContainerFileChecksum(kvData, null), storedChecksum);
+    assertThat(computeContainerFileChecksum(kvData, kvData.getStorageType()))
+        .isNotEqualTo(storedChecksum);
+    ContainerUtils.verifyContainerFileChecksum(kvData, conf);
+
+    cleanup();
+  }
+
+  private String computeContainerFileChecksum(KeyValueContainerData kvData,
+      StorageType storageType) throws IOException {
+    String storedChecksum = kvData.getContainerFileChecksum();
+    try {
+      kvData.setContainerFileChecksum(ContainerData.ZERO_CHECKSUM);
+      Yaml yaml = ContainerDataYaml.getYamlForContainerType(
+          kvData.getContainerType(), kvData.getReplicaIndex() > 0,
+          storageType);
+      return ContainerUtils.getContainerFileChecksum(yaml.dump(kvData));
+    } finally {
+      kvData.setContainerFileChecksum(storedChecksum);
+    }
+  }
+
   private KeyValueContainerData getKeyValueContainerData() throws IOException {
     String containerFile = "incorrect.checksum.container";
     //Get file from resources folder
@@ -322,4 +368,19 @@ public void testDisabledChecksum(ContainerLayoutVersion 
layout)
         HDDS_CONTAINER_CHECKSUM_VERIFICATION_ENABLED, false);
     ContainerUtils.verifyContainerFileChecksum(kvData, conf);
   }
+
+  @Test
+  public void testCreateContainerFileWithoutStorageType() throws IOException {
+    setLayoutVersion(FILE_PER_CHUNK);
+    long containerID = testContainerID++;
+
+    File containerFile = createContainerFile(containerID, 0, null);
+
+    final String content =
+        FileUtils.readFileToString(containerFile, Charset.defaultCharset());
+
+    assertFalse(content.contains(CONTAINER_STORAGE_TYPE),
+        "StorageType shouldn't be persisted if it is null");
+    cleanup();
+  }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to