Skip to content

Commit 70949c5

Browse files
authored
HDDS-11603. Reclaimable Key Filter for Snapshots garbage reclaimation (apache#8392)
1 parent 08283f3 commit 70949c5

File tree

12 files changed

+621
-71
lines changed

12 files changed

+621
-71
lines changed

hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestKeyManagerImpl.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import static org.junit.jupiter.api.Assertions.assertThrows;
4242
import static org.junit.jupiter.api.Assertions.assertTrue;
4343
import static org.junit.jupiter.api.Assumptions.assumeFalse;
44+
import static org.mockito.ArgumentMatchers.eq;
4445
import static org.mockito.Mockito.any;
4546
import static org.mockito.Mockito.anyInt;
4647
import static org.mockito.Mockito.anyLong;
@@ -145,6 +146,7 @@
145146
import org.junit.jupiter.api.io.TempDir;
146147
import org.junit.jupiter.params.ParameterizedTest;
147148
import org.junit.jupiter.params.provider.Arguments;
149+
import org.junit.jupiter.params.provider.EnumSource;
148150
import org.junit.jupiter.params.provider.MethodSource;
149151
import org.junit.jupiter.params.provider.ValueSource;
150152

@@ -1628,6 +1630,51 @@ private String getRenameKey(String volume, String bucket, long objectId) {
16281630
return volume + "/" + bucket + "/" + objectId;
16291631
}
16301632

1633+
@ParameterizedTest
1634+
@EnumSource(value = BucketLayout.class)
1635+
public void testPreviousSnapshotOzoneKeyInfo(BucketLayout bucketLayout) throws IOException {
1636+
OMMetadataManager omMetadataManager = mock(OMMetadataManager.class);
1637+
if (bucketLayout.isFileSystemOptimized()) {
1638+
when(omMetadataManager.getOzonePathKey(anyLong(), anyLong(), anyLong(), anyString()))
1639+
.thenAnswer(i -> Arrays.stream(i.getArguments()).map(Object::toString)
1640+
.collect(Collectors.joining("/")));
1641+
} else {
1642+
when(omMetadataManager.getOzoneKey(anyString(), anyString(), anyString()))
1643+
.thenAnswer(i -> Arrays.stream(i.getArguments()).map(Object::toString)
1644+
.collect(Collectors.joining("/")));
1645+
}
1646+
when(omMetadataManager.getRenameKey(anyString(), anyString(), anyLong())).thenAnswer(
1647+
i -> getRenameKey(i.getArgument(0), i.getArgument(1), i.getArgument(2)));
1648+
1649+
OMMetadataManager previousMetadataManager = mock(OMMetadataManager.class);
1650+
OzoneConfiguration configuration = new OzoneConfiguration();
1651+
KeyManagerImpl km = new KeyManagerImpl(null, null, omMetadataManager, configuration, null, null, null);
1652+
KeyManagerImpl prevKM = new KeyManagerImpl(null, null, previousMetadataManager, configuration, null, null, null);
1653+
long volumeId = 1L;
1654+
OmBucketInfo bucketInfo = OmBucketInfo.newBuilder().setBucketName(BUCKET_NAME).setVolumeName(VOLUME_NAME)
1655+
.setObjectID(2L).setBucketLayout(bucketLayout).build();
1656+
OmKeyInfo prevKey = getMockedOmKeyInfo(bucketInfo, 5, "key", 1);
1657+
OmKeyInfo prevKey2 = getMockedOmKeyInfo(bucketInfo, 7, "key2", 2);
1658+
OmKeyInfo currentKey = getMockedOmKeyInfo(bucketInfo, 6, "renamedKey", 1);
1659+
OmKeyInfo currentKey2 = getMockedOmKeyInfo(bucketInfo, 7, "key2", 2);
1660+
OmKeyInfo currentKey3 = getMockedOmKeyInfo(bucketInfo, 8, "key3", 3);
1661+
OmKeyInfo currentKey4 = getMockedOmKeyInfo(bucketInfo, 8, "key4", 4);
1662+
Table<String, OmKeyInfo> prevKeyTable =
1663+
new InMemoryTestTable<>(ImmutableMap.of(
1664+
getDirectoryKey(volumeId, bucketInfo, prevKey), prevKey,
1665+
getDirectoryKey(volumeId, bucketInfo, prevKey2), prevKey2));
1666+
Table<String, String> renameTable = new InMemoryTestTable<>(
1667+
ImmutableMap.of(getRenameKey(VOLUME_NAME, BUCKET_NAME, 1), getDirectoryKey(volumeId, bucketInfo, prevKey),
1668+
getRenameKey(VOLUME_NAME, BUCKET_NAME, 3), getDirectoryKey(volumeId, bucketInfo,
1669+
getMockedOmKeyInfo(bucketInfo, 6, "unknownKey", 9))));
1670+
when(previousMetadataManager.getKeyTable(eq(bucketLayout))).thenReturn(prevKeyTable);
1671+
when(omMetadataManager.getSnapshotRenamedTable()).thenReturn(renameTable);
1672+
assertEquals(prevKey, km.getPreviousSnapshotOzoneKeyInfo(volumeId, bucketInfo, currentKey).apply(prevKM));
1673+
assertEquals(prevKey2, km.getPreviousSnapshotOzoneKeyInfo(volumeId, bucketInfo, currentKey2).apply(prevKM));
1674+
assertNull(km.getPreviousSnapshotOzoneKeyInfo(volumeId, bucketInfo, currentKey3).apply(prevKM));
1675+
assertNull(km.getPreviousSnapshotOzoneKeyInfo(volumeId, bucketInfo, currentKey4).apply(prevKM));
1676+
}
1677+
16311678
@Test
16321679
public void testPreviousSnapshotOzoneDirInfo() throws IOException {
16331680
OMMetadataManager omMetadataManager = mock(OMMetadataManager.class);

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/KeyManager.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ CheckedFunction<KeyManager, OmDirectoryInfo, IOException> getPreviousSnapshotOzo
149149
CheckedFunction<KeyManager, OmDirectoryInfo, IOException> getPreviousSnapshotOzoneDirInfo(
150150
long volumeId, OmBucketInfo bucketInfo, OmKeyInfo directoryInfo) throws IOException;
151151

152+
/**
153+
* Returns the previous snapshot's ozone keyInfo corresponding for the object.
154+
*/
155+
CheckedFunction<KeyManager, OmKeyInfo, IOException> getPreviousSnapshotOzoneKeyInfo(
156+
long volumeId, OmBucketInfo bucketInfo, OmKeyInfo keyInfo) throws IOException;
157+
152158
/**
153159
* Returns a list deleted entries from the deletedTable.
154160
*

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/KeyManagerImpl.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,17 @@ public CheckedFunction<KeyManager, OmDirectoryInfo, IOException> getPreviousSnap
793793
(previousSnapshotKM) -> previousSnapshotKM.getMetadataManager().getDirectoryTable());
794794
}
795795

796+
@Override
797+
public CheckedFunction<KeyManager, OmKeyInfo, IOException> getPreviousSnapshotOzoneKeyInfo(
798+
long volumeId, OmBucketInfo bucketInfo, OmKeyInfo keyInfo) throws IOException {
799+
String currentKeyPath = bucketInfo.getBucketLayout().isFileSystemOptimized()
800+
? metadataManager.getOzonePathKey(volumeId, bucketInfo.getObjectID(), keyInfo.getParentObjectID(),
801+
keyInfo.getFileName()) : metadataManager.getOzoneKey(bucketInfo.getVolumeName(), bucketInfo.getBucketName(),
802+
keyInfo.getKeyName());
803+
return getPreviousSnapshotOzonePathInfo(bucketInfo, keyInfo.getObjectID(), currentKeyPath,
804+
(previousSnapshotKM) -> previousSnapshotKM.getMetadataManager().getKeyTable(bucketInfo.getBucketLayout()));
805+
}
806+
796807
private <T> CheckedFunction<KeyManager, T, IOException> getPreviousSnapshotOzonePathInfo(
797808
OmBucketInfo bucketInfo, long objectId, String currentKeyPath,
798809
Function<KeyManager, Table<String, T>> table) throws IOException {

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.FILE_NOT_FOUND;
3434
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.NO_SUCH_MULTIPART_UPLOAD_ERROR;
3535
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.VOLUME_NOT_FOUND;
36-
import static org.apache.hadoop.ozone.om.service.SnapshotDeletingService.isBlockLocationInfoSame;
3736
import static org.apache.hadoop.ozone.om.snapshot.SnapshotUtils.checkSnapshotDirExist;
37+
import static org.apache.hadoop.ozone.om.snapshot.SnapshotUtils.isBlockLocationInfoSame;
3838

3939
import com.google.common.annotations.VisibleForTesting;
4040
import com.google.common.base.Strings;

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/AbstractKeyDeletingService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import static org.apache.hadoop.ozone.OzoneConsts.OBJECT_ID_RECLAIM_BLOCKS;
2121
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
22-
import static org.apache.hadoop.ozone.om.service.SnapshotDeletingService.isBlockLocationInfoSame;
22+
import static org.apache.hadoop.ozone.om.snapshot.SnapshotUtils.isBlockLocationInfoSame;
2323

2424
import com.google.common.annotations.VisibleForTesting;
2525
import com.google.protobuf.ServiceException;

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/service/SnapshotDeletingService.java

Lines changed: 0 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,6 @@
5252
import org.apache.hadoop.ozone.om.OzoneManager;
5353
import org.apache.hadoop.ozone.om.SnapshotChainManager;
5454
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
55-
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
56-
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
5755
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
5856
import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerRatisUtils;
5957
import org.apache.hadoop.ozone.om.snapshot.ReferenceCounted;
@@ -330,60 +328,6 @@ boolean shouldIgnoreSnapshot(SnapshotInfo snapInfo) throws IOException {
330328
!OmSnapshotManager.areSnapshotChangesFlushedToDB(getOzoneManager().getMetadataManager(), snapInfo);
331329
}
332330

333-
// TODO: Move this util class.
334-
public static boolean isBlockLocationInfoSame(OmKeyInfo prevKeyInfo,
335-
OmKeyInfo deletedKeyInfo) {
336-
337-
if (prevKeyInfo == null && deletedKeyInfo == null) {
338-
LOG.debug("Both prevKeyInfo and deletedKeyInfo are null.");
339-
return true;
340-
}
341-
if (prevKeyInfo == null || deletedKeyInfo == null) {
342-
LOG.debug("prevKeyInfo: '{}' or deletedKeyInfo: '{}' is null.",
343-
prevKeyInfo, deletedKeyInfo);
344-
return false;
345-
}
346-
// For hsync, Though the blockLocationInfo of a key may not be same
347-
// at the time of snapshot and key deletion as blocks can be appended.
348-
// If the objectId is same then the key is same.
349-
if (prevKeyInfo.isHsync() && deletedKeyInfo.isHsync()) {
350-
return true;
351-
}
352-
353-
if (prevKeyInfo.getKeyLocationVersions().size() !=
354-
deletedKeyInfo.getKeyLocationVersions().size()) {
355-
return false;
356-
}
357-
358-
OmKeyLocationInfoGroup deletedOmKeyLocation =
359-
deletedKeyInfo.getLatestVersionLocations();
360-
OmKeyLocationInfoGroup prevOmKeyLocation =
361-
prevKeyInfo.getLatestVersionLocations();
362-
363-
if (deletedOmKeyLocation == null || prevOmKeyLocation == null) {
364-
return false;
365-
}
366-
367-
List<OmKeyLocationInfo> deletedLocationList =
368-
deletedOmKeyLocation.getLocationList();
369-
List<OmKeyLocationInfo> prevLocationList =
370-
prevOmKeyLocation.getLocationList();
371-
372-
if (deletedLocationList.size() != prevLocationList.size()) {
373-
return false;
374-
}
375-
376-
for (int idx = 0; idx < deletedLocationList.size(); idx++) {
377-
OmKeyLocationInfo deletedLocationInfo = deletedLocationList.get(idx);
378-
OmKeyLocationInfo prevLocationInfo = prevLocationList.get(idx);
379-
if (!deletedLocationInfo.hasSameBlockAs(prevLocationInfo)) {
380-
return false;
381-
}
382-
}
383-
384-
return true;
385-
}
386-
387331
@Override
388332
public BackgroundTaskQueue getTasks() {
389333
BackgroundTaskQueue queue = new BackgroundTaskQueue();

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotDiffManager.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@
117117
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
118118
import org.apache.hadoop.ozone.om.helpers.WithObjectID;
119119
import org.apache.hadoop.ozone.om.helpers.WithParentObjectId;
120-
import org.apache.hadoop.ozone.om.service.SnapshotDeletingService;
121120
import org.apache.hadoop.ozone.snapshot.CancelSnapshotDiffResponse;
122121
import org.apache.hadoop.ozone.snapshot.ListSnapshotDiffJobResponse;
123122
import org.apache.hadoop.ozone.snapshot.SnapshotDiffReportOzone;
@@ -1460,8 +1459,7 @@ long generateDiffReport(
14601459
private boolean isKeyModified(OmKeyInfo fromKey, OmKeyInfo toKey) {
14611460
return !fromKey.isKeyInfoSame(toKey,
14621461
false, false, false, false, true)
1463-
|| !SnapshotDeletingService.isBlockLocationInfoSame(
1464-
fromKey, toKey);
1462+
|| !SnapshotUtils.isBlockLocationInfoSame(fromKey, toKey);
14651463
}
14661464

14671465
private boolean isObjectModified(String fromObjectName, String toObjectName,

hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/snapshot/SnapshotUtils.java

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@
4040
import org.apache.hadoop.ozone.om.SnapshotChainManager;
4141
import org.apache.hadoop.ozone.om.exceptions.OMException;
4242
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
43+
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
44+
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfoGroup;
4345
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
4446
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
4547
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo.SnapshotStatus;
@@ -53,8 +55,7 @@
5355
* Util class for snapshot diff APIs.
5456
*/
5557
public final class SnapshotUtils {
56-
private static final Logger LOG =
57-
LoggerFactory.getLogger(SnapshotUtils.class);
58+
private static final Logger LOG = LoggerFactory.getLogger(SnapshotUtils.class);
5859

5960
private SnapshotUtils() {
6061
throw new IllegalStateException("SnapshotUtils should not be initialized.");
@@ -189,7 +190,7 @@ public static SnapshotInfo getPreviousSnapshot(OzoneManager ozoneManager,
189190
/**
190191
* Get the previous snapshot in the snapshot chain.
191192
*/
192-
private static UUID getPreviousSnapshotId(SnapshotInfo snapInfo, SnapshotChainManager chainManager)
193+
public static UUID getPreviousSnapshotId(SnapshotInfo snapInfo, SnapshotChainManager chainManager)
193194
throws IOException {
194195
// If the snapshot is deleted in the previous run, then the in-memory
195196
// SnapshotChainManager might throw NoSuchElementException as the snapshot
@@ -299,4 +300,59 @@ public static void validatePreviousSnapshotId(SnapshotInfo snapshotInfo,
299300
OMException.ResultCodes.INVALID_REQUEST);
300301
}
301302
}
303+
304+
/**
305+
* Compares the block location info of 2 key info.
306+
* @return true if block locations are same else false.
307+
*/
308+
public static boolean isBlockLocationInfoSame(OmKeyInfo prevKeyInfo,
309+
OmKeyInfo deletedKeyInfo) {
310+
if (prevKeyInfo == null && deletedKeyInfo == null) {
311+
LOG.debug("Both prevKeyInfo and deletedKeyInfo are null.");
312+
return true;
313+
}
314+
if (prevKeyInfo == null || deletedKeyInfo == null) {
315+
LOG.debug("prevKeyInfo: '{}' or deletedKeyInfo: '{}' is null.",
316+
prevKeyInfo, deletedKeyInfo);
317+
return false;
318+
}
319+
// For hsync, Though the blockLocationInfo of a key may not be same
320+
// at the time of snapshot and key deletion as blocks can be appended.
321+
// If the objectId is same then the key is same.
322+
if (prevKeyInfo.isHsync() && deletedKeyInfo.isHsync()) {
323+
return true;
324+
}
325+
326+
if (prevKeyInfo.getKeyLocationVersions().size() !=
327+
deletedKeyInfo.getKeyLocationVersions().size()) {
328+
return false;
329+
}
330+
331+
OmKeyLocationInfoGroup deletedOmKeyLocation =
332+
deletedKeyInfo.getLatestVersionLocations();
333+
OmKeyLocationInfoGroup prevOmKeyLocation =
334+
prevKeyInfo.getLatestVersionLocations();
335+
336+
if (deletedOmKeyLocation == null || prevOmKeyLocation == null) {
337+
return false;
338+
}
339+
340+
List<OmKeyLocationInfo> deletedLocationList =
341+
deletedOmKeyLocation.getLocationList();
342+
List<OmKeyLocationInfo> prevLocationList =
343+
prevOmKeyLocation.getLocationList();
344+
345+
if (deletedLocationList.size() != prevLocationList.size()) {
346+
return false;
347+
}
348+
349+
for (int idx = 0; idx < deletedLocationList.size(); idx++) {
350+
OmKeyLocationInfo deletedLocationInfo = deletedLocationList.get(idx);
351+
OmKeyLocationInfo prevLocationInfo = prevLocationList.get(idx);
352+
if (!deletedLocationInfo.hasSameBlockAs(prevLocationInfo)) {
353+
return false;
354+
}
355+
}
356+
return true;
357+
}
302358
}

0 commit comments

Comments
 (0)