diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CacheConfig.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CacheConfig.java index d020eb0..b99fb90 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CacheConfig.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CacheConfig.java @@ -126,6 +126,13 @@ public class CacheConfig { public static final String PREFETCH_BLOCKS_ON_OPEN_KEY = "hbase.rs.prefetchblocksonopen"; + /** + * Configuration key to cache blocks when a compacted file is written, predicated on prefetching being enabled for + * the column family. + */ + public static final String PREFETCH_COMPACTED_BLOCKS_ON_WRITE_KEY = + "hbase.rs.prefetchcompactedblocksonwrite"; + /** * The target block size used by blockcache instances. Defaults to * {@link HConstants#DEFAULT_BLOCKSIZE}. @@ -170,6 +177,7 @@ public class CacheConfig { public static final boolean DEFAULT_EVICT_ON_CLOSE = false; public static final boolean DEFAULT_CACHE_DATA_COMPRESSED = false; public static final boolean DEFAULT_PREFETCH_ON_OPEN = false; + public static final boolean DEFAULT_PREFETCH_COMPACTED_BLOCKS_ON_WRITE = false; /** Local reference to the block cache, null if completely disabled */ private final BlockCache blockCache; @@ -203,6 +211,9 @@ public class CacheConfig { /** Whether data blocks should be prefetched into the cache */ private final boolean prefetchOnOpen; + /** Whether data blocks should be cached when compacted file is written for column families with prefetching */ + private final boolean prefetchCompactedDataOnWrite; + /** * If true and if more than one tier in this cache deploy -- e.g. CombinedBlockCache has an L1 * and an L2 tier -- then cache data blocks up in the L1 tier (The meta blocks are likely being @@ -235,6 +246,7 @@ public class CacheConfig { conf.getBoolean(CACHE_DATA_BLOCKS_COMPRESSED_KEY, DEFAULT_CACHE_DATA_COMPRESSED), conf.getBoolean(PREFETCH_BLOCKS_ON_OPEN_KEY, DEFAULT_PREFETCH_ON_OPEN) || family.isPrefetchBlocksOnOpen(), + conf.getBoolean(PREFETCH_COMPACTED_BLOCKS_ON_WRITE_KEY, DEFAULT_PREFETCH_COMPACTED_BLOCKS_ON_WRITE), conf.getBoolean(HColumnDescriptor.CACHE_DATA_IN_L1, HColumnDescriptor.DEFAULT_CACHE_DATA_IN_L1) || family.isCacheDataInL1(), conf.getBoolean(DROP_BEHIND_CACHE_COMPACTION_KEY,DROP_BEHIND_CACHE_COMPACTION_DEFAULT) @@ -260,6 +272,7 @@ public class CacheConfig { conf.getBoolean(EVICT_BLOCKS_ON_CLOSE_KEY, DEFAULT_EVICT_ON_CLOSE), conf.getBoolean(CACHE_DATA_BLOCKS_COMPRESSED_KEY, DEFAULT_CACHE_DATA_COMPRESSED), conf.getBoolean(PREFETCH_BLOCKS_ON_OPEN_KEY, DEFAULT_PREFETCH_ON_OPEN), + conf.getBoolean(PREFETCH_COMPACTED_BLOCKS_ON_WRITE_KEY, DEFAULT_PREFETCH_COMPACTED_BLOCKS_ON_WRITE), conf.getBoolean(HColumnDescriptor.CACHE_DATA_IN_L1, HColumnDescriptor.DEFAULT_CACHE_DATA_IN_L1), conf.getBoolean(DROP_BEHIND_CACHE_COMPACTION_KEY,DROP_BEHIND_CACHE_COMPACTION_DEFAULT) @@ -280,6 +293,8 @@ public class CacheConfig { * @param evictOnClose whether blocks should be evicted when HFile is closed * @param cacheDataCompressed whether to store blocks as compressed in the cache * @param prefetchOnOpen whether to prefetch blocks upon open + * @param prefetchCompactedDataOnWrite whether to cache data blocks should be cached when compacted files are written + * for column families with prefetching enabled * @param cacheDataInL1 If more than one cache tier deployed, if true, cache this column families * data blocks up in the L1 tier. */ @@ -288,7 +303,8 @@ public class CacheConfig { final boolean cacheDataOnWrite, final boolean cacheIndexesOnWrite, final boolean cacheBloomsOnWrite, final boolean evictOnClose, final boolean cacheDataCompressed, final boolean prefetchOnOpen, - final boolean cacheDataInL1, final boolean dropBehindCompaction) { + final boolean prefetchCompactedDataOnWrite, final boolean cacheDataInL1, + final boolean dropBehindCompaction) { this.blockCache = blockCache; this.cacheDataOnRead = cacheDataOnRead; this.inMemory = inMemory; @@ -298,6 +314,7 @@ public class CacheConfig { this.evictOnClose = evictOnClose; this.cacheDataCompressed = cacheDataCompressed; this.prefetchOnOpen = prefetchOnOpen; + this.prefetchCompactedDataOnWrite = prefetchCompactedDataOnWrite; this.cacheDataInL1 = cacheDataInL1; this.dropBehindCompaction = dropBehindCompaction; } @@ -311,7 +328,8 @@ public class CacheConfig { cacheConf.cacheDataOnWrite, cacheConf.cacheIndexesOnWrite, cacheConf.cacheBloomsOnWrite, cacheConf.evictOnClose, cacheConf.cacheDataCompressed, cacheConf.prefetchOnOpen, - cacheConf.cacheDataInL1, cacheConf.dropBehindCompaction); + cacheConf.prefetchCompactedDataOnWrite, cacheConf.cacheDataInL1, + cacheConf.dropBehindCompaction); } /** @@ -459,6 +477,13 @@ public class CacheConfig { return isBlockCacheEnabled() && this.prefetchOnOpen; } + /** + * @return true if blocks should be cached while writing during compaction, false if not + */ + public boolean shouldCacheCompactedBlocksOnWrite() { + return isBlockCacheEnabled() && this.prefetchCompactedDataOnWrite && this.prefetchOnOpen; + } + /** * Return true if we may find this type of block in block cache. *

diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java index 31a55fe..52cb157 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/regionserver/HStore.java @@ -1085,9 +1085,9 @@ public class HStore implements Store { throws IOException { final CacheConfig writerCacheConf; if (isCompaction) { - // Don't cache data on write on compactions. + // Don't cache data on write on compactions, unless specifically configured to do so writerCacheConf = new CacheConfig(cacheConf); - writerCacheConf.setCacheDataOnWrite(false); + writerCacheConf.setCacheDataOnWrite(cacheConf.shouldCacheCompactedBlocksOnWrite()); } else { writerCacheConf = cacheConf; } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/TestCacheOnWrite.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/TestCacheOnWrite.java index c72c039..97d8b4b 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/TestCacheOnWrite.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/TestCacheOnWrite.java @@ -89,6 +89,7 @@ public class TestCacheOnWrite { private final CacheOnWriteType cowType; private final Compression.Algorithm compress; private final boolean cacheCompressedData; + private final boolean prefetchCompactedBlocksOnWrite; private static final int DATA_BLOCK_SIZE = 2048; private static final int NUM_KV = 25000; @@ -136,11 +137,12 @@ public class TestCacheOnWrite { } public TestCacheOnWrite(CacheOnWriteType cowType, Compression.Algorithm compress, - boolean cacheCompressedData, BlockCache blockCache) { + boolean cacheCompressedData, BlockCache blockCache, boolean prefetchCompactedBlocksOnWrite) { this.cowType = cowType; this.compress = compress; this.cacheCompressedData = cacheCompressedData; this.blockCache = blockCache; + this.prefetchCompactedBlocksOnWrite = prefetchCompactedBlocksOnWrite; testDescription = "[cacheOnWrite=" + cowType + ", compress=" + compress + ", cacheCompressedData=" + cacheCompressedData + "]"; LOG.info(testDescription); @@ -175,7 +177,10 @@ public class TestCacheOnWrite { for (CacheOnWriteType cowType : CacheOnWriteType.values()) { for (Compression.Algorithm compress : HBaseTestingUtility.COMPRESSION_ALGORITHMS) { for (boolean cacheCompressedData : new boolean[] { false, true }) { - params.add(new Object[] { cowType, compress, cacheCompressedData, blockCache }); + for (boolean prefetchCompactedBlocksOnWrite : new boolean[] { false, true}) { + params.add(new Object[] { cowType, compress, cacheCompressedData, blockCache, + prefetchCompactedBlocksOnWrite }); + } } } } @@ -217,6 +222,7 @@ public class TestCacheOnWrite { conf.setInt(BloomFilterFactory.IO_STOREFILE_BLOOM_BLOCK_SIZE, BLOOM_BLOCK_SIZE); conf.setBoolean(CacheConfig.CACHE_DATA_BLOCKS_COMPRESSED_KEY, cacheCompressedData); + conf.setBoolean(CacheConfig.PREFETCH_COMPACTED_BLOCKS_ON_WRITE_KEY, prefetchCompactedBlocksOnWrite); cowType.modifyConf(conf); fs = HFileSystem.get(conf); CacheConfig.GLOBAL_BLOCK_CACHE_INSTANCE = blockCache; @@ -224,7 +230,7 @@ public class TestCacheOnWrite { new CacheConfig(blockCache, true, true, cowType.shouldBeCached(BlockType.DATA), cowType.shouldBeCached(BlockType.LEAF_INDEX), cowType.shouldBeCached(BlockType.BLOOM_CHUNK), false, cacheCompressedData, - false, false, false); + false, prefetchCompactedBlocksOnWrite, false, false); } @After @@ -381,7 +387,7 @@ public class TestCacheOnWrite { storeFilePath = sfw.getPath(); } - private void testNotCachingDataBlocksDuringCompactionInternals(boolean useTags) + private void testCachingDataBlocksDuringCompactionInternals(boolean useTags, boolean prefetchOnOpen) throws IOException, InterruptedException { if (useTags) { TEST_UTIL.getConfiguration().setInt("hfile.format.version", 3); @@ -397,6 +403,7 @@ public class TestCacheOnWrite { final int maxVersions = 3; Region region = TEST_UTIL.createTestRegion(table, new HColumnDescriptor(cf) + .setPrefetchBlocksOnOpen(prefetchOnOpen) .setCompressionType(compress) .setBloomFilterType(BLOOM_TYPE) .setMaxVersions(maxVersions) @@ -436,10 +443,26 @@ public class TestCacheOnWrite { region.compact(false); LOG.debug("compactStores() returned"); + // In cases where we are prefetching, the prefetch may or may not happen in time before we check if data blocks + // were cached, so we should sleep for a bit. But if we are caching on write, then there is no need to wait. + if (prefetchOnOpen && !prefetchCompactedBlocksOnWrite) { + Thread.sleep(1000); + } + + boolean dataBlockCached = false; for (CachedBlock block: blockCache) { - assertNotEquals(BlockType.ENCODED_DATA, block.getBlockType()); - assertNotEquals(BlockType.DATA, block.getBlockType()); + if (BlockType.ENCODED_DATA.equals(block.getBlockType()) || BlockType.DATA.equals(block.getBlockType())) { + dataBlockCached = true; + break; + } } + + // Data blocks should be cached in instances where we are prefetching. In the case of testing BucketCache, + // we cannot verify block type as it is not stored in the cache. + assertTrue("\nTest description: " + testDescription + "\nprefetchOnOpen: " + prefetchOnOpen + + "\nprefetchCompactedBlocksOnWrite: " + prefetchCompactedBlocksOnWrite + "\n", + (prefetchOnOpen && !(blockCache instanceof BucketCache)) == dataBlockCached); + ((HRegion)region).close(); } @@ -450,8 +473,9 @@ public class TestCacheOnWrite { } @Test - public void testNotCachingDataBlocksDuringCompaction() throws IOException, InterruptedException { - testNotCachingDataBlocksDuringCompactionInternals(false); - testNotCachingDataBlocksDuringCompactionInternals(true); + public void testCachingDataBlocksDuringCompaction() throws IOException, InterruptedException { + testCachingDataBlocksDuringCompactionInternals(false, false); + testCachingDataBlocksDuringCompactionInternals(true, false); + testCachingDataBlocksDuringCompactionInternals(true, true); } }