From 05bbc619caac419092058c34355e933b5b72f6e6 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Thu, 13 Nov 2025 16:48:08 +0530 Subject: [PATCH 01/14] added component specific ratis name --- .../apache/hadoop/hdds/scm/ha/SCMHAUtils.java | 2 +- .../hadoop/hdds/server/ServerUtils.java | 15 +++++++- .../hadoop/hdds/utils/HddsServerUtil.java | 2 +- .../hadoop/hdds/server/TestServerUtils.java | 38 +++++++++++++++++++ .../src/main/smoketest/omha/testOMHA.robot | 2 +- .../parser/TestOzoneHARatisLogParser.java | 7 ++-- .../ratis/utils/OzoneManagerRatisUtils.java | 2 +- 7 files changed, 59 insertions(+), 9 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java index 3d3b48185e3f..c8398f8bf055 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java @@ -97,7 +97,7 @@ public static String getSCMRatisDirectory(ConfigurationSource conf) { conf.get(ScmConfigKeys.OZONE_SCM_HA_RATIS_STORAGE_DIR); if (Strings.isNullOrEmpty(scmRatisDirectory)) { - scmRatisDirectory = ServerUtils.getDefaultRatisDirectory(conf); + scmRatisDirectory = ServerUtils.getDefaultRatisDirectory(conf, "scm"); } return scmRatisDirectory; } diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index 9dffa3e1f18a..22e2d19bf2b3 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -300,11 +300,22 @@ public static String getRemoteUserName() { return remoteUser != null ? remoteUser.getUserName() : null; } - public static String getDefaultRatisDirectory(ConfigurationSource conf) { + /** + * Get the default Ratis directory for a component when the specific + * configuration is not set. This creates a component-specific subdirectory + * under ozone.metadata.dirs to avoid conflicts when multiple components + * are colocated on the same host. + * + * @param conf Configuration source + * @param componentName Name of the component (e.g., "scm", "om", "dn") + * @return Path to the component-specific ratis directory + */ + public static String getDefaultRatisDirectory(ConfigurationSource conf, + String componentName) { LOG.warn("Storage directory for Ratis is not configured. It is a good " + "idea to map this to an SSD disk. Falling back to {}", HddsConfigKeys.OZONE_METADATA_DIRS); File metaDirPath = ServerUtils.getOzoneMetaDirPath(conf); - return (new File(metaDirPath, "ratis")).getPath(); + return (new File(metaDirPath, componentName + ".ratis")).getPath(); } } diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/HddsServerUtil.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/HddsServerUtil.java index 2da151faed6a..a38dc40af8a3 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/HddsServerUtil.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/HddsServerUtil.java @@ -422,7 +422,7 @@ public static Collection getOzoneDatanodeRatisDirectory( if (rawLocations.isEmpty()) { rawLocations = new ArrayList<>(1); - rawLocations.add(ServerUtils.getDefaultRatisDirectory(conf)); + rawLocations.add(ServerUtils.getDefaultRatisDirectory(conf, "dn")); } return rawLocations; } diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index a7bbeccbd19e..533a2665c81d 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -263,4 +263,42 @@ public void ozoneMetadataDirRejectsList() { () -> ServerUtils.getOzoneMetaDirPath(conf)); } + /** + * Test that SCM, OM, and Datanode colocated on the same host with only + * ozone.metadata.dirs configured don't conflict with Ratis directories. + */ + @Test + public void testColocatedComponentsWithSharedMetadataDir() { + final File metaDir = new File(folder.toFile(), "sharedMetaDir"); + final OzoneConfiguration conf = new OzoneConfiguration(); + + // Only configure ozone.metadata.dirs (the fallback config) + conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); + + try { + assertFalse(metaDir.exists()); + + // Test Ratis directories - each component should get its own with flat naming + String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "scm"); + String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "om"); + String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "dn"); + + // Verify Ratis directories use flat naming pattern (component.ratis) + assertEquals(new File(metaDir, "scm.ratis").getPath(), scmRatisDir); + assertEquals(new File(metaDir, "om.ratis").getPath(), omRatisDir); + assertEquals(new File(metaDir, "dn.ratis").getPath(), dnRatisDir); + + // Verify all Ratis directories are different + assertFalse(scmRatisDir.equals(omRatisDir)); + assertFalse(scmRatisDir.equals(dnRatisDir)); + assertFalse(omRatisDir.equals(dnRatisDir)); + + // Verify the base metadata dir exists + assertTrue(metaDir.exists()); + + } finally { + FileUtils.deleteQuietly(metaDir); + } + } + } diff --git a/hadoop-ozone/dist/src/main/smoketest/omha/testOMHA.robot b/hadoop-ozone/dist/src/main/smoketest/omha/testOMHA.robot index 70fc66a228f2..df7c914273ed 100644 --- a/hadoop-ozone/dist/src/main/smoketest/omha/testOMHA.robot +++ b/hadoop-ozone/dist/src/main/smoketest/omha/testOMHA.robot @@ -28,7 +28,7 @@ ${USERNAME} hadoop ${PUBLIC_KEY} /opt/.ssh/id_rsa ${OM_SERVICE_ID} %{OM_SERVICE_ID} ${OZONE_LOG_DIR} /ozone/logs/ -${RATIS_DIR} /data/metadata/ratis +${RATIS_DIR} /data/metadata/om.ratis ${VOLUME} volume1 ${BUCKET} bucket1 ${TEST_FILE} NOTICE.txt diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/parser/TestOzoneHARatisLogParser.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/parser/TestOzoneHARatisLogParser.java index cd85abe90213..b00990bbe312 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/parser/TestOzoneHARatisLogParser.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/parser/TestOzoneHARatisLogParser.java @@ -18,7 +18,6 @@ package org.apache.hadoop.ozone.parser; import static java.nio.charset.StandardCharsets.UTF_8; -import static org.apache.hadoop.hdds.HddsConfigKeys.OZONE_METADATA_DIRS; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -40,6 +39,7 @@ import org.apache.hadoop.ozone.client.OzoneClientFactory; import org.apache.hadoop.ozone.debug.ratis.parse.RatisLogParser; import org.apache.hadoop.ozone.om.helpers.OMRatisHelper; +import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerRatisUtils; import org.apache.ozone.test.GenericTestUtils; import org.apache.ozone.test.tag.Flaky; import org.junit.jupiter.api.AfterEach; @@ -105,8 +105,9 @@ void testRatisLogParsing() throws Exception { cluster.stop(); - File omMetaDir = new File(ozoneConfiguration.get(OZONE_METADATA_DIRS), - "ratis"); + // Get the OM Ratis directory using the proper utility method + File omMetaDir = new File( + OzoneManagerRatisUtils.getOMRatisDirectory(ozoneConfiguration)); assertThat(omMetaDir).isDirectory(); String[] ratisDirs = omMetaDir.list(); diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java index 5548be7bd8ba..378e43f5928d 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java @@ -472,7 +472,7 @@ public static String getOMRatisDirectory(ConfigurationSource conf) { String storageDir = conf.get(OMConfigKeys.OZONE_OM_RATIS_STORAGE_DIR); if (Strings.isNullOrEmpty(storageDir)) { - storageDir = ServerUtils.getDefaultRatisDirectory(conf); + storageDir = ServerUtils.getDefaultRatisDirectory(conf, "om"); } return storageDir; } From d20f6a0c9661a0032e01768aa282ac6e305f8df3 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Thu, 13 Nov 2025 17:05:45 +0530 Subject: [PATCH 02/14] fix pmd failures --- .../hadoop/hdds/server/ServerUtils.java | 68 ++++++++++++++++++- .../hadoop/hdds/server/TestServerUtils.java | 7 +- 2 files changed, 71 insertions(+), 4 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index 22e2d19bf2b3..cc8585a0999e 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -306,16 +306,82 @@ public static String getRemoteUserName() { * under ozone.metadata.dirs to avoid conflicts when multiple components * are colocated on the same host. * + *

For backward compatibility during upgrades, this method checks for + * existing Ratis data in old locations before using the new component-specific + * location. See {@link #findExistingRatisDirectory} for details on old locations. + * * @param conf Configuration source * @param componentName Name of the component (e.g., "scm", "om", "dn") * @return Path to the component-specific ratis directory */ public static String getDefaultRatisDirectory(ConfigurationSource conf, - String componentName) { + String componentName) { LOG.warn("Storage directory for Ratis is not configured. It is a good " + "idea to map this to an SSD disk. Falling back to {}", HddsConfigKeys.OZONE_METADATA_DIRS); File metaDirPath = ServerUtils.getOzoneMetaDirPath(conf); + + // Check for existing Ratis data from old versions for backward compatibility + String existingDir = findExistingRatisDirectory(metaDirPath, componentName); + if (existingDir != null) { + return existingDir; + } + + // Use new component-specific location for new installations return (new File(metaDirPath, componentName + ".ratis")).getPath(); } + + /** + * Checks for existing Ratis directories from previous versions for backward + * compatibility during upgrades. + * + *

Older versions of Ozone used different directory structures: + *

    + *
  • Versions up to 2.0.0: Shared {@code /ratis} for all components
  • + *
  • Some SCM versions: Used {@code /scm-ha}
  • + *
+ * + * @param metaDirPath The ozone metadata directory path + * @param componentName Name of the component (e.g., "scm", "om", "dn") + * @return Path to existing old Ratis directory if found, null otherwise + */ + private static String findExistingRatisDirectory(File metaDirPath, + String componentName) { + // Check old shared Ratis location first (used by version 2.0.0 and earlier) + // All components (OM, SCM) shared /data/metadata/ratis + File oldSharedRatisDir = new File(metaDirPath, "ratis"); + if (isNonEmptyDirectory(oldSharedRatisDir)) { + LOG.info("Found existing Ratis directory at old shared location: {}. " + + "Using it for backward compatibility during upgrade.", + oldSharedRatisDir.getPath()); + return oldSharedRatisDir.getPath(); + } + + // Check component-specific old location (SCM used scm-ha in some versions) + if ("scm".equals(componentName)) { + File oldScmRatisDir = new File(metaDirPath, "scm-ha"); + if (isNonEmptyDirectory(oldScmRatisDir)) { + LOG.info("Found existing SCM Ratis directory at old location: {}. " + + "Using it for backward compatibility during upgrade.", + oldScmRatisDir.getPath()); + return oldScmRatisDir.getPath(); + } + } + + return null; + } + + /** + * Checks if a directory exists and is non-empty. + * + * @param dir Directory to check + * @return true if directory exists and contains at least one file + */ + private static boolean isNonEmptyDirectory(File dir) { + if (dir != null && dir.exists() && dir.isDirectory()) { + File[] files = dir.listFiles(); + return files != null && files.length > 0; + } + return false; + } } diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index 533a2665c81d..ebd1da93ca23 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -19,6 +19,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +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.assertThrows; @@ -289,9 +290,9 @@ public void testColocatedComponentsWithSharedMetadataDir() { assertEquals(new File(metaDir, "dn.ratis").getPath(), dnRatisDir); // Verify all Ratis directories are different - assertFalse(scmRatisDir.equals(omRatisDir)); - assertFalse(scmRatisDir.equals(dnRatisDir)); - assertFalse(omRatisDir.equals(dnRatisDir)); + assertNotEquals(scmRatisDir, omRatisDir); + assertNotEquals(scmRatisDir, dnRatisDir); + assertNotEquals(omRatisDir, dnRatisDir); // Verify the base metadata dir exists assertTrue(metaDir.exists()); From 64cbce14d09999dd9f90955ce42622811f3294e7 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Tue, 18 Nov 2025 12:55:41 +0530 Subject: [PATCH 03/14] added unit test for backward compatibility check --- .../hadoop/hdds/server/ServerUtils.java | 2 +- .../hadoop/hdds/server/TestServerUtils.java | 31 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index cc8585a0999e..05dca51aa3f0 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -346,7 +346,7 @@ public static String getDefaultRatisDirectory(ConfigurationSource conf, * @return Path to existing old Ratis directory if found, null otherwise */ private static String findExistingRatisDirectory(File metaDirPath, - String componentName) { + String componentName) { // Check old shared Ratis location first (used by version 2.0.0 and earlier) // All components (OM, SCM) shared /data/metadata/ratis File oldSharedRatisDir = new File(metaDirPath, "ratis"); diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index ebd1da93ca23..b0bd1c6ac554 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -302,4 +302,35 @@ public void testColocatedComponentsWithSharedMetadataDir() { } } + /** + * Test backward compatibility: old shared /ratis directory should be used + * when it exists and is non-empty (simulating upgrade from version 2.0.0). + */ + @Test + public void testBackwardCompatibilityWithOldSharedRatisDir() throws IOException { + final File metaDir = new File(folder.toFile(), "upgradeMetaDir"); + final File oldSharedRatisDir = new File(metaDir, "ratis"); + final OzoneConfiguration conf = new OzoneConfiguration(); + conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); + + try { + // Create old shared ratis directory with some files (simulating existing data) + assertTrue(oldSharedRatisDir.mkdirs()); + File testFile = new File(oldSharedRatisDir, "test-file"); + assertTrue(testFile.createNewFile()); + + // Test that all components use the old shared location + String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "scm"); + String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "om"); + String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "dn"); + + // All should use the old shared location + assertEquals(oldSharedRatisDir.getPath(), scmRatisDir); + assertEquals(oldSharedRatisDir.getPath(), omRatisDir); + assertEquals(oldSharedRatisDir.getPath(), dnRatisDir); + + } finally { + FileUtils.deleteQuietly(metaDir); + } + } } From d757e5577102121be832fc04569a89140fdf9c7c Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Sat, 6 Dec 2025 14:24:47 +0530 Subject: [PATCH 04/14] used NodeType for componentName and changed ratis snapshot structure --- .../apache/hadoop/hdds/scm/ha/SCMHAUtils.java | 25 +-- .../hadoop/hdds/server/ServerUtils.java | 155 +++++++++++++++--- .../hadoop/hdds/utils/HddsServerUtil.java | 3 +- .../hadoop/hdds/server/TestServerUtils.java | 13 +- .../apache/hadoop/hdds/scm/ha/RatisUtil.java | 2 +- .../hdds/scm/TestStorageContainerManager.java | 2 +- .../parser/TestOzoneHARatisLogParser.java | 2 +- .../apache/hadoop/ozone/om/OzoneManager.java | 2 +- .../ratis/utils/OzoneManagerRatisUtils.java | 15 +- 9 files changed, 155 insertions(+), 64 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java index 8f98d362fcce..9428f0d1019c 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java @@ -17,19 +17,15 @@ package org.apache.hadoop.hdds.scm.ha; -import static org.apache.hadoop.hdds.HddsConfigKeys.OZONE_METADATA_DIRS; -import static org.apache.hadoop.ozone.OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR; - import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; -import java.io.File; import java.io.IOException; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import org.apache.hadoop.hdds.HddsUtils; import org.apache.hadoop.hdds.conf.ConfigurationSource; import org.apache.hadoop.hdds.conf.OzoneConfiguration; +import org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeType; import org.apache.hadoop.hdds.ratis.ServerNotLeaderException; import org.apache.hadoop.hdds.scm.ScmConfigKeys; import org.apache.hadoop.hdds.scm.container.ContainerNotFoundException; @@ -97,31 +93,18 @@ public static String getSCMRatisDirectory(ConfigurationSource conf) { conf.get(ScmConfigKeys.OZONE_SCM_HA_RATIS_STORAGE_DIR); if (Strings.isNullOrEmpty(scmRatisDirectory)) { - scmRatisDirectory = ServerUtils.getDefaultRatisDirectory(conf, "scm"); + scmRatisDirectory = ServerUtils.getDefaultRatisDirectory(conf, NodeType.SCM); } return scmRatisDirectory; } - public static String getRatisStorageDir(final ConfigurationSource conf) { - String storageDir = conf.get(ScmConfigKeys.OZONE_SCM_HA_RATIS_STORAGE_DIR); - if (Strings.isNullOrEmpty(storageDir)) { - File metaDirPath = ServerUtils.getOzoneMetaDirPath(conf); - storageDir = (new File(metaDirPath, "scm-ha")).getPath(); - } - return storageDir; - } - public static String getSCMRatisSnapshotDirectory(ConfigurationSource conf) { String snapshotDir = conf.get(ScmConfigKeys.OZONE_SCM_HA_RATIS_SNAPSHOT_DIR); - // If ratis snapshot directory is not set, fall back to ozone.metadata.dir. + // If ratis snapshot directory is not set, fall back to ozone.metadata.dir with component-specific location. if (Strings.isNullOrEmpty(snapshotDir)) { - LOG.warn("SCM snapshot dir is not configured. Falling back to {} config", - OZONE_METADATA_DIRS); - File metaDirPath = ServerUtils.getOzoneMetaDirPath(conf); - snapshotDir = - Paths.get(metaDirPath.getPath(), OZONE_RATIS_SNAPSHOT_DIR).toString(); + snapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, NodeType.SCM); } return snapshotDir; } diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index 2b547347a898..5cfca3ce4d79 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -21,17 +21,21 @@ import java.net.InetSocketAddress; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.PosixFilePermissions; import java.util.Collection; import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.hdds.HddsConfigKeys; import org.apache.hadoop.hdds.conf.ConfigurationSource; import org.apache.hadoop.hdds.conf.OzoneConfiguration; +import org.apache.hadoop.hdds.protocol.proto.HddsProtos; +import org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeType; import org.apache.hadoop.hdds.recon.ReconConfigKeys; import org.apache.hadoop.hdds.scm.ScmConfigKeys; import org.apache.hadoop.ipc_.RPC; import org.apache.hadoop.ipc_.Server; import org.apache.hadoop.ozone.OzoneConfigKeys; +import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.security.UserGroupInformation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -311,23 +315,24 @@ public static String getRemoteUserName() { * location. See {@link #findExistingRatisDirectory} for details on old locations. * * @param conf Configuration source - * @param componentName Name of the component (e.g., "scm", "om", "dn") + * @param nodeType Type of the node component * @return Path to the component-specific ratis directory */ public static String getDefaultRatisDirectory(ConfigurationSource conf, - String componentName) { + HddsProtos.NodeType nodeType) { LOG.warn("Storage directory for Ratis is not configured. It is a good " + "idea to map this to an SSD disk. Falling back to {}", HddsConfigKeys.OZONE_METADATA_DIRS); File metaDirPath = ServerUtils.getOzoneMetaDirPath(conf); // Check for existing Ratis data from old versions for backward compatibility - String existingDir = findExistingRatisDirectory(metaDirPath, componentName); + String existingDir = findExistingRatisDirectory(metaDirPath, nodeType); if (existingDir != null) { return existingDir; } // Use new component-specific location for new installations + String componentName = getComponentName(nodeType); return (new File(metaDirPath, componentName + ".ratis")).getPath(); } @@ -342,32 +347,140 @@ public static String getDefaultRatisDirectory(ConfigurationSource conf, * * * @param metaDirPath The ozone metadata directory path - * @param componentName Name of the component (e.g., "scm", "om", "dn") + * @param nodeType Type of the node component * @return Path to existing old Ratis directory if found, null otherwise */ private static String findExistingRatisDirectory(File metaDirPath, - String componentName) { - // Check old shared Ratis location first (used by version 2.0.0 and earlier) - // All components (OM, SCM) shared /data/metadata/ratis - File oldSharedRatisDir = new File(metaDirPath, "ratis"); - if (isNonEmptyDirectory(oldSharedRatisDir)) { - LOG.info("Found existing Ratis directory at old shared location: {}. " + - "Using it for backward compatibility during upgrade.", - oldSharedRatisDir.getPath()); - return oldSharedRatisDir.getPath(); + NodeType nodeType) { + // Check old Ratis directory locations in order of precedence + String[] oldRatisDirs = getOldRatisDirectoryNames(nodeType); + for (String dirName : oldRatisDirs) { + File oldRatisDir = new File(metaDirPath, dirName); + if (isNonEmptyDirectory(oldRatisDir)) { + LOG.info("Found existing Ratis directory at old location: {}. " + + "Using it for backward compatibility during upgrade.", + oldRatisDir.getPath()); + return oldRatisDir.getPath(); + } } + return null; + } - // Check component-specific old location (SCM used scm-ha in some versions) - if ("scm".equals(componentName)) { - File oldScmRatisDir = new File(metaDirPath, "scm-ha"); - if (isNonEmptyDirectory(oldScmRatisDir)) { - LOG.info("Found existing SCM Ratis directory at old location: {}. " + - "Using it for backward compatibility during upgrade.", - oldScmRatisDir.getPath()); - return oldScmRatisDir.getPath(); + /** + * Returns array of old Ratis directory names to check, in order of precedence. + * + * @param nodeType Type of the node component + * @return Array of directory names to check + */ + private static String[] getOldRatisDirectoryNames(NodeType nodeType) { + // Component-specific old locations take precedence over shared locations + if (nodeType == NodeType.SCM) { + return new String[]{"scm-ha", "ratis"}; + } + return new String[]{"ratis"}; + } + + /** + * Converts NodeType enum to the component name string used for directory naming. + * + * @param nodeType Type of the node component + * @return Component name string (e.g., "om", "scm", "dn", "recon") + */ + private static String getComponentName(NodeType nodeType) { + switch (nodeType) { + case OM: + return "om"; + case SCM: + return "scm"; + case DATANODE: + return "dn"; + case RECON: + return "recon"; + default: + throw new IllegalArgumentException("Unknown NodeType: " + nodeType); + } + } + + /** + * Get the default Ratis snapshot directory for a component when the specific + * configuration is not set. This creates a component-specific subdirectory + * under ozone.metadata.dirs to avoid conflicts when multiple components + * are colocated on the same host. + * + *

For backward compatibility during upgrades, this method checks for + * existing snapshot data in old locations before using the new component-specific + * location. See {@link #findExistingRatisSnapshotDirectory} for details on old locations. + * + * @param conf Configuration source + * @param nodeType Type of the node component + * @return Path to the component-specific ratis snapshot directory + */ + public static String getDefaultRatisSnapshotDirectory(ConfigurationSource conf, + HddsProtos.NodeType nodeType) { + LOG.warn("Snapshot directory for Ratis is not configured. Falling back to {}", + HddsConfigKeys.OZONE_METADATA_DIRS); + File metaDirPath = ServerUtils.getOzoneMetaDirPath(conf); + + // Check for existing snapshot data from old versions for backward compatibility + String existingSnapshotDir = findExistingRatisSnapshotDirectory(metaDirPath, nodeType); + if (existingSnapshotDir != null) { + return existingSnapshotDir; + } + + // Use new component-specific location for new installations + String componentName = getComponentName(nodeType); + return Paths.get(metaDirPath.getPath(), + componentName + "." + OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR).toString(); + } + + /** + * Checks for existing Ratis snapshot directories from previous versions for backward + * compatibility during upgrades. + * + *

Note: These are Ratis consensus protocol snapshots (used for HA). + * + *

Older versions of Ozone used different directory structures: + *

    + *
  • Versions up to 2.0.0: Shared {@code /snapshot} for Ratis snapshots (OM, SCM)
  • + *
  • Some versions: Ratis snapshot directory inside Ratis storage directory {@code /snapshot}
  • + *
+ * + * @param metaDirPath The ozone metadata directory path + * @param nodeType Type of the node component + * @return Path to existing old Ratis snapshot directory if found, null otherwise + */ + private static String findExistingRatisSnapshotDirectory(File metaDirPath, HddsProtos.NodeType nodeType) { + // Check snapshot directory inside old Ratis directories first (nested structure) + // This handles cases where snapshots were stored inside the Ratis storage directory. + // For SCM: checks /scm-ha/snapshot then /ratis/snapshot + // For OM/DATANODE: checks /ratis/snapshot + // This nested structure was primarily used by OM in some intermediate versions + + String[] oldRatisDirs = getOldRatisDirectoryNames(nodeType); + for (String ratisDirName : oldRatisDirs) { + File oldRatisDir = new File(metaDirPath, ratisDirName); + if (oldRatisDir.exists() && oldRatisDir.isDirectory()) { + File snapshotInRatisDir = new File(oldRatisDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); + if (isNonEmptyDirectory(snapshotInRatisDir)) { + LOG.info("Found existing Ratis snapshot directory at old location inside {} dir: {}. " + + "Using it for backward compatibility during upgrade.", + ratisDirName, snapshotInRatisDir.getPath()); + return snapshotInRatisDir.getPath(); + } } } + // Check old shared standalone Ratis snapshot location (flat structure) + // Used by version 2.0.0 and earlier: /data/metadata/snapshot (shared by OM and SCM) + // This standalone structure was shared by both OM and SCM + File oldSharedSnapshotDir = new File(metaDirPath, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); + if (isNonEmptyDirectory(oldSharedSnapshotDir)) { + LOG.info("Found existing Ratis snapshot directory at old shared location: {}. " + + "Using it for backward compatibility during upgrade.", + oldSharedSnapshotDir.getPath()); + return oldSharedSnapshotDir.getPath(); + } + return null; } diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/HddsServerUtil.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/HddsServerUtil.java index dc4bb89c8127..df4c31077aa6 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/HddsServerUtil.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/utils/HddsServerUtil.java @@ -76,6 +76,7 @@ import org.apache.hadoop.hdds.conf.OzoneConfiguration; import org.apache.hadoop.hdds.protocol.SCMSecurityProtocol; import org.apache.hadoop.hdds.protocol.SecretKeyProtocolScm; +import org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeType; import org.apache.hadoop.hdds.protocolPB.SCMSecurityProtocolClientSideTranslatorPB; import org.apache.hadoop.hdds.protocolPB.SecretKeyProtocolClientSideTranslatorPB; import org.apache.hadoop.hdds.protocolPB.SecretKeyProtocolDatanodePB; @@ -424,7 +425,7 @@ public static Collection getOzoneDatanodeRatisDirectory( if (rawLocations.isEmpty()) { rawLocations = new ArrayList<>(1); - rawLocations.add(ServerUtils.getDefaultRatisDirectory(conf, "dn")); + rawLocations.add(ServerUtils.getDefaultRatisDirectory(conf, NodeType.DATANODE)); } return rawLocations; } diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index b0bd1c6ac554..2e7b132a5cbe 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -35,6 +35,7 @@ import org.apache.commons.io.FileUtils; import org.apache.hadoop.hdds.HddsConfigKeys; import org.apache.hadoop.hdds.conf.OzoneConfiguration; +import org.apache.hadoop.hdds.protocol.proto.HddsProtos; import org.apache.hadoop.hdds.recon.ReconConfigKeys; import org.apache.hadoop.hdds.scm.ScmConfigKeys; import org.apache.hadoop.ozone.OzoneConfigKeys; @@ -280,9 +281,9 @@ public void testColocatedComponentsWithSharedMetadataDir() { assertFalse(metaDir.exists()); // Test Ratis directories - each component should get its own with flat naming - String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "scm"); - String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "om"); - String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "dn"); + String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.SCM); + String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.OM); + String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.DATANODE); // Verify Ratis directories use flat naming pattern (component.ratis) assertEquals(new File(metaDir, "scm.ratis").getPath(), scmRatisDir); @@ -320,9 +321,9 @@ public void testBackwardCompatibilityWithOldSharedRatisDir() throws IOException assertTrue(testFile.createNewFile()); // Test that all components use the old shared location - String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "scm"); - String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "om"); - String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, "dn"); + String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.SCM); + String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.OM); + String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.DATANODE); // All should use the old shared location assertEquals(oldSharedRatisDir.getPath(), scmRatisDir); diff --git a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/RatisUtil.java b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/RatisUtil.java index 5860d2523d49..f2900e38f405 100644 --- a/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/RatisUtil.java +++ b/hadoop-hdds/server-scm/src/main/java/org/apache/hadoop/hdds/scm/ha/RatisUtil.java @@ -90,7 +90,7 @@ public static RaftProperties newRaftProperties( public static void setRaftStorageDir(final RaftProperties properties, final ConfigurationSource conf) { RaftServerConfigKeys.setStorageDir(properties, Collections - .singletonList(new File(SCMHAUtils.getRatisStorageDir(conf)))); + .singletonList(new File(SCMHAUtils.getSCMRatisDirectory(conf)))); } /** diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/TestStorageContainerManager.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/TestStorageContainerManager.java index 7276dc871eac..8af00a8b0ede 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/TestStorageContainerManager.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/hdds/scm/TestStorageContainerManager.java @@ -183,7 +183,7 @@ void test(@TempDir Path tempDir) throws Exception { StorageContainerManager scm = cluster.getStorageContainerManager(); List directories = Arrays.asList( - new File(SCMHAUtils.getRatisStorageDir(scm.getConfiguration())), + new File(SCMHAUtils.getSCMRatisDirectory(scm.getConfiguration())), scm.getScmMetadataStore().getStore().getDbLocation(), new File(scm.getScmStorageConfig().getStorageDir()) ); diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/parser/TestOzoneHARatisLogParser.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/parser/TestOzoneHARatisLogParser.java index 9161ab4d954f..02f518c65e88 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/parser/TestOzoneHARatisLogParser.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/parser/TestOzoneHARatisLogParser.java @@ -135,7 +135,7 @@ void testRatisLogParsing() throws Exception { // Now check for SCM. File scmMetadataDir = - new File(SCMHAUtils.getRatisStorageDir(leaderSCMConfig)); + new File(SCMHAUtils.getSCMRatisDirectory(leaderSCMConfig)); assertThat(scmMetadataDir).isDirectory(); ratisDirs = scmMetadataDir.list(); diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java index 36d05e140744..8b0d7ab2c6b1 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java @@ -1607,7 +1607,7 @@ private void initializeRatisDirs(OzoneConfiguration conf) throws IOException { } OmUtils.createOMDir(omRatisDirectory); - String scmStorageDir = SCMHAUtils.getRatisStorageDir(conf); + String scmStorageDir = SCMHAUtils.getSCMRatisDirectory(conf); if (!Strings.isNullOrEmpty(omRatisDirectory) && !Strings .isNullOrEmpty(scmStorageDir) && omRatisDirectory .equals(scmStorageDir)) { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java index 378e43f5928d..1778de3520d9 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/ratis/utils/OzoneManagerRatisUtils.java @@ -17,21 +17,18 @@ package org.apache.hadoop.ozone.om.ratis.utils; -import static org.apache.hadoop.hdds.HddsConfigKeys.OZONE_METADATA_DIRS; -import static org.apache.hadoop.ozone.OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR; import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RATIS_SNAPSHOT_DIR; import static org.apache.hadoop.ozone.om.OzoneManagerUtils.getBucketLayout; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.protobuf.ServiceException; -import java.io.File; import java.io.IOException; import java.nio.file.InvalidPathException; import java.nio.file.Path; -import java.nio.file.Paths; import org.apache.hadoop.hdds.conf.ConfigurationSource; import org.apache.hadoop.hdds.conf.OzoneConfiguration; +import org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeType; import org.apache.hadoop.hdds.security.SecurityConfig; import org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient; import org.apache.hadoop.hdds.server.ServerUtils; @@ -472,7 +469,7 @@ public static String getOMRatisDirectory(ConfigurationSource conf) { String storageDir = conf.get(OMConfigKeys.OZONE_OM_RATIS_STORAGE_DIR); if (Strings.isNullOrEmpty(storageDir)) { - storageDir = ServerUtils.getDefaultRatisDirectory(conf, "om"); + storageDir = ServerUtils.getDefaultRatisDirectory(conf, NodeType.OM); } return storageDir; } @@ -483,13 +480,9 @@ public static String getOMRatisDirectory(ConfigurationSource conf) { public static String getOMRatisSnapshotDirectory(ConfigurationSource conf) { String snapshotDir = conf.get(OZONE_OM_RATIS_SNAPSHOT_DIR); - // If ratis snapshot directory is not set, fall back to ozone.metadata.dir. + // If ratis snapshot directory is not set, fall back to default component-specific location. if (Strings.isNullOrEmpty(snapshotDir)) { - LOG.warn("{} is not configured. Falling back to {} config", - OZONE_OM_RATIS_SNAPSHOT_DIR, OZONE_METADATA_DIRS); - File metaDirPath = ServerUtils.getOzoneMetaDirPath(conf); - snapshotDir = Paths.get(metaDirPath.getPath(), - OZONE_RATIS_SNAPSHOT_DIR).toString(); + snapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, NodeType.OM); } return snapshotDir; } From 17c9cd13ac471467123b6178c1090b037905fdc1 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Sat, 6 Dec 2025 14:48:24 +0530 Subject: [PATCH 05/14] fix pmd failure --- .../main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java index 9428f0d1019c..939777bebd15 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/scm/ha/SCMHAUtils.java @@ -42,15 +42,11 @@ import org.apache.ratis.protocol.exceptions.ReconfigurationTimeoutException; import org.apache.ratis.protocol.exceptions.ResourceUnavailableException; import org.apache.ratis.protocol.exceptions.StateMachineException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * Utility class used by SCM HA. */ public final class SCMHAUtils { - private static final Logger LOG = - LoggerFactory.getLogger(SCMHAUtils.class); private static final ImmutableList> RETRIABLE_WITH_NO_FAILOVER_EXCEPTION_LIST = From 6afa467c9281db9f94a6513dd6c8e6f89ac236d0 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Mon, 8 Dec 2025 11:56:36 +0530 Subject: [PATCH 06/14] updated unit test to cover ratis snapshot cases --- .../hadoop/hdds/server/TestServerUtils.java | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index 2e7b132a5cbe..560556b1a479 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -39,6 +39,7 @@ import org.apache.hadoop.hdds.recon.ReconConfigKeys; import org.apache.hadoop.hdds.scm.ScmConfigKeys; import org.apache.hadoop.ozone.OzoneConfigKeys; +import org.apache.hadoop.ozone.OzoneConsts; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -334,4 +335,135 @@ public void testBackwardCompatibilityWithOldSharedRatisDir() throws IOException FileUtils.deleteQuietly(metaDir); } } + + /** + * Test that SCM and OM colocated on the same host with only + * ozone.metadata.dirs configured get separate Ratis snapshot directories. + */ + @Test + public void testColocatedComponentsWithSharedMetadataDirForSnapshots() { + final File metaDir = new File(folder.toFile(), "sharedMetaDir"); + final OzoneConfiguration conf = new OzoneConfiguration(); + + // Only configure ozone.metadata.dirs (the fallback config) + conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); + + try { + assertFalse(metaDir.exists()); + + // Test Ratis snapshot directories - OM and SCM should get their own + String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); + String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.OM); + + // Verify snapshot directories use component-specific naming pattern + // New structure: /.snapshot + assertEquals(new File(metaDir, "scm.snapshot").getPath(), scmSnapshotDir); + assertEquals(new File(metaDir, "om.snapshot").getPath(), omSnapshotDir); + + // Verify snapshot directories are different + assertNotEquals(scmSnapshotDir, omSnapshotDir); + + // Verify the base metadata dir exists + assertTrue(metaDir.exists()); + + } finally { + FileUtils.deleteQuietly(metaDir); + } + } + + /** + * Test backward compatibility: snapshot directory inside old shared /ratis directory + * should be used when it exists and is non-empty (nested structure). + * Note: This tests OM and SCM backward compatibility. SCM checks /ratis/snapshot + * after checking /scm-ha/snapshot (which is tested separately). + */ + @Test + public void testBackwardCompatibilityWithSnapshotInOldRatisDir() throws IOException { + final File metaDir = new File(folder.toFile(), "upgradeMetaDir"); + final File oldRatisDir = new File(metaDir, "ratis"); + final File snapshotInRatisDir = new File(oldRatisDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); + final OzoneConfiguration conf = new OzoneConfiguration(); + conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); + + try { + // Create old nested structure: /ratis/snapshot with some files + assertTrue(snapshotInRatisDir.mkdirs()); + File testFile = new File(snapshotInRatisDir, "snapshot-file"); + assertTrue(testFile.createNewFile()); + + // Test that OM uses the old nested location + String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.OM); + assertEquals(snapshotInRatisDir.getPath(), omSnapshotDir); + + // Test that SCM also uses /ratis/snapshot when /scm-ha/snapshot doesn't exist + String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); + assertEquals(snapshotInRatisDir.getPath(), scmSnapshotDir); + + } finally { + FileUtils.deleteQuietly(metaDir); + } + } + + /** + * Test backward compatibility: SCM-specific old location /scm-ha/snapshot + * should be checked before shared /ratis/snapshot. + */ + @Test + public void testBackwardCompatibilityWithSCMSpecificOldLocation() throws IOException { + final File metaDir = new File(folder.toFile(), "upgradeMetaDir"); + final File oldScmHaDir = new File(metaDir, "scm-ha"); + final File snapshotInScmHaDir = new File(oldScmHaDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); + final File oldRatisDir = new File(metaDir, "ratis"); + final File snapshotInRatisDir = new File(oldRatisDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); + final OzoneConfiguration conf = new OzoneConfiguration(); + conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); + + try { + // Create both old locations with files + assertTrue(snapshotInScmHaDir.mkdirs()); + File scmSnapshotFile = new File(snapshotInScmHaDir, "scm-snapshot"); + assertTrue(scmSnapshotFile.createNewFile()); + + assertTrue(snapshotInRatisDir.mkdirs()); + File ratisSnapshotFile = new File(snapshotInRatisDir, "ratis-snapshot"); + assertTrue(ratisSnapshotFile.createNewFile()); + + // SCM should prefer scm-ha/snapshot over ratis/snapshot + String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); + assertEquals(snapshotInScmHaDir.getPath(), scmSnapshotDir); + + } finally { + FileUtils.deleteQuietly(metaDir); + } + } + + /** + * Test backward compatibility: old shared standalone /snapshot directory + * should be used when it exists and is non-empty (flat structure). + */ + @Test + public void testBackwardCompatibilityWithOldSharedStandaloneSnapshotDir() throws IOException { + final File metaDir = new File(folder.toFile(), "upgradeMetaDir"); + final File oldSharedSnapshotDir = new File(metaDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); + final OzoneConfiguration conf = new OzoneConfiguration(); + conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); + + try { + // Create old shared standalone snapshot directory with some files + assertTrue(oldSharedSnapshotDir.mkdirs()); + File testFile = new File(oldSharedSnapshotDir, "snapshot-file"); + assertTrue(testFile.createNewFile()); + + // Test that OM and SCM use the old shared standalone location + String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); + String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.OM); + + // Both OM and SCM should use the old shared standalone location + assertEquals(oldSharedSnapshotDir.getPath(), scmSnapshotDir); + assertEquals(oldSharedSnapshotDir.getPath(), omSnapshotDir); + + } finally { + FileUtils.deleteQuietly(metaDir); + } + } } From 6845c22f45aa7de35147fbc383d110cf61cfc272 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Tue, 9 Dec 2025 09:56:32 +0530 Subject: [PATCH 07/14] updated code for robot test to work --- .../hadoop/hdds/server/ServerUtils.java | 16 ++------------- .../hadoop/hdds/server/TestServerUtils.java | 20 +++++++++++++------ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index 5cfca3ce4d79..f6f9c5c47d15 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -441,8 +441,8 @@ public static String getDefaultRatisSnapshotDirectory(ConfigurationSource conf, * *

Older versions of Ozone used different directory structures: *

    - *
  • Versions up to 2.0.0: Shared {@code /snapshot} for Ratis snapshots (OM, SCM)
  • *
  • Some versions: Ratis snapshot directory inside Ratis storage directory {@code /snapshot}
  • + *
  • Versions up to 2.0.0: Shared {@code /snapshot} (OM, SCM)
  • *
* * @param metaDirPath The ozone metadata directory path @@ -453,8 +453,7 @@ private static String findExistingRatisSnapshotDirectory(File metaDirPath, HddsP // Check snapshot directory inside old Ratis directories first (nested structure) // This handles cases where snapshots were stored inside the Ratis storage directory. // For SCM: checks /scm-ha/snapshot then /ratis/snapshot - // For OM/DATANODE: checks /ratis/snapshot - // This nested structure was primarily used by OM in some intermediate versions + // For OM: checks /ratis/snapshot String[] oldRatisDirs = getOldRatisDirectoryNames(nodeType); for (String ratisDirName : oldRatisDirs) { @@ -470,17 +469,6 @@ private static String findExistingRatisSnapshotDirectory(File metaDirPath, HddsP } } - // Check old shared standalone Ratis snapshot location (flat structure) - // Used by version 2.0.0 and earlier: /data/metadata/snapshot (shared by OM and SCM) - // This standalone structure was shared by both OM and SCM - File oldSharedSnapshotDir = new File(metaDirPath, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); - if (isNonEmptyDirectory(oldSharedSnapshotDir)) { - LOG.info("Found existing Ratis snapshot directory at old shared location: {}. " + - "Using it for backward compatibility during upgrade.", - oldSharedSnapshotDir.getPath()); - return oldSharedSnapshotDir.getPath(); - } - return null; } diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index 560556b1a479..2ba06973b812 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -438,8 +438,9 @@ public void testBackwardCompatibilityWithSCMSpecificOldLocation() throws IOExcep } /** - * Test backward compatibility: old shared standalone /snapshot directory - * should be used when it exists and is non-empty (flat structure). + * Test that old shared standalone /snapshot directory is NOT used to avoid conflicts. + * Instead, each component should use its own component-specific directory. + * This prevents conflicts when both OM and SCM try to use the same directory during upgrades. */ @Test public void testBackwardCompatibilityWithOldSharedStandaloneSnapshotDir() throws IOException { @@ -450,17 +451,24 @@ public void testBackwardCompatibilityWithOldSharedStandaloneSnapshotDir() throws try { // Create old shared standalone snapshot directory with some files + // This simulates an upgrade scenario from version 2.0.0 assertTrue(oldSharedSnapshotDir.mkdirs()); File testFile = new File(oldSharedSnapshotDir, "snapshot-file"); assertTrue(testFile.createNewFile()); - // Test that OM and SCM use the old shared standalone location + // Test that OM and SCM use component-specific directories, NOT the shared one String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.OM); - // Both OM and SCM should use the old shared standalone location - assertEquals(oldSharedSnapshotDir.getPath(), scmSnapshotDir); - assertEquals(oldSharedSnapshotDir.getPath(), omSnapshotDir); + // Both OM and SCM should use component-specific locations, not the shared one + // This prevents conflicts when both components try to use the same directory + assertEquals(new File(metaDir, "scm.snapshot").getPath(), scmSnapshotDir); + assertEquals(new File(metaDir, "om.snapshot").getPath(), omSnapshotDir); + + // Verify they are different from each other and from the old shared location + assertNotEquals(scmSnapshotDir, omSnapshotDir); + assertNotEquals(oldSharedSnapshotDir.getPath(), scmSnapshotDir); + assertNotEquals(oldSharedSnapshotDir.getPath(), omSnapshotDir); } finally { FileUtils.deleteQuietly(metaDir); From c2631d836260b25a19884180676e92edf563c70b Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Tue, 9 Dec 2025 15:04:34 +0530 Subject: [PATCH 08/14] change path for ratis snapshot to componentName.ratis.OZONE_RATIS_SNAPSHOT_DIR and other comments --- .../org/apache/hadoop/hdds/server/ServerUtils.java | 8 ++++++-- .../apache/hadoop/hdds/server/TestServerUtils.java | 13 ++++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index f6f9c5c47d15..32693c0d0d2a 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -393,7 +393,7 @@ private static String getComponentName(NodeType nodeType) { case SCM: return "scm"; case DATANODE: - return "dn"; + return "datanode"; case RECON: return "recon"; default: @@ -407,6 +407,10 @@ private static String getComponentName(NodeType nodeType) { * under ozone.metadata.dirs to avoid conflicts when multiple components * are colocated on the same host. * + * New path format: {ozone.metadata.dirs}/{NodeType}.ratis.snapshot + * eg: /data/metadata/om.ratis.snapshot + * /data/metadata/scm.ratis.snapshot + * *

For backward compatibility during upgrades, this method checks for * existing snapshot data in old locations before using the new component-specific * location. See {@link #findExistingRatisSnapshotDirectory} for details on old locations. @@ -430,7 +434,7 @@ public static String getDefaultRatisSnapshotDirectory(ConfigurationSource conf, // Use new component-specific location for new installations String componentName = getComponentName(nodeType); return Paths.get(metaDirPath.getPath(), - componentName + "." + OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR).toString(); + componentName + ".ratis." + OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR).toString(); } /** diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index 2ba06973b812..1b57750b95ed 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -289,7 +289,7 @@ public void testColocatedComponentsWithSharedMetadataDir() { // Verify Ratis directories use flat naming pattern (component.ratis) assertEquals(new File(metaDir, "scm.ratis").getPath(), scmRatisDir); assertEquals(new File(metaDir, "om.ratis").getPath(), omRatisDir); - assertEquals(new File(metaDir, "dn.ratis").getPath(), dnRatisDir); + assertEquals(new File(metaDir, "datanode.ratis").getPath(), dnRatisDir); // Verify all Ratis directories are different assertNotEquals(scmRatisDir, omRatisDir); @@ -355,10 +355,9 @@ public void testColocatedComponentsWithSharedMetadataDirForSnapshots() { String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.OM); - // Verify snapshot directories use component-specific naming pattern - // New structure: /.snapshot - assertEquals(new File(metaDir, "scm.snapshot").getPath(), scmSnapshotDir); - assertEquals(new File(metaDir, "om.snapshot").getPath(), omSnapshotDir); + // Verify snapshot directories use: /.ratis.snapshot + assertEquals(new File(metaDir, "scm.ratis.snapshot").getPath(), scmSnapshotDir); + assertEquals(new File(metaDir, "om.ratis.snapshot").getPath(), omSnapshotDir); // Verify snapshot directories are different assertNotEquals(scmSnapshotDir, omSnapshotDir); @@ -462,8 +461,8 @@ public void testBackwardCompatibilityWithOldSharedStandaloneSnapshotDir() throws // Both OM and SCM should use component-specific locations, not the shared one // This prevents conflicts when both components try to use the same directory - assertEquals(new File(metaDir, "scm.snapshot").getPath(), scmSnapshotDir); - assertEquals(new File(metaDir, "om.snapshot").getPath(), omSnapshotDir); + assertEquals(new File(metaDir, "scm.ratis.snapshot").getPath(), scmSnapshotDir); + assertEquals(new File(metaDir, "om.ratis.snapshot").getPath(), omSnapshotDir); // Verify they are different from each other and from the old shared location assertNotEquals(scmSnapshotDir, omSnapshotDir); From 41a40a0a843b1a140e4a6c8db921c47bcc998955 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Wed, 10 Dec 2025 11:23:53 +0530 Subject: [PATCH 09/14] removed backward compatibility for ratis snapshot as its not required --- .../hadoop/hdds/server/ServerUtils.java | 53 +------ .../hadoop/hdds/server/TestServerUtils.java | 142 +++++------------- 2 files changed, 43 insertions(+), 152 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index 32693c0d0d2a..5b4b5c3eb2b9 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -393,7 +393,7 @@ private static String getComponentName(NodeType nodeType) { case SCM: return "scm"; case DATANODE: - return "datanode"; + return "dn"; case RECON: return "recon"; default: @@ -411,10 +411,6 @@ private static String getComponentName(NodeType nodeType) { * eg: /data/metadata/om.ratis.snapshot * /data/metadata/scm.ratis.snapshot * - *

For backward compatibility during upgrades, this method checks for - * existing snapshot data in old locations before using the new component-specific - * location. See {@link #findExistingRatisSnapshotDirectory} for details on old locations. - * * @param conf Configuration source * @param nodeType Type of the node component * @return Path to the component-specific ratis snapshot directory @@ -425,57 +421,12 @@ public static String getDefaultRatisSnapshotDirectory(ConfigurationSource conf, HddsConfigKeys.OZONE_METADATA_DIRS); File metaDirPath = ServerUtils.getOzoneMetaDirPath(conf); - // Check for existing snapshot data from old versions for backward compatibility - String existingSnapshotDir = findExistingRatisSnapshotDirectory(metaDirPath, nodeType); - if (existingSnapshotDir != null) { - return existingSnapshotDir; - } - - // Use new component-specific location for new installations + // Use component-specific location String componentName = getComponentName(nodeType); return Paths.get(metaDirPath.getPath(), componentName + ".ratis." + OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR).toString(); } - /** - * Checks for existing Ratis snapshot directories from previous versions for backward - * compatibility during upgrades. - * - *

Note: These are Ratis consensus protocol snapshots (used for HA). - * - *

Older versions of Ozone used different directory structures: - *

    - *
  • Some versions: Ratis snapshot directory inside Ratis storage directory {@code /snapshot}
  • - *
  • Versions up to 2.0.0: Shared {@code /snapshot} (OM, SCM)
  • - *
- * - * @param metaDirPath The ozone metadata directory path - * @param nodeType Type of the node component - * @return Path to existing old Ratis snapshot directory if found, null otherwise - */ - private static String findExistingRatisSnapshotDirectory(File metaDirPath, HddsProtos.NodeType nodeType) { - // Check snapshot directory inside old Ratis directories first (nested structure) - // This handles cases where snapshots were stored inside the Ratis storage directory. - // For SCM: checks /scm-ha/snapshot then /ratis/snapshot - // For OM: checks /ratis/snapshot - - String[] oldRatisDirs = getOldRatisDirectoryNames(nodeType); - for (String ratisDirName : oldRatisDirs) { - File oldRatisDir = new File(metaDirPath, ratisDirName); - if (oldRatisDir.exists() && oldRatisDir.isDirectory()) { - File snapshotInRatisDir = new File(oldRatisDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); - if (isNonEmptyDirectory(snapshotInRatisDir)) { - LOG.info("Found existing Ratis snapshot directory at old location inside {} dir: {}. " + - "Using it for backward compatibility during upgrade.", - ratisDirName, snapshotInRatisDir.getPath()); - return snapshotInRatisDir.getPath(); - } - } - } - - return null; - } - /** * Checks if a directory exists and is non-empty. * diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index 1b57750b95ed..a9caa2489395 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -289,7 +289,7 @@ public void testColocatedComponentsWithSharedMetadataDir() { // Verify Ratis directories use flat naming pattern (component.ratis) assertEquals(new File(metaDir, "scm.ratis").getPath(), scmRatisDir); assertEquals(new File(metaDir, "om.ratis").getPath(), omRatisDir); - assertEquals(new File(metaDir, "datanode.ratis").getPath(), dnRatisDir); + assertEquals(new File(metaDir, "dn.ratis").getPath(), dnRatisDir); // Verify all Ratis directories are different assertNotEquals(scmRatisDir, omRatisDir); @@ -337,99 +337,43 @@ public void testBackwardCompatibilityWithOldSharedRatisDir() throws IOException } /** - * Test that SCM and OM colocated on the same host with only - * ozone.metadata.dirs configured get separate Ratis snapshot directories. + * Test backward compatibility: SCM-specific /scm-ha directory should be preferred + * over shared /ratis directory when both exist and are non-empty. + * OM and DATANODE should continue using /ratis even when /scm-ha exists. */ @Test - public void testColocatedComponentsWithSharedMetadataDirForSnapshots() { - final File metaDir = new File(folder.toFile(), "sharedMetaDir"); - final OzoneConfiguration conf = new OzoneConfiguration(); - - // Only configure ozone.metadata.dirs (the fallback config) - conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); - - try { - assertFalse(metaDir.exists()); - - // Test Ratis snapshot directories - OM and SCM should get their own - String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); - String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.OM); - - // Verify snapshot directories use: /.ratis.snapshot - assertEquals(new File(metaDir, "scm.ratis.snapshot").getPath(), scmSnapshotDir); - assertEquals(new File(metaDir, "om.ratis.snapshot").getPath(), omSnapshotDir); - - // Verify snapshot directories are different - assertNotEquals(scmSnapshotDir, omSnapshotDir); - - // Verify the base metadata dir exists - assertTrue(metaDir.exists()); - - } finally { - FileUtils.deleteQuietly(metaDir); - } - } - - /** - * Test backward compatibility: snapshot directory inside old shared /ratis directory - * should be used when it exists and is non-empty (nested structure). - * Note: This tests OM and SCM backward compatibility. SCM checks /ratis/snapshot - * after checking /scm-ha/snapshot (which is tested separately). - */ - @Test - public void testBackwardCompatibilityWithSnapshotInOldRatisDir() throws IOException { + public void testBackwardCompatibilityWithScmHaDirectory() throws IOException { final File metaDir = new File(folder.toFile(), "upgradeMetaDir"); - final File oldRatisDir = new File(metaDir, "ratis"); - final File snapshotInRatisDir = new File(oldRatisDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); + final File oldScmHaDir = new File(metaDir, "scm-ha"); + final File oldSharedRatisDir = new File(metaDir, "ratis"); final OzoneConfiguration conf = new OzoneConfiguration(); conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); try { - // Create old nested structure: /ratis/snapshot with some files - assertTrue(snapshotInRatisDir.mkdirs()); - File testFile = new File(snapshotInRatisDir, "snapshot-file"); - assertTrue(testFile.createNewFile()); - - // Test that OM uses the old nested location - String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.OM); - assertEquals(snapshotInRatisDir.getPath(), omSnapshotDir); + // Create both scm-ha and ratis directories with files + assertTrue(oldScmHaDir.mkdirs()); + File scmHaTestFile = new File(oldScmHaDir, "scm-ha-file"); + assertTrue(scmHaTestFile.createNewFile()); - // Test that SCM also uses /ratis/snapshot when /scm-ha/snapshot doesn't exist - String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); - assertEquals(snapshotInRatisDir.getPath(), scmSnapshotDir); - - } finally { - FileUtils.deleteQuietly(metaDir); - } - } - - /** - * Test backward compatibility: SCM-specific old location /scm-ha/snapshot - * should be checked before shared /ratis/snapshot. - */ - @Test - public void testBackwardCompatibilityWithSCMSpecificOldLocation() throws IOException { - final File metaDir = new File(folder.toFile(), "upgradeMetaDir"); - final File oldScmHaDir = new File(metaDir, "scm-ha"); - final File snapshotInScmHaDir = new File(oldScmHaDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); - final File oldRatisDir = new File(metaDir, "ratis"); - final File snapshotInRatisDir = new File(oldRatisDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); - final OzoneConfiguration conf = new OzoneConfiguration(); - conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); + assertTrue(oldSharedRatisDir.mkdirs()); + File ratisTestFile = new File(oldSharedRatisDir, "ratis-file"); + assertTrue(ratisTestFile.createNewFile()); - try { - // Create both old locations with files - assertTrue(snapshotInScmHaDir.mkdirs()); - File scmSnapshotFile = new File(snapshotInScmHaDir, "scm-snapshot"); - assertTrue(scmSnapshotFile.createNewFile()); + // SCM should prefer scm-ha over ratis + String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.SCM); + assertEquals(oldScmHaDir.getPath(), scmRatisDir); + assertNotEquals(oldSharedRatisDir.getPath(), scmRatisDir); - assertTrue(snapshotInRatisDir.mkdirs()); - File ratisSnapshotFile = new File(snapshotInRatisDir, "ratis-snapshot"); - assertTrue(ratisSnapshotFile.createNewFile()); + // OM and DATANODE should still use ratis even when scm-ha exists + String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.OM); + String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.DATANODE); + assertEquals(oldSharedRatisDir.getPath(), omRatisDir); + assertEquals(oldSharedRatisDir.getPath(), dnRatisDir); - // SCM should prefer scm-ha/snapshot over ratis/snapshot - String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); - assertEquals(snapshotInScmHaDir.getPath(), scmSnapshotDir); + // Test that empty scm-ha directory is ignored (SCM should fall back to ratis) + FileUtils.deleteQuietly(scmHaTestFile); + String scmRatisDirWithEmptyScmHa = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.SCM); + assertEquals(oldSharedRatisDir.getPath(), scmRatisDirWithEmptyScmHa); } finally { FileUtils.deleteQuietly(metaDir); @@ -437,37 +381,33 @@ public void testBackwardCompatibilityWithSCMSpecificOldLocation() throws IOExcep } /** - * Test that old shared standalone /snapshot directory is NOT used to avoid conflicts. - * Instead, each component should use its own component-specific directory. - * This prevents conflicts when both OM and SCM try to use the same directory during upgrades. + * Test that SCM and OM colocated on the same host with only + * ozone.metadata.dirs configured get separate Ratis snapshot directories. */ @Test - public void testBackwardCompatibilityWithOldSharedStandaloneSnapshotDir() throws IOException { - final File metaDir = new File(folder.toFile(), "upgradeMetaDir"); - final File oldSharedSnapshotDir = new File(metaDir, OzoneConsts.OZONE_RATIS_SNAPSHOT_DIR); + public void testColocatedComponentsWithSharedMetadataDirForSnapshots() { + final File metaDir = new File(folder.toFile(), "sharedMetaDir"); final OzoneConfiguration conf = new OzoneConfiguration(); + + // Only configure ozone.metadata.dirs (the fallback config) conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); try { - // Create old shared standalone snapshot directory with some files - // This simulates an upgrade scenario from version 2.0.0 - assertTrue(oldSharedSnapshotDir.mkdirs()); - File testFile = new File(oldSharedSnapshotDir, "snapshot-file"); - assertTrue(testFile.createNewFile()); + assertFalse(metaDir.exists()); - // Test that OM and SCM use component-specific directories, NOT the shared one + // Test Ratis snapshot directories - OM and SCM should get their own String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.OM); - // Both OM and SCM should use component-specific locations, not the shared one - // This prevents conflicts when both components try to use the same directory + // Verify snapshot directories use: /.ratis.snapshot assertEquals(new File(metaDir, "scm.ratis.snapshot").getPath(), scmSnapshotDir); assertEquals(new File(metaDir, "om.ratis.snapshot").getPath(), omSnapshotDir); - - // Verify they are different from each other and from the old shared location + + // Verify snapshot directories are different assertNotEquals(scmSnapshotDir, omSnapshotDir); - assertNotEquals(oldSharedSnapshotDir.getPath(), scmSnapshotDir); - assertNotEquals(oldSharedSnapshotDir.getPath(), omSnapshotDir); + + // Verify the base metadata dir exists + assertTrue(metaDir.exists()); } finally { FileUtils.deleteQuietly(metaDir); From dbd7cab906549068837803066912c09262b56430 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Wed, 10 Dec 2025 12:37:15 +0530 Subject: [PATCH 10/14] fix checkstyle error --- .../test/java/org/apache/hadoop/hdds/server/TestServerUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index a9caa2489395..57721a61f00f 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -39,7 +39,6 @@ import org.apache.hadoop.hdds.recon.ReconConfigKeys; import org.apache.hadoop.hdds.scm.ScmConfigKeys; import org.apache.hadoop.ozone.OzoneConfigKeys; -import org.apache.hadoop.ozone.OzoneConsts; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; From fe09dd280b6b8f08706b2bf82682058428c6e12a Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Thu, 11 Dec 2025 12:15:41 +0530 Subject: [PATCH 11/14] added test case for existing old dir is empty and other review comments --- .../hadoop/hdds/server/ServerUtils.java | 2 +- .../hadoop/hdds/server/TestServerUtils.java | 53 ++++++++++++++----- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index 5b4b5c3eb2b9..f9e826be9303 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -333,7 +333,7 @@ public static String getDefaultRatisDirectory(ConfigurationSource conf, // Use new component-specific location for new installations String componentName = getComponentName(nodeType); - return (new File(metaDirPath, componentName + ".ratis")).getPath(); + return Paths.get(metaDirPath.getPath(), componentName + ".ratis").toString(); } /** diff --git a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java index 57721a61f00f..1eb633f455ed 100644 --- a/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java +++ b/hadoop-hdds/framework/src/test/java/org/apache/hadoop/hdds/server/TestServerUtils.java @@ -17,6 +17,9 @@ package org.apache.hadoop.hdds.server; +import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeType.DATANODE; +import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeType.OM; +import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeType.SCM; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; @@ -29,13 +32,13 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; import java.util.Set; import org.apache.commons.io.FileUtils; import org.apache.hadoop.hdds.HddsConfigKeys; import org.apache.hadoop.hdds.conf.OzoneConfiguration; -import org.apache.hadoop.hdds.protocol.proto.HddsProtos; import org.apache.hadoop.hdds.recon.ReconConfigKeys; import org.apache.hadoop.hdds.scm.ScmConfigKeys; import org.apache.hadoop.ozone.OzoneConfigKeys; @@ -281,9 +284,9 @@ public void testColocatedComponentsWithSharedMetadataDir() { assertFalse(metaDir.exists()); // Test Ratis directories - each component should get its own with flat naming - String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.SCM); - String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.OM); - String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.DATANODE); + String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, SCM); + String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, OM); + String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, DATANODE); // Verify Ratis directories use flat naming pattern (component.ratis) assertEquals(new File(metaDir, "scm.ratis").getPath(), scmRatisDir); @@ -303,6 +306,30 @@ public void testColocatedComponentsWithSharedMetadataDir() { } } + @Test + public void testEmptyOldSharedRatisIgnored() throws IOException { + final File metaDir = new File(folder.toFile(), "upgradeMetaDir"); + final File oldSharedRatisDir = new File(metaDir, "ratis"); + final OzoneConfiguration conf = new OzoneConfiguration(); + conf.set(HddsConfigKeys.OZONE_METADATA_DIRS, metaDir.getPath()); + + try { + // Create old Ratis directory (empty) + assertTrue(oldSharedRatisDir.mkdirs()); + + // SCM should use new SCM path + String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, SCM); + assertEquals(Paths.get(metaDir.getPath(), "scm.ratis").toString(), scmRatisDir); + + // OM should use new OM path + String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, OM); + assertEquals(Paths.get(metaDir.getPath(), "om.ratis").toString(), omRatisDir); + + } finally { + FileUtils.deleteQuietly(metaDir); + } + } + /** * Test backward compatibility: old shared /ratis directory should be used * when it exists and is non-empty (simulating upgrade from version 2.0.0). @@ -321,9 +348,9 @@ public void testBackwardCompatibilityWithOldSharedRatisDir() throws IOException assertTrue(testFile.createNewFile()); // Test that all components use the old shared location - String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.SCM); - String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.OM); - String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.DATANODE); + String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, SCM); + String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, OM); + String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, DATANODE); // All should use the old shared location assertEquals(oldSharedRatisDir.getPath(), scmRatisDir); @@ -359,19 +386,19 @@ public void testBackwardCompatibilityWithScmHaDirectory() throws IOException { assertTrue(ratisTestFile.createNewFile()); // SCM should prefer scm-ha over ratis - String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.SCM); + String scmRatisDir = ServerUtils.getDefaultRatisDirectory(conf, SCM); assertEquals(oldScmHaDir.getPath(), scmRatisDir); assertNotEquals(oldSharedRatisDir.getPath(), scmRatisDir); // OM and DATANODE should still use ratis even when scm-ha exists - String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.OM); - String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.DATANODE); + String omRatisDir = ServerUtils.getDefaultRatisDirectory(conf, OM); + String dnRatisDir = ServerUtils.getDefaultRatisDirectory(conf, DATANODE); assertEquals(oldSharedRatisDir.getPath(), omRatisDir); assertEquals(oldSharedRatisDir.getPath(), dnRatisDir); // Test that empty scm-ha directory is ignored (SCM should fall back to ratis) FileUtils.deleteQuietly(scmHaTestFile); - String scmRatisDirWithEmptyScmHa = ServerUtils.getDefaultRatisDirectory(conf, HddsProtos.NodeType.SCM); + String scmRatisDirWithEmptyScmHa = ServerUtils.getDefaultRatisDirectory(conf, SCM); assertEquals(oldSharedRatisDir.getPath(), scmRatisDirWithEmptyScmHa); } finally { @@ -395,8 +422,8 @@ public void testColocatedComponentsWithSharedMetadataDirForSnapshots() { assertFalse(metaDir.exists()); // Test Ratis snapshot directories - OM and SCM should get their own - String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.SCM); - String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, HddsProtos.NodeType.OM); + String scmSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, SCM); + String omSnapshotDir = ServerUtils.getDefaultRatisSnapshotDirectory(conf, OM); // Verify snapshot directories use: /.ratis.snapshot assertEquals(new File(metaDir, "scm.ratis.snapshot").getPath(), scmSnapshotDir); From f27b2230014b540a22da351dec934c937eb7f9c6 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Fri, 12 Dec 2025 10:27:20 +0530 Subject: [PATCH 12/14] updated backward compatibility logic --- .../hadoop/hdds/server/ServerUtils.java | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index f9e826be9303..38b1badd74cc 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -352,32 +352,28 @@ public static String getDefaultRatisDirectory(ConfigurationSource conf, */ private static String findExistingRatisDirectory(File metaDirPath, NodeType nodeType) { - // Check old Ratis directory locations in order of precedence - String[] oldRatisDirs = getOldRatisDirectoryNames(nodeType); - for (String dirName : oldRatisDirs) { - File oldRatisDir = new File(metaDirPath, dirName); - if (isNonEmptyDirectory(oldRatisDir)) { - LOG.info("Found existing Ratis directory at old location: {}. " + + // Check component-specific old location (SCM used scm-ha in some versions) + if ("scm".equals(getComponentName(nodeType))) { + File oldScmRatisDir = new File(metaDirPath, "scm-ha"); + if (isNonEmptyDirectory(oldScmRatisDir)) { + LOG.info("Found existing SCM Ratis directory at old location: {}. " + "Using it for backward compatibility during upgrade.", - oldRatisDir.getPath()); - return oldRatisDir.getPath(); + oldScmRatisDir.getPath()); + return oldScmRatisDir.getPath(); } } - return null; - } - /** - * Returns array of old Ratis directory names to check, in order of precedence. - * - * @param nodeType Type of the node component - * @return Array of directory names to check - */ - private static String[] getOldRatisDirectoryNames(NodeType nodeType) { - // Component-specific old locations take precedence over shared locations - if (nodeType == NodeType.SCM) { - return new String[]{"scm-ha", "ratis"}; + // Check old shared Ratis location (used by version 2.0.0 and earlier) + // All components (OM, SCM) shared /data/metadata/ratis + File oldSharedRatisDir = new File(metaDirPath, "ratis"); + if (isNonEmptyDirectory(oldSharedRatisDir)) { + LOG.info("Found existing Ratis directory at old shared location: {}. " + + "Using it for backward compatibility during upgrade.", + oldSharedRatisDir.getPath()); + return oldSharedRatisDir.getPath(); } - return new String[]{"ratis"}; + + return null; } /** From 2638de4cd57b2856e000e347d661f9d938db2986 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Sat, 13 Dec 2025 20:59:54 +0530 Subject: [PATCH 13/14] in OzoneManager only check co-location if Both om and scm are explicity configured --- .../org/apache/hadoop/ozone/om/OzoneManager.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java index 83805d86f9dd..a51a0b56ecd0 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneManager.java @@ -184,7 +184,6 @@ import org.apache.hadoop.hdds.scm.ScmInfo; import org.apache.hadoop.hdds.scm.client.HddsClientUtils; import org.apache.hadoop.hdds.scm.client.ScmTopologyClient; -import org.apache.hadoop.hdds.scm.ha.SCMHAUtils; import org.apache.hadoop.hdds.scm.ha.SCMNodeInfo; import org.apache.hadoop.hdds.scm.net.NetworkTopology; import org.apache.hadoop.hdds.scm.protocol.ScmBlockLocationProtocol; @@ -1607,10 +1606,13 @@ private void initializeRatisDirs(OzoneConfiguration conf) throws IOException { } OmUtils.createOMDir(omRatisDirectory); - String scmStorageDir = SCMHAUtils.getSCMRatisDirectory(conf); - if (!Strings.isNullOrEmpty(omRatisDirectory) && !Strings - .isNullOrEmpty(scmStorageDir) && omRatisDirectory - .equals(scmStorageDir)) { + String omRatisConfigured = conf.get(OMConfigKeys.OZONE_OM_RATIS_STORAGE_DIR); + String scmRatisConfigured = conf.get(ScmConfigKeys.OZONE_SCM_HA_RATIS_STORAGE_DIR); + + // Only check co-location if BOTH are explicitly configured + if (!Strings.isNullOrEmpty(omRatisConfigured) && + !Strings.isNullOrEmpty(scmRatisConfigured) && + omRatisConfigured.equals(scmRatisConfigured)) { throw new IOException( "Path of " + OMConfigKeys.OZONE_OM_RATIS_STORAGE_DIR + " and " + ScmConfigKeys.OZONE_SCM_HA_RATIS_STORAGE_DIR From 5d048596fc078247ce05e4d3d1b30f98bbceba78 Mon Sep 17 00:00:00 2001 From: Gargi Jaiswal Date: Mon, 15 Dec 2025 09:47:17 +0530 Subject: [PATCH 14/14] used NodeType consistently --- .../main/java/org/apache/hadoop/hdds/server/ServerUtils.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java index 38b1badd74cc..d6864d4f15db 100644 --- a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java +++ b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/server/ServerUtils.java @@ -28,7 +28,6 @@ import org.apache.hadoop.hdds.HddsConfigKeys; import org.apache.hadoop.hdds.conf.ConfigurationSource; import org.apache.hadoop.hdds.conf.OzoneConfiguration; -import org.apache.hadoop.hdds.protocol.proto.HddsProtos; import org.apache.hadoop.hdds.protocol.proto.HddsProtos.NodeType; import org.apache.hadoop.hdds.recon.ReconConfigKeys; import org.apache.hadoop.hdds.scm.ScmConfigKeys; @@ -319,7 +318,7 @@ public static String getRemoteUserName() { * @return Path to the component-specific ratis directory */ public static String getDefaultRatisDirectory(ConfigurationSource conf, - HddsProtos.NodeType nodeType) { + NodeType nodeType) { LOG.warn("Storage directory for Ratis is not configured. It is a good " + "idea to map this to an SSD disk. Falling back to {}", HddsConfigKeys.OZONE_METADATA_DIRS); @@ -412,7 +411,7 @@ private static String getComponentName(NodeType nodeType) { * @return Path to the component-specific ratis snapshot directory */ public static String getDefaultRatisSnapshotDirectory(ConfigurationSource conf, - HddsProtos.NodeType nodeType) { + NodeType nodeType) { LOG.warn("Snapshot directory for Ratis is not configured. Falling back to {}", HddsConfigKeys.OZONE_METADATA_DIRS); File metaDirPath = ServerUtils.getOzoneMetaDirPath(conf);