001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.io.hfile; 019 020import java.util.Iterator; 021import org.apache.hadoop.hbase.io.HeapSize; 022import org.apache.hadoop.hbase.io.hfile.bucket.BucketCache; 023import org.apache.yetus.audience.InterfaceAudience; 024 025/** 026 * CombinedBlockCache is an abstraction layer that combines {@link FirstLevelBlockCache} and 027 * {@link BucketCache}. The smaller lruCache is used to cache bloom blocks and index blocks. The 028 * larger Cache is used to cache data blocks. 029 * {@link #getBlock(BlockCacheKey, boolean, boolean, boolean)} reads first from the smaller l1Cache 030 * before looking for the block in the l2Cache. Blocks evicted from l1Cache are put into the bucket 031 * cache. Metrics are the combined size and hits and misses of both caches. 032 */ 033@InterfaceAudience.Private 034public class CombinedBlockCache implements ResizableBlockCache, HeapSize { 035 protected final FirstLevelBlockCache l1Cache; 036 protected final BlockCache l2Cache; 037 protected final CombinedCacheStats combinedCacheStats; 038 039 public CombinedBlockCache(FirstLevelBlockCache l1Cache, BlockCache l2Cache) { 040 this.l1Cache = l1Cache; 041 this.l2Cache = l2Cache; 042 this.combinedCacheStats = new CombinedCacheStats(l1Cache.getStats(), l2Cache.getStats()); 043 } 044 045 @Override 046 public long heapSize() { 047 long l2size = 0; 048 if (l2Cache instanceof HeapSize) { 049 l2size = ((HeapSize) l2Cache).heapSize(); 050 } 051 return l1Cache.heapSize() + l2size; 052 } 053 054 @Override 055 public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory) { 056 cacheBlock(cacheKey, buf, inMemory, false); 057 } 058 059 @Override 060 public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory, 061 boolean waitWhenCache) { 062 boolean metaBlock = isMetaBlock(buf.getBlockType()); 063 if (metaBlock) { 064 l1Cache.cacheBlock(cacheKey, buf, inMemory); 065 } else { 066 l2Cache.cacheBlock(cacheKey, buf, inMemory, waitWhenCache); 067 } 068 } 069 070 @Override 071 public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf) { 072 cacheBlock(cacheKey, buf, false); 073 } 074 075 @Override 076 public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat, 077 boolean updateCacheMetrics) { 078 // We are not in a position to exactly look at LRU cache or BC as BlockType may not be getting 079 // passed always. 080 boolean existInL1 = l1Cache.containsBlock(cacheKey); 081 if (!existInL1 && updateCacheMetrics && !repeat) { 082 // If the block does not exist in L1, the containsBlock should be counted as one miss. 083 l1Cache.getStats().miss(caching, cacheKey.isPrimary(), cacheKey.getBlockType()); 084 } 085 return existInL1 086 ? l1Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics) 087 : l2Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics); 088 } 089 090 @Override 091 public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat, 092 boolean updateCacheMetrics, BlockType blockType) { 093 if (blockType == null) { 094 return getBlock(cacheKey, caching, repeat, updateCacheMetrics); 095 } 096 boolean metaBlock = isMetaBlock(blockType); 097 if (metaBlock) { 098 return l1Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics); 099 } else { 100 return l2Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics); 101 } 102 } 103 104 @Override 105 public boolean evictBlock(BlockCacheKey cacheKey) { 106 return l1Cache.evictBlock(cacheKey) || l2Cache.evictBlock(cacheKey); 107 } 108 109 @Override 110 public int evictBlocksByHfileName(String hfileName) { 111 return l1Cache.evictBlocksByHfileName(hfileName) + l2Cache.evictBlocksByHfileName(hfileName); 112 } 113 114 @Override 115 public CacheStats getStats() { 116 return this.combinedCacheStats; 117 } 118 119 @Override 120 public void shutdown() { 121 l1Cache.shutdown(); 122 l2Cache.shutdown(); 123 } 124 125 @Override 126 public long size() { 127 return l1Cache.size() + l2Cache.size(); 128 } 129 130 @Override 131 public long getMaxSize() { 132 return l1Cache.getMaxSize() + l2Cache.getMaxSize(); 133 } 134 135 @Override 136 public long getCurrentDataSize() { 137 return l1Cache.getCurrentDataSize() + l2Cache.getCurrentDataSize(); 138 } 139 140 @Override 141 public long getFreeSize() { 142 return l1Cache.getFreeSize() + l2Cache.getFreeSize(); 143 } 144 145 @Override 146 public long getCurrentSize() { 147 return l1Cache.getCurrentSize() + l2Cache.getCurrentSize(); 148 } 149 150 @Override 151 public long getBlockCount() { 152 return l1Cache.getBlockCount() + l2Cache.getBlockCount(); 153 } 154 155 @Override 156 public long getDataBlockCount() { 157 return l1Cache.getDataBlockCount() + l2Cache.getDataBlockCount(); 158 } 159 160 public static class CombinedCacheStats extends CacheStats { 161 private final CacheStats lruCacheStats; 162 private final CacheStats bucketCacheStats; 163 164 CombinedCacheStats(CacheStats lbcStats, CacheStats fcStats) { 165 super("CombinedBlockCache"); 166 this.lruCacheStats = lbcStats; 167 this.bucketCacheStats = fcStats; 168 } 169 170 public CacheStats getLruCacheStats() { 171 return this.lruCacheStats; 172 } 173 174 public CacheStats getBucketCacheStats() { 175 return this.bucketCacheStats; 176 } 177 178 @Override 179 public long getDataMissCount() { 180 return lruCacheStats.getDataMissCount() + bucketCacheStats.getDataMissCount(); 181 } 182 183 @Override 184 public long getLeafIndexMissCount() { 185 return lruCacheStats.getLeafIndexMissCount() + bucketCacheStats.getLeafIndexMissCount(); 186 } 187 188 @Override 189 public long getBloomChunkMissCount() { 190 return lruCacheStats.getBloomChunkMissCount() + bucketCacheStats.getBloomChunkMissCount(); 191 } 192 193 @Override 194 public long getMetaMissCount() { 195 return lruCacheStats.getMetaMissCount() + bucketCacheStats.getMetaMissCount(); 196 } 197 198 @Override 199 public long getRootIndexMissCount() { 200 return lruCacheStats.getRootIndexMissCount() + bucketCacheStats.getRootIndexMissCount(); 201 } 202 203 @Override 204 public long getIntermediateIndexMissCount() { 205 return lruCacheStats.getIntermediateIndexMissCount() 206 + bucketCacheStats.getIntermediateIndexMissCount(); 207 } 208 209 @Override 210 public long getFileInfoMissCount() { 211 return lruCacheStats.getFileInfoMissCount() + bucketCacheStats.getFileInfoMissCount(); 212 } 213 214 @Override 215 public long getGeneralBloomMetaMissCount() { 216 return lruCacheStats.getGeneralBloomMetaMissCount() 217 + bucketCacheStats.getGeneralBloomMetaMissCount(); 218 } 219 220 @Override 221 public long getDeleteFamilyBloomMissCount() { 222 return lruCacheStats.getDeleteFamilyBloomMissCount() 223 + bucketCacheStats.getDeleteFamilyBloomMissCount(); 224 } 225 226 @Override 227 public long getTrailerMissCount() { 228 return lruCacheStats.getTrailerMissCount() + bucketCacheStats.getTrailerMissCount(); 229 } 230 231 @Override 232 public long getDataHitCount() { 233 return lruCacheStats.getDataHitCount() + bucketCacheStats.getDataHitCount(); 234 } 235 236 @Override 237 public long getLeafIndexHitCount() { 238 return lruCacheStats.getLeafIndexHitCount() + bucketCacheStats.getLeafIndexHitCount(); 239 } 240 241 @Override 242 public long getBloomChunkHitCount() { 243 return lruCacheStats.getBloomChunkHitCount() + bucketCacheStats.getBloomChunkHitCount(); 244 } 245 246 @Override 247 public long getMetaHitCount() { 248 return lruCacheStats.getMetaHitCount() + bucketCacheStats.getMetaHitCount(); 249 } 250 251 @Override 252 public long getRootIndexHitCount() { 253 return lruCacheStats.getRootIndexHitCount() + bucketCacheStats.getRootIndexHitCount(); 254 } 255 256 @Override 257 public long getIntermediateIndexHitCount() { 258 return lruCacheStats.getIntermediateIndexHitCount() 259 + bucketCacheStats.getIntermediateIndexHitCount(); 260 } 261 262 @Override 263 public long getFileInfoHitCount() { 264 return lruCacheStats.getFileInfoHitCount() + bucketCacheStats.getFileInfoHitCount(); 265 } 266 267 @Override 268 public long getGeneralBloomMetaHitCount() { 269 return lruCacheStats.getGeneralBloomMetaHitCount() 270 + bucketCacheStats.getGeneralBloomMetaHitCount(); 271 } 272 273 @Override 274 public long getDeleteFamilyBloomHitCount() { 275 return lruCacheStats.getDeleteFamilyBloomHitCount() 276 + bucketCacheStats.getDeleteFamilyBloomHitCount(); 277 } 278 279 @Override 280 public long getTrailerHitCount() { 281 return lruCacheStats.getTrailerHitCount() + bucketCacheStats.getTrailerHitCount(); 282 } 283 284 @Override 285 public long getRequestCount() { 286 return lruCacheStats.getRequestCount() + bucketCacheStats.getRequestCount(); 287 } 288 289 @Override 290 public long getRequestCachingCount() { 291 return lruCacheStats.getRequestCachingCount() + bucketCacheStats.getRequestCachingCount(); 292 } 293 294 @Override 295 public long getMissCount() { 296 return lruCacheStats.getMissCount() + bucketCacheStats.getMissCount(); 297 } 298 299 @Override 300 public long getPrimaryMissCount() { 301 return lruCacheStats.getPrimaryMissCount() + bucketCacheStats.getPrimaryMissCount(); 302 } 303 304 @Override 305 public long getMissCachingCount() { 306 return lruCacheStats.getMissCachingCount() + bucketCacheStats.getMissCachingCount(); 307 } 308 309 @Override 310 public long getHitCount() { 311 return lruCacheStats.getHitCount() + bucketCacheStats.getHitCount(); 312 } 313 314 @Override 315 public long getPrimaryHitCount() { 316 return lruCacheStats.getPrimaryHitCount() + bucketCacheStats.getPrimaryHitCount(); 317 } 318 319 @Override 320 public long getHitCachingCount() { 321 return lruCacheStats.getHitCachingCount() + bucketCacheStats.getHitCachingCount(); 322 } 323 324 @Override 325 public long getEvictionCount() { 326 return lruCacheStats.getEvictionCount() + bucketCacheStats.getEvictionCount(); 327 } 328 329 @Override 330 public long getEvictedCount() { 331 return lruCacheStats.getEvictedCount() + bucketCacheStats.getEvictedCount(); 332 } 333 334 @Override 335 public long getPrimaryEvictedCount() { 336 return lruCacheStats.getPrimaryEvictedCount() + bucketCacheStats.getPrimaryEvictedCount(); 337 } 338 339 @Override 340 public void rollMetricsPeriod() { 341 lruCacheStats.rollMetricsPeriod(); 342 bucketCacheStats.rollMetricsPeriod(); 343 } 344 345 @Override 346 public long getFailedInserts() { 347 return lruCacheStats.getFailedInserts() + bucketCacheStats.getFailedInserts(); 348 } 349 350 @Override 351 public long getSumHitCountsPastNPeriods() { 352 return lruCacheStats.getSumHitCountsPastNPeriods() 353 + bucketCacheStats.getSumHitCountsPastNPeriods(); 354 } 355 356 @Override 357 public long getSumRequestCountsPastNPeriods() { 358 return lruCacheStats.getSumRequestCountsPastNPeriods() 359 + bucketCacheStats.getSumRequestCountsPastNPeriods(); 360 } 361 362 @Override 363 public long getSumHitCachingCountsPastNPeriods() { 364 return lruCacheStats.getSumHitCachingCountsPastNPeriods() 365 + bucketCacheStats.getSumHitCachingCountsPastNPeriods(); 366 } 367 368 @Override 369 public long getSumRequestCachingCountsPastNPeriods() { 370 return lruCacheStats.getSumRequestCachingCountsPastNPeriods() 371 + bucketCacheStats.getSumRequestCachingCountsPastNPeriods(); 372 } 373 } 374 375 @Override 376 public Iterator<CachedBlock> iterator() { 377 return new BlockCachesIterator(getBlockCaches()); 378 } 379 380 @Override 381 public BlockCache[] getBlockCaches() { 382 return new BlockCache[] { this.l1Cache, this.l2Cache }; 383 } 384 385 @Override 386 public void setMaxSize(long size) { 387 this.l1Cache.setMaxSize(size); 388 } 389 390 public int getRpcRefCount(BlockCacheKey cacheKey) { 391 return (this.l2Cache instanceof BucketCache) 392 ? ((BucketCache) this.l2Cache).getRpcRefCount(cacheKey) 393 : 0; 394 } 395 396 public FirstLevelBlockCache getFirstLevelCache() { 397 return l1Cache; 398 } 399 400 public BlockCache getSecondLevelCache() { 401 return l2Cache; 402 } 403}