From 15158fced7540354e01dc6c3508edd653f2c96d5 Mon Sep 17 00:00:00 2001 From: weimingdiit Date: Tue, 10 Mar 2026 19:40:18 +0800 Subject: [PATCH] HDDS-14591. Cache HBASE_SUPPORT finalization status for putBlock --- .../keyvalue/impl/BlockManagerImpl.java | 26 +++++++++++++++--- .../keyvalue/impl/TestBlockManagerImpl.java | 27 +++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/impl/BlockManagerImpl.java b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/impl/BlockManagerImpl.java index 62dbcbe808eb..c987b32ea717 100644 --- a/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/impl/BlockManagerImpl.java +++ b/hadoop-hdds/container-service/src/main/java/org/apache/hadoop/ozone/container/keyvalue/impl/BlockManagerImpl.java @@ -21,11 +21,13 @@ import static org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos.Result.UNSUPPORTED_REQUEST; import static org.apache.hadoop.ozone.OzoneConsts.INCREMENTAL_CHUNK_LIST; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; import org.apache.hadoop.hdds.client.BlockID; import org.apache.hadoop.hdds.conf.ConfigurationSource; import org.apache.hadoop.hdds.scm.ScmConfigKeys; @@ -63,6 +65,7 @@ public class BlockManagerImpl implements BlockManager { private final int readMappedBufferThreshold; private final int readMappedBufferMaxCount; private final boolean readNettyChunkedNioFile; + private final AtomicBoolean hbaseSupportFinalized; /** * Constructs a Block Manager. @@ -84,6 +87,8 @@ public BlockManagerImpl(ConfigurationSource conf) { this.readNettyChunkedNioFile = config.getBoolean( ScmConfigKeys.OZONE_CHUNK_READ_NETTY_CHUNKED_NIO_FILE_KEY, ScmConfigKeys.OZONE_CHUNK_READ_NETTY_CHUNKED_NIO_FILE_DEFAULT); + this.hbaseSupportFinalized = new AtomicBoolean( + VersionedDatanodeFeatures.isFinalized(HDDSLayoutFeature.HBASE_SUPPORT)); } @Override @@ -227,13 +232,12 @@ public long persistPutBlock(KeyValueContainer container, } } - boolean incrementalEnabled = true; - if (!VersionedDatanodeFeatures.isFinalized(HDDSLayoutFeature.HBASE_SUPPORT)) { + boolean incrementalEnabled = isIncrementalChunkListFeatureFinalized(); + if (!incrementalEnabled) { if (isPartialChunkList(data)) { throw new StorageContainerException("DataNode has not finalized " + "upgrading to a version that supports incremental chunk list.", UNSUPPORTED_REQUEST); } - incrementalEnabled = false; } db.getStore().putBlockByID(batch, incrementalEnabled, localID, data, containerData, endOfBlock); @@ -461,6 +465,22 @@ private BlockData getBlockByID(DBHandle db, BlockID blockID, return db.getStore().getBlockByID(blockID, blockKey); } + @VisibleForTesting + boolean isIncrementalChunkListFeatureFinalized() { + if (hbaseSupportFinalized.get()) { + return true; + } + if (VersionedDatanodeFeatures.isFinalized(HDDSLayoutFeature.HBASE_SUPPORT)) { + if (hbaseSupportFinalized.compareAndSet(false, true)) { + LOG.info("Layout feature {} is finalized. Skipping finalization checks " + + "for incremental chunk list on subsequent putBlock requests.", + HDDSLayoutFeature.HBASE_SUPPORT); + } + return true; + } + return false; + } + private static boolean isPartialChunkList(BlockData data) { return data.getMetadata().containsKey(INCREMENTAL_CHUNK_LIST); } diff --git a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/impl/TestBlockManagerImpl.java b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/impl/TestBlockManagerImpl.java index eb58ac3ce843..c1ad83a89fc2 100644 --- a/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/impl/TestBlockManagerImpl.java +++ b/hadoop-hdds/container-service/src/test/java/org/apache/hadoop/ozone/container/keyvalue/impl/TestBlockManagerImpl.java @@ -22,11 +22,15 @@ import static org.apache.hadoop.ozone.container.keyvalue.helpers.KeyValueContainerUtil.isSameSchemaVersion; import static org.apache.hadoop.ozone.container.keyvalue.impl.BlockManagerImpl.FULL_CHUNK; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.when; import java.io.IOException; @@ -39,6 +43,7 @@ import org.apache.hadoop.hdds.conf.OzoneConfiguration; import org.apache.hadoop.hdds.protocol.datanode.proto.ContainerProtos; import org.apache.hadoop.hdds.scm.container.common.helpers.StorageContainerException; +import org.apache.hadoop.hdds.upgrade.HDDSLayoutFeature; import org.apache.hadoop.ozone.OzoneConsts; import org.apache.hadoop.ozone.container.common.helpers.BlockData; import org.apache.hadoop.ozone.container.common.helpers.ChunkInfo; @@ -53,9 +58,12 @@ import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainer; import org.apache.hadoop.ozone.container.keyvalue.KeyValueContainerData; import org.apache.hadoop.ozone.container.keyvalue.helpers.BlockUtils; +import org.apache.hadoop.ozone.container.upgrade.VersionedDatanodeFeatures; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; +import org.mockito.MockedStatic; /** * This class is used to test key related operations on the container. @@ -143,6 +151,25 @@ public void cleanup() { BlockUtils.shutdownCache(config); } + @Test + public void testFinalizationStatusCachedForIncrementalChunkListChecks() { + config = new OzoneConfiguration(); + try (MockedStatic mockedFeatures = + mockStatic(VersionedDatanodeFeatures.class)) { + mockedFeatures.when(() -> VersionedDatanodeFeatures.isFinalized( + HDDSLayoutFeature.HBASE_SUPPORT)) + .thenReturn(false, false, true); + + BlockManagerImpl manager = new BlockManagerImpl(config); + assertFalse(manager.isIncrementalChunkListFeatureFinalized()); + assertTrue(manager.isIncrementalChunkListFeatureFinalized()); + assertTrue(manager.isIncrementalChunkListFeatureFinalized()); + + mockedFeatures.verify(() -> VersionedDatanodeFeatures.isFinalized( + HDDSLayoutFeature.HBASE_SUPPORT), times(3)); + } + } + @ContainerTestVersionInfo.ContainerTest public void testPutBlock(ContainerTestVersionInfo versionInfo) throws Exception {