diff --git hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileReaderV2.java hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileReaderV2.java index e252f38..26505ba 100644 --- hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileReaderV2.java +++ hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/HFileReaderV2.java @@ -289,69 +289,87 @@ public class HFileReaderV2 extends AbstractHFileReader { new BlockCacheKey(name, dataBlockOffset, dataBlockEncoder.getEffectiveEncodingInCache(isCompaction), expectedBlockType); - IdLock.Entry lockEntry = offsetLock.getLockEntry(dataBlockOffset); - try { - blockLoads.incrementAndGet(); - // Check cache for block. If found return. - if (cacheConf.isBlockCacheEnabled()) { - HFileBlock cachedBlock = (HFileBlock) - cacheConf.getBlockCache().getBlock(cacheKey, cacheBlock); - if (cachedBlock != null) { - BlockCategory blockCategory = - cachedBlock.getBlockType().getCategory(); - cacheHits.incrementAndGet(); + boolean useLock = false; + IdLock.Entry lockEntry = null; + blockLoads.incrementAndGet(); - getSchemaMetrics().updateOnCacheHit(blockCategory, isCompaction); + try { + while (true) { - if (cachedBlock.getBlockType() == BlockType.DATA) { - HFile.dataBlockReadCnt.incrementAndGet(); - } + if (useLock) { + lockEntry = offsetLock.getLockEntry(dataBlockOffset); + } - validateBlockType(cachedBlock, expectedBlockType); + // Check cache for block. If found return. + if (cacheConf.isBlockCacheEnabled()) { + // Try and get the block from the block cache. If the useLock variable is true then this + // is the second time through the loop and it should not be counted as a block cache miss. + HFileBlock cachedBlock = (HFileBlock) + cacheConf.getBlockCache().getBlock(cacheKey, !useLock && cacheBlock); + if (cachedBlock != null) { + BlockCategory blockCategory = + cachedBlock.getBlockType().getCategory(); + cacheHits.incrementAndGet(); + + getSchemaMetrics().updateOnCacheHit(blockCategory, isCompaction); + + if (cachedBlock.getBlockType() == BlockType.DATA) { + HFile.dataBlockReadCnt.incrementAndGet(); + } - // Validate encoding type for encoded blocks. We include encoding - // type in the cache key, and we expect it to match on a cache hit. - if (cachedBlock.getBlockType() == BlockType.ENCODED_DATA && - cachedBlock.getDataBlockEncoding() != - dataBlockEncoder.getEncodingInCache()) { - throw new IOException("Cached block under key " + cacheKey + " " + - "has wrong encoding: " + cachedBlock.getDataBlockEncoding() + - " (expected: " + dataBlockEncoder.getEncodingInCache() + ")"); + validateBlockType(cachedBlock, expectedBlockType); + + // Validate encoding type for encoded blocks. We include encoding + // type in the cache key, and we expect it to match on a cache hit. + if (cachedBlock.getBlockType() == BlockType.ENCODED_DATA && + cachedBlock.getDataBlockEncoding() != + dataBlockEncoder.getEncodingInCache()) { + throw new IOException("Cached block under key " + cacheKey + " " + + "has wrong encoding: " + cachedBlock.getDataBlockEncoding() + + " (expected: " + dataBlockEncoder.getEncodingInCache() + ")"); + } + return cachedBlock; } - return cachedBlock; + // Carry on, please load. + } + if (!useLock) { + // check cache again with lock + useLock = true; + continue; } - // Carry on, please load. - } - - // Load block from filesystem. - long startTimeNs = System.nanoTime(); - HFileBlock hfileBlock = fsBlockReader.readBlockData(dataBlockOffset, - onDiskBlockSize, -1, pread); - hfileBlock = dataBlockEncoder.diskToCacheFormat(hfileBlock, - isCompaction); - validateBlockType(hfileBlock, expectedBlockType); - passSchemaMetricsTo(hfileBlock); - BlockCategory blockCategory = hfileBlock.getBlockType().getCategory(); - final long delta = System.nanoTime() - startTimeNs; - HFile.offerReadLatency(delta, pread); - getSchemaMetrics().updateOnCacheMiss(blockCategory, isCompaction, delta); + // Load block from filesystem. + long startTimeNs = System.nanoTime(); + HFileBlock hfileBlock = fsBlockReader.readBlockData(dataBlockOffset, + onDiskBlockSize, -1, pread); + hfileBlock = dataBlockEncoder.diskToCacheFormat(hfileBlock, + isCompaction); + validateBlockType(hfileBlock, expectedBlockType); + passSchemaMetricsTo(hfileBlock); + BlockCategory blockCategory = hfileBlock.getBlockType().getCategory(); + + final long delta = System.nanoTime() - startTimeNs; + HFile.offerReadLatency(delta, pread); + getSchemaMetrics().updateOnCacheMiss(blockCategory, isCompaction, delta); + + // Cache the block if necessary + if (cacheBlock && cacheConf.shouldCacheBlockOnRead( + hfileBlock.getBlockType().getCategory())) { + cacheConf.getBlockCache().cacheBlock(cacheKey, hfileBlock, + cacheConf.isInMemory()); + } - // Cache the block if necessary - if (cacheBlock && cacheConf.shouldCacheBlockOnRead( - hfileBlock.getBlockType().getCategory())) { - cacheConf.getBlockCache().cacheBlock(cacheKey, hfileBlock, - cacheConf.isInMemory()); - } + if (hfileBlock.getBlockType() == BlockType.DATA) { + HFile.dataBlockReadCnt.incrementAndGet(); + } - if (hfileBlock.getBlockType() == BlockType.DATA) { - HFile.dataBlockReadCnt.incrementAndGet(); + return hfileBlock; } - - return hfileBlock; } finally { - offsetLock.releaseLockEntry(lockEntry); + if (lockEntry != null) { + offsetLock.releaseLockEntry(lockEntry); + } } }