echonesis commented on code in PR #11841:
URL: https://github.com/apache/ozone/pull/11841#discussion_r4438408844


##########
hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/snapshot/TestSnapshotDiffManager.java:
##########
@@ -368,19 +373,118 @@ public void init() throws RocksDBException, IOException, 
ExecutionException {
     SnapshotCache snapshotCache = new SnapshotCache(mockCacheLoader(), 10, 
omMetrics, 0, true,
         new OmReadOnlyLock());
 
-    when(omSnapshotManager.getActiveSnapshot(anyString(), anyString(), 
anyString()))
-        .thenAnswer(invocationOnMock -> {
-          SnapshotInfo snapInfo = SnapshotUtils.getSnapshotInfo(ozoneManager, 
invocationOnMock.getArgument(0),
-              invocationOnMock.getArgument(1), 
invocationOnMock.getArgument(2));
-          return snapshotCache.get(snapInfo.getSnapshotId());
-        });
+    HddsWhiteboxTestUtils.setInternalState(omSnapshotManager, "ozoneManager", 
ozoneManager);
+    HddsWhiteboxTestUtils.setInternalState(omSnapshotManager, "snapshotCache", 
snapshotCache);
+    Mockito.doCallRealMethod().when(omSnapshotManager)
+        .getActiveSnapshot(anyString(), anyString(), anyString(), 
any(UUID.class));
     when(ozoneManager.getOmSnapshotManager()).thenReturn(omSnapshotManager);
     snapshotDiffManager = new SnapshotDiffManager(db, ozoneManager,
         snapDiffJobTable, snapDiffReportTable, snapDiffPurgedJobTable,
         columnFamilyOptions, codecRegistry);
     when(omSnapshotManager.getDiffCleanupServiceInterval()).thenReturn(0L);
   }
 
+  @ParameterizedTest
+  @CsvSource({"0, false, false", "1, false, false", "2, false, false", "3, 
false, false",
+      "3, true, false", "0, false, true", "1, false, true", "2, false, true", 
"3, false, true", "3, true, true"})
+  public void testSnapshotDiffLocks(int failOnOpen, boolean sameSnapshot, 
boolean optimized) throws Exception {
+    SnapshotInfo from = snapshotInfo;
+    SnapshotInfo to = sameSnapshot ? from : snapshotInfoList.get(0);
+    OzoneManagerLock lock = new OzoneManagerLock(new OzoneConfiguration());
+    when(omMetadataManager.getLock()).thenReturn(lock);
+    try (SnapshotCache cache = new SnapshotCache(mockCacheLoader(), 10, 
ozoneManager.getMetrics(), 0, true, lock)) {
+      SnapshotDiffManager manager = 
spy(newSnapshotDiffManagerWithOptimizedEnabled(optimized));
+      doReturn(failOnOpen != 0, 
false).when(manager).areDiffJobAndSnapshotsActive(
+          VOLUME_NAME, BUCKET_NAME, from.getName(), to.getName());
+      AtomicInteger opens = new AtomicInteger();
+      OmSnapshotManager omSnapshotManager = 
ozoneManager.getOmSnapshotManager();
+      doAnswer(invocation -> {
+        // Both stripes must be held before even the first snapshot is opened.
+        assertTrue(lock.getReadHoldCount(SNAPSHOT_DB_LOCK, 
from.getSnapshotId().toString()) > 0);
+        assertTrue(lock.getReadHoldCount(SNAPSHOT_DB_LOCK, 
to.getSnapshotId().toString()) > 0);
+        if (opens.incrementAndGet() == failOnOpen) {
+          throw new IOException("Snapshot load failed");
+        }
+        String name = invocation.getArgument(2);
+        return cache.get(name.equals(from.getName()) ? from.getSnapshotId() : 
to.getSnapshotId());
+      }).when(omSnapshotManager).getActiveSnapshot(anyString(), anyString(), 
anyString(), any(UUID.class));
+      String jobKey = generateSnapDiffJobKey.apply(from, to);
+      String jobId = UUID.randomUUID().toString();
+      manager.getSnapDiffJobTable().put(jobKey, new 
SnapshotDiffJob(System.currentTimeMillis(), jobId,
+          IN_PROGRESS, VOLUME_NAME, BUCKET_NAME, from.getName(), to.getName(), 
false, false, 0, null, 0.0, ""));
+      if (failOnOpen == 1 || failOnOpen == 2) {
+        RuntimeException failure = assertThrows(RuntimeException.class, () -> 
manager.generateSnapshotDiffReport(
+            jobKey, jobId, VOLUME_NAME, BUCKET_NAME, from.getName(), 
to.getName(), true, false, false));
+        assertEquals("Snapshot load failed", failure.getCause().getMessage());
+        assertEquals(FAILED, 
manager.getSnapDiffJobTable().get(jobKey).getStatus());
+      } else {
+        manager.generateSnapshotDiffReport(jobKey, jobId, VOLUME_NAME, 
BUCKET_NAME,
+            from.getName(), to.getName(), true, false, false);
+      }
+      assertEquals(failOnOpen == 0 ? 0 : Math.min(failOnOpen, 2), opens.get());
+      assertEquals(0, lock.getReadHoldCount(SNAPSHOT_DB_LOCK, 
from.getSnapshotId().toString()));
+      assertEquals(0, lock.getReadHoldCount(SNAPSHOT_DB_LOCK, 
to.getSnapshotId().toString()));
+      assertEquals(0, cache.totalRefCount(from.getSnapshotId()));
+      assertEquals(0, cache.totalRefCount(to.getSnapshotId()));
+    }
+  }
+
+  @ParameterizedTest
+  @org.junit.jupiter.params.provider.ValueSource(ints = {1, 2})
+  public void testSnapshotDiffLocksAfterSnapshotNameReuse(int replaceOnOpen) 
throws Exception {
+    SnapshotInfo from = snapshotInfo;
+    SnapshotInfo to = snapshotInfoList.get(0);
+    OzoneManagerLock lock = new OzoneManagerLock(new OzoneConfiguration());
+    when(omMetadataManager.getLock()).thenReturn(lock);
+    try (SnapshotCache cache = new SnapshotCache(mockCacheLoader(), 10, 
ozoneManager.getMetrics(), 0, true, lock)) {
+      SnapshotDiffManager manager = spy(snapshotDiffManager);
+      doReturn(true, false).when(manager).areDiffJobAndSnapshotsActive(
+          VOLUME_NAME, BUCKET_NAME, from.getName(), to.getName());
+      Set<UUID> openedIds = new LinkedHashSet<>();
+      Set<UUID> replacementIds = new LinkedHashSet<>();
+      AtomicInteger opens = new AtomicInteger();
+      OmSnapshotManager omSnapshotManager = 
ozoneManager.getOmSnapshotManager();
+      HddsWhiteboxTestUtils.setInternalState(omSnapshotManager, 
"snapshotCache", cache);
+      doAnswer(invocation -> {
+        if (opens.incrementAndGet() == replaceOnOpen) {
+          assertTrue(lock.getReadHoldCount(SNAPSHOT_DB_LOCK, 
from.getSnapshotId().toString()) > 0);
+          assertTrue(lock.getReadHoldCount(SNAPSHOT_DB_LOCK, 
to.getSnapshotId().toString()) > 0);
+          UUID replacementId = LongStream.range(0, 1024).mapToObj(id -> new 
UUID(0, id))
+              .filter(id -> lock.getReadHoldCount(SNAPSHOT_DB_LOCK, 
id.toString()) == 0)
+              .findFirst().orElseThrow(() -> new AssertionError("No unheld 
snapshot DB stripe found"));
+          // Simulate A being renamed away and C taking A's old name after A 
and B were prelocked.
+          SnapshotInfo original = replaceOnOpen == 1 ? from : to;
+          SnapshotInfo replacement = 
original.toBuilder().setSnapshotId(replacementId).build();
+          replacementIds.add(replacementId);
+          
when(snapshotInfoTable.get(original.getTableKey())).thenReturn(replacement);
+        }
+        UUID id = invocation.getArgument(3);
+        assertTrue(lock.getReadHoldCount(SNAPSHOT_DB_LOCK, id.toString()) > 0);
+        Object handle = invocation.callRealMethod();
+        openedIds.add(id);
+        return handle;
+      }).when(omSnapshotManager).getActiveSnapshot(anyString(), anyString(), 
anyString(), any(UUID.class));
+      String jobKey = generateSnapDiffJobKey.apply(from, to);
+      String jobId = UUID.randomUUID().toString();
+      manager.getSnapDiffJobTable().put(jobKey, new 
SnapshotDiffJob(System.currentTimeMillis(), jobId,
+          IN_PROGRESS, VOLUME_NAME, BUCKET_NAME, from.getName(), to.getName(), 
false, false, 0, null, 0.0, ""));
+
+      RuntimeException failure = assertThrows(RuntimeException.class, () -> 
manager.generateSnapshotDiffReport(
+          jobKey, jobId, VOLUME_NAME, BUCKET_NAME, from.getName(), 
to.getName(), true, false, false));
+      assertTrue(failure.getCause().getMessage().contains("Snapshot name 
mapping changed"));

Review Comment:
   Thanks, updated to 
assertThat(failure).cause().hasMessageContaining("Snapshot name mapping 
changed") as suggested.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to