This is an automated email from the ASF dual-hosted git repository. jojochuang pushed a commit to branch ozone-2.1 in repository https://gitbox.apache.org/repos/asf/ozone.git
commit d5125b4b2c45668330c20972186621fc0bf10ab3 Author: Priyesh Karatha <[email protected]> AuthorDate: Wed Jul 8 17:54:18 2026 +0530 HDDS-14577. Handle missing metadata dir when updating container state (#10565). (cherry picked from commit 7a95fdda18019ebfbad70ff2dc086d4b6531de11) --- .../container/keyvalue/KeyValueContainer.java | 12 ++++++++- .../container/keyvalue/TestKeyValueContainer.java | 30 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java index 78abd811386..45b8e4525f0 100644 --- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueContainer.java @@ -389,7 +389,17 @@ public void markContainerUnhealthy() throws StorageContainerException { writeLock(); final State prevState = containerData.getState(); try { - updateContainerState(UNHEALTHY); + if (!getContainerFile().getParentFile().exists()) { + // Metadata directory is absent (e.g. MISSING_METADATA_DIR detected by scanner). + // Attempting to write the .container file would fail + // The in-memory UNHEALTHY state is sufficient: SCM will receive it via ICR + // and schedule deletion without requiring a persisted .container file. + containerData.setState(UNHEALTHY); + LOG.debug("Skipping .container file update for container {} with missing metadata directory", + containerData.getContainerID()); + } else { + updateContainerState(UNHEALTHY); + } clearPendingPutBlockCache(); } finally { writeUnlock(); diff --git a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueContainer.java b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueContainer.java index 28c118b517f..e3111176799 100644 --- a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueContainer.java +++ b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueContainer.java @@ -23,6 +23,7 @@ import static org.apache.hadoop.ozone.container.checksum.ContainerMerkleTreeTestUtils.buildTestTree; import static org.apache.hadoop.ozone.container.checksum.ContainerMerkleTreeTestUtils.verifyAllDataChecksumsMatch; import static org.apache.hadoop.ozone.container.common.statemachine.DatanodeConfiguration.CONTAINER_SCHEMA_V3_ENABLED; +import static org.apache.hadoop.ozone.container.keyvalue.TestContainerCorruptions.MISSING_METADATA_DIR; import static org.apache.hadoop.ozone.container.keyvalue.helpers.KeyValueContainerUtil.isSameSchemaVersion; import static org.apache.hadoop.ozone.container.replication.CopyContainerCompression.NO_COMPRESSION; import static org.assertj.core.api.Assertions.assertThat; @@ -694,6 +695,35 @@ public void testReportOfUnhealthyContainer( assertNotNull(keyValueContainer.getContainerReport()); } + /** + * When a container's metadata directory is missing (MISSING_METADATA_DIR detected by the scanner), + * markContainerUnhealthy must succeed without throwing. Writing a partial .container file with only + * the state field would lose other metadata and is more harmful than writing nothing. The in-memory + * UNHEALTHY state is sufficient for SCM to receive it via ICR and schedule deletion. + */ + @ContainerTestVersionInfo.ContainerTest + public void testMarkUnhealthyWithMissingMetadataDir(ContainerTestVersionInfo versionInfo) throws Exception { + init(versionInfo); + keyValueContainer.create(volumeSet, volumeChoosingPolicy, scmId); + + // Simulate MISSING_METADATA_DIR using the same corruption helper used in scanner tests. + File metadataDir = new File(keyValueContainerData.getMetadataPath()); + assertTrue(metadataDir.exists(), "Metadata dir should exist before corruption"); + MISSING_METADATA_DIR.applyTo(keyValueContainer); + + // markContainerUnhealthy must not throw even though the metadata dir is absent. + keyValueContainer.markContainerUnhealthy(); + + // In-memory state must be UNHEALTHY. + assertEquals(ContainerProtos.ContainerDataProto.State.UNHEALTHY, + keyValueContainer.getContainerState()); + + // Regression guards: if a future change adds mkdirs/persist logic, these catch it early. + assertFalse(metadataDir.exists(), "Metadata dir should not be recreated by markContainerUnhealthy"); + assertFalse(keyValueContainer.getContainerFile().exists(), + "Container file should not be written when metadata dir is missing"); + } + @ContainerTestVersionInfo.ContainerTest public void testUpdateContainer(ContainerTestVersionInfo versionInfo) throws Exception { --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
