This is an automated email from the ASF dual-hosted git repository.
erose pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 8b0cdfff74 HDDS-8770. Cleanup of failed container delete may remove
datanode RocksDB entries of active container (#4972)
8b0cdfff74 is described below
commit 8b0cdfff7410e878bf87ef0ba70c64647755fd5a
Author: Sumit Agrawal <[email protected]>
AuthorDate: Thu Jul 13 23:07:13 2023 +0530
HDDS-8770. Cleanup of failed container delete may remove datanode RocksDB
entries of active container (#4972)
---
.../container/common/interfaces/Container.java | 5 +
.../ozone/container/common/volume/HddsVolume.java | 56 ---------
.../container/keyvalue/KeyValueContainer.java | 27 ++++-
.../ozone/container/keyvalue/KeyValueHandler.java | 27 ++---
.../keyvalue/helpers/KeyValueContainerUtil.java | 82 ++++++-------
.../ozone/container/ozoneimpl/ContainerReader.java | 24 ++++
.../hadoop/ozone/TestHddsDatanodeService.java | 7 +-
.../ozone/container/common/ContainerTestUtils.java | 32 +++--
.../common/impl/TestContainerPersistence.java | 16 ++-
.../container/keyvalue/TestKeyValueContainer.java | 10 ++
.../container/keyvalue/TestKeyValueHandler.java | 11 +-
.../container/ozoneimpl/TestContainerReader.java | 63 ++++++++++
.../ozone/container/common/TestEndPoint.java | 130 ++++++++++-----------
13 files changed, 290 insertions(+), 200 deletions(-)
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/Container.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/Container.java
index de59f9bbea..6a9793a691 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/Container.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/interfaces/Container.java
@@ -160,6 +160,11 @@ public interface Container<CONTAINERDATA extends
ContainerData> extends RwLock {
*/
void markContainerUnhealthy() throws StorageContainerException;
+ /**
+ * Marks the container replica as deleted.
+ */
+ void markContainerForDelete();
+
/**
* Quasi Closes a open container, if it is already closed or does not exist a
* StorageContainerException is thrown.
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/HddsVolume.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/HddsVolume.java
index 2a2de08cb2..581e5aaa43 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/HddsVolume.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/common/volume/HddsVolume.java
@@ -31,18 +31,11 @@ import org.apache.hadoop.hdds.annotation.InterfaceAudience;
import org.apache.hadoop.hdds.annotation.InterfaceStability;
import org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature;
import org.apache.hadoop.hdfs.server.datanode.checker.VolumeCheckResult;
-import org.apache.hadoop.ozone.OzoneConsts;
-import org.apache.hadoop.ozone.container.common.helpers.ContainerUtils;
-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.statemachine.DatanodeConfiguration;
import org.apache.hadoop.ozone.container.common.utils.DatanodeStoreCache;
import org.apache.hadoop.ozone.container.common.utils.HddsVolumeUtil;
import org.apache.hadoop.ozone.container.common.utils.RawDB;
import org.apache.hadoop.ozone.container.common.utils.StorageVolumeUtil;
-import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
-import org.apache.hadoop.ozone.container.keyvalue.helpers.BlockUtils;
-import
org.apache.hadoop.ozone.container.keyvalue.helpers.KeyValueContainerLocationUtil;
import org.apache.hadoop.ozone.container.upgrade.VersionedDatanodeFeatures;
import
org.apache.hadoop.ozone.container.upgrade.VersionedDatanodeFeatures.SchemaV3;
import org.slf4j.Logger;
@@ -240,62 +233,13 @@ public class HddsVolume extends StorageVolume {
}
for (File containerDir: containerDirs) {
- // Check the case where we have Schema V3 and
- // removing the container's entries from RocksDB fails.
// --------------------------------------------
// On datanode restart, we populate the container set
// based on the available datanode volumes and
// populate the container metadata based on the values in RocksDB.
// The container is in the tmp directory,
// so it won't be loaded in the container set
- // but there will be orphaned entries in the volume's RocksDB.
// --------------------------------------------
- // For every .container file we find under /tmp,
- // we use it to get the RocksDB entries and delete them.
- // If the .container file doesn't exist then the contents of the
- // directory are probably leftovers of a failed delete and
- // the RocksDB entries must have already been removed.
- // In any case we can proceed with deleting the directory's contents.
- // --------------------------------------------
- // Get container file and check Schema version. If Schema is V3
- // then remove the container from RocksDB.
- File containerFile = ContainerUtils.getContainerFile(containerDir);
-
- if (containerFile.exists()) {
- KeyValueContainerData keyValueContainerData;
- try {
- ContainerData containerData =
- ContainerDataYaml.readContainerFile(containerFile);
- keyValueContainerData = (KeyValueContainerData) containerData;
- } catch (IOException ex) {
- LOG.warn("Failed to read container file {}. Container cannot be " +
- "removed from the delete directory.", containerFile, ex);
- continue;
- }
-
- if (keyValueContainerData.hasSchema(OzoneConsts.SCHEMA_V3)) {
- // Container file doesn't include the volume
- // so we need to set it here in order to get the DB location.
- keyValueContainerData.setVolume(this);
- File dbFile = KeyValueContainerLocationUtil
- .getContainerDBFile(keyValueContainerData);
- keyValueContainerData.setDbFile(dbFile);
- try {
- // Remove container from Rocks DB
- BlockUtils.removeContainerFromDB(keyValueContainerData, getConf());
- } catch (IOException ex) {
- LOG.warn("Failed to remove container data from DB while" +
- "deleting container {}. Container cannot be removed from" +
- "the delete directory {}.",
- keyValueContainerData.getContainerID(),
- deletedContainerDir, ex);
- continue;
- }
- }
- }
-
- // If the container file was already deleted, the RocksDB entries were
- // cleared.
try {
if (containerDir.isDirectory()) {
FileUtils.deleteDirectory(containerDir);
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 7d5ab92e81..d6d0e74ce0 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
@@ -306,7 +306,10 @@ public class KeyValueContainer implements
Container<KeyValueContainerData> {
public void delete() throws StorageContainerException {
long containerId = containerData.getContainerID();
try {
- KeyValueContainerUtil.removeContainer(containerData, config);
+ // Delete the Container from tmp directory.
+ File tmpDirectoryPath = KeyValueContainerUtil.getTmpDirectoryPath(
+ containerData, containerData.getVolume()).toFile();
+ FileUtils.deleteDirectory(tmpDirectoryPath);
} catch (StorageContainerException ex) {
// Disk needs replacement.
throw ex;
@@ -365,6 +368,26 @@ public class KeyValueContainer implements
Container<KeyValueContainerData> {
prevState);
}
+ @Override
+ public void markContainerForDelete() {
+ writeLock();
+ ContainerDataProto.State prevState = containerData.getState();
+ try {
+ containerData.setState(ContainerDataProto.State.DELETED);
+ File containerFile = getContainerFile();
+ // update the new container data to .container File
+ updateContainerFile(containerFile);
+ } catch (IOException ioe) {
+ LOG.error("Exception occur while update container {} state",
+ containerData.getContainerID(), ioe);
+ } finally {
+ writeUnlock();
+ }
+ LOG.info("Moving container {} to state {} from state:{}",
+ containerData.getContainerPath(), containerData.getState(),
+ prevState);
+ }
+
@Override
public void quasiClose() throws StorageContainerException {
closeAndFlushIfNeeded(containerData::quasiCloseContainer);
@@ -738,7 +761,7 @@ public class KeyValueContainer implements
Container<KeyValueContainerData> {
containerData.getContainerID());
}
- static File getContainerFile(String metadataPath, long containerId) {
+ public static File getContainerFile(String metadataPath, long containerId) {
return new File(metadataPath,
containerId + OzoneConsts.CONTAINER_EXTENSION);
}
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java
index 5db14e5d87..d43900a6c5 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/KeyValueHandler.java
@@ -1348,10 +1348,18 @@ public class KeyValueHandler extends Handler {
(KeyValueContainerData) container.getContainerData();
HddsVolume hddsVolume = keyValueContainerData.getVolume();
- // Rename container location
+ // Steps to delete
+ // 1. container marked deleted
+ // 2. container is removed from container set
+ // 3. container db handler and content removed from db
+ // 4. container moved to tmp folder
+ // 5. container content deleted from tmp folder
try {
-
KeyValueContainerUtil.moveToDeletedContainerDir(keyValueContainerData,
- hddsVolume);
+ container.markContainerForDelete();
+ long containerId = container.getContainerData().getContainerID();
+ containerSet.removeContainer(containerId);
+ ContainerLogger.logDeleted(container.getContainerData(), force);
+ KeyValueContainerUtil.removeContainer(keyValueContainerData, conf);
} catch (IOException ioe) {
LOG.error("Failed to move container under " + hddsVolume
.getDeletedContainerDir());
@@ -1361,18 +1369,7 @@ public class KeyValueHandler extends Handler {
triggerVolumeScanAndThrowException(container, errorMsg,
CONTAINER_INTERNAL_ERROR);
}
-
- if (LOG.isDebugEnabled()) {
- String containerPath = keyValueContainerData
- .getContainerPath();
- File containerDir = new File(containerPath);
-
- LOG.debug("Container {} has been successfully moved under {}",
- containerDir.getName(), hddsVolume.getDeletedContainerDir());
- }
}
- long containerId = container.getContainerData().getContainerID();
- containerSet.removeContainer(containerId);
} catch (StorageContainerException e) {
throw e;
} catch (IOException e) {
@@ -1390,8 +1387,6 @@ public class KeyValueHandler extends Handler {
}
// Avoid holding write locks for disk operations
container.delete();
- container.getContainerData().setState(State.DELETED);
- ContainerLogger.logDeleted(container.getContainerData(), force);
sendICR(container);
}
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/helpers/KeyValueContainerUtil.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/helpers/KeyValueContainerUtil.java
index 1b714dacbf..f47d17d738 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/helpers/KeyValueContainerUtil.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/helpers/KeyValueContainerUtil.java
@@ -49,7 +49,6 @@ import
org.apache.hadoop.ozone.container.metadata.DatanodeStoreSchemaTwoImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
import static org.apache.hadoop.ozone.OzoneConsts.SCHEMA_V1;
/**
@@ -130,25 +129,30 @@ public final class KeyValueContainerUtil {
}
/**
- * remove Container if it is empty.
- * <p>
- * There are three things we need to delete.
- * <p>
- * 1. Container file and metadata file. 2. The Level DB file 3. The path that
- * we created on the data location.
+ * remove Container 1. remove db, 2. move to tmp directory.
*
* @param containerData - Data of the container to remove.
- * @param conf - configuration of the cluster.
* @throws IOException
*/
- public static void removeContainer(KeyValueContainerData containerData,
- ConfigurationSource conf)
+ public static void removeContainer(
+ KeyValueContainerData containerData, ConfigurationSource conf)
throws IOException {
Preconditions.checkNotNull(containerData);
- File containerMetaDataPath = new File(containerData
- .getMetadataPath());
- File chunksPath = new File(containerData.getChunksPath());
+ KeyValueContainerUtil.removeContainerDB(containerData, conf);
+ KeyValueContainerUtil.moveToDeletedContainerDir(containerData,
+ containerData.getVolume());
+ }
+ /**
+ * remove Container db, the Level DB file.
+ *
+ * @param containerData - Data of the container to remove.
+ * @param conf - configuration of the cluster.
+ * @throws IOException
+ */
+ public static void removeContainerDB(
+ KeyValueContainerData containerData, ConfigurationSource conf)
+ throws IOException {
if (containerData.hasSchema(OzoneConsts.SCHEMA_V3)) {
// DB failure is catastrophic, the disk needs to be replaced.
// In case of an exception, LOG the message and rethrow the exception.
@@ -163,15 +167,6 @@ public final class KeyValueContainerUtil {
// Close the DB connection and remove the DB handler from cache
BlockUtils.removeDB(containerData, conf);
}
-
- // Delete the Container MetaData path.
- FileUtils.deleteDirectory(containerMetaDataPath);
-
- //Delete the Container Chunks Path.
- FileUtils.deleteDirectory(chunksPath);
-
- //Delete Container directory
- FileUtils.deleteDirectory(containerMetaDataPath.getParentFile());
}
/**
@@ -472,15 +467,18 @@ public final class KeyValueContainerUtil {
* on the default container path on the disk.
*
* Delete operation for Schema < V3
- * 1. Container directory renamed to tmp directory.
- * 2. Container is removed from in memory container set.
- * 3. Container is deleted from tmp directory.
+ * 1. Container is marked DELETED
+ * 2. Container is removed from memory container set
+ * 3. Container DB handler from cache is removed and closed
+ * 4. Container directory renamed to tmp directory.
+ * 5. Container is deleted from tmp directory.
*
* Delete operation for Schema V3
- * 1. Container directory renamed to tmp directory.
- * 2. Container is removed from in memory container set.
- * 3. Container's entries are removed from RocksDB.
- * 4. Container is deleted from tmp directory.
+ * 1. Container is marked DELETED
+ * 2. Container is removed from memory container set
+ * 3. Container from DB is removed
+ * 4. Container directory renamed to tmp directory.
+ * 5. Container is deleted from tmp directory.
*
* @param keyValueContainerData
* @return true if renaming was successful
@@ -490,10 +488,8 @@ public final class KeyValueContainerUtil {
HddsVolume hddsVolume) throws IOException {
String containerPath = keyValueContainerData.getContainerPath();
File container = new File(containerPath);
- String containerDirName = container.getName();
-
- Path destinationDirPath = hddsVolume.getDeletedContainerDir().toPath()
- .resolve(Paths.get(containerDirName));
+ Path destinationDirPath = getTmpDirectoryPath(keyValueContainerData,
+ hddsVolume);
File destinationDirFile = destinationDirPath.toFile();
// If a container by the same name was moved to the delete directory but
@@ -504,14 +500,18 @@ public final class KeyValueContainerUtil {
}
Files.move(container.toPath(), destinationDirPath);
+ LOG.debug("Container {} has been successfully moved under {}",
+ container.getName(), hddsVolume.getDeletedContainerDir());
+ }
- // Updating in memory values of the container's location
- // which is used by KeyValueContainerUtil#removeContainer().
- // In case of a datanode restart these values won't persist but
- // tmp delete directory will be wiped, so this won't be an issue.
- keyValueContainerData.setMetadataPath(destinationDirPath +
- OZONE_URI_DELIMITER + OzoneConsts.CONTAINER_META_PATH);
- keyValueContainerData.setChunksPath(destinationDirPath +
- OZONE_URI_DELIMITER + OzoneConsts.STORAGE_DIR_CHUNKS);
+ public static Path getTmpDirectoryPath(
+ KeyValueContainerData keyValueContainerData,
+ HddsVolume hddsVolume) {
+ String containerPath = keyValueContainerData.getContainerPath();
+ File container = new File(containerPath);
+ String containerDirName = container.getName();
+ Path destinationDirPath = hddsVolume.getDeletedContainerDir().toPath()
+ .resolve(Paths.get(containerDirName));
+ return destinationDirPath;
}
}
diff --git
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerReader.java
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerReader.java
index 573cee9bf5..1ffc9e00cb 100644
---
a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerReader.java
+++
b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/ozoneimpl/ContainerReader.java
@@ -34,6 +34,8 @@ import
org.apache.hadoop.ozone.container.common.volume.HddsVolume;
import org.apache.hadoop.ozone.container.common.volume.MutableVolumeSet;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
+
+import static
org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerDataProto.State.DELETED;
import static org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos
.ContainerDataProto.State.RECOVERING;
@@ -212,12 +214,17 @@ public class ContainerReader implements Runnable {
config);
if (kvContainer.getContainerState() == RECOVERING) {
if (shouldDeleteRecovering) {
+ cleanupContainer(hddsVolume, kvContainer);
kvContainer.delete();
LOG.info("Delete recovering container {}.",
kvContainer.getContainerData().getContainerID());
}
return;
}
+ if (kvContainer.getContainerState() == DELETED) {
+ cleanupContainer(hddsVolume, kvContainer);
+ return;
+ }
containerSet.addContainer(kvContainer);
} else {
throw new StorageContainerException("Container File is corrupted. " +
@@ -232,4 +239,21 @@ public class ContainerReader implements Runnable {
ContainerProtos.Result.UNKNOWN_CONTAINER_TYPE);
}
}
+
+ private void cleanupContainer(
+ HddsVolume volume, KeyValueContainer kvContainer) {
+ try {
+ LOG.info("Finishing delete of container {}.",
+ kvContainer.getContainerData().getContainerID());
+ // container information from db is removed for V3
+ // and container moved to tmp folder
+ // then container content removed from tmp folder
+ KeyValueContainerUtil.removeContainer(kvContainer.getContainerData(),
+ volume.getConf());
+ kvContainer.delete();
+ } catch (IOException ex) {
+ LOG.warn("Failed to remove deleted container {}.",
+ kvContainer.getContainerData().getContainerID(), ex);
+ }
+ }
}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/TestHddsDatanodeService.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/TestHddsDatanodeService.java
index 01188b6799..fa26ebcb62 100644
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/TestHddsDatanodeService.java
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/TestHddsDatanodeService.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.ozone;
import java.io.File;
import java.io.IOException;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
@@ -37,6 +38,7 @@ import
org.apache.hadoop.ozone.container.common.volume.MutableVolumeSet;
import org.apache.hadoop.ozone.container.common.volume.StorageVolume;
import org.apache.hadoop.ozone.container.keyvalue.ContainerTestVersionInfo;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer;
+import
org.apache.hadoop.ozone.container.keyvalue.helpers.KeyValueContainerUtil;
import org.apache.ozone.test.GenericTestUtils;
import org.apache.hadoop.util.ServicePlugin;
@@ -156,8 +158,9 @@ public class TestHddsDatanodeService {
KeyValueContainer container = ContainerTestUtils
.addContainerToDeletedDir(
hddsVolume, clusterId, conf, schemaVersion);
- assertTrue(container.getContainerFile().exists());
- assertTrue(container.getContainerDBFile().exists());
+ Path containerTmpPath = KeyValueContainerUtil.getTmpDirectoryPath(
+ container.getContainerData(), hddsVolume);
+ assertTrue(containerTmpPath.toFile().exists());
File[] deletedContainersAfterShutdown =
hddsVolume.getDeletedContainerDir().listFiles();
assertNotNull(deletedContainersAfterShutdown);
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/ContainerTestUtils.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/ContainerTestUtils.java
index 530a59c35f..5b2a1c0831 100644
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/ContainerTestUtils.java
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/ContainerTestUtils.java
@@ -206,9 +206,33 @@ public final class ContainerTestUtils {
HddsVolume volume, String clusterId,
OzoneConfiguration conf, String schemaVersion)
throws IOException {
+ KeyValueContainer container = addContainerToVolumeDir(volume, clusterId,
+ conf, schemaVersion);
+
+ // For testing, we are moving the container
+ // under the tmp directory, in order to delete
+ // it from there, during datanode startup or shutdown
+ KeyValueContainerUtil
+ .moveToDeletedContainerDir(container.getContainerData(), volume);
+
+ return container;
+ }
+
+ public static KeyValueContainer addContainerToVolumeDir(
+ HddsVolume volume, String clusterId,
+ OzoneConfiguration conf, String schemaVersion)
+ throws IOException {
+ long containerId = ContainerTestHelper.getTestContainerID();
+ return addContainerToVolumeDir(volume, clusterId, conf, schemaVersion,
+ containerId);
+ }
+
+ public static KeyValueContainer addContainerToVolumeDir(
+ HddsVolume volume, String clusterId,
+ OzoneConfiguration conf, String schemaVersion, long containerId)
+ throws IOException {
VolumeChoosingPolicy volumeChoosingPolicy =
new RoundRobinVolumeChoosingPolicy();
- long containerId = ContainerTestHelper.getTestContainerID();
ContainerLayoutVersion layout = ContainerLayoutVersion.FILE_PER_BLOCK;
KeyValueContainerData keyValueContainerData = new KeyValueContainerData(
@@ -224,12 +248,6 @@ public final class ContainerTestUtils {
container.close();
- // For testing, we are moving the container
- // under the tmp directory, in order to delete
- // it from there, during datanode startup or shutdown
- KeyValueContainerUtil
- .moveToDeletedContainerDir(keyValueContainerData, volume);
-
return container;
}
}
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/impl/TestContainerPersistence.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/impl/TestContainerPersistence.java
index 8be60132be..15b0b8fc05 100644
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/impl/TestContainerPersistence.java
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/common/impl/TestContainerPersistence.java
@@ -289,6 +289,7 @@ public class TestContainerPersistence {
Assert.assertTrue(containerSet.getContainerMapCopy()
.containsKey(testContainerID));
+ KeyValueContainerUtil.removeContainer(container.getContainerData(), conf);
container.delete();
containerSet.removeContainer(testContainerID);
Assert.assertFalse(containerSet.getContainerMapCopy()
@@ -352,6 +353,9 @@ public class TestContainerPersistence {
// Block data and metadata tables should have data.
assertContainerInSchema3DB(containerData, blockID);
+ KeyValueContainerUtil.removeContainerDB(
+ container.getContainerData(),
+ container.getContainerData().getVolume().getConf());
container.delete();
containerSet.removeContainer(testContainerID);
Assert.assertFalse(containerSet.getContainerMapCopy()
@@ -475,13 +479,18 @@ public class TestContainerPersistence {
.collect(Collectors.toSet());
Assert.assertEquals(2, deleteDirFiles.size());
- File container1Dir = new File(container1Data.getContainerPath());
+ File container1Dir = KeyValueContainerUtil.getTmpDirectoryPath(
+ container1Data, hddsVolume).toFile();
Assert.assertTrue(deleteDirFiles.contains(container1Dir));
- File container2Dir = new File(container2Data.getContainerPath());
+ File container2Dir = KeyValueContainerUtil.getTmpDirectoryPath(
+ container2Data, hddsVolume).toFile();
Assert.assertTrue(deleteDirFiles.contains(container2Dir));
// Delete container1 from the disk. Container2 should remain in the
// deleted containers directory.
+ KeyValueContainerUtil.removeContainerDB(
+ container1.getContainerData(),
+ container1.getContainerData().getVolume().getConf());
container1.delete();
assertContainerNotInSchema3DB(container1Data, container1Block);
assertContainerInSchema3DB(container2Data, container2Block);
@@ -493,6 +502,9 @@ public class TestContainerPersistence {
Assert.assertEquals(deleteDirFilesArray[0], container2Dir);
// Delete container2 from the disk.
+ KeyValueContainerUtil.removeContainerDB(
+ container2.getContainerData(),
+ container2.getContainerData().getVolume().getConf());
container2.delete();
assertContainerNotInSchema3DB(container1Data, container1Block);
assertContainerNotInSchema3DB(container2Data, container2Block);
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 713936ed58..7efbe8a1b3 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
@@ -222,6 +222,8 @@ public class TestKeyValueContainer {
keyValueContainer.exportContainerData(fos, packer);
}
+ KeyValueContainerUtil.removeContainer(
+ keyValueContainer.getContainerData(), CONF);
keyValueContainer.delete();
// import container.
@@ -253,6 +255,8 @@ public class TestKeyValueContainer {
}
//delete the original one
+ KeyValueContainerUtil.removeContainer(
+ keyValueContainer.getContainerData(), CONF);
keyValueContainer.delete();
//create a new one
@@ -468,6 +472,8 @@ public class TestKeyValueContainer {
keyValueContainer = new KeyValueContainer(
keyValueContainerData, CONF);
keyValueContainer.create(volumeSet, volumeChoosingPolicy, scmId);
+ KeyValueContainerUtil.removeContainer(
+ keyValueContainer.getContainerData(), CONF);
keyValueContainer.delete();
String containerMetaDataPath = keyValueContainerData
@@ -807,6 +813,8 @@ public class TestKeyValueContainer {
}
//delete the original one
+ KeyValueContainerUtil.removeContainer(
+ keyValueContainer.getContainerData(), CONF);
keyValueContainer.delete();
//create a new one
@@ -852,6 +860,8 @@ public class TestKeyValueContainer {
}
//delete the original one
+ KeyValueContainerUtil.removeContainer(
+ keyValueContainer.getContainerData(), CONF);
keyValueContainer.delete();
//create a new one
KeyValueContainerData containerData =
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueHandler.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueHandler.java
index 31c9173bd8..745e8a0682 100644
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueHandler.java
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/TestKeyValueHandler.java
@@ -42,6 +42,7 @@ import
org.apache.hadoop.ozone.container.common.helpers.ContainerMetrics;
import org.apache.hadoop.ozone.container.common.impl.ContainerLayoutVersion;
import org.apache.hadoop.ozone.container.common.impl.ContainerSet;
import org.apache.hadoop.ozone.container.common.impl.HddsDispatcher;
+import org.apache.hadoop.ozone.container.common.interfaces.Container;
import org.apache.hadoop.ozone.container.common.interfaces.Handler;
import
org.apache.hadoop.ozone.container.common.statemachine.DatanodeStateMachine;
import org.apache.hadoop.ozone.container.common.statemachine.StateContext;
@@ -420,14 +421,14 @@ public class TestKeyValueHandler {
kvHandler.handleCreateContainer(createContainer2, null);
Assert.assertEquals(3, icrReceived.get());
- Assert.assertNotNull(containerSet.getContainer(container2ID));
+ Container<?> container = containerSet.getContainer(container2ID);
+ Assert.assertNotNull(container);
File deletedContainerDir = hddsVolume.getDeletedContainerDir();
// to simulate failed move
File dummyDir = new File(DUMMY_PATH);
hddsVolume.setDeletedContainerDir(dummyDir);
try {
- kvHandler.deleteContainer(containerSet.getContainer(container2ID),
- true);
+ kvHandler.deleteContainer(container, true);
} catch (StorageContainerException sce) {
Assert.assertTrue(
sce.getMessage().contains("Failed to move container"));
@@ -440,7 +441,9 @@ public class TestKeyValueHandler {
hddsVolume.failVolume();
GenericTestUtils.LogCapturer kvHandlerLogs =
GenericTestUtils.LogCapturer.captureLogs(KeyValueHandler.getLogger());
- kvHandler.deleteContainer(containerSet.getContainer(container2ID), true);
+ // add the container back to containerSet as removed in previous delete
+ containerSet.addContainer(container);
+ kvHandler.deleteContainer(container, true);
String expectedLog =
"Delete container issued on containerID 2 which is " +
"in a failed volume";
diff --git
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerReader.java
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerReader.java
index 229e883ad8..e9f60b5c6c 100644
---
a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerReader.java
+++
b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/ozoneimpl/TestContainerReader.java
@@ -42,11 +42,13 @@ import
org.apache.hadoop.ozone.container.keyvalue.ContainerTestVersionInfo;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
import org.apache.hadoop.ozone.container.keyvalue.helpers.BlockUtils;
+import org.apache.hadoop.ozone.container.metadata.DatanodeStoreSchemaThreeImpl;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -57,6 +59,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import static
org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerDataProto.State.DELETED;
import static
org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.ContainerDataProto.State.RECOVERING;
import static
org.apache.hadoop.ozone.container.common.ContainerTestUtils.createDbInstancesForTestIfNeeded;
import static org.mockito.ArgumentMatchers.anyList;
@@ -379,4 +382,64 @@ public class TestContainerReader {
// opens and closed them avoiding the cache.
Assert.assertEquals(0, cache.size());
}
+
+ @Test
+ public void testMarkedDeletedContainerCleared() throws Exception {
+ KeyValueContainerData containerData = new KeyValueContainerData(
+ 101, layout, (long) StorageUnit.GB.toBytes(5),
+ UUID.randomUUID().toString(), datanodeId.toString());
+ //create a container with deleted state
+ containerData.setState(DELETED);
+
+ KeyValueContainer kvContainer =
+ new KeyValueContainer(containerData, conf);
+ kvContainer.create(
+ volumeSet, volumeChoosingPolicy, clusterId);
+ long baseCount = 0;
+ if (containerData.hasSchema(OzoneConsts.SCHEMA_V3)) {
+ // add db entry for the container ID 101 for V3
+ baseCount = addDbEntry(containerData);
+ }
+ ContainerReader containerReader = new ContainerReader(volumeSet,
+ hddsVolume, containerSet, conf, false);
+
+ containerReader.run();
+
+ // assert that tmp dir is empty
+ File[] leftoverContainers =
+ hddsVolume.getDeletedContainerDir().listFiles();
+ Assertions.assertNotNull(leftoverContainers);
+ Assertions.assertEquals(0, leftoverContainers.length);
+
+ Assertions.assertNull(containerSet.getContainer(101));
+
+ if (containerData.hasSchema(OzoneConsts.SCHEMA_V3)) {
+ // verify if newly added container is not present as added
+ try (DBHandle dbHandle = BlockUtils.getDB(
+ kvContainer.getContainerData(), conf)) {
+ DatanodeStoreSchemaThreeImpl store = (DatanodeStoreSchemaThreeImpl)
+ dbHandle.getStore();
+ Assertions.assertEquals(baseCount, store.getMetadataTable()
+ .getEstimatedKeyCount());
+ }
+ }
+ }
+
+ private long addDbEntry(KeyValueContainerData containerData)
+ throws Exception {
+ try (DBHandle dbHandle = BlockUtils.getDB(containerData, conf)) {
+ DatanodeStoreSchemaThreeImpl store = (DatanodeStoreSchemaThreeImpl)
+ dbHandle.getStore();
+ Table<String, Long> metadataTable = store.getMetadataTable();
+ long baseSize = metadataTable.getEstimatedKeyCount();
+ metadataTable.put(containerData.getBytesUsedKey(), 0L);
+ metadataTable.put(containerData.getBlockCountKey(), 0L);
+ metadataTable.put(containerData.getPendingDeleteBlockCountKey(), 0L);
+
+ // The new keys should have been added in the MetadataTable
+ Assertions.assertEquals(baseSize + 3,
+ metadataTable.getEstimatedKeyCount());
+ return baseSize;
+ }
+ }
}
diff --git
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/ozone/container/common/TestEndPoint.java
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/ozone/container/common/TestEndPoint.java
index 62f4f116e2..577bf9f34d 100644
---
a/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/ozone/container/common/TestEndPoint.java
+++
b/hadoop-hdds/server-scm/src/test/java/org/apache/hadoop/ozone/container/common/TestEndPoint.java
@@ -17,7 +17,9 @@
package org.apache.hadoop.ozone.container.common;
import java.io.File;
+import java.io.IOException;
import java.net.InetSocketAddress;
+import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -44,11 +46,9 @@ import org.apache.hadoop.hdds.scm.HddsTestUtils;
import org.apache.hadoop.hdds.scm.VersionInfo;
import org.apache.hadoop.hdds.scm.pipeline.PipelineID;
import org.apache.hadoop.hdds.upgrade.HDDSLayoutVersionManager;
-import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ozone.OzoneConfigKeys;
import org.apache.hadoop.ozone.OzoneConsts;
-import org.apache.hadoop.ozone.container.common.interfaces.DBHandle;
import
org.apache.hadoop.ozone.container.common.statemachine.DatanodeStateMachine;
import
org.apache.hadoop.ozone.container.common.statemachine.EndpointStateMachine;
import org.apache.hadoop.ozone.container.common.statemachine.StateContext;
@@ -60,9 +60,7 @@ import
org.apache.hadoop.ozone.container.common.volume.HddsVolume;
import org.apache.hadoop.ozone.container.common.volume.MutableVolumeSet;
import org.apache.hadoop.ozone.container.common.volume.StorageVolume;
import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer;
-import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData;
-import org.apache.hadoop.ozone.container.keyvalue.helpers.BlockUtils;
-import org.apache.hadoop.ozone.container.metadata.DatanodeStoreSchemaThreeImpl;
+import
org.apache.hadoop.ozone.container.keyvalue.helpers.KeyValueContainerUtil;
import org.apache.hadoop.ozone.container.ozoneimpl.ContainerController;
import org.apache.hadoop.ozone.container.ozoneimpl.OzoneContainer;
import
org.apache.hadoop.ozone.container.replication.ReplicationServer.ReplicationConfig;
@@ -171,9 +169,6 @@ public class TestEndPoint {
*/
@Test
public void testDeletedContainersClearedOnStartup() throws Exception {
- // TODO HDDS-8770. If cleanup of RocksDB is no longer required on tmp dir
- // cleanup, this test can be removed.
-
OzoneConfiguration conf = SCMTestUtils.getConf();
conf.setBoolean(OzoneConfigKeys.DFS_CONTAINER_IPC_RANDOM_PORT,
true);
@@ -182,70 +177,33 @@ public class TestEndPoint {
conf.setFromObject(new ReplicationConfig().setPort(0));
try (EndpointStateMachine rpcEndPoint = createEndpoint(conf,
serverAddress, 1000)) {
- DatanodeDetails datanodeDetails = randomDatanodeDetails();
- OzoneContainer ozoneContainer = new OzoneContainer(
- datanodeDetails, conf, getContext(datanodeDetails));
+ OzoneContainer ozoneContainer = createVolume(conf);
+ HddsVolume hddsVolume = (HddsVolume) ozoneContainer.getVolumeSet()
+ .getVolumesList().get(0);
+ KeyValueContainer kvContainer = addContainer(conf, hddsVolume);
+ // For testing, we are moving the container under the tmp directory,
+ // in order to delete during datanode startup or shutdown
+ KeyValueContainerUtil.moveToDeletedContainerDir(
+ kvContainer.getContainerData(), hddsVolume);
+ Path containerTmpPath = KeyValueContainerUtil.getTmpDirectoryPath(
+ kvContainer.getContainerData(), hddsVolume);
+ Assertions.assertTrue(containerTmpPath.toFile().exists());
+
rpcEndPoint.setState(EndpointStateMachine.EndPointStates.GETVERSION);
- String clusterId = scmServerImpl.getClusterId();
-
- MutableVolumeSet volumeSet = ozoneContainer.getVolumeSet();
- ContainerTestUtils.createDbInstancesForTestIfNeeded(volumeSet,
- clusterId, clusterId, conf);
- // VolumeSet for this test, contains only 1 volume
- Assertions.assertEquals(1, volumeSet.getVolumesList().size());
- StorageVolume volume = volumeSet.getVolumesList().get(0);
-
- // Check instanceof and typecast
- Assertions.assertTrue(volume instanceof HddsVolume);
- HddsVolume hddsVolume = (HddsVolume) volume;
-
- // Write some data before calling versionTask.call()
- // Create a container and move it under the tmp delete dir.
- KeyValueContainer container = ContainerTestUtils.
- addContainerToDeletedDir(hddsVolume, clusterId,
- conf, OzoneConsts.SCHEMA_V3);
- File containerDBFile = container.getContainerDBFile();
-
- Assertions.assertTrue(container.getContainerFile().exists());
- Assertions.assertTrue(containerDBFile.exists());
-
- KeyValueContainerData containerData = container.getContainerData();
-
- // Get DBHandle
- try (DBHandle dbHandle = BlockUtils.getDB(containerData, conf)) {
-
- DatanodeStoreSchemaThreeImpl store = (DatanodeStoreSchemaThreeImpl)
- dbHandle.getStore();
- Table<String, Long> metadataTable = store.getMetadataTable();
-
- // DB MetadataTable is empty
- Assertions.assertEquals(0, metadataTable.getEstimatedKeyCount());
-
- // Add some keys to MetadataTable
- metadataTable.put(containerData.getBytesUsedKey(), 0L);
- metadataTable.put(containerData.getBlockCountKey(), 0L);
- metadataTable.put(containerData.getPendingDeleteBlockCountKey(), 0L);
-
- // The new keys should have been added in the MetadataTable
- Assertions.assertEquals(3, metadataTable.getEstimatedKeyCount());
-
- // versionTask.call() cleans the tmp dir and removes container from DB
- VersionEndpointTask versionTask = new VersionEndpointTask(rpcEndPoint,
- conf, ozoneContainer);
- EndpointStateMachine.EndPointStates newState = versionTask.call();
-
- Assertions.assertEquals(EndpointStateMachine.EndPointStates.REGISTER,
- newState);
-
- // assert that tmp dir is empty
- File[] leftoverContainers =
- hddsVolume.getDeletedContainerDir().listFiles();
- Assertions.assertNotNull(leftoverContainers);
- Assertions.assertEquals(0, leftoverContainers.length);
- // All DB keys have been deleted, MetadataTable should be empty
- Assertions.assertEquals(0, metadataTable.getEstimatedKeyCount());
- }
+ // versionTask.call() cleans the tmp dir and removes container from DB
+ VersionEndpointTask versionTask = new VersionEndpointTask(rpcEndPoint,
+ conf, ozoneContainer);
+ EndpointStateMachine.EndPointStates newState = versionTask.call();
+
+ Assertions.assertEquals(EndpointStateMachine.EndPointStates.REGISTER,
+ newState);
+
+ // assert that tmp dir is empty
+ File[] leftoverContainers =
+ hddsVolume.getDeletedContainerDir().listFiles();
+ Assertions.assertNotNull(leftoverContainers);
+ Assertions.assertEquals(0, leftoverContainers.length);
}
}
@@ -638,4 +596,36 @@ public class TestEndPoint {
return context;
}
+ private OzoneContainer createVolume(OzoneConfiguration conf)
+ throws IOException {
+ DatanodeDetails datanodeDetails = randomDatanodeDetails();
+ OzoneContainer ozoneContainer = new OzoneContainer(
+ datanodeDetails, conf, getContext(datanodeDetails));
+
+ String clusterId = scmServerImpl.getClusterId();
+
+ MutableVolumeSet volumeSet = ozoneContainer.getVolumeSet();
+ ContainerTestUtils.createDbInstancesForTestIfNeeded(volumeSet,
+ clusterId, clusterId, conf);
+ // VolumeSet for this test, contains only 1 volume
+ Assertions.assertEquals(1, volumeSet.getVolumesList().size());
+ StorageVolume volume = volumeSet.getVolumesList().get(0);
+
+ // Check instanceof and typecast
+ Assertions.assertTrue(volume instanceof HddsVolume);
+ return ozoneContainer;
+ }
+
+ private KeyValueContainer addContainer(
+ OzoneConfiguration conf, HddsVolume hddsVolume)
+ throws IOException {
+ String clusterId = scmServerImpl.getClusterId();
+ KeyValueContainer container = ContainerTestUtils.
+ addContainerToVolumeDir(hddsVolume, clusterId,
+ conf, OzoneConsts.SCHEMA_V3);
+ File containerDBFile = container.getContainerDBFile();
+ Assertions.assertTrue(container.getContainerFile().exists());
+ Assertions.assertTrue(containerDBFile.exists());
+ return container;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]