Skip to content

Commit

Permalink
HDDS-10650. Delete hsync key info from openFileTable while deleting d…
Browse files Browse the repository at this point in the history
…irectory recursively. (apache#6495)
  • Loading branch information
ashishkumar50 authored and chungen0126 committed May 3, 2024
1 parent 5fa934c commit 063022c
Show file tree
Hide file tree
Showing 17 changed files with 132 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ private OzoneConsts() {
/** Metadata stored in OmKeyInfo. */
public static final String HSYNC_CLIENT_ID = "hsyncClientId";
public static final String LEASE_RECOVERY = "leaseRecovery";
public static final String DELETED_HSYNC_KEY = "deletedHsyncKey";
public static final String FORCE_LEASE_RECOVERY_ENV = "OZONE.CLIENT.RECOVER.LEASE.FORCE";

//GDPR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1838,8 +1838,10 @@ public ExpiredOpenKeys getExpiredOpenKeys(Duration expireThreshold,
.filter(id -> id.equals(clientIdString))
.isPresent();

if (!isHsync && openKeyInfo.getCreationTime() <= expiredCreationTimestamp) {
if ((!isHsync && openKeyInfo.getCreationTime() <= expiredCreationTimestamp) ||
(openKeyInfo.getMetadata().containsKey(OzoneConsts.DELETED_HSYNC_KEY))) {
// add non-hsync'ed keys
// also add hsync keys which are already deleted from keyTable
expiredKeys.addOpenKey(openKeyInfo, dbOpenKeyName);
num++;
} else if (isHsync && openKeyInfo.getModificationTime() <= expiredLeaseTimestamp &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,10 @@ private RecoverLeaseResponse doWork(OzoneManager ozoneManager,
throw new OMException("Open Key " + dbOpenFileKey + " not found in openKeyTable", KEY_NOT_FOUND);
}

if (openKeyInfo.getMetadata().containsKey(OzoneConsts.DELETED_HSYNC_KEY)) {
throw new OMException("Open Key " + keyName + " is already deleted",
KEY_NOT_FOUND);
}
long openKeyModificationTime = openKeyInfo.getModificationTime();
if (openKeyInfo.getMetadata().containsKey(OzoneConsts.LEASE_RECOVERY)) {
LOG.debug("Key: " + keyName + " is already under recovery");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
throw new OMException("Open Key " + openKeyName + " is under lease recovery",
KEY_UNDER_LEASE_RECOVERY);
}
if (openKeyInfo.getMetadata().containsKey(OzoneConsts.DELETED_HSYNC_KEY)) {
throw new OMException("Open Key " + openKeyName + " is already deleted",
KEY_NOT_FOUND);
}
List<OmKeyLocationInfo> newLocationList = Collections.singletonList(
OmKeyLocationInfo.getFromProtobuf(blockLocation));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.om.OMMetrics;
import org.apache.ratis.server.protocol.TermIndex;
import org.apache.hadoop.ozone.om.OMMetadataManager;
Expand All @@ -39,8 +41,7 @@
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;

import java.util.List;

import static org.apache.hadoop.ozone.OzoneConsts.DELETED_HSYNC_KEY;
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;

/**
Expand All @@ -66,6 +67,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
Set<Pair<String, String>> lockSet = new HashSet<>();
Map<Pair<String, String>, OmBucketInfo> volBucketInfoMap = new HashMap<>();
OMMetadataManager omMetadataManager = ozoneManager.getMetadataManager();
Map<String, OmKeyInfo> openKeyInfoMap = new HashMap<>();

OMMetrics omMetrics = ozoneManager.getMetrics();
try {
Expand Down Expand Up @@ -110,6 +112,21 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
volumeName, bucketName);
lockSet.add(volBucketPair);
}

// If omKeyInfo has hsync metadata, delete its corresponding open key as well
String dbOpenKey;
String hsyncClientId = keyInfo.getMetadata().get(OzoneConsts.HSYNC_CLIENT_ID);
if (hsyncClientId != null) {
long parentId = keyInfo.getParentObjectID();
dbOpenKey = omMetadataManager.getOpenFileName(path.getVolumeId(), path.getBucketId(),
parentId, keyInfo.getFileName(), hsyncClientId);
OmKeyInfo openKeyInfo = omMetadataManager.getOpenKeyTable(getBucketLayout()).get(dbOpenKey);
if (openKeyInfo != null) {
openKeyInfo.getMetadata().put(DELETED_HSYNC_KEY, "true");
openKeyInfoMap.put(dbOpenKey, openKeyInfo);
}
}

omMetrics.decNumKeys();
OmBucketInfo omBucketInfo = getBucketInfo(omMetadataManager,
volumeName, bucketName);
Expand Down Expand Up @@ -142,7 +159,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
getOmRequest());
OMClientResponse omClientResponse = new OMDirectoriesPurgeResponseWithFSO(
omResponse.build(), purgeRequests, ozoneManager.isRatisEnabled(),
getBucketLayout(), volBucketInfoMap, fromSnapshotInfo);
getBucketLayout(), volBucketInfoMap, fromSnapshotInfo, openKeyInfoMap);

return omClientResponse;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
throw new OMException("Failed to " + action + " key, as " + dbOpenKey +
" entry is not found in the OpenKey table", KEY_NOT_FOUND);
}
if (omKeyInfo.getMetadata().containsKey(OzoneConsts.DELETED_HSYNC_KEY)) {
throw new OMException("Open Key " + keyName + " is already deleted",
KEY_NOT_FOUND);
}
if (omKeyInfo.getMetadata().containsKey(OzoneConsts.LEASE_RECOVERY) &&
omKeyInfo.getMetadata().containsKey(OzoneConsts.HSYNC_CLIENT_ID)) {
if (!isRecovery) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import org.apache.hadoop.hdds.utils.db.cache.CacheKey;
import org.apache.hadoop.hdds.utils.db.cache.CacheValue;

import static org.apache.hadoop.ozone.OzoneConsts.DELETED_HSYNC_KEY;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_NOT_FOUND;
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;

Expand Down Expand Up @@ -161,6 +162,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
long quotaReleased = sumBlockLengths(omKeyInfo);
omBucketInfo.incrUsedBytes(-quotaReleased);
omBucketInfo.incrUsedNamespace(-1L);
OmKeyInfo deletedOpenKeyInfo = null;

// If omKeyInfo has hsync metadata, delete its corresponding open key as well
String dbOpenKey = null;
Expand All @@ -170,8 +172,9 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
dbOpenKey = omMetadataManager.getOpenKey(volumeName, bucketName, keyName, hsyncClientId);
OmKeyInfo openKeyInfo = openKeyTable.get(dbOpenKey);
if (openKeyInfo != null) {
// Remove the open key by putting a tombstone entry
openKeyTable.addCacheEntry(dbOpenKey, trxnLogIndex);
openKeyInfo.getMetadata().put(DELETED_HSYNC_KEY, "true");
openKeyTable.addCacheEntry(dbOpenKey, openKeyInfo, trxnLogIndex);
deletedOpenKeyInfo = openKeyInfo;
} else {
LOG.warn("Potentially inconsistent DB state: open key not found with dbOpenKey '{}'", dbOpenKey);
}
Expand All @@ -180,7 +183,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
omClientResponse = new OMKeyDeleteResponse(
omResponse.setDeleteKeyResponse(DeleteKeyResponse.newBuilder())
.build(), omKeyInfo, ozoneManager.isRatisEnabled(),
omBucketInfo.copyObject(), dbOpenKey);
omBucketInfo.copyObject(), deletedOpenKeyInfo);

result = Result.SUCCESS;
} catch (IOException | InvalidPathException ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import java.nio.file.InvalidPathException;
import java.util.Map;

import static org.apache.hadoop.ozone.OzoneConsts.DELETED_HSYNC_KEY;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.DIRECTORY_NOT_EMPTY;
import static org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes.KEY_NOT_FOUND;
import static org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_LOCK;
Expand Down Expand Up @@ -129,6 +130,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
String ozonePathKey = omMetadataManager.getOzonePathKey(volumeId,
bucketId, omKeyInfo.getParentObjectID(),
omKeyInfo.getFileName());
OmKeyInfo deletedOpenKeyInfo = null;

if (keyStatus.isDirectory()) {
// Check if there are any sub path exists under the user requested path
Expand Down Expand Up @@ -165,8 +167,9 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
dbOpenKey = omMetadataManager.getOpenFileName(volumeId, bucketId, parentId, fileName, hsyncClientId);
OmKeyInfo openKeyInfo = openKeyTable.get(dbOpenKey);
if (openKeyInfo != null) {
// Remove the open key by putting a tombstone entry
openKeyTable.addCacheEntry(dbOpenKey, trxnLogIndex);
openKeyInfo.getMetadata().put(DELETED_HSYNC_KEY, "true");
openKeyTable.addCacheEntry(dbOpenKey, openKeyInfo, trxnLogIndex);
deletedOpenKeyInfo = openKeyInfo;
} else {
LOG.warn("Potentially inconsistent DB state: open key not found with dbOpenKey '{}'", dbOpenKey);
}
Expand All @@ -175,7 +178,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
omClientResponse = new OMKeyDeleteResponseWithFSO(omResponse
.setDeleteKeyResponse(DeleteKeyResponse.newBuilder()).build(),
keyName, omKeyInfo, ozoneManager.isRatisEnabled(),
omBucketInfo.copyObject(), keyStatus.isDirectory(), volumeId, dbOpenKey);
omBucketInfo.copyObject(), keyStatus.isDirectory(), volumeId, deletedOpenKeyInfo);

result = Result.SUCCESS;
} catch (IOException | InvalidPathException ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,13 @@
import java.io.IOException;
import java.nio.file.InvalidPathException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static org.apache.hadoop.ozone.OzoneConsts.BUCKET;
import static org.apache.hadoop.ozone.OzoneConsts.DELETED_HSYNC_KEY;
import static org.apache.hadoop.ozone.OzoneConsts.DELETED_KEYS_LIST;
import static org.apache.hadoop.ozone.OzoneConsts.UNDELETED_KEYS_LIST;
import static org.apache.hadoop.ozone.OzoneConsts.VOLUME;
Expand Down Expand Up @@ -174,18 +176,18 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn
OmBucketInfo omBucketInfo =
getBucketInfo(omMetadataManager, volumeName, bucketName);

List<String> dbOpenKeys = new ArrayList<>();
Map<String, OmKeyInfo> openKeyInfoMap = new HashMap<>();
// Mark all keys which can be deleted, in cache as deleted.
quotaReleased =
markKeysAsDeletedInCache(ozoneManager, trxnLogIndex, omKeyInfoList,
dirList, omMetadataManager, quotaReleased, dbOpenKeys);
dirList, omMetadataManager, quotaReleased, openKeyInfoMap);
omBucketInfo.incrUsedBytes(-quotaReleased);
omBucketInfo.incrUsedNamespace(-1L * omKeyInfoList.size());

final long volumeId = omMetadataManager.getVolumeId(volumeName);
omClientResponse =
getOmClientResponse(ozoneManager, omKeyInfoList, dirList, omResponse,
unDeletedKeys, deleteStatus, omBucketInfo, volumeId, dbOpenKeys);
unDeletedKeys, deleteStatus, omBucketInfo, volumeId, openKeyInfoMap);

result = Result.SUCCESS;

Expand Down Expand Up @@ -260,21 +262,21 @@ protected OMClientResponse getOmClientResponse(OzoneManager ozoneManager,
List<OmKeyInfo> omKeyInfoList, List<OmKeyInfo> dirList,
OMResponse.Builder omResponse,
OzoneManagerProtocolProtos.DeleteKeyArgs.Builder unDeletedKeys,
boolean deleteStatus, OmBucketInfo omBucketInfo, long volumeId, List<String> dbOpenKeys) {
boolean deleteStatus, OmBucketInfo omBucketInfo, long volumeId, Map<String, OmKeyInfo> openKeyInfoMap) {
OMClientResponse omClientResponse;
omClientResponse = new OMKeysDeleteResponse(omResponse
.setDeleteKeysResponse(
DeleteKeysResponse.newBuilder().setStatus(deleteStatus)
.setUnDeletedKeys(unDeletedKeys))
.setStatus(deleteStatus ? OK : PARTIAL_DELETE).setSuccess(deleteStatus)
.build(), omKeyInfoList, ozoneManager.isRatisEnabled(),
omBucketInfo.copyObject(), dbOpenKeys);
omBucketInfo.copyObject(), openKeyInfoMap);
return omClientResponse;
}

protected long markKeysAsDeletedInCache(OzoneManager ozoneManager,
long trxnLogIndex, List<OmKeyInfo> omKeyInfoList, List<OmKeyInfo> dirList,
OMMetadataManager omMetadataManager, long quotaReleased, List<String> dbOpenKeys)
OMMetadataManager omMetadataManager, long quotaReleased, Map<String, OmKeyInfo> openKeyInfoMap)
throws IOException {
for (OmKeyInfo omKeyInfo : omKeyInfoList) {
String volumeName = omKeyInfo.getVolumeName();
Expand All @@ -294,10 +296,10 @@ protected long markKeysAsDeletedInCache(OzoneManager ozoneManager,
String dbOpenKey = omMetadataManager.getOpenKey(volumeName, bucketName, keyName, hsyncClientId);
OmKeyInfo openKeyInfo = openKeyTable.get(dbOpenKey);
if (openKeyInfo != null) {
// Remove the open key by putting a tombstone entry
openKeyTable.addCacheEntry(dbOpenKey, trxnLogIndex);
// Append to the list of open keys to be deleted. The list is not expected to be large.
dbOpenKeys.add(dbOpenKey);
openKeyInfo.getMetadata().put(DELETED_HSYNC_KEY, "true");
openKeyTable.addCacheEntry(dbOpenKey, openKeyInfo, trxnLogIndex);
// Add to the map of open keys to be deleted.
openKeyInfoMap.put(dbOpenKey, openKeyInfo);
} else {
LOG.warn("Potentially inconsistent DB state: open key not found with dbOpenKey '{}'", dbOpenKey);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@

import java.io.IOException;
import java.util.List;
import java.util.Map;

import static org.apache.hadoop.ozone.OzoneConsts.DELETED_HSYNC_KEY;
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status.OK;
import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status.PARTIAL_DELETE;

Expand Down Expand Up @@ -88,7 +90,7 @@ protected long markKeysAsDeletedInCache(
OzoneManager ozoneManager, long trxnLogIndex,
List<OmKeyInfo> omKeyInfoList,
List<OmKeyInfo> dirList, OMMetadataManager omMetadataManager,
long quotaReleased, List<String> dbOpenKeys) throws IOException {
long quotaReleased, Map<String, OmKeyInfo> openKeyInfoMap) throws IOException {

// Mark all keys which can be deleted, in cache as deleted.
for (OmKeyInfo omKeyInfo : omKeyInfoList) {
Expand All @@ -113,10 +115,10 @@ protected long markKeysAsDeletedInCache(
String dbOpenKey = omMetadataManager.getOpenFileName(volumeId, bucketId, parentId, fileName, hsyncClientId);
OmKeyInfo openKeyInfo = openKeyTable.get(dbOpenKey);
if (openKeyInfo != null) {
// Remove the open key by putting a tombstone entry
openKeyTable.addCacheEntry(dbOpenKey, trxnLogIndex);
// Append to the list of open keys to be deleted. The list is not expected to be large.
dbOpenKeys.add(dbOpenKey);
openKeyInfo.getMetadata().put(DELETED_HSYNC_KEY, "true");
openKeyTable.addCacheEntry(dbOpenKey, openKeyInfo, trxnLogIndex);
// Add to the map of open keys to be deleted.
openKeyInfoMap.put(dbOpenKey, openKeyInfo);
} else {
LOG.warn("Potentially inconsistent DB state: open key not found with dbOpenKey '{}'", dbOpenKey);
}
Expand Down Expand Up @@ -146,15 +148,15 @@ protected OMClientResponse getOmClientResponse(OzoneManager ozoneManager,
List<OmKeyInfo> omKeyInfoList, List<OmKeyInfo> dirList,
OzoneManagerProtocolProtos.OMResponse.Builder omResponse,
OzoneManagerProtocolProtos.DeleteKeyArgs.Builder unDeletedKeys,
boolean deleteStatus, OmBucketInfo omBucketInfo, long volumeId, List<String> dbOpenKeys) {
boolean deleteStatus, OmBucketInfo omBucketInfo, long volumeId, Map<String, OmKeyInfo> openKeyInfoMap) {
OMClientResponse omClientResponse;
omClientResponse = new OMKeysDeleteResponseWithFSO(omResponse
.setDeleteKeysResponse(
OzoneManagerProtocolProtos.DeleteKeysResponse.newBuilder()
.setStatus(deleteStatus).setUnDeletedKeys(unDeletedKeys))
.setStatus(deleteStatus ? OK : PARTIAL_DELETE).setSuccess(deleteStatus)
.build(), omKeyInfoList, dirList, ozoneManager.isRatisEnabled(),
omBucketInfo.copyObject(), volumeId, dbOpenKeys);
omBucketInfo.copyObject(), volumeId, openKeyInfoMap);
return omClientResponse;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,19 @@ public class OMDirectoriesPurgeResponseWithFSO extends OmKeyResponse {
private boolean isRatisEnabled;
private Map<Pair<String, String>, OmBucketInfo> volBucketInfoMap;
private SnapshotInfo fromSnapshotInfo;
private Map<String, OmKeyInfo> openKeyInfoMap;

public OMDirectoriesPurgeResponseWithFSO(@Nonnull OMResponse omResponse,
@Nonnull List<OzoneManagerProtocolProtos.PurgePathRequest> paths,
boolean isRatisEnabled, @Nonnull BucketLayout bucketLayout,
Map<Pair<String, String>, OmBucketInfo> volBucketInfoMap,
SnapshotInfo fromSnapshotInfo) {
SnapshotInfo fromSnapshotInfo, Map<String, OmKeyInfo> openKeyInfoMap) {
super(omResponse, bucketLayout);
this.paths = paths;
this.isRatisEnabled = isRatisEnabled;
this.volBucketInfoMap = volBucketInfoMap;
this.fromSnapshotInfo = fromSnapshotInfo;
this.openKeyInfoMap = openKeyInfoMap;
}

@Override
Expand Down Expand Up @@ -165,6 +167,13 @@ public void processPaths(OMMetadataManager omMetadataManager,
deletedKey, repeatedOmKeyInfo);
}

if (!openKeyInfoMap.isEmpty()) {
for (Map.Entry<String, OmKeyInfo> entry : openKeyInfoMap.entrySet()) {
omMetadataManager.getOpenKeyTable(getBucketLayout()).putWithBatch(
batchOperation, entry.getKey(), entry.getValue());
}
}

// Delete the visited directory from deleted directory table
if (path.hasDeletedDir()) {
omMetadataManager.getDeletedDirTable().deleteWithBatch(batchOperation,
Expand Down
Loading

0 comments on commit 063022c

Please sign in to comment.