Skip to content

Commit 1bfabc0

Browse files
committed
CDPD-45890: HBASE-28189 Fix the miss count in one of CombinedBlockCache getBlock implementations (apache#5506)
Signed-off-by: Peter Somogyi <[email protected]> Change-Id: Icee78a9c839b3c4e4aac2176aa4091cdcd47a08b
1 parent bd25e27 commit 1bfabc0

File tree

2 files changed

+101
-9
lines changed

2 files changed

+101
-9
lines changed

hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/CombinedBlockCache.java

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.apache.hadoop.hbase.io.HeapSize;
2525
import org.apache.hadoop.hbase.io.hfile.bucket.BucketCache;
2626
import org.apache.yetus.audience.InterfaceAudience;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
2729

2830
/**
2931
* CombinedBlockCache is an abstraction layer that combines {@link FirstLevelBlockCache} and
@@ -39,6 +41,8 @@ public class CombinedBlockCache implements ResizableBlockCache, HeapSize {
3941
protected final BlockCache l2Cache;
4042
protected final CombinedCacheStats combinedCacheStats;
4143

44+
private static final Logger LOG = LoggerFactory.getLogger(CombinedBlockCache.class);
45+
4246
public CombinedBlockCache(FirstLevelBlockCache l1Cache, BlockCache l2Cache) {
4347
this.l1Cache = l1Cache;
4448
this.l2Cache = l2Cache;
@@ -78,17 +82,59 @@ public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf) {
7882
@Override
7983
public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat,
8084
boolean updateCacheMetrics) {
81-
// We are not in a position to exactly look at LRU cache or BC as BlockType may not be getting
82-
// passed always.
85+
Cacheable block = null;
86+
// We don't know the block type. We should try to get it on one of the caches only,
87+
// but not both otherwise we'll over compute on misses. Here we check if the key is on L1,
88+
// if so, call getBlock on L1 and that will compute the hit. Otherwise, we'll try to get it from
89+
// L2 and whatever happens, we'll update the stats there.
8390
boolean existInL1 = l1Cache.containsBlock(cacheKey);
84-
if (!existInL1 && updateCacheMetrics && !repeat) {
85-
// If the block does not exist in L1, the containsBlock should be counted as one miss.
86-
l1Cache.getStats().miss(caching, cacheKey.isPrimary(), cacheKey.getBlockType());
91+
// if we know it's in L1, just delegate call to l1 and return it
92+
if (existInL1) {
93+
block = l1Cache.getBlock(cacheKey, caching, repeat, false);
94+
} else {
95+
block = l2Cache.getBlock(cacheKey, caching, repeat, false);
96+
}
97+
if (updateCacheMetrics) {
98+
boolean metaBlock = isMetaBlock(cacheKey.getBlockType());
99+
if (metaBlock) {
100+
if (!existInL1 && block != null) {
101+
LOG.warn("Cache key {} had block type {}, but was found in L2 cache.", cacheKey,
102+
cacheKey.getBlockType());
103+
updateBlockMetrics(block, cacheKey, l2Cache, caching);
104+
} else {
105+
updateBlockMetrics(block, cacheKey, l1Cache, caching);
106+
}
107+
} else {
108+
if (existInL1) {
109+
LOG.warn("Cache key {} had block type {}, but was found in L1 cache.", cacheKey,
110+
cacheKey.getBlockType());
111+
updateBlockMetrics(block, cacheKey, l1Cache, caching);
112+
} else {
113+
updateBlockMetrics(block, cacheKey, l2Cache, caching);
114+
}
115+
}
116+
}
117+
return block;
118+
}
119+
120+
private void updateBlockMetrics(Cacheable block, BlockCacheKey key, BlockCache cache,
121+
boolean caching) {
122+
if (block == null) {
123+
cache.getStats().miss(caching, key.isPrimary(), key.getBlockType());
124+
} else {
125+
cache.getStats().hit(caching, key.isPrimary(), key.getBlockType());
126+
87127
}
128+
}
88129

89-
return existInL1
90-
? l1Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics)
91-
: l2Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics);
130+
private Cacheable getBlockWithType(BlockCacheKey cacheKey, boolean caching, boolean repeat,
131+
boolean updateCacheMetrics) {
132+
boolean metaBlock = isMetaBlock(cacheKey.getBlockType());
133+
if (metaBlock) {
134+
return l1Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics);
135+
} else {
136+
return l2Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics);
137+
}
92138
}
93139

94140
@Override

hbase-server/src/test/java/org/apache/hadoop/hbase/io/hfile/TestCombinedBlockCache.java

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,16 @@
1919

2020
import static org.apache.hadoop.hbase.HConstants.BUCKET_CACHE_IOENGINE_KEY;
2121
import static org.apache.hadoop.hbase.HConstants.BUCKET_CACHE_SIZE_KEY;
22+
import static org.apache.hadoop.hbase.io.ByteBuffAllocator.HEAP;
2223
import static org.junit.Assert.assertEquals;
2324

25+
import java.nio.ByteBuffer;
2426
import org.apache.hadoop.conf.Configuration;
2527
import org.apache.hadoop.hbase.HBaseClassTestRule;
2628
import org.apache.hadoop.hbase.HBaseTestingUtility;
29+
import org.apache.hadoop.hbase.HConstants;
2730
import org.apache.hadoop.hbase.io.hfile.CombinedBlockCache.CombinedCacheStats;
31+
import org.apache.hadoop.hbase.nio.ByteBuff;
2832
import org.apache.hadoop.hbase.testclassification.SmallTests;
2933
import org.junit.Assert;
3034
import org.junit.ClassRule;
@@ -110,11 +114,53 @@ public void testCombinedCacheStats() {
110114

111115
@Test
112116
public void testMultiThreadGetAndEvictBlock() throws Exception {
117+
BlockCache blockCache = createCombinedBlockCache();
118+
TestLruBlockCache.testMultiThreadGetAndEvictBlockInternal(blockCache);
119+
}
120+
121+
@Test
122+
public void testCombinedBlockCacheStatsWithDataBlockType() throws Exception {
123+
testCombinedBlockCacheStats(BlockType.DATA, 0, 1);
124+
}
125+
126+
@Test
127+
public void testCombinedBlockCacheStatsWithMetaBlockType() throws Exception {
128+
testCombinedBlockCacheStats(BlockType.META, 1, 0);
129+
}
130+
131+
@Test
132+
public void testCombinedBlockCacheStatsWithNoBlockType() throws Exception {
133+
testCombinedBlockCacheStats(null, 0, 1);
134+
}
135+
136+
private CombinedBlockCache createCombinedBlockCache() {
113137
Configuration conf = UTIL.getConfiguration();
114138
conf.set(BUCKET_CACHE_IOENGINE_KEY, "offheap");
115139
conf.setInt(BUCKET_CACHE_SIZE_KEY, 32);
116140
BlockCache blockCache = BlockCacheFactory.createBlockCache(conf);
117141
Assert.assertTrue(blockCache instanceof CombinedBlockCache);
118-
TestLruBlockCache.testMultiThreadGetAndEvictBlockInternal(blockCache);
142+
return (CombinedBlockCache) blockCache;
143+
}
144+
145+
public void testCombinedBlockCacheStats(BlockType type, int expectedL1Miss, int expectedL2Miss)
146+
throws Exception {
147+
CombinedBlockCache blockCache = createCombinedBlockCache();
148+
BlockCacheKey key = new BlockCacheKey("key1", 0, false, type);
149+
int size = 100;
150+
int length = HConstants.HFILEBLOCK_HEADER_SIZE + size;
151+
byte[] byteArr = new byte[length];
152+
HFileContext meta = new HFileContextBuilder().build();
153+
HFileBlock blk = new HFileBlock(type != null ? type : BlockType.DATA, size, size, -1,
154+
ByteBuff.wrap(ByteBuffer.wrap(byteArr, 0, size)), HFileBlock.FILL_HEADER, -1, 52, -1, meta,
155+
HEAP);
156+
blockCache.cacheBlock(key, blk);
157+
blockCache.getBlock(key, true, false, true);
158+
assertEquals(0, blockCache.getStats().getMissCount());
159+
blockCache.evictBlock(key);
160+
blockCache.getBlock(key, true, false, true);
161+
assertEquals(1, blockCache.getStats().getMissCount());
162+
assertEquals(expectedL1Miss, blockCache.getFirstLevelCache().getStats().getMissCount());
163+
assertEquals(expectedL2Miss, blockCache.getSecondLevelCache().getStats().getMissCount());
119164
}
165+
120166
}

0 commit comments

Comments
 (0)