This is an automated email from the ASF dual-hosted git repository.
siyao pushed a commit to branch HDDS-6517-Snapshot
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-6517-Snapshot by this
push:
new 0bcd697107 HDDS-7690. [Snapshot] Use SST file list output from
compaction DAG as SnapshotDiff input (#4119)
0bcd697107 is described below
commit 0bcd6971072932020a8d0aabea4202cc1c17cbc6
Author: Siyao Meng <[email protected]>
AuthorDate: Mon Jan 9 11:15:57 2023 -0800
HDDS-7690. [Snapshot] Use SST file list output from compaction DAG as
SnapshotDiff input (#4119)
---
.../ozone/rocksdiff/RocksDBCheckpointDiffer.java | 55 ++++++
.../apache/hadoop/ozone/om/OmSnapshotManager.java | 10 +-
.../ozone/om/snapshot/SnapshotDiffManager.java | 199 ++++++++++++++++-----
3 files changed, 217 insertions(+), 47 deletions(-)
diff --git
a/hadoop-hdds/rocksdb-checkpoint-differ/src/main/java/org/apache/ozone/rocksdiff/RocksDBCheckpointDiffer.java
b/hadoop-hdds/rocksdb-checkpoint-differ/src/main/java/org/apache/ozone/rocksdiff/RocksDBCheckpointDiffer.java
index 9b015b24e1..06db74bf6d 100644
---
a/hadoop-hdds/rocksdb-checkpoint-differ/src/main/java/org/apache/ozone/rocksdiff/RocksDBCheckpointDiffer.java
+++
b/hadoop-hdds/rocksdb-checkpoint-differ/src/main/java/org/apache/ozone/rocksdiff/RocksDBCheckpointDiffer.java
@@ -710,13 +710,64 @@ public class RocksDBCheckpointDiffer implements
AutoCloseable {
}
}
+ /**
+ * Helper function that prepends SST file name with SST backup directory
path,
+ * and appends the extension '.sst'.
+ */
+ private String getSSTFullPathInBackupDir(String sstFilenameWithoutExtension,
+ String dbPath) {
+
+ // Try to locate the SST in the backup dir first
+ final Path sstPathInBackupDir = Paths.get(sstBackupDir,
+ sstFilenameWithoutExtension + SST_FILE_EXTENSION);
+ if (Files.exists(sstPathInBackupDir)) {
+ return sstPathInBackupDir.toString();
+ }
+
+ // SST file does not exist in the SST backup dir, this means the SST file
+ // has not gone through any compactions yet and is only available in the
+ // src DB directory
+ final Path sstPathInDBDir = Paths.get(dbPath,
+ sstFilenameWithoutExtension + SST_FILE_EXTENSION);
+ if (Files.exists(sstPathInDBDir)) {
+ return sstPathInDBDir.toString();
+ }
+
+ // TODO: More graceful error handling?
+ throw new RuntimeException("Unable to locate SST file: " +
+ sstFilenameWithoutExtension);
+ }
+
+ /**
+ * A wrapper of getSSTDiffList() that returns the absolute path of SST files,
+ * rather than SST file names without extension.
+ *
+ * @param src source snapshot
+ * @param dest destination snapshot
+ * @return A list of SST files without extension.
+ * e.g. ["/path/to/sstBackupDir/000050.sst",
+ * "/path/to/sstBackupDir/000060.sst"]
+ */
+ public List<String> getSSTDiffListWithFullPath(
+ DifferSnapshotInfo src, DifferSnapshotInfo dest) {
+
+ List<String> sstDiffList = getSSTDiffList(src, dest);
+
+ return sstDiffList.stream()
+ .map(sst -> getSSTFullPathInBackupDir(sst, src.getDbPath()))
+ .collect(Collectors.toList());
+ }
+
/**
* Get a list of SST files that differs between src and destination
snapshots.
* <p>
* Expected input: src is a snapshot taken AFTER the dest.
+ * <p>
+ * Use getSSTDiffListWithFullPath() instead if you need the full path to
SSTs.
*
* @param src source snapshot
* @param dest destination snapshot
+ * @return A list of SST files without extension. e.g. ["000050", "000060"]
*/
public synchronized List<String> getSSTDiffList(
DifferSnapshotInfo src, DifferSnapshotInfo dest) {
@@ -1257,6 +1308,10 @@ public class RocksDBCheckpointDiffer implements
AutoCloseable {
return asList(outputFiles);
}
+ public String getSSTBackupDir() {
+ return sstBackupDir;
+ }
+
private static final class SnapshotLogInfo {
private final long snapshotGenerationId;
private final String snapshotId;
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 bbf0939a2a..8aab246345 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
@@ -62,7 +62,12 @@ public final class OmSnapshotManager {
OmSnapshotManager(OzoneManager ozoneManager) {
this.ozoneManager = ozoneManager;
- this.snapshotDiffManager = new SnapshotDiffManager();
+ // Pass in the differ
+ final RocksDBCheckpointDiffer differ = ozoneManager
+ .getMetadataManager()
+ .getStore()
+ .getRocksDBCheckpointDiffer();
+ this.snapshotDiffManager = new SnapshotDiffManager(differ);
// size of lru cache
int cacheSize = ozoneManager.getConfiguration().getInt(
@@ -242,7 +247,8 @@ public final class OmSnapshotManager {
try {
final OmSnapshot fs = snapshotCache.get(fsKey);
final OmSnapshot ts = snapshotCache.get(tsKey);
- return snapshotDiffManager.getSnapshotDiffReport(volume, bucket, fs, ts);
+ return snapshotDiffManager.getSnapshotDiffReport(volume, bucket, fs, ts,
+ fsInfo, tsInfo);
} catch (ExecutionException | RocksDBException e) {
throw new IOException(e.getCause());
}
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 ec70478312..ed13ba8eae 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
@@ -20,10 +20,12 @@ package org.apache.hadoop.ozone.om.snapshot;
import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
import org.apache.hadoop.ozone.om.OmSnapshot;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.om.helpers.OmDirectoryInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
import org.apache.hadoop.ozone.om.helpers.WithObjectID;
import org.apache.hadoop.ozone.snapshot.SnapshotDiffReport;
import org.apache.hadoop.ozone.snapshot.SnapshotDiffReport.DiffType;
@@ -31,8 +33,12 @@ import
org.apache.hadoop.ozone.snapshot.SnapshotDiffReport.DiffReportEntry;
import org.apache.ozone.rocksdb.util.ManagedSstFileReader;
import org.apache.ozone.rocksdb.util.RdbUtil;
+import org.apache.ozone.rocksdiff.DifferSnapshotInfo;
+import org.apache.ozone.rocksdiff.RocksDBCheckpointDiffer;
import org.jetbrains.annotations.NotNull;
import org.rocksdb.RocksDBException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList;
@@ -44,24 +50,74 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
+import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
+
/**
* Class to generate snapshot diff.
*/
public class SnapshotDiffManager {
+ private static final Logger LOG =
+ LoggerFactory.getLogger(SnapshotDiffManager.class);
+ private RocksDBCheckpointDiffer differ;
+
+ public SnapshotDiffManager(RocksDBCheckpointDiffer differ) {
+ this.differ = differ;
+ }
+
+ /**
+ * Copied straight from TestOMSnapshotDAG. TODO: Dedup. Move this to util.
+ */
+ private Map<String, String> getTablePrefixes(
+ OMMetadataManager omMetadataManager,
+ String volumeName, String bucketName) throws IOException {
+ HashMap<String, String> tablePrefixes = new HashMap<>();
+ String volumeId =
String.valueOf(omMetadataManager.getVolumeId(volumeName));
+ String bucketId = String.valueOf(
+ omMetadataManager.getBucketId(volumeName, bucketName));
+ tablePrefixes.put(OmMetadataManagerImpl.KEY_TABLE,
+ OM_KEY_PREFIX + volumeName + OM_KEY_PREFIX + bucketName);
+ tablePrefixes.put(OmMetadataManagerImpl.FILE_TABLE,
+ OM_KEY_PREFIX + volumeId + OM_KEY_PREFIX + bucketId);
+ tablePrefixes.put(OmMetadataManagerImpl.DIRECTORY_TABLE,
+ OM_KEY_PREFIX + volumeId + OM_KEY_PREFIX + bucketId);
+ return tablePrefixes;
+ }
+
+ /**
+ * Convert from SnapshotInfo to DifferSnapshotInfo.
+ */
+ private DifferSnapshotInfo getDSIFromSI(SnapshotInfo snapshotInfo,
+ OmSnapshot omSnapshot,
+ final String volumeName,
+ final String bucketName)
+ throws IOException {
+
+ final OMMetadataManager snapshotOMMM = omSnapshot.getMetadataManager();
+ final String checkpointPath =
+ snapshotOMMM.getStore().getDbLocation().getPath();
+ final String snapshotId = snapshotInfo.getSnapshotID();
+ final long dbTxSequenceNumber = snapshotInfo.getDbTxSequenceNumber();
+
+ DifferSnapshotInfo dsi = new DifferSnapshotInfo(
+ checkpointPath,
+ snapshotId,
+ dbTxSequenceNumber,
+ getTablePrefixes(snapshotOMMM, volumeName, bucketName));
+ return dsi;
+ }
+
public SnapshotDiffReport getSnapshotDiffReport(final String volume,
final String bucket,
final OmSnapshot
fromSnapshot,
- final OmSnapshot toSnapshot)
+ final OmSnapshot toSnapshot,
+ final SnapshotInfo fsInfo,
+ final SnapshotInfo tsInfo)
throws IOException, RocksDBException {
- // TODO: Once RocksDBCheckpointDiffer exposes method to get list
- // of delta SST files, plug it in here.
-
final BucketLayout bucketLayout = getBucketLayout(volume, bucket,
fromSnapshot.getMetadataManager());
- // TODO: Filter out the files.
/*
* The reason for having ObjectID to KeyName mapping instead of OmKeyInfo
* is to reduce the memory footprint.
@@ -81,7 +137,8 @@ public class SnapshotDiffManager {
.getMetadataManager().getKeyTable(bucketLayout);
final Set<String> deltaFilesForKeyOrFileTable =
getDeltaFiles(fromSnapshot, toSnapshot,
- Collections.singletonList(fsKeyTable.getName()));
+ Collections.singletonList(fsKeyTable.getName()),
+ fsInfo, tsInfo, volume, bucket);
addToObjectIdMap(fsKeyTable, tsKeyTable, deltaFilesForKeyOrFileTable,
oldObjIdToKeyMap, newObjIdToKeyMap, objectIDsToCheck, false);
@@ -94,7 +151,8 @@ public class SnapshotDiffManager {
toSnapshot.getMetadataManager().getDirectoryTable();
final Set<String> deltaFilesForDirTable =
getDeltaFiles(fromSnapshot, toSnapshot,
- Collections.singletonList(fsDirTable.getName()));
+ Collections.singletonList(fsDirTable.getName()),
+ fsInfo, tsInfo, volume, bucket);
addToObjectIdMap(fsDirTable, tsDirTable, deltaFilesForDirTable,
oldObjIdToKeyMap, newObjIdToKeyMap, objectIDsToCheck, true);
}
@@ -107,38 +165,41 @@ public class SnapshotDiffManager {
private void addToObjectIdMap(Table<String, ? extends WithObjectID> fsTable,
Table<String, ? extends WithObjectID> tsTable, Set<String> deltaFiles,
Map<Long, String> oldObjIdToKeyMap, Map<Long, String> newObjIdToKeyMap,
- Set<Long> objectIDsToCheck, boolean isDirectoryTable)
- throws RocksDBException {
+ Set<Long> objectIDsToCheck, boolean isDirectoryTable) {
+
if (deltaFiles.isEmpty()) {
return;
}
- final Stream<String> keysToCheck =
- new ManagedSstFileReader(deltaFiles).getKeyStream();
- keysToCheck.forEach(key -> {
- try {
- final WithObjectID oldKey = fsTable.get(key);
- final WithObjectID newKey = tsTable.get(key);
- if (areKeysEqual(oldKey, newKey)) {
- // We don't have to do anything.
- return;
- }
- if (oldKey != null) {
- final long oldObjId = oldKey.getObjectID();
- oldObjIdToKeyMap
- .put(oldObjId, getKeyOrDirectoryName(isDirectoryTable, oldKey));
- objectIDsToCheck.add(oldObjId);
+ try (Stream<String> keysToCheck = new ManagedSstFileReader(deltaFiles)
+ .getKeyStream()) {
+ keysToCheck.forEach(key -> {
+ try {
+ final WithObjectID oldKey = fsTable.get(key);
+ final WithObjectID newKey = tsTable.get(key);
+ if (areKeysEqual(oldKey, newKey)) {
+ // We don't have to do anything.
+ return;
+ }
+ if (oldKey != null) {
+ final long oldObjId = oldKey.getObjectID();
+ oldObjIdToKeyMap.put(oldObjId,
+ getKeyOrDirectoryName(isDirectoryTable, oldKey));
+ objectIDsToCheck.add(oldObjId);
+ }
+ if (newKey != null) {
+ final long newObjId = newKey.getObjectID();
+ newObjIdToKeyMap.put(newObjId,
+ getKeyOrDirectoryName(isDirectoryTable, newKey));
+ objectIDsToCheck.add(newObjId);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
- if (newKey != null) {
- final long newObjId = newKey.getObjectID();
- newObjIdToKeyMap
- .put(newObjId, getKeyOrDirectoryName(isDirectoryTable, newKey));
- objectIDsToCheck.add(newObjId);
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- });
- keysToCheck.close();
+ });
+ } catch (RocksDBException rocksDBException) {
+ // TODO: Gracefully handle exception e.g. when input files do not exist
+ throw new RuntimeException(rocksDBException);
+ }
}
private String getKeyOrDirectoryName(boolean isDirectory,
@@ -152,19 +213,67 @@ public class SnapshotDiffManager {
}
@NotNull
+ @SuppressWarnings("parameternumber")
private Set<String> getDeltaFiles(OmSnapshot fromSnapshot,
- OmSnapshot toSnapshot, List<String> tablesToLookUp)
- throws RocksDBException {
- Set<String> fromSnapshotFiles = RdbUtil.getSSTFilesForComparison(
- fromSnapshot.getMetadataManager().getStore().getDbLocation().getPath(),
- tablesToLookUp);
- Set<String> toSnapshotFiles = RdbUtil.getSSTFilesForComparison(
- toSnapshot.getMetadataManager().getStore().getDbLocation().getPath(),
- tablesToLookUp);
+ OmSnapshot toSnapshot, List<String> tablesToLookUp,
+ SnapshotInfo fsInfo, SnapshotInfo tsInfo,
+ String volume, String bucket)
+ throws RocksDBException, IOException {
+ // TODO: Refactor the parameter list
final Set<String> deltaFiles = new HashSet<>();
- deltaFiles.addAll(fromSnapshotFiles);
- deltaFiles.addAll(toSnapshotFiles);
+
+ // Check if compaction DAG is available, use that if so
+ if (differ != null && fsInfo != null && tsInfo != null) {
+ // Construct DifferSnapshotInfo
+ final DifferSnapshotInfo fromDSI =
+ getDSIFromSI(fsInfo, fromSnapshot, volume, bucket);
+ final DifferSnapshotInfo toDSI =
+ getDSIFromSI(tsInfo, toSnapshot, volume, bucket);
+
+ LOG.debug("Calling RocksDBCheckpointDiffer");
+ List<String> sstDiffList =
+ differ.getSSTDiffListWithFullPath(toDSI, fromDSI);
+ LOG.debug("SST diff list: {}", sstDiffList);
+ deltaFiles.addAll(sstDiffList);
+
+ // TODO: Remove the workaround below when the SnapDiff logic can read
+ // tombstones in SST files.
+ // Workaround: Append "From DB" SST files to the deltaFiles list so that
+ // the current SnapDiff logic correctly handles deleted keys.
+ if (!deltaFiles.isEmpty()) {
+ Set<String> fromSnapshotFiles =
+ RdbUtil.getSSTFilesForComparison(
+ fromSnapshot.getMetadataManager().getStore()
+ .getDbLocation().getPath(),
+ tablesToLookUp);
+ deltaFiles.addAll(fromSnapshotFiles);
+ }
+ // End of Workaround
+
+ }
+
+ if (deltaFiles.isEmpty()) {
+ // If compaction DAG is not available (already cleaned up), fall back to
+ // the slower approach.
+ LOG.warn("RocksDBCheckpointDiffer is not available, falling back to" +
+ " slow path");
+
+ Set<String> fromSnapshotFiles =
+ RdbUtil.getSSTFilesForComparison(
+ fromSnapshot.getMetadataManager().getStore()
+ .getDbLocation().getPath(),
+ tablesToLookUp);
+ Set<String> toSnapshotFiles =
+ RdbUtil.getSSTFilesForComparison(
+ toSnapshot.getMetadataManager().getStore()
+ .getDbLocation().getPath(),
+ tablesToLookUp);
+
+ deltaFiles.addAll(fromSnapshotFiles);
+ deltaFiles.addAll(toSnapshotFiles);
+ }
+
return deltaFiles;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]