Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hdds.utils.db.Codec;
import org.apache.hadoop.hdds.utils.db.CopyObject;
import org.apache.hadoop.hdds.utils.db.DelegatedCodec;
import org.apache.hadoop.hdds.utils.db.Proto2Codec;
import org.apache.hadoop.ozone.OzoneConsts;
Expand Down Expand Up @@ -52,15 +53,11 @@
* snapshot checkpoint directory, previous snapshotid
* for the snapshot path & global amongst other necessary fields.
*/
public final class SnapshotInfo implements Auditable {
public final class SnapshotInfo implements Auditable, CopyObject<SnapshotInfo> {
private static final Codec<SnapshotInfo> CODEC = new DelegatedCodec<>(
Proto2Codec.get(OzoneManagerProtocolProtos.SnapshotInfo.class),
SnapshotInfo::getFromProtobuf,
SnapshotInfo::getProtobuf,
// FIXME: HDDS-8665 Deep copy will cause failures
// - TestOMSnapshotDeleteRequest NullPointerException
// - TestOMSnapshotPurgeRequestAndResponse AssertionFailedError
DelegatedCodec.CopyType.SHALLOW);
SnapshotInfo::getProtobuf);

public static Codec<SnapshotInfo> getCodec() {
return CODEC;
Expand Down Expand Up @@ -599,4 +596,27 @@ public int hashCode() {
creationTime, deletionTime, pathPreviousSnapshotId,
globalPreviousSnapshotId, snapshotPath, checkpointDir);
}

/**
* Return a new copy of the object.
*/
@Override
public SnapshotInfo copyObject() {
return new Builder()
.setSnapshotId(snapshotId)
.setName(name)
.setVolumeName(volumeName)
.setBucketName(bucketName)
.setSnapshotStatus(snapshotStatus)
.setCreationTime(creationTime)
.setDeletionTime(deletionTime)
.setPathPreviousSnapshotId(pathPreviousSnapshotId)
.setGlobalPreviousSnapshotId(globalPreviousSnapshotId)
.setSnapshotPath(snapshotPath)
.setCheckpointDir(checkpointDir)
.setDbTxSequenceNumber(dbTxSequenceNumber)
.setDeepClean(deepClean)
.setSstFiltered(sstFiltered)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
*/
package org.apache.hadoop.ozone.om;

import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.hdds.utils.db.Table;
import org.apache.hadoop.hdds.utils.db.TableIterator;
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
Expand Down Expand Up @@ -430,4 +431,15 @@ public LinkedHashMap<UUID, SnapshotChainInfo> getSnapshotChainPath(
String path) {
return snapshotChainByPath.get(path);
}

@VisibleForTesting
public Map<UUID, SnapshotChainInfo> getGlobalSnapshotChain() {
return globalSnapshotChain;
}

@VisibleForTesting
public Map<String,
LinkedHashMap<UUID, SnapshotChainInfo>> getSnapshotChainByPath() {
return snapshotChainByPath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.UUID;

/**
* Handles OMSnapshotPurge Request.
Expand Down Expand Up @@ -73,6 +75,8 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
List<String> snapInfosToUpdate = snapshotPurgeRequest
.getUpdatedSnapshotDBKeyList();
Map<String, SnapshotInfo> updatedSnapInfos = new HashMap<>();
Map<String, SnapshotInfo> updatedPathPreviousAndGlobalSnapshots =
new HashMap<>();

// Snapshots that are already deepCleaned by the KeyDeletingService
// can be marked as deepCleaned.
Expand All @@ -94,12 +98,16 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
SnapshotInfo nextSnapshot = SnapshotUtils
.getNextActiveSnapshot(fromSnapshot,
snapshotChainManager, omSnapshotManager);

updateSnapshotInfoAndCache(nextSnapshot, omMetadataManager,
trxnLogIndex, updatedSnapInfos, true);
updateSnapshotChainAndCache(omMetadataManager, fromSnapshot,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a possibility that snapshot chain may get corrupted because of batch operation.
Created jira to revisit it: https://issues.apache.org/jira/browse/HDDS-9198

trxnLogIndex, updatedPathPreviousAndGlobalSnapshots);
}

omClientResponse = new OMSnapshotPurgeResponse(omResponse.build(),
snapshotDbKeys, updatedSnapInfos);
snapshotDbKeys, updatedSnapInfos,
updatedPathPreviousAndGlobalSnapshots);
} catch (IOException ex) {
omClientResponse = new OMSnapshotPurgeResponse(
createErrorOMResponse(omResponse, ex));
Expand All @@ -124,4 +132,95 @@ private void updateSnapshotInfoAndCache(SnapshotInfo snapInfo,
updatedSnapInfos.put(snapInfo.getTableKey(), snapInfo);
}
}

/**
* Removes the snapshot from the chain and updates the next snapshot's
* previousPath and previousGlobal IDs in DB cache.
* It also returns the pair of updated next path and global snapshots to
* update in DB.
*/
private void updateSnapshotChainAndCache(
OmMetadataManagerImpl metadataManager,
SnapshotInfo snapInfo,
long trxnLogIndex,
Map<String, SnapshotInfo> updatedPathPreviousAndGlobalSnapshots
) throws IOException {
if (snapInfo == null) {
return;
}

SnapshotChainManager snapshotChainManager = metadataManager
.getSnapshotChainManager();
SnapshotInfo nextPathSnapInfo = null;

// If the snapshot is deleted in the previous run, then the in-memory
// SnapshotChainManager might throw NoSuchElementException as the snapshot
// is removed in-memory but OMDoubleBuffer has not flushed yet.
boolean hasNextPathSnapshot;
boolean hasNextGlobalSnapshot;
try {
hasNextPathSnapshot = snapshotChainManager.hasNextPathSnapshot(
snapInfo.getSnapshotPath(), snapInfo.getSnapshotId());
hasNextGlobalSnapshot = snapshotChainManager.hasNextGlobalSnapshot(
snapInfo.getSnapshotId());
} catch (NoSuchElementException ex) {
return;
}

// Updates next path snapshot's previous snapshot ID
if (hasNextPathSnapshot) {
UUID nextPathSnapshotId = snapshotChainManager.nextPathSnapshot(
snapInfo.getSnapshotPath(), snapInfo.getSnapshotId());

String snapshotTableKey = snapshotChainManager
.getTableKey(nextPathSnapshotId);
nextPathSnapInfo = metadataManager.getSnapshotInfoTable()
.get(snapshotTableKey);
if (nextPathSnapInfo != null) {
nextPathSnapInfo.setPathPreviousSnapshotId(
snapInfo.getPathPreviousSnapshotId());
metadataManager.getSnapshotInfoTable().addCacheEntry(
new CacheKey<>(nextPathSnapInfo.getTableKey()),
CacheValue.get(trxnLogIndex, nextPathSnapInfo));
updatedPathPreviousAndGlobalSnapshots
.put(nextPathSnapInfo.getTableKey(), nextPathSnapInfo);
}
}

// Updates next global snapshot's previous snapshot ID
if (hasNextGlobalSnapshot) {
UUID nextGlobalSnapshotId =
snapshotChainManager.nextGlobalSnapshot(snapInfo.getSnapshotId());

String snapshotTableKey = snapshotChainManager
.getTableKey(nextGlobalSnapshotId);

SnapshotInfo nextGlobalSnapInfo = metadataManager.getSnapshotInfoTable()
.get(snapshotTableKey);
// If both next global and path snapshot are same, it may overwrite
// nextPathSnapInfo.setPathPreviousSnapshotID(), adding this check
// will prevent it.
if (nextGlobalSnapInfo != null && nextPathSnapInfo != null &&
nextGlobalSnapInfo.getSnapshotId().equals(
nextPathSnapInfo.getSnapshotId())) {
nextPathSnapInfo.setGlobalPreviousSnapshotId(
snapInfo.getGlobalPreviousSnapshotId());
metadataManager.getSnapshotInfoTable().addCacheEntry(
new CacheKey<>(nextPathSnapInfo.getTableKey()),
CacheValue.get(trxnLogIndex, nextPathSnapInfo));
updatedPathPreviousAndGlobalSnapshots
.put(nextPathSnapInfo.getTableKey(), nextPathSnapInfo);
} else if (nextGlobalSnapInfo != null) {
nextGlobalSnapInfo.setGlobalPreviousSnapshotId(
snapInfo.getGlobalPreviousSnapshotId());
metadataManager.getSnapshotInfoTable().addCacheEntry(
new CacheKey<>(nextGlobalSnapInfo.getTableKey()),
CacheValue.get(trxnLogIndex, nextGlobalSnapInfo));
updatedPathPreviousAndGlobalSnapshots
.put(nextGlobalSnapInfo.getTableKey(), nextGlobalSnapInfo);
}
}

snapshotChainManager.deleteSnapshot(snapInfo);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
import org.apache.hadoop.hdds.utils.db.RDBStore;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
import org.apache.hadoop.ozone.om.SnapshotChainManager;
import org.apache.hadoop.ozone.om.helpers.SnapshotInfo;
import org.apache.hadoop.ozone.om.response.CleanupTableInfo;
import org.apache.hadoop.ozone.om.response.OMClientResponse;
Expand All @@ -37,8 +36,6 @@
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.UUID;

import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.SNAPSHOT_INFO_TABLE;

Expand All @@ -51,13 +48,18 @@ public class OMSnapshotPurgeResponse extends OMClientResponse {
LoggerFactory.getLogger(OMSnapshotPurgeResponse.class);
private final List<String> snapshotDbKeys;
private final Map<String, SnapshotInfo> updatedSnapInfos;
private final Map<String, SnapshotInfo> updatedPreviousAndGlobalSnapInfos;

public OMSnapshotPurgeResponse(@Nonnull OMResponse omResponse,
public OMSnapshotPurgeResponse(
@Nonnull OMResponse omResponse,
@Nonnull List<String> snapshotDbKeys,
Map<String, SnapshotInfo> updatedSnapInfos) {
Map<String, SnapshotInfo> updatedSnapInfos,
Map<String, SnapshotInfo> updatedPreviousAndGlobalSnapInfos
) {
super(omResponse);
this.snapshotDbKeys = snapshotDbKeys;
this.updatedSnapInfos = updatedSnapInfos;
this.updatedPreviousAndGlobalSnapInfos = updatedPreviousAndGlobalSnapInfos;
}

/**
Expand All @@ -69,6 +71,7 @@ public OMSnapshotPurgeResponse(@Nonnull OMResponse omResponse) {
checkStatusNotOK();
this.snapshotDbKeys = null;
this.updatedSnapInfos = null;
this.updatedPreviousAndGlobalSnapInfos = null;
}

@Override
Expand All @@ -77,7 +80,9 @@ protected void addToDBBatch(OMMetadataManager omMetadataManager,

OmMetadataManagerImpl metadataManager = (OmMetadataManagerImpl)
omMetadataManager;
updateSnapInfo(metadataManager, batchOperation);
updateSnapInfo(metadataManager, batchOperation, updatedSnapInfos);
updateSnapInfo(metadataManager, batchOperation,
updatedPreviousAndGlobalSnapInfos);
for (String dbKey: snapshotDbKeys) {
SnapshotInfo snapshotInfo = omMetadataManager
.getSnapshotInfoTable().get(dbKey);
Expand All @@ -88,7 +93,7 @@ protected void addToDBBatch(OMMetadataManager omMetadataManager,
if (snapshotInfo == null) {
continue;
}
cleanupSnapshotChain(metadataManager, snapshotInfo, batchOperation);

// Delete Snapshot checkpoint directory.
deleteCheckpointDirectory(omMetadataManager, snapshotInfo);
omMetadataManager.getSnapshotInfoTable().deleteWithBatch(batchOperation,
Expand All @@ -97,91 +102,15 @@ protected void addToDBBatch(OMMetadataManager omMetadataManager,
}

private void updateSnapInfo(OmMetadataManagerImpl metadataManager,
BatchOperation batchOp)
BatchOperation batchOp,
Map<String, SnapshotInfo> snapshotInfos)
throws IOException {
for (Map.Entry<String, SnapshotInfo> entry : updatedSnapInfos.entrySet()) {
for (Map.Entry<String, SnapshotInfo> entry : snapshotInfos.entrySet()) {
metadataManager.getSnapshotInfoTable().putWithBatch(batchOp,
entry.getKey(), entry.getValue());
}
}

/**
* Cleans up the snapshot chain and updates next snapshot's
* previousPath and previousGlobal IDs.
*/
private void cleanupSnapshotChain(OmMetadataManagerImpl metadataManager,
SnapshotInfo snapInfo,
BatchOperation batchOperation)
throws IOException {
SnapshotChainManager snapshotChainManager = metadataManager
.getSnapshotChainManager();
SnapshotInfo nextPathSnapInfo = null;
SnapshotInfo nextGlobalSnapInfo;

// If the snapshot is deleted in the previous run, then the in-memory
// SnapshotChainManager might throw NoSuchElementException as the snapshot
// is removed in-memory but OMDoubleBuffer has not flushed yet.
boolean hasNextPathSnapshot;
boolean hasNextGlobalSnapshot;
try {
hasNextPathSnapshot = snapshotChainManager.hasNextPathSnapshot(
snapInfo.getSnapshotPath(), snapInfo.getSnapshotId());
hasNextGlobalSnapshot = snapshotChainManager.hasNextGlobalSnapshot(
snapInfo.getSnapshotId());
} catch (NoSuchElementException ex) {
LOG.warn("The Snapshot {} could have been deleted in the previous run.",
snapInfo.getSnapshotId(), ex);
return;
}

// Updates next path snapshot's previous snapshot ID
if (hasNextPathSnapshot) {
UUID nextPathSnapshotId = snapshotChainManager.nextPathSnapshot(
snapInfo.getSnapshotPath(), snapInfo.getSnapshotId());

String snapshotTableKey = snapshotChainManager
.getTableKey(nextPathSnapshotId);
nextPathSnapInfo = metadataManager.getSnapshotInfoTable()
.get(snapshotTableKey);
if (nextPathSnapInfo != null) {
nextPathSnapInfo.setPathPreviousSnapshotId(
snapInfo.getPathPreviousSnapshotId());
metadataManager.getSnapshotInfoTable().putWithBatch(batchOperation,
nextPathSnapInfo.getTableKey(), nextPathSnapInfo);
}
}

// Updates next global snapshot's previous snapshot ID
if (hasNextGlobalSnapshot) {
UUID nextGlobalSnapshotId =
snapshotChainManager.nextGlobalSnapshot(snapInfo.getSnapshotId());

String snapshotTableKey = snapshotChainManager
.getTableKey(nextGlobalSnapshotId);
nextGlobalSnapInfo = metadataManager.getSnapshotInfoTable()
.get(snapshotTableKey);
// If both next global and path snapshot are same, it may overwrite
// nextPathSnapInfo.setPathPreviousSnapshotID(), adding this check
// will prevent it.
if (nextGlobalSnapInfo != null && nextPathSnapInfo != null &&
nextGlobalSnapInfo.getSnapshotId().equals(
nextPathSnapInfo.getSnapshotId())) {
nextPathSnapInfo.setGlobalPreviousSnapshotId(
snapInfo.getGlobalPreviousSnapshotId());
metadataManager.getSnapshotInfoTable().putWithBatch(batchOperation,
nextPathSnapInfo.getTableKey(), nextPathSnapInfo);
} else if (nextGlobalSnapInfo != null) {
nextGlobalSnapInfo.setGlobalPreviousSnapshotId(
snapInfo.getGlobalPreviousSnapshotId());
metadataManager.getSnapshotInfoTable().putWithBatch(batchOperation,
nextGlobalSnapInfo.getTableKey(), nextGlobalSnapInfo);
}
}

// Removes current snapshot from the snapshot chain.
snapshotChainManager.deleteSnapshot(snapInfo);
}

/**
* Deletes the checkpoint directory for a snapshot.
*/
Expand Down
Loading