This is an automated email from the ASF dual-hosted git repository.
siyao 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 71087dd092 HDDS-8064. [Snapshot] Clean up FSO deletedDirTable as well
during snapshot creation (#4651)
71087dd092 is described below
commit 71087dd09252360245fbce7d8dfc0f9d9cdfcce5
Author: Siyao Meng <[email protected]>
AuthorDate: Tue May 9 12:16:54 2023 -0700
HDDS-8064. [Snapshot] Clean up FSO deletedDirTable as well during snapshot
creation (#4651)
---
.../apache/hadoop/ozone/om/OmSnapshotManager.java | 180 +++++++++++++++------
.../ozone/om/service/DirectoryDeletingService.java | 6 +-
.../ozone/om/service/KeyDeletingService.java | 6 +-
.../hadoop/ozone/om/snapshot/SnapshotUtils.java | 2 +-
.../hadoop/ozone/om/TestOmSnapshotManager.java | 51 ++++--
.../snapshot/OMSnapshotResponseTestUtil.java | 69 ++++++++
.../snapshot/TestOMSnapshotCreateResponse.java | 130 ++++++++++++---
.../snapshot/TestOMSnapshotDeleteResponse.java | 3 +-
8 files changed, 359 insertions(+), 88 deletions(-)
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
index 0120ca892f..5cdccae48e 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmSnapshotManager.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.ozone.om;
+import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
@@ -53,6 +54,7 @@ import
org.apache.hadoop.hdds.utils.db.managed.ManagedDBOptions;
import org.apache.hadoop.hdds.utils.db.managed.ManagedRocksDB;
import org.apache.hadoop.ozone.om.codec.OmDBDiffReportEntryCodec;
import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
import org.apache.hadoop.ozone.om.service.SnapshotDiffCleanupService;
@@ -372,15 +374,19 @@ public final class OmSnapshotManager implements
AutoCloseable {
// Acquire deletedTable write lock
omMetadataManager.getTableLock(OmMetadataManagerImpl.DELETED_TABLE)
.writeLock().lock();
+ // TODO: [SNAPSHOT] HDDS-8067. Acquire deletedDirectoryTable write lock
try {
// Create DB checkpoint for snapshot
dbCheckpoint = store.getSnapshot(snapshotInfo.getCheckpointDirName());
// Clean up active DB's deletedTable right after checkpoint is taken,
// with table write lock held
- deleteKeysInSnapshotScopeFromDTableInternal(omMetadataManager,
+ deleteKeysFromDelKeyTableInSnapshotScope(omMetadataManager,
+ snapshotInfo.getVolumeName(), snapshotInfo.getBucketName());
+ // Clean up deletedDirectoryTable as well
+ deleteKeysFromDelDirTableInSnapshotScope(omMetadataManager,
snapshotInfo.getVolumeName(), snapshotInfo.getBucketName());
- // TODO: [SNAPSHOT] HDDS-8064. Clean up deletedDirTable as well
} finally {
+ // TODO: [SNAPSHOT] HDDS-8067. Release deletedDirectoryTable write lock
// Release deletedTable write lock
omMetadataManager.getTableLock(OmMetadataManagerImpl.DELETED_TABLE)
.writeLock().unlock();
@@ -413,73 +419,153 @@ public final class OmSnapshotManager implements
AutoCloseable {
}
/**
- * Helper method to delete keys in the snapshot scope from active DB's
- * deletedTable.
- *
+ * Helper method to delete DB keys in the snapshot scope (bucket)
+ * from active DB's deletedDirectoryTable.
* @param omMetadataManager OMMetadataManager instance
* @param volumeName volume name
* @param bucketName bucket name
*/
- private static void deleteKeysInSnapshotScopeFromDTableInternal(
+ private static void deleteKeysFromDelDirTableInSnapshotScope(
OMMetadataManager omMetadataManager,
String volumeName,
String bucketName) throws IOException {
// Range delete start key (inclusive)
- String beginKey =
- omMetadataManager.getOzoneKey(volumeName, bucketName, "");
-
- // Range delete end key (exclusive) to be found
+ final String beginKey = getOzonePathKeyWithVolumeBucketNames(
+ omMetadataManager, volumeName, bucketName);
+ // Range delete end key (exclusive). To be calculated
String endKey;
- // Start performance tracking timer
- long startTime = System.nanoTime();
+ try (TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>>
+ iter = omMetadataManager.getDeletedDirTable().iterator()) {
+ endKey = findEndKeyGivenPrefix(iter, beginKey);
+ }
- try (TableIterator<String,
- ? extends Table.KeyValue<String, RepeatedOmKeyInfo>>
- keyIter = omMetadataManager.getDeletedTable().iterator()) {
-
- keyIter.seek(beginKey);
- // Continue only when there are entries of snapshot (bucket) scope
- // in deletedTable in the first place
- if (!keyIter.hasNext()) {
- // Use null as a marker. No need to do deleteRange() at all.
- endKey = null;
- } else {
- // Remember the last key with a matching prefix
- endKey = keyIter.next().getKey();
-
- // Loop until prefix mismatches.
- // TODO: [SNAPSHOT] Try to seek next predicted bucket name (speed up?)
- while (keyIter.hasNext()) {
- Table.KeyValue<String, RepeatedOmKeyInfo> entry = keyIter.next();
- String dbKey = entry.getKey();
- if (dbKey.startsWith(beginKey)) {
- endKey = dbKey;
- }
+ // Clean up deletedDirectoryTable
+ deleteRangeInclusive(omMetadataManager.getDeletedDirTable(),
+ beginKey, endKey);
+ }
+
+ /**
+ * Helper method to generate /volumeId/bucketId/ DB key prefix from given
+ * volume name and bucket name as a prefix in FSO deletedDirectoryTable.
+ * Follows:
+ * {@link OmMetadataManagerImpl#getOzonePathKey(long, long, long, String)}.
+ * <p>
+ * Note: Currently, this is only intended to be a special use case in
+ * {@link OmSnapshotManager}. If this is used elsewhere, consider moving this
+ * to {@link OMMetadataManager}.
+ *
+ * @param volumeName volume name
+ * @param bucketName bucket name
+ * @return /volumeId/bucketId/
+ * e.g. /-9223372036854772480/-9223372036854771968/
+ */
+ @VisibleForTesting
+ public static String getOzonePathKeyWithVolumeBucketNames(
+ OMMetadataManager omMetadataManager,
+ String volumeName,
+ String bucketName) throws IOException {
+
+ final long volumeId = omMetadataManager.getVolumeId(volumeName);
+ final long bucketId = omMetadataManager.getBucketId(volumeName,
bucketName);
+ return OM_KEY_PREFIX + volumeId + OM_KEY_PREFIX + bucketId + OM_KEY_PREFIX;
+ }
+
+ /**
+ * Helper method to locate the end key with the given prefix and iterator.
+ * @param keyIter TableIterator
+ * @param keyPrefix DB key prefix String
+ * @return endKey String, or null if no keys with such prefix is found
+ */
+ private static String findEndKeyGivenPrefix(
+ TableIterator<String, ? extends Table.KeyValue<String, ?>> keyIter,
+ String keyPrefix) throws IOException {
+
+ String endKey;
+ keyIter.seek(keyPrefix);
+ // Continue only when there are entries of snapshot (bucket) scope
+ // in deletedTable in the first place
+ if (!keyIter.hasNext()) {
+ // No key matching keyPrefix. No need to do delete or deleteRange at all.
+ endKey = null;
+ } else {
+ // Remember the last key with a matching prefix
+ endKey = keyIter.next().getKey();
+
+ // Loop until prefix mismatches.
+ // TODO: [SNAPSHOT] Try to seek to next predicted bucket name instead of
+ // the while-loop for a potential speed up?
+ // Start performance tracking timer
+ long startTime = System.nanoTime();
+ while (keyIter.hasNext()) {
+ Table.KeyValue<String, ?> entry = keyIter.next();
+ String dbKey = entry.getKey();
+ if (dbKey.startsWith(keyPrefix)) {
+ endKey = dbKey;
}
}
+ // Time took for the iterator to finish (in ns)
+ long timeElapsed = System.nanoTime() - startTime;
+ if (timeElapsed >= DB_TABLE_ITER_LOOP_THRESHOLD_NS) {
+ // Print time elapsed
+ LOG.warn("Took {} ns to find endKey. Caller is {}", timeElapsed,
+ new Throwable().fillInStackTrace().getStackTrace()[1]
+ .getMethodName());
+ }
}
+ return endKey;
+ }
- // Time took for the iterator to finish (in ns)
- long timeElapsed = System.nanoTime() - startTime;
- if (timeElapsed >= DB_TABLE_ITER_LOOP_THRESHOLD_NS) {
- // Print time elapsed
- LOG.warn("Took {} ns to clean up deletedTable", timeElapsed);
- }
+ /**
+ * Helper method to do deleteRange on a table, including endKey.
+ * TODO: Move this into {@link Table} ?
+ * @param table Table
+ * @param beginKey begin key
+ * @param endKey end key
+ */
+ private static void deleteRangeInclusive(
+ Table<String, ?> table, String beginKey, String endKey)
+ throws IOException {
if (endKey != null) {
- // Clean up deletedTable
- omMetadataManager.getDeletedTable().deleteRange(beginKey, endKey);
-
+ table.deleteRange(beginKey, endKey);
// Remove range end key itself
- omMetadataManager.getDeletedTable().delete(endKey);
+ table.delete(endKey);
}
+ }
- // Note: We do not need to invalidate deletedTable cache since entries
- // are not added to its table cache in the first place.
- // See OMKeyDeleteRequest and OMKeyPurgeRequest#validateAndUpdateCache.
+ /**
+ * Helper method to delete DB keys in the snapshot scope (bucket)
+ * from active DB's deletedTable.
+ * @param omMetadataManager OMMetadataManager instance
+ * @param volumeName volume name
+ * @param bucketName bucket name
+ */
+ private static void deleteKeysFromDelKeyTableInSnapshotScope(
+ OMMetadataManager omMetadataManager,
+ String volumeName,
+ String bucketName) throws IOException {
+
+ // Range delete start key (inclusive)
+ final String beginKey =
+ omMetadataManager.getOzoneKey(volumeName, bucketName, "");
+ // Range delete end key (exclusive). To be found
+ String endKey;
+ try (TableIterator<String,
+ ? extends Table.KeyValue<String, RepeatedOmKeyInfo>>
+ iter = omMetadataManager.getDeletedTable().iterator()) {
+ endKey = findEndKeyGivenPrefix(iter, beginKey);
+ }
+
+ // Clean up deletedTable
+ deleteRangeInclusive(omMetadataManager.getDeletedTable(), beginKey,
endKey);
+
+ // No need to invalidate deletedTable (or deletedDirectoryTable) table
+ // cache since entries are not added to its table cache in the first place.
+ // See OMKeyDeleteRequest and OMKeyPurgeRequest#validateAndUpdateCache.
+ //
// This makes the table clean up efficient as we only need one
// deleteRange() operation. No need to invalidate cache entries
// one by one.
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/DirectoryDeletingService.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/DirectoryDeletingService.java
index ceed9ebe9a..a59b6f9041 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/DirectoryDeletingService.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/DirectoryDeletingService.java
@@ -108,7 +108,7 @@ public class DirectoryDeletingService extends
AbstractKeyDeletingService {
}
@Override
- public BackgroundTaskResult call() throws Exception {
+ public BackgroundTaskResult call() {
if (shouldRun()) {
if (LOG.isDebugEnabled()) {
LOG.debug("Running DirectoryDeletingService");
@@ -122,6 +122,8 @@ public class DirectoryDeletingService extends
AbstractKeyDeletingService {
List<Pair<String, OmKeyInfo>> allSubDirList
= new ArrayList<>((int) remainNum);
+ // TODO: [SNAPSHOT] HDDS-8067. Acquire deletedDirectoryTable write lock
+
Table.KeyValue<String, OmKeyInfo> pendingDeletedDirInfo;
try (TableIterator<String, ? extends KeyValue<String, OmKeyInfo>>
deleteTableIterator = getOzoneManager().getMetadataManager().
@@ -159,6 +161,8 @@ public class DirectoryDeletingService extends
AbstractKeyDeletingService {
LOG.error("Error while running delete directories and files " +
"background task. Will retry at next run.", e);
}
+ // TODO: [SNAPSHOT] HDDS-8067. Release deletedDirectoryTable write lock
+ // in finally block
}
// place holder by returning empty results of this call back.
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/KeyDeletingService.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/KeyDeletingService.java
index 284eb9aa11..5cf186428e 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/KeyDeletingService.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/KeyDeletingService.java
@@ -113,7 +113,7 @@ public class KeyDeletingService extends
AbstractKeyDeletingService {
}
@Override
- public BackgroundTaskResult call() throws Exception {
+ public BackgroundTaskResult call() {
// Check if this is the Leader OM. If not leader, no need to execute this
// task.
if (shouldRun()) {
@@ -125,6 +125,8 @@ public class KeyDeletingService extends
AbstractKeyDeletingService {
// OM would have to keep track of which snapshot the key is coming
// from. And PurgeKeysRequest would have to be adjusted to be able
// to operate on snapshot checkpoints.
+
+ // TODO: [SNAPSHOT] HDDS-8067. Acquire deletedTable write lock
List<BlockGroup> keyBlocksList = manager
.getPendingDeletionKeys(keyLimitPerTask);
if (keyBlocksList != null && !keyBlocksList.isEmpty()) {
@@ -136,6 +138,8 @@ public class KeyDeletingService extends
AbstractKeyDeletingService {
LOG.error("Error while running delete keys background task. Will " +
"retry at next run.", e);
}
+ // TODO: [SNAPSHOT] HDDS-8067. Release deletedTable write lock
+ // in finally block
}
// By design, no one cares about the results of this call back.
return EmptyTaskResult.newResult();
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotUtils.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotUtils.java
index 5491c54611..096218585d 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotUtils.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotUtils.java
@@ -63,7 +63,7 @@ public final class SnapshotUtils {
.getSnapshotInfoTable()
.get(snapshotKey);
} catch (IOException e) {
- LOG.error("Snapshot {}: not found.", snapshotKey, e);
+ LOG.error("Snapshot '{}' is not found.", snapshotKey, e);
throw e;
}
if (snapshotInfo == null) {
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
index 6287cc00cb..cd1589ee63 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshotManager.java
@@ -26,6 +26,8 @@ import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.scm.HddsWhiteboxTestUtils;
import org.apache.hadoop.hdds.utils.db.DBStore;
import org.apache.hadoop.hdds.utils.db.Table;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
import org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils;
import org.apache.ozone.test.GenericTestUtils;
@@ -47,6 +49,9 @@ import static
org.apache.hadoop.ozone.OzoneConsts.OM_CHECKPOINT_DIR;
import static org.apache.hadoop.ozone.OzoneConsts.OM_DB_NAME;
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
import static org.apache.hadoop.ozone.OzoneConsts.OM_SNAPSHOT_CHECKPOINT_DIR;
+import static org.apache.hadoop.ozone.OzoneConsts.SNAPSHOT_INFO_TABLE;
+import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.BUCKET_TABLE;
+import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.VOLUME_TABLE;
import static org.apache.hadoop.ozone.om.OmSnapshotManager.OM_HARDLINK_FILE;
import static org.apache.hadoop.ozone.om.snapshot.OmSnapshotUtils.getINode;
import static org.apache.hadoop.ozone.om.OmSnapshotManager.getSnapshotPrefix;
@@ -91,14 +96,39 @@ public class TestOmSnapshotManager {
@Test
public void testCloseOnEviction() throws IOException {
- // set up db table
- SnapshotInfo first = createSnapshotInfo();
- SnapshotInfo second = createSnapshotInfo();
+ // set up db tables
+ Table<String, OmVolumeArgs> volumeTable = mock(Table.class);
+ Table<String, OmBucketInfo> bucketTable = mock(Table.class);
Table<String, SnapshotInfo> snapshotInfoTable = mock(Table.class);
+ HddsWhiteboxTestUtils.setInternalState(
+ om.getMetadataManager(), VOLUME_TABLE, volumeTable);
+ HddsWhiteboxTestUtils.setInternalState(
+ om.getMetadataManager(), BUCKET_TABLE, bucketTable);
+ HddsWhiteboxTestUtils.setInternalState(
+ om.getMetadataManager(), SNAPSHOT_INFO_TABLE, snapshotInfoTable);
+
+ final String volumeName = UUID.randomUUID().toString();
+ final String dbVolumeKey =
om.getMetadataManager().getVolumeKey(volumeName);
+ final OmVolumeArgs omVolumeArgs = OmVolumeArgs.newBuilder()
+ .setVolume(volumeName)
+ .setAdminName("bilbo")
+ .setOwnerName("bilbo")
+ .build();
+ when(volumeTable.get(dbVolumeKey)).thenReturn(omVolumeArgs);
+
+ String bucketName = UUID.randomUUID().toString();
+ final String dbBucketKey = om.getMetadataManager().getBucketKey(
+ volumeName, bucketName);
+ final OmBucketInfo omBucketInfo = OmBucketInfo.newBuilder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .build();
+ when(bucketTable.get(dbBucketKey)).thenReturn(omBucketInfo);
+
+ SnapshotInfo first = createSnapshotInfo(volumeName, bucketName);
+ SnapshotInfo second = createSnapshotInfo(volumeName, bucketName);
when(snapshotInfoTable.get(first.getTableKey())).thenReturn(first);
when(snapshotInfoTable.get(second.getTableKey())).thenReturn(second);
- HddsWhiteboxTestUtils.setInternalState(
- om.getMetadataManager(), "snapshotInfoTable", snapshotInfoTable);
// create the first snapshot checkpoint
OmSnapshotManager.createOmSnapshotCheckpoint(om.getMetadataManager(),
@@ -188,15 +218,12 @@ public class TestOmSnapshotManager {
}
}
- private SnapshotInfo createSnapshotInfo() {
+ private SnapshotInfo createSnapshotInfo(
+ String volumeName, String bucketName) {
String snapshotName = UUID.randomUUID().toString();
- String volumeName = UUID.randomUUID().toString();
- String bucketName = UUID.randomUUID().toString();
String snapshotId = UUID.randomUUID().toString();
- return SnapshotInfo.newInstance(volumeName,
- bucketName,
- snapshotName,
- snapshotId);
+ return SnapshotInfo.newInstance(
+ volumeName, bucketName, snapshotName, snapshotId);
}
}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotResponseTestUtil.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotResponseTestUtil.java
new file mode 100644
index 0000000000..577d6ac9dd
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/OMSnapshotResponseTestUtil.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.hadoop.ozone.om.response.snapshot;
+
+import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
+import org.apache.hadoop.hdds.utils.db.cache.CacheValue;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.helpers.OmBucketInfo;
+import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
+
+import java.io.IOException;
+
+/**
+ * Common test utility method(s) shared between
+ * {@link TestOMSnapshotCreateResponse} and
+ * {@link TestOMSnapshotDeleteResponse}.
+ */
+public final class OMSnapshotResponseTestUtil {
+
+ private OMSnapshotResponseTestUtil() {
+ throw new IllegalStateException("Util class should not be initialized.");
+ }
+
+ static void addVolumeBucketInfoToTable(OMMetadataManager omMetadataManager,
+ String volumeName,
+ String bucketName)
+ throws IOException {
+
+ // Add volume entry to volumeTable for volumeId lookup
+ final OmVolumeArgs omVolumeArgs = OmVolumeArgs.newBuilder()
+ .setVolume(volumeName)
+ .setAdminName("bilbo")
+ .setOwnerName("bilbo")
+ .build();
+ final String dbVolumeKey = omMetadataManager.getVolumeKey(volumeName);
+ omMetadataManager.getVolumeTable().addCacheEntry(
+ new CacheKey<>(dbVolumeKey),
+ CacheValue.get(1L, omVolumeArgs));
+ omMetadataManager.getVolumeTable().put(dbVolumeKey, omVolumeArgs);
+
+ // Add bucket entry to bucketTable for bucketId lookup
+ final OmBucketInfo omBucketInfo = OmBucketInfo.newBuilder()
+ .setVolumeName(volumeName)
+ .setBucketName(bucketName)
+ .build();
+ final String dbBucketKey = omMetadataManager.getBucketKey(
+ volumeName, bucketName);
+ omMetadataManager.getBucketTable().addCacheEntry(
+ new CacheKey<>(dbBucketKey),
+ CacheValue.get(2L, omBucketInfo));
+ omMetadataManager.getBucketTable().put(dbBucketKey, omBucketInfo);
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotCreateResponse.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotCreateResponse.java
index f8a67fbe96..8ec9e2713c 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotCreateResponse.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotCreateResponse.java
@@ -26,8 +26,11 @@ import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
+import org.apache.hadoop.hdds.client.StandaloneReplicationConfig;
import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.hdds.utils.db.TableIterator;
+import org.apache.hadoop.ozone.om.OmSnapshotManager;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
import org.junit.After;
@@ -47,6 +50,8 @@ import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
.OMResponse;
import org.apache.hadoop.hdds.utils.db.BatchOperation;
+
+import static
org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.ONE;
import static org.apache.hadoop.ozone.om.OmSnapshotManager.getSnapshotPath;
/**
@@ -60,6 +65,7 @@ public class TestOMSnapshotCreateResponse {
private OMMetadataManager omMetadataManager;
private BatchOperation batchOperation;
private OzoneConfiguration ozoneConfiguration;
+
@Before
public void setup() throws Exception {
ozoneConfiguration = new OzoneConfiguration();
@@ -93,9 +99,11 @@ public class TestOMSnapshotCreateResponse {
omMetadataManager
.countRowsInTable(omMetadataManager.getSnapshotInfoTable()));
- // Prepare for deletedTable clean up logic verification
- Set<String> dtSentinelKeys = addTestKeysToDeletedTable(
- volumeName, bucketName);
+ // Populate deletedTable and deletedDirectoryTable
+ Set<String> dtSentinelKeys =
+ addTestKeysToDeletedTable(volumeName, bucketName);
+ Set<String> ddtSentinelKeys =
+ addTestKeysToDeletedDirTable(volumeName, bucketName);
// commit to table
OMSnapshotCreateResponse omSnapshotCreateResponse =
@@ -124,8 +132,9 @@ public class TestOMSnapshotCreateResponse {
Assert.assertEquals(snapshotInfo.getTableKey(), keyValue.getKey());
Assert.assertEquals(snapshotInfo, storedInfo);
- // Check deletedTable clean up works as expected
+ // Check deletedTable and deletedDirectoryTable clean up work as expected
verifyEntriesLeftInDeletedTable(dtSentinelKeys);
+ verifyEntriesLeftInDeletedDirTable(ddtSentinelKeys);
}
private Set<String> addTestKeysToDeletedTable(
@@ -134,60 +143,131 @@ public class TestOMSnapshotCreateResponse {
RepeatedOmKeyInfo dummyRepeatedKeyInfo = new RepeatedOmKeyInfo.Builder()
.setOmKeyInfos(new ArrayList<>()).build();
- // Add deletedTable key entries that surround the snapshot scope
- Set<String> dtSentinelKeys = new HashSet<>();
+ // Add deletedTable key entries that "surround" the snapshot scope
+ Set<String> sentinelKeys = new HashSet<>();
// Get a bucket name right before and after the bucketName
// e.g. When bucketName is buck2, bucketNameBefore is buck1,
// bucketNameAfter is buck3
// This will not guarantee the bucket name is valid for Ozone but
// this would be good enough for this unit test.
char bucketNameLastChar = bucketName.charAt(bucketName.length() - 1);
+
String bucketNameBefore = bucketName.substring(0, bucketName.length() - 1)
+
- Character.toString((char)(bucketNameLastChar - 1));
+ (char) (bucketNameLastChar - 1);
for (int i = 0; i < 3; i++) {
String dtKey = omMetadataManager.getOzoneKey(volumeName,
bucketNameBefore,
"dtkey" + i);
omMetadataManager.getDeletedTable().put(dtKey, dummyRepeatedKeyInfo);
- dtSentinelKeys.add(dtKey);
+ sentinelKeys.add(dtKey);
}
+
String bucketNameAfter = bucketName.substring(0, bucketName.length() - 1) +
- Character.toString((char)(bucketNameLastChar + 1));
+ (char) (bucketNameLastChar + 1);
for (int i = 0; i < 3; i++) {
String dtKey = omMetadataManager.getOzoneKey(volumeName, bucketNameAfter,
"dtkey" + i);
omMetadataManager.getDeletedTable().put(dtKey, dummyRepeatedKeyInfo);
- dtSentinelKeys.add(dtKey);
+ sentinelKeys.add(dtKey);
}
+
// Add deletedTable key entries in the snapshot (bucket) scope
for (int i = 0; i < 10; i++) {
String dtKey = omMetadataManager.getOzoneKey(volumeName, bucketName,
"dtkey" + i);
omMetadataManager.getDeletedTable().put(dtKey, dummyRepeatedKeyInfo);
+ // These are the keys that should be deleted.
+ // Thus not added to sentinelKeys list.
+ }
+
+ return sentinelKeys;
+ }
+
+ /**
+ * Populates deletedDirectoryTable for the test.
+ * @param volumeName volume name
+ * @param bucketName bucket name
+ * @return A set of DB keys
+ */
+ private Set<String> addTestKeysToDeletedDirTable(
+ String volumeName, String bucketName) throws IOException {
+
+ OMSnapshotResponseTestUtil.addVolumeBucketInfoToTable(
+ omMetadataManager, volumeName, bucketName);
+
+ final OmKeyInfo dummyOmKeyInfo = new OmKeyInfo.Builder()
+ .setBucketName(bucketName)
+ .setVolumeName(volumeName)
+ .setKeyName("dummyKey")
+ .setReplicationConfig(StandaloneReplicationConfig.getInstance(ONE))
+ .build();
+ // Add deletedDirectoryTable key entries that "surround" the snapshot scope
+ Set<String> sentinelKeys = new HashSet<>();
+
+ final String dbKeyPfx =
+ OmSnapshotManager.getOzonePathKeyWithVolumeBucketNames(
+ omMetadataManager, volumeName, bucketName);
+
+ // Calculate offset to bucketId's last character in dbKeyPfx.
+ // First -1 for offset, second -1 for second to last char (before '/')
+ final int offset = dbKeyPfx.length() - 1 - 1;
+
+ char bucketIdLastChar = dbKeyPfx.charAt(offset);
+
+ String dbKeyPfxBefore = dbKeyPfx.substring(0, offset) +
+ (char) (bucketIdLastChar - 1) + dbKeyPfx.substring(offset);
+ for (int i = 0; i < 3; i++) {
+ String dtKey = dbKeyPfxBefore + "dir" + i;
+ omMetadataManager.getDeletedDirTable().put(dtKey, dummyOmKeyInfo);
+ sentinelKeys.add(dtKey);
+ }
+
+ String dbKeyPfxAfter = dbKeyPfx.substring(0, offset) +
+ (char) (bucketIdLastChar + 1) + dbKeyPfx.substring(offset);
+ for (int i = 0; i < 3; i++) {
+ String dtKey = dbKeyPfxAfter + "dir" + i;
+ omMetadataManager.getDeletedDirTable().put(dtKey, dummyOmKeyInfo);
+ sentinelKeys.add(dtKey);
+ }
+
+ // Add key entries in the snapshot (bucket) scope
+ for (int i = 0; i < 10; i++) {
+ String dtKey = dbKeyPfx + "dir" + i;
+ omMetadataManager.getDeletedDirTable().put(dtKey, dummyOmKeyInfo);
+ // These are the keys that should be deleted.
+ // Thus not added to sentinelKeys list.
}
- return dtSentinelKeys;
+ return sentinelKeys;
}
- private void verifyEntriesLeftInDeletedTable(Set<String> dtSentinelKeys)
+ private void verifyEntriesLeftInDeletedTable(Set<String> expectedKeys)
throws IOException {
+ // Only keys inside the snapshot scope would be deleted from deletedTable.
+ verifyEntriesLeftInTable(omMetadataManager.getDeletedTable(),
expectedKeys);
+ }
+
+ private void verifyEntriesLeftInDeletedDirTable(Set<String> expectedKeys)
+ throws IOException {
+ verifyEntriesLeftInTable(omMetadataManager.getDeletedDirTable(),
+ expectedKeys);
+ }
+
+ private void verifyEntriesLeftInTable(
+ Table<String, ?> table, Set<String> expectedKeys) throws IOException {
- // Verify that only keys inside the snapshot scope are gone from
- // deletedTable.
- try (TableIterator<String,
- ? extends Table.KeyValue<String, RepeatedOmKeyInfo>>
- keyIter = omMetadataManager.getDeletedTable().iterator()) {
+ try (TableIterator<String, ? extends Table.KeyValue<String, ?>>
+ keyIter = table.iterator()) {
keyIter.seekToFirst();
while (keyIter.hasNext()) {
- Table.KeyValue<String, RepeatedOmKeyInfo> entry = keyIter.next();
- String dtKey = entry.getKey();
- // deletedTable should not have bucketName keys
- Assert.assertTrue("deletedTable should contain key",
- dtSentinelKeys.contains(dtKey));
- dtSentinelKeys.remove(dtKey);
+ Table.KeyValue<String, ?> entry = keyIter.next();
+ String dbKey = entry.getKey();
+ Assert.assertTrue(table.getName() + " should contain key",
+ expectedKeys.contains(dbKey));
+ expectedKeys.remove(dbKey);
}
}
- Assert.assertTrue("deletedTable is missing keys that should be there",
- dtSentinelKeys.isEmpty());
+ Assert.assertTrue(table.getName() + " is missing keys that should be
there",
+ expectedKeys.isEmpty());
}
}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotDeleteResponse.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotDeleteResponse.java
index bfbeeafb2b..296636ed51 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotDeleteResponse.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/snapshot/TestOMSnapshotDeleteResponse.java
@@ -47,7 +47,6 @@ import java.util.UUID;
import static
org.apache.hadoop.ozone.om.helpers.SnapshotInfo.SnapshotStatus.SNAPSHOT_ACTIVE;
import static
org.apache.hadoop.ozone.om.helpers.SnapshotInfo.SnapshotStatus.SNAPSHOT_DELETED;
-
/**
* This class tests OMSnapshotDeleteResponse.
*/
@@ -94,6 +93,8 @@ public class TestOMSnapshotDeleteResponse {
.countRowsInTable(omMetadataManager.getSnapshotInfoTable()));
// Prepare the table, write an entry with SnapshotCreate
+ OMSnapshotResponseTestUtil.addVolumeBucketInfoToTable(
+ omMetadataManager, volumeName, bucketName);
OMSnapshotCreateResponse omSnapshotCreateResponse =
new OMSnapshotCreateResponse(OMResponse.newBuilder()
.setCmdType(Type.CreateSnapshot)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]