diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSync.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSync.java index 559b8da4982e..9b4be85ba51e 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSync.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestHSync.java @@ -58,6 +58,7 @@ import org.apache.hadoop.ozone.client.io.OzoneOutputStream; import org.apache.hadoop.ozone.om.OMMetadataManager; import org.apache.hadoop.ozone.om.OzoneManager; +import org.apache.hadoop.ozone.om.exceptions.OMException; import org.apache.hadoop.ozone.om.helpers.BucketLayout; import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; @@ -226,6 +227,46 @@ public void testOfsHSync() throws Exception { } } + @Test + public void testHSyncDeletedKey() throws Exception { + // Verify that a key can't be successfully hsync'ed again after it's deleted, + // and that key won't reappear after a failed hsync. + + // Set the fs.defaultFS + final String rootPath = String.format("%s://%s/", + OZONE_OFS_URI_SCHEME, CONF.get(OZONE_OM_ADDRESS_KEY)); + CONF.set(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY, rootPath); + + final String dir = OZONE_ROOT + bucket.getVolumeName() + + OZONE_URI_DELIMITER + bucket.getName(); + final Path key1 = new Path(dir, "key-hsync-del"); + + try (FileSystem fs = FileSystem.get(CONF)) { + // Create key1 + try (FSDataOutputStream os = fs.create(key1, true)) { + os.write(1); + os.hsync(); + fs.delete(key1, false); + + // getFileStatus should throw FNFE because the key is deleted + assertThrows(FileNotFoundException.class, + () -> fs.getFileStatus(key1)); + // hsync should throw because the open key is gone + try { + os.hsync(); + } catch (OMException omEx) { + assertEquals(OMException.ResultCodes.KEY_NOT_FOUND, omEx.getResult()); + } + // key1 should not reappear after failed hsync + assertThrows(FileNotFoundException.class, + () -> fs.getFileStatus(key1)); + } catch (OMException ex) { + // os.close() throws OMException because the key is deleted + assertEquals(OMException.ResultCodes.KEY_NOT_FOUND, ex.getResult()); + } + } + } + @Test public void testUncommittedBlocks() throws Exception { // Set the fs.defaultFS diff --git a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java index 00bf5752053e..38ce62c538d1 100644 --- a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java +++ b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java @@ -158,7 +158,21 @@ String getOzoneKeyFSO(String volumeName, * @param id - the id for this open * @return bytes of DB key. */ - String getOpenKey(String volume, String bucket, String key, long id); + default String getOpenKey(String volume, String bucket, String key, long id) { + return getOpenKey(volume, bucket, key, String.valueOf(id)); + } + + /** + * Returns the DB key name of a open key in OM metadata store. Should be + * #open# prefix followed by actual key name. + * + * @param volume - volume name + * @param bucket - bucket name + * @param key - key name + * @param clientId - client Id String for this open key + * @return bytes of DB key. + */ + String getOpenKey(String volume, String bucket, String key, String clientId); /** * Returns client ID in Long of an OpenKeyTable DB Key String. @@ -572,9 +586,22 @@ default String getOzonePathKey(long volumeId, long bucketId, * @param id - client id for this open request * @return DB directory key as String. */ - String getOpenFileName(long volumeId, long bucketId, - long parentObjectId, String fileName, long id); + default String getOpenFileName(long volumeId, long bucketId, long parentObjectId, String fileName, long id) { + return getOpenFileName(volumeId, bucketId, parentObjectId, fileName, String.valueOf(id)); + } + /** + * Returns DB key name of an open file in OM metadata store. Should be + * #open# prefix followed by actual leaf node name. + * + * @param volumeId - ID of the volume + * @param bucketId - ID of the bucket + * @param parentObjectId - parent object Id + * @param fileName - file name + * @param clientId - client id String for this open request + * @return DB directory key as String. + */ + String getOpenFileName(long volumeId, long bucketId, long parentObjectId, String fileName, String clientId); /** * Given a volume, bucket and a objectID, return the DB key name in diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java index 1969bce918f9..6ccecfe6b4e6 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java @@ -865,9 +865,9 @@ public String getOzoneDirKey(String volume, String bucket, String key) { @Override public String getOpenKey(String volume, String bucket, - String key, long id) { + String key, String clientId) { String openKey = OM_KEY_PREFIX + volume + OM_KEY_PREFIX + bucket + - OM_KEY_PREFIX + key + OM_KEY_PREFIX + id; + OM_KEY_PREFIX + key + OM_KEY_PREFIX + clientId; return openKey; } @@ -2178,13 +2178,13 @@ public String getOzoneDeletePathDirKey(String ozoneDeletePath) { @Override public String getOpenFileName(long volumeId, long bucketId, long parentID, String fileName, - long id) { + String clientId) { StringBuilder openKey = new StringBuilder(); openKey.append(OM_KEY_PREFIX).append(volumeId); openKey.append(OM_KEY_PREFIX).append(bucketId); openKey.append(OM_KEY_PREFIX).append(parentID); openKey.append(OM_KEY_PREFIX).append(fileName); - openKey.append(OM_KEY_PREFIX).append(id); + openKey.append(OM_KEY_PREFIX).append(clientId); return openKey.toString(); } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java index dbf50230ffac..ab6357a01d83 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequest.java @@ -251,7 +251,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn if (omKeyInfo == null) { String action = isRecovery ? "recovery" : isHSync ? "hsync" : "commit"; throw new OMException("Failed to " + action + " key, as " + dbOpenKey + - "entry is not found in the OpenKey table", KEY_NOT_FOUND); + " entry is not found in the OpenKey table", KEY_NOT_FOUND); } if (omKeyInfo.getMetadata().containsKey(OzoneConsts.LEASE_RECOVERY) && omKeyInfo.getMetadata().containsKey(OzoneConsts.HSYNC_CLIENT_ID)) { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java index 82d3bdc9e8ec..61e5976f8052 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequest.java @@ -22,6 +22,8 @@ import java.nio.file.InvalidPathException; import java.util.Map; +import org.apache.hadoop.hdds.utils.db.Table; +import org.apache.hadoop.ozone.OzoneConsts; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.ozone.OmUtils; import org.apache.hadoop.ozone.om.helpers.BucketLayout; @@ -147,7 +149,7 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn // Set the UpdateID to current transactionLogIndex omKeyInfo.setUpdateID(trxnLogIndex, ozoneManager.isRatisEnabled()); - // Update table cache. + // Update table cache. Put a tombstone entry omMetadataManager.getKeyTable(getBucketLayout()).addCacheEntry( new CacheKey<>( omMetadataManager.getOzoneKey(volumeName, bucketName, keyName)), @@ -160,15 +162,25 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn omBucketInfo.incrUsedBytes(-quotaReleased); omBucketInfo.incrUsedNamespace(-1L); - // No need to add cache entries to delete table. As delete table will - // be used by DeleteKeyService only, not used for any client response - // validation, so we don't need to add to cache. - // TODO: Revisit if we need it later. + // If omKeyInfo has hsync metadata, delete its corresponding open key as well + String dbOpenKey = null; + String hsyncClientId = omKeyInfo.getMetadata().get(OzoneConsts.HSYNC_CLIENT_ID); + if (hsyncClientId != null) { + Table openKeyTable = omMetadataManager.getOpenKeyTable(getBucketLayout()); + 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); + } else { + LOG.warn("Potentially inconsistent DB state: open key not found with dbOpenKey '{}'", dbOpenKey); + } + } omClientResponse = new OMKeyDeleteResponse( omResponse.setDeleteKeyResponse(DeleteKeyResponse.newBuilder()) .build(), omKeyInfo, ozoneManager.isRatisEnabled(), - omBucketInfo.copyObject()); + omBucketInfo.copyObject(), dbOpenKey); result = Result.SUCCESS; } catch (IOException | InvalidPathException ex) { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequestWithFSO.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequestWithFSO.java index a817c7116597..a0b2cfcbb154 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequestWithFSO.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyDeleteRequestWithFSO.java @@ -18,6 +18,8 @@ package org.apache.hadoop.ozone.om.request.key; +import org.apache.hadoop.hdds.utils.db.Table; +import org.apache.hadoop.ozone.OzoneConsts; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.hdds.utils.db.cache.CacheKey; import org.apache.hadoop.hdds.utils.db.cache.CacheValue; @@ -154,15 +156,26 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn omBucketInfo.incrUsedBytes(-quotaReleased); omBucketInfo.incrUsedNamespace(-1L); - // No need to add cache entries to delete table. As delete table will - // be used by DeleteKeyService only, not used for any client response - // validation, so we don't need to add to cache. - // TODO: Revisit if we need it later. + // If omKeyInfo has hsync metadata, delete its corresponding open key as well + String dbOpenKey = null; + String hsyncClientId = omKeyInfo.getMetadata().get(OzoneConsts.HSYNC_CLIENT_ID); + if (hsyncClientId != null) { + Table openKeyTable = omMetadataManager.getOpenKeyTable(getBucketLayout()); + long parentId = omKeyInfo.getParentObjectID(); + 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); + } else { + LOG.warn("Potentially inconsistent DB state: open key not found with dbOpenKey '{}'", dbOpenKey); + } + } omClientResponse = new OMKeyDeleteResponseWithFSO(omResponse .setDeleteKeyResponse(DeleteKeyResponse.newBuilder()).build(), keyName, omKeyInfo, ozoneManager.isRatisEnabled(), - omBucketInfo.copyObject(), keyStatus.isDirectory(), volumeId); + omBucketInfo.copyObject(), keyStatus.isDirectory(), volumeId, dbOpenKey); result = Result.SUCCESS; } catch (IOException | InvalidPathException ex) { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysDeleteRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysDeleteRequest.java index 20879a509457..6ddd257e22c3 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysDeleteRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeysDeleteRequest.java @@ -19,6 +19,8 @@ package org.apache.hadoop.ozone.om.request.key; import org.apache.commons.lang3.tuple.Pair; +import org.apache.hadoop.hdds.utils.db.Table; +import org.apache.hadoop.ozone.OzoneConsts; import org.apache.ratis.server.protocol.TermIndex; import org.apache.hadoop.hdds.utils.db.cache.CacheKey; import org.apache.hadoop.hdds.utils.db.cache.CacheValue; @@ -172,17 +174,18 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, TermIn OmBucketInfo omBucketInfo = getBucketInfo(omMetadataManager, volumeName, bucketName); + List dbOpenKeys = new ArrayList<>(); // Mark all keys which can be deleted, in cache as deleted. quotaReleased = markKeysAsDeletedInCache(ozoneManager, trxnLogIndex, omKeyInfoList, - dirList, omMetadataManager, quotaReleased); + dirList, omMetadataManager, quotaReleased, dbOpenKeys); omBucketInfo.incrUsedBytes(-quotaReleased); omBucketInfo.incrUsedNamespace(-1L * omKeyInfoList.size()); final long volumeId = omMetadataManager.getVolumeId(volumeName); omClientResponse = getOmClientResponse(ozoneManager, omKeyInfoList, dirList, omResponse, - unDeletedKeys, deleteStatus, omBucketInfo, volumeId); + unDeletedKeys, deleteStatus, omBucketInfo, volumeId, dbOpenKeys); result = Result.SUCCESS; @@ -257,7 +260,7 @@ protected OMClientResponse getOmClientResponse(OzoneManager ozoneManager, List omKeyInfoList, List dirList, OMResponse.Builder omResponse, OzoneManagerProtocolProtos.DeleteKeyArgs.Builder unDeletedKeys, - boolean deleteStatus, OmBucketInfo omBucketInfo, long volumeId) { + boolean deleteStatus, OmBucketInfo omBucketInfo, long volumeId, List dbOpenKeys) { OMClientResponse omClientResponse; omClientResponse = new OMKeysDeleteResponse(omResponse .setDeleteKeysResponse( @@ -265,23 +268,40 @@ protected OMClientResponse getOmClientResponse(OzoneManager ozoneManager, .setUnDeletedKeys(unDeletedKeys)) .setStatus(deleteStatus ? OK : PARTIAL_DELETE).setSuccess(deleteStatus) .build(), omKeyInfoList, ozoneManager.isRatisEnabled(), - omBucketInfo.copyObject()); + omBucketInfo.copyObject(), dbOpenKeys); return omClientResponse; } protected long markKeysAsDeletedInCache(OzoneManager ozoneManager, long trxnLogIndex, List omKeyInfoList, List dirList, - OMMetadataManager omMetadataManager, long quotaReleased) + OMMetadataManager omMetadataManager, long quotaReleased, List dbOpenKeys) throws IOException { for (OmKeyInfo omKeyInfo : omKeyInfoList) { + String volumeName = omKeyInfo.getVolumeName(); + String bucketName = omKeyInfo.getBucketName(); + String keyName = omKeyInfo.getKeyName(); omMetadataManager.getKeyTable(getBucketLayout()).addCacheEntry( - new CacheKey<>(omMetadataManager - .getOzoneKey(omKeyInfo.getVolumeName(), omKeyInfo.getBucketName(), - omKeyInfo.getKeyName())), + new CacheKey<>(omMetadataManager.getOzoneKey(volumeName, bucketName, keyName)), CacheValue.get(trxnLogIndex)); omKeyInfo.setUpdateID(trxnLogIndex, ozoneManager.isRatisEnabled()); quotaReleased += sumBlockLengths(omKeyInfo); + + // If omKeyInfo has hsync metadata, delete its corresponding open key as well + String hsyncClientId = omKeyInfo.getMetadata().get(OzoneConsts.HSYNC_CLIENT_ID); + if (hsyncClientId != null) { + Table openKeyTable = omMetadataManager.getOpenKeyTable(getBucketLayout()); + 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); + } else { + LOG.warn("Potentially inconsistent DB state: open key not found with dbOpenKey '{}'", dbOpenKey); + } + } } return quotaReleased; } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OmKeysDeleteRequestWithFSO.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OmKeysDeleteRequestWithFSO.java index e71c178ba50b..8858458f2c84 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OmKeysDeleteRequestWithFSO.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OmKeysDeleteRequestWithFSO.java @@ -17,8 +17,10 @@ */ package org.apache.hadoop.ozone.om.request.key; +import org.apache.hadoop.hdds.utils.db.Table; import org.apache.hadoop.hdds.utils.db.cache.CacheKey; import org.apache.hadoop.hdds.utils.db.cache.CacheValue; +import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.om.OMMetadataManager; import org.apache.hadoop.ozone.om.OzoneManager; import org.apache.hadoop.ozone.om.helpers.BucketLayout; @@ -30,6 +32,8 @@ import org.apache.hadoop.ozone.om.response.key.OMKeysDeleteResponseWithFSO; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos; import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.List; @@ -42,6 +46,8 @@ */ public class OmKeysDeleteRequestWithFSO extends OMKeysDeleteRequest { + public static final Logger LOG = LoggerFactory.getLogger(OmKeysDeleteRequestWithFSO.class); + public OmKeysDeleteRequestWithFSO( OzoneManagerProtocolProtos.OMRequest omRequest, BucketLayout bucketLayout) { @@ -82,7 +88,7 @@ protected long markKeysAsDeletedInCache( OzoneManager ozoneManager, long trxnLogIndex, List omKeyInfoList, List dirList, OMMetadataManager omMetadataManager, - long quotaReleased) throws IOException { + long quotaReleased, List dbOpenKeys) throws IOException { // Mark all keys which can be deleted, in cache as deleted. for (OmKeyInfo omKeyInfo : omKeyInfoList) { @@ -90,16 +96,33 @@ protected long markKeysAsDeletedInCache( omKeyInfo.getVolumeName()); final long bucketId = omMetadataManager.getBucketId( omKeyInfo.getVolumeName(), omKeyInfo.getBucketName()); + final long parentId = omKeyInfo.getParentObjectID(); + final String fileName = omKeyInfo.getFileName(); omMetadataManager.getKeyTable(getBucketLayout()).addCacheEntry( new CacheKey<>(omMetadataManager - .getOzonePathKey(volumeId, bucketId, - omKeyInfo.getParentObjectID(), - omKeyInfo.getFileName())), + .getOzonePathKey(volumeId, bucketId, parentId, fileName)), CacheValue.get(trxnLogIndex)); omKeyInfo.setUpdateID(trxnLogIndex, ozoneManager.isRatisEnabled()); quotaReleased += sumBlockLengths(omKeyInfo); + + // If omKeyInfo has hsync metadata, delete its corresponding open key as well + String hsyncClientId = omKeyInfo.getMetadata().get(OzoneConsts.HSYNC_CLIENT_ID); + if (hsyncClientId != null) { + Table openKeyTable = omMetadataManager.getOpenKeyTable(getBucketLayout()); + 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); + } else { + LOG.warn("Potentially inconsistent DB state: open key not found with dbOpenKey '{}'", dbOpenKey); + } + } } + // Mark directory keys. for (OmKeyInfo omKeyInfo : dirList) { final long volumeId = omMetadataManager.getVolumeId( @@ -123,7 +146,7 @@ protected OMClientResponse getOmClientResponse(OzoneManager ozoneManager, List omKeyInfoList, List dirList, OzoneManagerProtocolProtos.OMResponse.Builder omResponse, OzoneManagerProtocolProtos.DeleteKeyArgs.Builder unDeletedKeys, - boolean deleteStatus, OmBucketInfo omBucketInfo, long volumeId) { + boolean deleteStatus, OmBucketInfo omBucketInfo, long volumeId, List dbOpenKeys) { OMClientResponse omClientResponse; omClientResponse = new OMKeysDeleteResponseWithFSO(omResponse .setDeleteKeysResponse( @@ -131,8 +154,7 @@ protected OMClientResponse getOmClientResponse(OzoneManager ozoneManager, .setStatus(deleteStatus).setUnDeletedKeys(unDeletedKeys)) .setStatus(deleteStatus ? OK : PARTIAL_DELETE).setSuccess(deleteStatus) .build(), omKeyInfoList, dirList, ozoneManager.isRatisEnabled(), - omBucketInfo.copyObject(), volumeId); + omBucketInfo.copyObject(), volumeId, dbOpenKeys); return omClientResponse; - } } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyDeleteResponse.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyDeleteResponse.java index 828f82d853c2..7e5339ee5444 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyDeleteResponse.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyDeleteResponse.java @@ -34,22 +34,26 @@ import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.BUCKET_TABLE; import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.DELETED_TABLE; import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.KEY_TABLE; +import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.OPEN_KEY_TABLE; /** * Response for DeleteKey request. */ -@CleanupTableInfo(cleanupTables = {KEY_TABLE, DELETED_TABLE, BUCKET_TABLE}) +@CleanupTableInfo(cleanupTables = {KEY_TABLE, OPEN_KEY_TABLE, DELETED_TABLE, BUCKET_TABLE}) public class OMKeyDeleteResponse extends AbstractOMKeyDeleteResponse { private OmKeyInfo omKeyInfo; private OmBucketInfo omBucketInfo; + // If not null, this key will be deleted from OpenKeyTable + private String dbOpenKey; public OMKeyDeleteResponse(@Nonnull OMResponse omResponse, @Nonnull OmKeyInfo omKeyInfo, boolean isRatisEnabled, - @Nonnull OmBucketInfo omBucketInfo) { + @Nonnull OmBucketInfo omBucketInfo, String dbOpenKey) { super(omResponse, isRatisEnabled, omBucketInfo.getBucketLayout()); this.omKeyInfo = omKeyInfo; this.omBucketInfo = omBucketInfo; + this.dbOpenKey = dbOpenKey; } /** @@ -78,6 +82,12 @@ public void addToDBBatch(OMMetadataManager omMetadataManager, omMetadataManager.getBucketTable().putWithBatch(batchOperation, omMetadataManager.getBucketKey(omBucketInfo.getVolumeName(), omBucketInfo.getBucketName()), omBucketInfo); + + // Remove open key (necessary when the file is hsync'ed but not committed) + if (dbOpenKey != null) { + omMetadataManager.getOpenKeyTable(getBucketLayout()).deleteWithBatch( + batchOperation, dbOpenKey); + } } protected OmKeyInfo getOmKeyInfo() { @@ -87,4 +97,8 @@ protected OmKeyInfo getOmKeyInfo() { protected OmBucketInfo getOmBucketInfo() { return omBucketInfo; } + + public String getDbOpenKey() { + return dbOpenKey; + } } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyDeleteResponseWithFSO.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyDeleteResponseWithFSO.java index c2773429f4d9..b52e4f44761f 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyDeleteResponseWithFSO.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyDeleteResponseWithFSO.java @@ -35,11 +35,12 @@ import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.DELETED_TABLE; import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.DIRECTORY_TABLE; import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.FILE_TABLE; +import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.OPEN_FILE_TABLE; /** * Response for DeleteKey request. */ -@CleanupTableInfo(cleanupTables = {FILE_TABLE, DIRECTORY_TABLE, +@CleanupTableInfo(cleanupTables = {FILE_TABLE, OPEN_FILE_TABLE, DIRECTORY_TABLE, DELETED_TABLE, DELETED_DIR_TABLE, BUCKET_TABLE}) public class OMKeyDeleteResponseWithFSO extends OMKeyDeleteResponse { @@ -51,8 +52,8 @@ public class OMKeyDeleteResponseWithFSO extends OMKeyDeleteResponse { public OMKeyDeleteResponseWithFSO(@Nonnull OMResponse omResponse, @Nonnull String keyName, @Nonnull OmKeyInfo omKeyInfo, boolean isRatisEnabled, @Nonnull OmBucketInfo omBucketInfo, - @Nonnull boolean isDeleteDirectory, @Nonnull long volumeId) { - super(omResponse, omKeyInfo, isRatisEnabled, omBucketInfo); + @Nonnull boolean isDeleteDirectory, @Nonnull long volumeId, String dbOpenKey) { + super(omResponse, omKeyInfo, isRatisEnabled, omBucketInfo, dbOpenKey); this.keyName = keyName; this.isDeleteDirectory = isDeleteDirectory; this.volumeId = volumeId; @@ -108,6 +109,11 @@ public void addToDBBatch(OMMetadataManager omMetadataManager, omMetadataManager.getBucketTable().putWithBatch(batchOperation, omMetadataManager.getBucketKey(getOmBucketInfo().getVolumeName(), getOmBucketInfo().getBucketName()), getOmBucketInfo()); + + if (getDbOpenKey() != null) { + omMetadataManager.getOpenKeyTable(getBucketLayout()).deleteWithBatch( + batchOperation, getDbOpenKey()); + } } @Override diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeysDeleteResponse.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeysDeleteResponse.java index cf09247e695e..3c5184219990 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeysDeleteResponse.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeysDeleteResponse.java @@ -34,23 +34,27 @@ import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.BUCKET_TABLE; import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.DELETED_TABLE; import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.KEY_TABLE; +import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.OPEN_KEY_TABLE; import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status.OK; import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status.PARTIAL_DELETE; /** * Response for DeleteKey request. */ -@CleanupTableInfo(cleanupTables = {KEY_TABLE, DELETED_TABLE, BUCKET_TABLE}) +@CleanupTableInfo(cleanupTables = {KEY_TABLE, OPEN_KEY_TABLE, DELETED_TABLE, BUCKET_TABLE}) public class OMKeysDeleteResponse extends AbstractOMKeyDeleteResponse { private List omKeyInfoList; private OmBucketInfo omBucketInfo; + private List dbOpenKeys; public OMKeysDeleteResponse(@Nonnull OMResponse omResponse, @Nonnull List keyDeleteList, - boolean isRatisEnabled, @Nonnull OmBucketInfo omBucketInfo) { + boolean isRatisEnabled, @Nonnull OmBucketInfo omBucketInfo, + @Nonnull List dbOpenKeys) { super(omResponse, isRatisEnabled); this.omKeyInfoList = keyDeleteList; this.omBucketInfo = omBucketInfo; + this.dbOpenKeys = dbOpenKeys; } /** @@ -95,6 +99,11 @@ public void addToDBBatch(OMMetadataManager omMetadataManager, omMetadataManager.getBucketTable().putWithBatch(batchOperation, omMetadataManager.getBucketKey(omBucketInfo.getVolumeName(), omBucketInfo.getBucketName()), omBucketInfo); + + for (String dbOpenKey : dbOpenKeys) { + omMetadataManager.getOpenKeyTable(getBucketLayout()).deleteWithBatch( + batchOperation, dbOpenKey); + } } public List getOmKeyInfoList() { @@ -104,4 +113,8 @@ public List getOmKeyInfoList() { public OmBucketInfo getOmBucketInfo() { return omBucketInfo; } + + public List getDbOpenKeys() { + return dbOpenKeys; + } } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeysDeleteResponseWithFSO.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeysDeleteResponseWithFSO.java index a5f578703007..43fed7ad150e 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeysDeleteResponseWithFSO.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeysDeleteResponseWithFSO.java @@ -36,11 +36,12 @@ import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.DELETED_TABLE; import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.DIRECTORY_TABLE; import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.FILE_TABLE; +import static org.apache.hadoop.ozone.om.OmMetadataManagerImpl.OPEN_FILE_TABLE; /** * Response for DeleteKeys request. */ -@CleanupTableInfo(cleanupTables = { FILE_TABLE, DIRECTORY_TABLE, +@CleanupTableInfo(cleanupTables = { FILE_TABLE, OPEN_FILE_TABLE, DIRECTORY_TABLE, DELETED_DIR_TABLE, DELETED_TABLE, BUCKET_TABLE }) public class OMKeysDeleteResponseWithFSO extends OMKeysDeleteResponse { @@ -51,8 +52,9 @@ public OMKeysDeleteResponseWithFSO( @NotNull OzoneManagerProtocolProtos.OMResponse omResponse, @NotNull List keyDeleteList, @NotNull List dirDeleteList, boolean isRatisEnabled, - @NotNull OmBucketInfo omBucketInfo, @Nonnull long volId) { - super(omResponse, keyDeleteList, isRatisEnabled, omBucketInfo); + @NotNull OmBucketInfo omBucketInfo, @Nonnull long volId, + @Nonnull List dbOpenKeys) { + super(omResponse, keyDeleteList, isRatisEnabled, omBucketInfo, dbOpenKeys); this.dirsList = dirDeleteList; this.volumeId = volId; } @@ -93,6 +95,11 @@ public void addToDBBatch(OMMetadataManager omMetadataManager, omMetadataManager.getBucketTable().putWithBatch(batchOperation, omMetadataManager.getBucketKey(getOmBucketInfo().getVolumeName(), getOmBucketInfo().getBucketName()), getOmBucketInfo()); + + for (String dbOpenKey : getDbOpenKeys()) { + omMetadataManager.getOpenKeyTable(getBucketLayout()).deleteWithBatch( + batchOperation, dbOpenKey); + } } @Override diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyDeleteResponse.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyDeleteResponse.java index 4690b6f56f72..a000c3f9694e 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyDeleteResponse.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyDeleteResponse.java @@ -173,7 +173,7 @@ protected String addKeyToTable() throws Exception { protected OMKeyDeleteResponse getOmKeyDeleteResponse(OmKeyInfo omKeyInfo, OzoneManagerProtocolProtos.OMResponse omResponse) throws Exception { - return new OMKeyDeleteResponse(omResponse, omKeyInfo, true, omBucketInfo); + return new OMKeyDeleteResponse(omResponse, omKeyInfo, true, omBucketInfo, null); } protected OmBucketInfo getOmBucketInfo() { diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyDeleteResponseWithFSO.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyDeleteResponseWithFSO.java index fda72eb91243..588907c6ce88 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyDeleteResponseWithFSO.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyDeleteResponseWithFSO.java @@ -36,7 +36,7 @@ protected OMKeyDeleteResponse getOmKeyDeleteResponse(OmKeyInfo omKeyInfo, OzoneManagerProtocolProtos.OMResponse omResponse) throws Exception { return new OMKeyDeleteResponseWithFSO(omResponse, omKeyInfo.getKeyName(), omKeyInfo, true, getOmBucketInfo(), false, - omMetadataManager.getVolumeId(volumeName)); + omMetadataManager.getVolumeId(volumeName), null); } @Override diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeysDeleteResponse.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeysDeleteResponse.java index 0c9c725c1b86..60f371ba1f88 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeysDeleteResponse.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeysDeleteResponse.java @@ -28,6 +28,7 @@ import org.junit.jupiter.api.Test; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static org.apache.hadoop.hdds.protocol.proto.HddsProtos.ReplicationFactor.THREE; @@ -103,7 +104,7 @@ public void testKeysDeleteResponse() throws Exception { protected OMClientResponse getOmKeysDeleteResponse(OMResponse omResponse, OmBucketInfo omBucketInfo) { return new OMKeysDeleteResponse( - omResponse, omKeyInfoList, true, omBucketInfo); + omResponse, omKeyInfoList, true, omBucketInfo, Collections.emptyList()); } @Test diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeysDeleteResponseWithFSO.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeysDeleteResponseWithFSO.java index fd70308c43d1..148a4e28c1b2 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeysDeleteResponseWithFSO.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeysDeleteResponseWithFSO.java @@ -38,6 +38,7 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status.OK; @@ -110,7 +111,7 @@ protected OMClientResponse getOmKeysDeleteResponse(OMResponse omResponse, OmBucketInfo omBucketInfo) { return new OMKeysDeleteResponseWithFSO( omResponse, getOmKeyInfoList(), dirDeleteList, true, omBucketInfo, - volId); + volId, Collections.emptyList()); } @Test