This is an automated email from the ASF dual-hosted git repository.
sammichen pushed a commit to branch HDDS-7593
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-7593 by this push:
new b532f81e00 HDDS-10077. Add hsync metadata to hsync'ed keys in
OpenKeyTable as well (#6046)
b532f81e00 is described below
commit b532f81e00c1df1b23562ddcfff32671949df453
Author: Siyao Meng <[email protected]>
AuthorDate: Mon Jan 29 19:47:17 2024 -0800
HDDS-10077. Add hsync metadata to hsync'ed keys in OpenKeyTable as well
(#6046)
---
.../java/org/apache/hadoop/fs/ozone/TestHSync.java | 107 ++++++++++++++++++++-
.../apache/hadoop/fs/ozone/TestLeaseRecovery.java | 12 ++-
.../hadoop/ozone/om/OmMetadataManagerImpl.java | 34 +------
.../om/request/file/OMRecoverLeaseRequest.java | 4 +-
.../ozone/om/request/key/OMKeyCommitRequest.java | 39 +++++---
.../om/request/key/OMKeyCommitRequestWithFSO.java | 38 +++++---
.../ozone/om/request/util/OmKeyHSyncUtil.java | 56 +++++++++++
.../ozone/om/response/key/OMKeyCommitResponse.java | 14 ++-
.../response/key/OMKeyCommitResponseWithFSO.java | 10 +-
.../om/request/key/TestOMKeyCommitRequest.java | 12 +--
.../om/response/key/TestOMKeyCommitResponse.java | 8 +-
.../key/TestOMKeyCommitResponseWithFSO.java | 4 +-
12 files changed, 261 insertions(+), 77 deletions(-)
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 c7a5c23164..8d7439604e 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
@@ -26,6 +26,7 @@ import java.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.lang3.RandomStringUtils;
@@ -66,6 +67,7 @@ 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.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
import org.apache.hadoop.ozone.om.request.key.OMKeyCommitRequest;
import org.apache.hadoop.ozone.om.request.key.OMKeyCommitRequestWithFSO;
@@ -75,13 +77,17 @@ import org.apache.hadoop.util.Time;
import org.apache.ozone.test.GenericTestUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
+import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import static java.nio.charset.StandardCharsets.UTF_8;
+import static
org.apache.hadoop.ozone.OzoneConfigKeys.OZONE_BLOCK_DELETING_SERVICE_INTERVAL;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_OFS_URI_SCHEME;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_ROOT;
import static org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_DELIMITER;
@@ -89,6 +95,7 @@ import static
org.apache.hadoop.ozone.OzoneConsts.OZONE_URI_SCHEME;
import static
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_DEFAULT_BUCKET_LAYOUT;
import static org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_ADDRESS_KEY;
import static
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_RATIS_ENABLE_KEY;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -101,6 +108,7 @@ import static org.mockito.Mockito.when;
* Test HSync.
*/
@Timeout(value = 300)
+@TestMethodOrder(OrderAnnotation.class)
public class TestHSync {
private static final Logger LOG =
LoggerFactory.getLogger(TestHSync.class);
@@ -110,6 +118,7 @@ public class TestHSync {
private static final OzoneConfiguration CONF = new OzoneConfiguration();
private static OzoneClient client;
+ private static final BucketLayout BUCKET_LAYOUT =
BucketLayout.FILE_SYSTEM_OPTIMIZED;
@BeforeAll
public static void init() throws Exception {
@@ -117,11 +126,13 @@ public class TestHSync {
final int flushSize = 2 * chunkSize;
final int maxFlushSize = 2 * flushSize;
final int blockSize = 2 * maxFlushSize;
- final BucketLayout layout = BucketLayout.FILE_SYSTEM_OPTIMIZED;
+ final BucketLayout layout = BUCKET_LAYOUT;
CONF.setBoolean(OZONE_OM_RATIS_ENABLE_KEY, false);
CONF.set(OZONE_DEFAULT_BUCKET_LAYOUT, layout.name());
CONF.setBoolean(OzoneConfigKeys.OZONE_FS_HSYNC_ENABLED, true);
+ // Reduce KeyDeletingService interval
+ CONF.setTimeDuration(OZONE_BLOCK_DELETING_SERVICE_INTERVAL, 100,
TimeUnit.MILLISECONDS);
cluster = MiniOzoneCluster.newBuilder(CONF)
.setNumDatanodes(5)
.setTotalPipelineNumLimit(10)
@@ -154,6 +165,83 @@ public class TestHSync {
}
}
+ @Test
+ // Making this the first test to be run to avoid db key composition headaches
+ @Order(1)
+ public void testKeyMetadata() throws Exception {
+ // Tests key metadata behavior upon create(), hsync() and close():
+ // 1. When a key is create()'d, neither OpenKeyTable nor KeyTable entry
shall have hsync metadata.
+ // 2. When the key is hsync()'ed, both OpenKeyTable and KeyTable shall
have hsync metadata.
+ // 3. When the key is hsync()'ed again, both OpenKeyTable and KeyTable
shall have hsync metadata.
+ // 4. When the key is close()'d, KeyTable entry shall not have hsync
metadata. Key shall not exist in OpenKeyTable.
+
+ 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 String keyName = "file-test-key-metadata";
+ final Path file = new Path(dir, keyName);
+
+ OMMetadataManager omMetadataManager =
+ cluster.getOzoneManager().getMetadataManager();
+
+ // Expect empty OpenKeyTable and KeyTable before key creation
+ Table<String, OmKeyInfo> openKeyTable =
omMetadataManager.getOpenKeyTable(BUCKET_LAYOUT);
+ assertTrue(openKeyTable.isEmpty());
+ Table<String, OmKeyInfo> keyTable =
omMetadataManager.getKeyTable(BUCKET_LAYOUT);
+ assertTrue(keyTable.isEmpty());
+
+ try (FileSystem fs = FileSystem.get(CONF)) {
+ try (FSDataOutputStream os = fs.create(file, true)) {
+ // Wait for double buffer flush to avoid flakiness because RDB
iterator bypasses table cache
+ cluster.getOzoneManager().awaitDoubleBufferFlush();
+ // OpenKeyTable key should NOT have HSYNC_CLIENT_ID
+ OmKeyInfo keyInfo = getFirstKeyInTable(keyName, openKeyTable);
+
assertFalse(keyInfo.getMetadata().containsKey(OzoneConsts.HSYNC_CLIENT_ID));
+ // KeyTable should still be empty
+ assertTrue(keyTable.isEmpty());
+
+ os.hsync();
+ cluster.getOzoneManager().awaitDoubleBufferFlush();
+ // OpenKeyTable key should have HSYNC_CLIENT_ID now
+ keyInfo = getFirstKeyInTable(keyName, openKeyTable);
+
assertTrue(keyInfo.getMetadata().containsKey(OzoneConsts.HSYNC_CLIENT_ID));
+ // KeyTable key should be there and have HSYNC_CLIENT_ID
+ keyInfo = getFirstKeyInTable(keyName, keyTable);
+
assertTrue(keyInfo.getMetadata().containsKey(OzoneConsts.HSYNC_CLIENT_ID));
+
+ // hsync again, metadata should not change
+ os.hsync();
+ cluster.getOzoneManager().awaitDoubleBufferFlush();
+ keyInfo = getFirstKeyInTable(keyName, openKeyTable);
+
assertTrue(keyInfo.getMetadata().containsKey(OzoneConsts.HSYNC_CLIENT_ID));
+ keyInfo = getFirstKeyInTable(keyName, keyTable);
+
assertTrue(keyInfo.getMetadata().containsKey(OzoneConsts.HSYNC_CLIENT_ID));
+ }
+ // key is closed, OpenKeyTable should be empty
+ cluster.getOzoneManager().awaitDoubleBufferFlush();
+ assertTrue(openKeyTable.isEmpty());
+ // KeyTable should have the key. But the key shouldn't have metadata
HSYNC_CLIENT_ID anymore
+ OmKeyInfo keyInfo = getFirstKeyInTable(keyName, keyTable);
+
assertFalse(keyInfo.getMetadata().containsKey(OzoneConsts.HSYNC_CLIENT_ID));
+
+ // Clean up
+ assertTrue(fs.delete(file, false));
+ // Wait for KeyDeletingService to finish to avoid interfering other tests
+ Table<String, RepeatedOmKeyInfo> deletedTable =
omMetadataManager.getDeletedTable();
+ GenericTestUtils.waitFor(
+ () -> {
+ try {
+ return deletedTable.isEmpty();
+ } catch (IOException e) {
+ return false;
+ }
+ }, 250, 10000);
+ }
+ }
+
@Test
public void testKeyHSyncThenClose() throws Exception {
// Check that deletedTable should not have keys with the same block as in
@@ -597,6 +685,23 @@ public class TestHSync {
}
}
+ /**
+ * Helper method to check and get the first key in the OpenKeyTable.
+ * @param keyName expect key name to contain this string
+ * @param openKeyTable Table<String, OmKeyInfo>
+ * @return OmKeyInfo
+ */
+ private OmKeyInfo getFirstKeyInTable(String keyName, Table<String,
OmKeyInfo> openKeyTable) throws IOException {
+ try (TableIterator<String, ? extends Table.KeyValue<String, OmKeyInfo>> it
= openKeyTable.iterator()) {
+ assertTrue(it.hasNext());
+ Table.KeyValue<String, OmKeyInfo> kv = it.next();
+ String dbOpenKey = kv.getKey();
+ assertNotNull(dbOpenKey);
+ assertTrue(dbOpenKey.contains(keyName));
+ return kv.getValue();
+ }
+ }
+
private void testEncryptedStreamCapabilities(boolean isEC) throws
IOException,
GeneralSecurityException {
KeyOutputStream kos;
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java
index a40c7f5275..93775f4013 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/fs/ozone/TestLeaseRecovery.java
@@ -92,10 +92,14 @@ public class TestLeaseRecovery {
* is no longer open in OM. This is currently expected (see HDDS-9358).
*/
public static void closeIgnoringKeyNotFound(OutputStream stream) {
+ closeIgnoringOMException(stream, OMException.ResultCodes.KEY_NOT_FOUND);
+ }
+
+ public static void closeIgnoringOMException(OutputStream stream,
OMException.ResultCodes expectedResultCode) {
try {
stream.close();
} catch (IOException e) {
- assertEquals(OMException.ResultCodes.KEY_NOT_FOUND,
((OMException)e).getResult());
+ assertEquals(expectedResultCode, ((OMException)e).getResult());
}
}
@@ -327,7 +331,11 @@ public class TestLeaseRecovery {
// Since all DNs are out, then the length in OM keyInfo will be used as
the final file length
assertEquals(dataSize, fileStatus.getLen());
} finally {
- closeIgnoringKeyNotFound(stream);
+ if (!forceRecovery) {
+ closeIgnoringOMException(stream,
OMException.ResultCodes.KEY_UNDER_LEASE_RECOVERY);
+ } else {
+ closeIgnoringKeyNotFound(stream);
+ }
KeyValueHandler.setInjector(null);
}
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 86ba834bc9..cd0382f599 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
@@ -104,7 +104,6 @@ import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import static org.apache.hadoop.ozone.OzoneConsts.DB_TRANSIENT_MARKER;
-import static org.apache.hadoop.ozone.OzoneConsts.HSYNC_CLIENT_ID;
import static org.apache.hadoop.ozone.OzoneConsts.OM_DB_NAME;
import static org.apache.hadoop.ozone.OzoneConsts.OM_KEY_PREFIX;
import static
org.apache.hadoop.ozone.om.OMConfigKeys.OZONE_OM_FS_SNAPSHOT_MAX_LIMIT;
@@ -1207,10 +1206,8 @@ public class OmMetadataManagerImpl implements
OMMetadataManager,
// listKeys do. But that complicates the iteration logic by quite a bit.
// And if we do that, we need to refactor listKeys as well to dedup.
- final Table<String, OmKeyInfo> okTable, kTable;
+ final Table<String, OmKeyInfo> okTable;
okTable = getOpenKeyTable(bucketLayout);
- // keyTable required to check key hsync metadata. TODO: HDDS-10077
- kTable = getKeyTable(bucketLayout);
// No lock required since table iterator creates a "snapshot"
try (TableIterator<String, ? extends KeyValue<String, OmKeyInfo>>
@@ -1228,13 +1225,7 @@ public class OmMetadataManagerImpl implements
OMMetadataManager,
String dbKey = kv.getKey();
long clientID = OMMetadataManager.getClientIDFromOpenKeyDBKey(dbKey);
OmKeyInfo omKeyInfo = kv.getValue();
-
- // Trim client ID to get the keyTable dbKey
- int lastSlashIdx = dbKey.lastIndexOf(OM_KEY_PREFIX);
- String ktDbKey = dbKey.substring(0, lastSlashIdx);
- // Check whether the key has been hsync'ed by checking keyTable
- checkAndUpdateKeyHsyncStatus(omKeyInfo, ktDbKey, kTable);
-
+ // Note with HDDS-10077, there is no need to check KeyTable for
hsync metadata
openKeySessionList.add(
new OpenKeySession(clientID, omKeyInfo,
omKeyInfo.getLatestVersionLocations().getVersion()));
@@ -1261,23 +1252,6 @@ public class OmMetadataManagerImpl implements
OMMetadataManager,
openKeySessionList);
}
- /**
- * Check and update OmKeyInfo from OpenKeyTable with hsync status in
KeyTable.
- */
- private void checkAndUpdateKeyHsyncStatus(OmKeyInfo omKeyInfo,
- String dbKey,
- Table<String, OmKeyInfo> kTable)
- throws IOException {
- OmKeyInfo ktOmKeyInfo = kTable.get(dbKey);
- if (ktOmKeyInfo != null) {
- // The same key in OpenKeyTable also exists in KeyTable, indicating
- // the key has been hsync'ed
- String hsyncClientId = ktOmKeyInfo.getMetadata().get(HSYNC_CLIENT_ID);
- // Append HSYNC_CLIENT_ID to OmKeyInfo to be returned to the client
- omKeyInfo.getMetadata().put(HSYNC_CLIENT_ID, hsyncClientId);
- }
- }
-
@Override
public ListKeysResult listKeys(String volumeName, String bucketName,
String startKey, String keyPrefix, int
maxKeys)
@@ -1878,8 +1852,7 @@ public class OmMetadataManagerImpl implements
OMMetadataManager,
final String clientIdString
= dbOpenKeyName.substring(lastPrefix + 1);
- final OmKeyInfo info = kt.get(dbKeyName);
- final boolean isHsync = java.util.Optional.ofNullable(info)
+ final boolean isHsync = java.util.Optional.of(openKeyInfo)
.map(WithMetadata::getMetadata)
.map(meta -> meta.get(OzoneConsts.HSYNC_CLIENT_ID))
.filter(id -> id.equals(clientIdString))
@@ -1892,6 +1865,7 @@ public class OmMetadataManagerImpl implements
OMMetadataManager,
} else if (isHsync && openKeyInfo.getModificationTime() <=
expiredLeaseTimestamp &&
!openKeyInfo.getMetadata().containsKey(OzoneConsts.LEASE_RECOVERY)) {
// add hsync'ed keys
+ final OmKeyInfo info = kt.get(dbKeyName);
final KeyArgs.Builder keyArgs = KeyArgs.newBuilder()
.setVolumeName(info.getVolumeName())
.setBucketName(info.getBucketName())
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMRecoverLeaseRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMRecoverLeaseRequest.java
index 6d997ed272..798fed7dcc 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMRecoverLeaseRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/file/OMRecoverLeaseRequest.java
@@ -22,8 +22,6 @@ import com.google.common.base.Preconditions;
import
org.apache.hadoop.hdds.scm.container.common.helpers.ContainerWithPipeline;
import org.apache.hadoop.hdds.security.token.OzoneBlockTokenSecretManager;
-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.audit.OMAction;
import org.apache.hadoop.ozone.om.OMMetadataManager;
@@ -238,7 +236,7 @@ public class OMRecoverLeaseRequest extends OMKeyRequest {
openKeyInfo.setModificationTime(Time.now());
// add to cache.
omMetadataManager.getOpenKeyTable(getBucketLayout()).addCacheEntry(
- new CacheKey<>(dbOpenFileKey), CacheValue.get(transactionLogIndex,
openKeyInfo));
+ dbOpenFileKey, openKeyInfo, transactionLogIndex);
}
// override key name with normalizedKeyPath
keyInfo.setKeyName(keyName);
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 ab6357a01d..154e456414 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
@@ -42,6 +42,7 @@ import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.WithMetadata;
import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
+import org.apache.hadoop.ozone.om.request.util.OmKeyHSyncUtil;
import org.apache.hadoop.ozone.om.request.validation.RequestFeatureValidator;
import org.apache.hadoop.ozone.om.request.validation.RequestProcessingPhase;
import org.apache.hadoop.ozone.om.request.validation.ValidationCondition;
@@ -81,8 +82,7 @@ import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.BUCKET_L
public class OMKeyCommitRequest extends OMKeyRequest {
@VisibleForTesting
- public static final Logger LOG =
- LoggerFactory.getLogger(OMKeyCommitRequest.class);
+ public static final Logger LOG =
LoggerFactory.getLogger(OMKeyCommitRequest.class);
public OMKeyCommitRequest(OMRequest omRequest, BucketLayout bucketLayout) {
super(omRequest, bucketLayout);
@@ -237,7 +237,7 @@ public class OMKeyCommitRequest extends OMKeyRequest {
final String clientIdString = String.valueOf(writerClientId);
if (null != keyToDelete) {
- isPreviousCommitHsync = java.util.Optional.ofNullable(keyToDelete)
+ isPreviousCommitHsync = java.util.Optional.of(keyToDelete)
.map(WithMetadata::getMetadata)
.map(meta -> meta.get(OzoneConsts.HSYNC_CLIENT_ID))
.filter(id -> id.equals(clientIdString))
@@ -260,17 +260,24 @@ public class OMKeyCommitRequest extends OMKeyRequest {
" metadata while recovery flag is not set in request",
KEY_UNDER_LEASE_RECOVERY);
}
}
- omKeyInfo.getMetadata().putAll(KeyValueUtil.getFromProtobuf(
- commitKeyArgs.getMetadataList()));
+
+ omKeyInfo.setModificationTime(commitKeyArgs.getModificationTime());
+
+ // non-null indicates it is necessary to update the open key
+ OmKeyInfo newOpenKeyInfo = null;
if (isHSync) {
- omKeyInfo.getMetadata().put(OzoneConsts.HSYNC_CLIENT_ID,
clientIdString);
- } else if (isRecovery) {
- omKeyInfo.getMetadata().remove(OzoneConsts.HSYNC_CLIENT_ID);
- omKeyInfo.getMetadata().remove(OzoneConsts.LEASE_RECOVERY);
+ if (!OmKeyHSyncUtil.isHSyncedPreviously(omKeyInfo, clientIdString,
dbOpenKey)) {
+ // Update open key as well if it is the first hsync of this key
+ omKeyInfo.getMetadata().put(OzoneConsts.HSYNC_CLIENT_ID,
clientIdString);
+ newOpenKeyInfo = omKeyInfo.copyObject();
+ }
}
+
+ omKeyInfo.getMetadata().putAll(KeyValueUtil.getFromProtobuf(
+ commitKeyArgs.getMetadataList()));
omKeyInfo.setDataSize(commitKeyArgs.getDataSize());
- omKeyInfo.setModificationTime(commitKeyArgs.getModificationTime());
+
// Update the block length for each block, return the allocated but
// uncommitted blocks
List<OmKeyLocationInfo> uncommitted =
@@ -337,6 +344,16 @@ public class OMKeyCommitRequest extends OMKeyRequest {
// So that this key can't be committed again.
omMetadataManager.getOpenKeyTable(getBucketLayout()).addCacheEntry(
dbOpenKey, trxnLogIndex);
+
+ // Prevent hsync metadata from getting committed to the final key
+ omKeyInfo.getMetadata().remove(OzoneConsts.HSYNC_CLIENT_ID);
+ if (isRecovery) {
+ omKeyInfo.getMetadata().remove(OzoneConsts.LEASE_RECOVERY);
+ }
+ } else if (newOpenKeyInfo != null) {
+ // isHSync is true and newOpenKeyInfo is set, update OpenKeyTable
+ omMetadataManager.getOpenKeyTable(getBucketLayout()).addCacheEntry(
+ dbOpenKey, newOpenKeyInfo, trxnLogIndex);
}
omMetadataManager.getKeyTable(getBucketLayout()).addCacheEntry(
@@ -346,7 +363,7 @@ public class OMKeyCommitRequest extends OMKeyRequest {
omClientResponse = new OMKeyCommitResponse(omResponse.build(),
omKeyInfo, dbOzoneKey, dbOpenKey, omBucketInfo.copyObject(),
- oldKeyVersionsToDeleteMap, isHSync);
+ oldKeyVersionsToDeleteMap, isHSync, newOpenKeyInfo);
result = Result.SUCCESS;
} catch (IOException | InvalidPathException ex) {
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequestWithFSO.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequestWithFSO.java
index 42bee999d8..f6f8f8b9cb 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequestWithFSO.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCommitRequestWithFSO.java
@@ -22,6 +22,7 @@ import java.nio.file.InvalidPathException;
import java.util.HashMap;
import com.google.common.annotations.VisibleForTesting;
+import org.apache.hadoop.ozone.om.request.util.OmKeyHSyncUtil;
import org.apache.ratis.server.protocol.TermIndex;
import org.apache.hadoop.ozone.OzoneConsts;
import org.apache.hadoop.ozone.audit.AuditLogger;
@@ -171,17 +172,23 @@ public class OMKeyCommitRequestWithFSO extends
OMKeyCommitRequest {
}
}
- omKeyInfo.getMetadata().putAll(KeyValueUtil.getFromProtobuf(
- commitKeyArgs.getMetadataList()));
+ omKeyInfo.setModificationTime(commitKeyArgs.getModificationTime());
+
+ final String clientIdString = String.valueOf(writerClientId);
+ // non-null indicates it is necessary to update the open key
+ OmKeyInfo newOpenKeyInfo = null;
+
if (isHSync) {
- omKeyInfo.getMetadata().put(OzoneConsts.HSYNC_CLIENT_ID,
String.valueOf(writerClientId));
- } else if (isRecovery) {
- omKeyInfo.getMetadata().remove(OzoneConsts.HSYNC_CLIENT_ID);
- omKeyInfo.getMetadata().remove(OzoneConsts.LEASE_RECOVERY);
+ if (!OmKeyHSyncUtil.isHSyncedPreviously(omKeyInfo, clientIdString,
dbOpenFileKey)) {
+ // Update open key as well if it is the first hsync of this key
+ omKeyInfo.getMetadata().put(OzoneConsts.HSYNC_CLIENT_ID,
clientIdString);
+ newOpenKeyInfo = omKeyInfo.copyObject();
+ }
}
+ omKeyInfo.getMetadata().putAll(KeyValueUtil.getFromProtobuf(
+ commitKeyArgs.getMetadataList()));
omKeyInfo.setDataSize(commitKeyArgs.getDataSize());
- omKeyInfo.setModificationTime(commitKeyArgs.getModificationTime());
List<OmKeyLocationInfo> uncommitted =
omKeyInfo.updateLocationInfoList(locationInfoList, false);
@@ -196,8 +203,7 @@ public class OMKeyCommitRequestWithFSO extends
OMKeyCommitRequest {
boolean isPreviousCommitHsync = false;
Map<String, RepeatedOmKeyInfo> oldKeyVersionsToDeleteMap = null;
if (null != keyToDelete) {
- final String clientIdString = String.valueOf(writerClientId);
- isPreviousCommitHsync = java.util.Optional.ofNullable(keyToDelete)
+ isPreviousCommitHsync = java.util.Optional.of(keyToDelete)
.map(WithMetadata::getMetadata)
.map(meta -> meta.get(OzoneConsts.HSYNC_CLIENT_ID))
.filter(id -> id.equals(clientIdString))
@@ -267,6 +273,16 @@ public class OMKeyCommitRequestWithFSO extends
OMKeyCommitRequest {
// So that this key can't be committed again.
OMFileRequest.addOpenFileTableCacheEntry(omMetadataManager,
dbOpenFileKey, null, fileName, trxnLogIndex);
+
+ // Prevent hsync metadata from getting committed to the final key
+ omKeyInfo.getMetadata().remove(OzoneConsts.HSYNC_CLIENT_ID);
+ if (isRecovery) {
+ omKeyInfo.getMetadata().remove(OzoneConsts.LEASE_RECOVERY);
+ }
+ } else if (newOpenKeyInfo != null) {
+ // isHSync is true and newOpenKeyInfo is set, update OpenKeyTable
+ OMFileRequest.addOpenFileTableCacheEntry(omMetadataManager,
+ dbOpenFileKey, newOpenKeyInfo, fileName, trxnLogIndex);
}
OMFileRequest.addFileTableCacheEntry(omMetadataManager, dbFileKey,
@@ -275,8 +291,8 @@ public class OMKeyCommitRequestWithFSO extends
OMKeyCommitRequest {
omBucketInfo.incrUsedBytes(correctedSpace);
omClientResponse = new OMKeyCommitResponseWithFSO(omResponse.build(),
- omKeyInfo, dbFileKey, dbOpenFileKey, omBucketInfo.copyObject(),
- oldKeyVersionsToDeleteMap, volumeId, isHSync);
+ omKeyInfo, dbFileKey, dbOpenFileKey, omBucketInfo.copyObject(),
+ oldKeyVersionsToDeleteMap, volumeId, isHSync, newOpenKeyInfo);
result = Result.SUCCESS;
} catch (IOException | InvalidPathException ex) {
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/util/OmKeyHSyncUtil.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/util/OmKeyHSyncUtil.java
new file mode 100644
index 0000000000..e32b2e2177
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/util/OmKeyHSyncUtil.java
@@ -0,0 +1,56 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.ozone.om.request.util;
+
+import org.apache.hadoop.ozone.OzoneConsts;
+import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper methods related to OM key HSync.
+ */
+public final class OmKeyHSyncUtil {
+
+ public static final Logger LOG =
LoggerFactory.getLogger(OmKeyHSyncUtil.class);
+
+ private OmKeyHSyncUtil() {
+ }
+
+ /**
+ * Returns true if the key has been hsync'ed before (has metadata
HSYNC_CLIENT_ID).
+ * @param omKeyInfo OmKeyInfo
+ * @param clientIdString Client ID String
+ * @param dbOpenKey dbOpenKey
+ */
+ public static boolean isHSyncedPreviously(OmKeyInfo omKeyInfo, String
clientIdString, String dbOpenKey) {
+ // Check whether the key has been hsync'ed before
+ final String previousHsyncClientId =
omKeyInfo.getMetadata().get(OzoneConsts.HSYNC_CLIENT_ID);
+ if (previousHsyncClientId != null) {
+ if (clientIdString.equals(previousHsyncClientId)) {
+ // Same client ID, no need to update OpenKeyTable. One less DB write
+ return true;
+ } else {
+ // Sanity check. Should never enter
+ LOG.warn("Client ID '{}' currently hsync'ing key does not match
previous hsync client ID '{}'. dbOpenKey='{}'",
+ clientIdString, previousHsyncClientId, dbOpenKey);
+ }
+ }
+ return false;
+ }
+}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyCommitResponse.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyCommitResponse.java
index c4f90958c7..0de6d27eb5 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyCommitResponse.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyCommitResponse.java
@@ -49,15 +49,17 @@ public class OMKeyCommitResponse extends OmKeyResponse {
private String openKeyName;
private OmBucketInfo omBucketInfo;
private Map<String, RepeatedOmKeyInfo> keyToDeleteMap;
-
private boolean isHSync;
+ private OmKeyInfo newOpenKeyInfo;
+ @SuppressWarnings("checkstyle:ParameterNumber")
public OMKeyCommitResponse(
@Nonnull OMResponse omResponse,
@Nonnull OmKeyInfo omKeyInfo, String ozoneKeyName, String openKeyName,
@Nonnull OmBucketInfo omBucketInfo,
Map<String, RepeatedOmKeyInfo> keyToDeleteMap,
- boolean isHSync) {
+ boolean isHSync,
+ OmKeyInfo newOpenKeyInfo) {
super(omResponse, omBucketInfo.getBucketLayout());
this.omKeyInfo = omKeyInfo;
this.ozoneKeyName = ozoneKeyName;
@@ -65,6 +67,7 @@ public class OMKeyCommitResponse extends OmKeyResponse {
this.omBucketInfo = omBucketInfo;
this.keyToDeleteMap = keyToDeleteMap;
this.isHSync = isHSync;
+ this.newOpenKeyInfo = newOpenKeyInfo;
}
/**
@@ -85,6 +88,9 @@ public class OMKeyCommitResponse extends OmKeyResponse {
if (!isHSync()) {
omMetadataManager.getOpenKeyTable(getBucketLayout())
.deleteWithBatch(batchOperation, openKeyName);
+ } else if (newOpenKeyInfo != null) {
+ omMetadataManager.getOpenKeyTable(getBucketLayout()).putWithBatch(
+ batchOperation, openKeyName, newOpenKeyInfo);
}
omMetadataManager.getKeyTable(getBucketLayout())
@@ -133,4 +139,8 @@ public class OMKeyCommitResponse extends OmKeyResponse {
protected boolean isHSync() {
return isHSync;
}
+
+ public OmKeyInfo getNewOpenKeyInfo() {
+ return newOpenKeyInfo;
+ }
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyCommitResponseWithFSO.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyCommitResponseWithFSO.java
index 6073632e55..c12c3a295d 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyCommitResponseWithFSO.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/key/OMKeyCommitResponseWithFSO.java
@@ -47,16 +47,17 @@ public class OMKeyCommitResponseWithFSO extends
OMKeyCommitResponse {
private long volumeId;
- @SuppressWarnings("parameternumber")
+ @SuppressWarnings("checkstyle:ParameterNumber")
public OMKeyCommitResponseWithFSO(
@Nonnull OMResponse omResponse,
@Nonnull OmKeyInfo omKeyInfo,
String ozoneKeyName, String openKeyName,
@Nonnull OmBucketInfo omBucketInfo,
Map<String, RepeatedOmKeyInfo> deleteKeyMap, long volumeId,
- boolean isHSync) {
+ boolean isHSync,
+ OmKeyInfo newOpenKeyInfo) {
super(omResponse, omKeyInfo, ozoneKeyName, openKeyName,
- omBucketInfo, deleteKeyMap, isHSync);
+ omBucketInfo, deleteKeyMap, isHSync, newOpenKeyInfo);
this.volumeId = volumeId;
}
@@ -78,6 +79,9 @@ public class OMKeyCommitResponseWithFSO extends
OMKeyCommitResponse {
if (!this.isHSync()) {
omMetadataManager.getOpenKeyTable(getBucketLayout())
.deleteWithBatch(batchOperation, getOpenKeyName());
+ } else if (getNewOpenKeyInfo() != null) {
+ omMetadataManager.getOpenKeyTable(getBucketLayout()).putWithBatch(
+ batchOperation, getOpenKeyName(), getNewOpenKeyInfo());
}
OMFileRequest.addToFileTable(omMetadataManager, batchOperation,
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCommitRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCommitRequest.java
index f71ddbf9b8..abc5fcbb49 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCommitRequest.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCommitRequest.java
@@ -45,14 +45,10 @@ import org.apache.hadoop.ozone.om.helpers.OmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.OmKeyLocationInfo;
import org.apache.hadoop.ozone.om.response.OMClientResponse;
import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos;
-import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
- .CommitKeyRequest;
-import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
- .KeyArgs;
-import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
- .KeyLocation;
-import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos
- .OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CommitKeyRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.KeyArgs;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.KeyLocation;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyCommitResponse.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyCommitResponse.java
index 78b2dcec7c..c26a07c97e 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyCommitResponse.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyCommitResponse.java
@@ -65,7 +65,7 @@ public class TestOMKeyCommitResponse extends
TestOMKeyResponse {
String ozoneKey = getOzoneKey();
OMKeyCommitResponse omKeyCommitResponse = getOmKeyCommitResponse(
- omKeyInfo, omResponse, openKey, ozoneKey, keysToDelete, false);
+ omKeyInfo, omResponse, openKey, ozoneKey, keysToDelete, false,
null);
omKeyCommitResponse.addToDBBatch(omMetadataManager, batchOperation);
@@ -94,7 +94,7 @@ public class TestOMKeyCommitResponse extends
TestOMKeyResponse {
String ozoneKey = getOzoneKey();
OMKeyCommitResponse omKeyCommitResponse = getOmKeyCommitResponse(
- omKeyInfo, omResponse, openKey, ozoneKey, null, false);
+ omKeyInfo, omResponse, openKey, ozoneKey, null, false, null);
// As during commit Key, entry will be already there in openKeyTable.
// Adding it here.
@@ -148,7 +148,7 @@ public class TestOMKeyCommitResponse extends
TestOMKeyResponse {
@NotNull
protected OMKeyCommitResponse getOmKeyCommitResponse(OmKeyInfo omKeyInfo,
OzoneManagerProtocolProtos.OMResponse omResponse, String openKey,
- String ozoneKey, RepeatedOmKeyInfo deleteKeys, Boolean isHSync)
+ String ozoneKey, RepeatedOmKeyInfo deleteKeys, Boolean isHSync,
OmKeyInfo newOpenKeyInfo)
throws IOException {
assertNotNull(omBucketInfo);
Map<String, RepeatedOmKeyInfo> deleteKeyMap = new HashMap<>();
@@ -158,6 +158,6 @@ public class TestOMKeyCommitResponse extends
TestOMKeyResponse {
new RepeatedOmKeyInfo(e)));
}
return new OMKeyCommitResponse(omResponse, omKeyInfo, ozoneKey, openKey,
- omBucketInfo, deleteKeyMap, isHSync);
+ omBucketInfo, deleteKeyMap, isHSync, newOpenKeyInfo);
}
}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyCommitResponseWithFSO.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyCommitResponseWithFSO.java
index b320667803..f5838ddc0f 100644
---
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyCommitResponseWithFSO.java
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/response/key/TestOMKeyCommitResponseWithFSO.java
@@ -42,7 +42,7 @@ public class TestOMKeyCommitResponseWithFSO extends
TestOMKeyCommitResponse {
@Override
protected OMKeyCommitResponse getOmKeyCommitResponse(OmKeyInfo omKeyInfo,
OzoneManagerProtocolProtos.OMResponse omResponse, String openKey,
- String ozoneKey, RepeatedOmKeyInfo deleteKeys, Boolean isHSync)
+ String ozoneKey, RepeatedOmKeyInfo deleteKeys, Boolean isHSync,
OmKeyInfo newOpenKeyInfo)
throws IOException {
assertNotNull(omBucketInfo);
long volumeId = omMetadataManager.getVolumeId(omKeyInfo.getVolumeName());
@@ -55,7 +55,7 @@ public class TestOMKeyCommitResponseWithFSO extends
TestOMKeyCommitResponse {
new RepeatedOmKeyInfo(e)));
}
return new OMKeyCommitResponseWithFSO(omResponse, omKeyInfo, ozoneKey,
- openKey, omBucketInfo, deleteKeyMap, volumeId, isHSync);
+ openKey, omBucketInfo, deleteKeyMap, volumeId, isHSync,
newOpenKeyInfo);
}
@NotNull
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]