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

hemant 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 f6f1769059 HDDS-9597. Snapdiff fails in case of key renames to deleted 
directories (#5526)
f6f1769059 is described below

commit f6f176905972f164292f655bd61712043e2a07b6
Author: Swaminathan Balachandran <[email protected]>
AuthorDate: Thu Nov 9 11:16:17 2023 -0800

    HDDS-9597. Snapdiff fails in case of key renames to deleted directories 
(#5526)
---
 .../org/apache/hadoop/ozone/om/TestOmSnapshot.java | 39 ++++++++++
 .../om/snapshot/FSODirectoryPathResolver.java      |  7 +-
 .../ozone/om/snapshot/ObjectPathResolver.java      |  8 ++-
 .../ozone/om/snapshot/SnapshotDiffManager.java     | 83 +++++++++++++---------
 .../om/snapshot/TestFSODirectoryPathResolver.java  |  4 +-
 5 files changed, 103 insertions(+), 38 deletions(-)

diff --git 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshot.java
 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshot.java
index 096d21d8e9..8d33ab999a 100644
--- 
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshot.java
+++ 
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOmSnapshot.java
@@ -1068,6 +1068,45 @@ public class TestOmSnapshot {
     Assert.assertEquals(diff.getDiffList(), diffEntries);
   }
 
+  /**
+   * Testing scenario:
+   * 1) Key k1 is created.
+   * 2) Snapshot snap1 created.
+   * 3) Dir dir1/dir2 is created.
+   * 4) Key k1 is renamed to key dir1/dir2/k1_renamed
+   * 5) Dir dir1 is deleted.
+   * 6) Snapshot snap2 created.
+   * 5) Snapdiff b/w snapshot of Active FS & snap1 taken to assert difference
+   *    of 1 delete key entry.
+   */
+  @Test
+  public void testSnapDiffWithDirectoryDelete() throws Exception {
+    Assume.assumeTrue(bucketLayout.isFileSystemOptimized());
+    String testVolumeName = "vol" + counter.incrementAndGet();
+    String testBucketName = "bucket1";
+    store.createVolume(testVolumeName);
+    OzoneVolume volume = store.getVolume(testVolumeName);
+    volume.createBucket(testBucketName);
+    OzoneBucket bucket = volume.getBucket(testBucketName);
+    String snap1 = "snap1";
+    String key1 = "k1";
+    key1 = createFileKeyWithPrefix(bucket, key1);
+    createSnapshot(testVolumeName, testBucketName, snap1);
+    bucket.createDirectory("dir1/dir2");
+    String key1Renamed = "dir1/dir2/" + key1 + "_renamed";
+    bucket.renameKey(key1, key1Renamed);
+    bucket.deleteDirectory("dir1", true);
+    String snap2 = "snap2";
+    createSnapshot(testVolumeName, testBucketName, snap2);
+    SnapshotDiffReport diff = getSnapDiffReport(testVolumeName, testBucketName,
+        snap1, snap2);
+
+    List<SnapshotDiffReport.DiffReportEntry> diffEntries = Lists.newArrayList(
+        SnapshotDiffReportOzone.getDiffReportEntry(
+            SnapshotDiffReport.DiffType.DELETE, key1));
+    Assert.assertEquals(diff.getDiffList(), diffEntries);
+  }
+
   private OzoneObj buildKeyObj(OzoneBucket bucket, String key) {
     return OzoneObjInfo.Builder.newBuilder()
         .setResType(OzoneObj.ResourceType.KEY)
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/FSODirectoryPathResolver.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/FSODirectoryPathResolver.java
index 0d0bcb2276..d37a37f20b 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/FSODirectoryPathResolver.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/FSODirectoryPathResolver.java
@@ -66,12 +66,15 @@ public class FSODirectoryPathResolver implements 
ObjectPathResolver {
    * Assuming all dirObjIds belong to a bucket this function resolves absolute
    * path for a given FSO bucket.
    * @param dirObjIds Object Ids corresponding to which absolute path is 
needed.
+   * @param skipUnresolvedObjs boolean value to skipUnresolved objects when
+   *                           false exception will be thrown.
    * @return Map of Path corresponding to provided directory object IDs
    */
   @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
   @Override
   public Map<Long, Path> getAbsolutePathForObjectIDs(
-      Optional<Set<Long>> dirObjIds) throws IOException {
+      Optional<Set<Long>> dirObjIds, boolean skipUnresolvedObjs)
+      throws IOException {
     // Root of a bucket would always have the
     // key as /volumeId/bucketId/bucketId/
     if (!dirObjIds.isPresent() || dirObjIds.get().isEmpty()) {
@@ -100,7 +103,7 @@ public class FSODirectoryPathResolver implements 
ObjectPathResolver {
       }
     }
     // Invalid directory objectId which does not exist in the given bucket.
-    if (objIds.size() > 0) {
+    if (objIds.size() > 0 && !skipUnresolvedObjs) {
       throw new IllegalArgumentException(
           "Dir object Ids required but not found in bucket: " + objIds);
     }
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/ObjectPathResolver.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/ObjectPathResolver.java
index b9c5bb0c45..dc6afed649 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/ObjectPathResolver.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/ObjectPathResolver.java
@@ -29,6 +29,12 @@ import java.util.Set;
  */
 public interface ObjectPathResolver {
 
-  Map<Long, Path> getAbsolutePathForObjectIDs(Optional<Set<Long>> objIds)
+  Map<Long, Path> getAbsolutePathForObjectIDs(Optional<Set<Long>> objIds,
+                                              boolean skipUnresolvedObjs)
       throws IOException;
+
+  default Map<Long, Path> getAbsolutePathForObjectIDs(
+      Optional<Set<Long>> objIds) throws IOException {
+    return getAbsolutePathForObjectIDs(objIds, false);
+  }
 }
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotDiffManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotDiffManager.java
index 0b38607f81..e0cba9575f 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotDiffManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotDiffManager.java
@@ -962,7 +962,7 @@ public class SnapshotDiffManager implements AutoCloseable {
               newParentIdPathMap.get().putAll(new FSODirectoryPathResolver(
                   tablePrefix, bucketId,
                   toSnapshot.getMetadataManager().getDirectoryTable())
-                  .getAbsolutePathForObjectIDs(newParentIds));
+                  .getAbsolutePathForObjectIDs(newParentIds, true));
             }
             return null;
           },
@@ -1248,16 +1248,22 @@ public class SnapshotDiffManager implements 
AutoCloseable {
 
   @SuppressFBWarnings("DMI_HARDCODED_ABSOLUTE_FILENAME")
   private String resolveBucketRelativePath(boolean isFSOBucket,
-      final Optional<Map<Long, Path>> parentIdMap, byte[] keyVal)
+      final Optional<Map<Long, Path>> parentIdMap, byte[] keyVal,
+      boolean skipUnresolvedObjIds)
       throws IOException {
     String key = codecRegistry.asObject(keyVal, String.class);
     if (isFSOBucket) {
       String[] splitKey = key.split(OM_KEY_PREFIX, 2);
       Long parentId = Long.valueOf(splitKey[0]);
       if (parentIdMap.map(m -> !m.containsKey(parentId)).orElse(true)) {
-        throw new IllegalStateException(String.format(
-            "Cannot resolve path for key: %s with parent Id: %d", key,
-            parentId));
+        if (skipUnresolvedObjIds) {
+          return null;
+        } else {
+          throw new IllegalStateException(String.format(
+              "Cannot resolve path for key: %s with parent Id: %d", key,
+              parentId));
+        }
+
       }
       return parentIdMap.map(m -> m.get(parentId).resolve(splitKey[1]))
           .get().toString().substring(1);
@@ -1350,47 +1356,56 @@ public class SnapshotDiffManager implements 
AutoCloseable {
                 "Old and new key name both are null");
           } else if (oldKeyName == null) { // Key Created.
             String key = resolveBucketRelativePath(isFSOBucket,
-                newParentIdPathMap, newKeyName);
-            DiffReportEntry entry =
-                SnapshotDiffReportOzone.getDiffReportEntry(CREATE, key);
-            createDiffs.add(codecRegistry.asRawData(entry));
+                newParentIdPathMap, newKeyName, true);
+            if (key != null) {
+              DiffReportEntry entry =
+                  SnapshotDiffReportOzone.getDiffReportEntry(CREATE, key);
+              createDiffs.add(codecRegistry.asRawData(entry));
+            }
           } else if (newKeyName == null) { // Key Deleted.
             String key = resolveBucketRelativePath(isFSOBucket,
-                oldParentIdPathMap, oldKeyName);
+                oldParentIdPathMap, oldKeyName, false);
             DiffReportEntry entry =
                 SnapshotDiffReportOzone.getDiffReportEntry(DELETE, key);
             deleteDiffs.add(codecRegistry.asRawData(entry));
           } else if (isDirectoryObject &&
               Arrays.equals(oldKeyName, newKeyName)) {
             String key = resolveBucketRelativePath(isFSOBucket,
-                newParentIdPathMap, newKeyName);
-            DiffReportEntry entry =
-                SnapshotDiffReportOzone.getDiffReportEntry(MODIFY, key);
-            modifyDiffs.add(codecRegistry.asRawData(entry));
+                newParentIdPathMap, newKeyName, true);
+            if (key != null) {
+              DiffReportEntry entry =
+                  SnapshotDiffReportOzone.getDiffReportEntry(MODIFY, key);
+              modifyDiffs.add(codecRegistry.asRawData(entry));
+            }
           } else {
             String keyPrefix = getTablePrefix(tablePrefix,
                 (isDirectoryObject ? fsDirTable : fsTable).getName());
             String oldKey = resolveBucketRelativePath(isFSOBucket,
-                oldParentIdPathMap, oldKeyName);
-            // Check if block location is same or not. If it is not same,
-            // key must have been overridden as well.
-            boolean isObjectModified = isObjectModified(
-                keyPrefix + codecRegistry.asObject(oldKeyName, String.class),
-                keyPrefix + codecRegistry.asObject(newKeyName, String.class),
-                isDirectoryObject ? fsDirTable : fsTable,
-                isDirectoryObject ? tsDirTable : tsTable);
-            if (isObjectModified) {
-              // Here, oldKey name is returned as modified. Modified key name 
is
-              // based on base snapshot (from snapshot).
-              modifyDiffs.add(codecRegistry.asRawData(
-                  SnapshotDiffReportOzone.getDiffReportEntry(MODIFY, oldKey)));
-            }
-            if (!isObjectModified || !Arrays.equals(oldKeyName, newKeyName)) {
-              String newKey = resolveBucketRelativePath(isFSOBucket,
-                  newParentIdPathMap, newKeyName);
-              renameDiffs.add(codecRegistry.asRawData(
-                  SnapshotDiffReportOzone.getDiffReportEntry(RENAME, oldKey,
-                      newKey)));
+                oldParentIdPathMap, oldKeyName, false);
+            String newKey = resolveBucketRelativePath(isFSOBucket,
+                newParentIdPathMap, newKeyName, true);
+            if (newKey == null) {
+              deleteDiffs.add(codecRegistry.asRawData(SnapshotDiffReportOzone
+                  .getDiffReportEntry(DELETE, oldKey)));
+            } else {
+              // Check if block location is same or not. If it is not same,
+              // key must have been overridden as well.
+              boolean isObjectModified = isObjectModified(
+                  keyPrefix + codecRegistry.asObject(oldKeyName, String.class),
+                  keyPrefix + codecRegistry.asObject(newKeyName, String.class),
+                  isDirectoryObject ? fsDirTable : fsTable,
+                  isDirectoryObject ? tsDirTable : tsTable);
+              if (isObjectModified) {
+                // Here, oldKey name is returned as modified. Modified key name
+                // is based on base snapshot (from snapshot).
+                modifyDiffs.add(codecRegistry.asRawData(SnapshotDiffReportOzone
+                    .getDiffReportEntry(MODIFY, oldKey)));
+              }
+              if (!isObjectModified || !Arrays.equals(oldKeyName, newKeyName)) 
{
+                renameDiffs.add(codecRegistry.asRawData(
+                    SnapshotDiffReportOzone.getDiffReportEntry(RENAME, oldKey,
+                        newKey)));
+              }
             }
           }
 
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestFSODirectoryPathResolver.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestFSODirectoryPathResolver.java
index f56b8657e4..22120409f9 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestFSODirectoryPathResolver.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestFSODirectoryPathResolver.java
@@ -127,6 +127,8 @@ public class TestFSODirectoryPathResolver {
         new FSODirectoryPathResolver(prefix, 1,
             getMockedDirectoryInfoTable(prefix, dirMap));
     Set<Long> objIds = Sets.newHashSet(17L, 9L, 10L, 15L, 4L, 3L, 1L);
+    Set<Long> invalidObjIds = Sets.newHashSet(17L, 9L, 10L, 15L, 4L, 3L, 1L,
+        19L);
     Map<Long, Path> absolutePathMap = fsoDirectoryPathResolver
         .getAbsolutePathForObjectIDs(Optional.of(objIds));
 
@@ -143,7 +145,7 @@ public class TestFSODirectoryPathResolver {
     // Invalid Obj Id 19 with dirInfo dir19 which is not present in the bucket.
     Assertions.assertThrows(IllegalArgumentException.class,
         () -> fsoDirectoryPathResolver.getAbsolutePathForObjectIDs(
-            Optional.of(Sets.newHashSet(17L, 9L, 10L, 15L, 4L, 3L, 1L, 19L))),
+            Optional.of(invalidObjIds)),
         "Dir object Ids required but not found in bucket: [19]");
   }
 


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

Reply via email to