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 boolean metaBlock = isMetaBlock(buf.getBlockType()); 057 if (metaBlock) { 058 l1Cache.cacheBlock(cacheKey, buf, inMemory); 059 } else { 060 l2Cache.cacheBlock(cacheKey, buf, inMemory); 061 } 062 } 063 064 @Override 065 public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf) { 066 cacheBlock(cacheKey, buf, false); 067 } 068 069 @Override 070 public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat, 071 boolean updateCacheMetrics) { 072 // We are not in a position to exactly look at LRU cache or BC as BlockType may not be getting 073 // passed always. 074 boolean existInL1 = l1Cache.containsBlock(cacheKey); 075 if (!existInL1 && updateCacheMetrics && !repeat) { 076 // If the block does not exist in L1, the containsBlock should be counted as one miss. 077 l1Cache.getStats().miss(caching, cacheKey.isPrimary(), cacheKey.getBlockType()); 078 } 079 return existInL1 080 ? l1Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics) 081 : l2Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics); 082 } 083 084 @Override 085 public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching, boolean repeat, 086 boolean updateCacheMetrics, BlockType blockType) { 087 if (blockType == null) { 088 return getBlock(cacheKey, caching, repeat, updateCacheMetrics); 089 } 090 boolean metaBlock = isMetaBlock(blockType); 091 if (metaBlock) { 092 return l1Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics); 093 } else { 094 return l2Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics); 095 } 096 } 097 098 @Override 099 public boolean evictBlock(BlockCacheKey cacheKey) { 100 return l1Cache.evictBlock(cacheKey) || l2Cache.evictBlock(cacheKey); 101 } 102 103 @Override 104 public int evictBlocksByHfileName(String hfileName) { 105 return l1Cache.evictBlocksByHfileName(hfileName) + l2Cache.evictBlocksByHfileName(hfileName); 106 } 107 108 @Override 109 public CacheStats getStats() { 110 return this.combinedCacheStats; 111 } 112 113 @Override 114 public void shutdown() { 115 l1Cache.shutdown(); 116 l2Cache.shutdown(); 117 } 118 119 @Override 120 public long size() { 121 return l1Cache.size() + l2Cache.size(); 122 } 123 124 @Override 125 public long getMaxSize() { 126 return l1Cache.getMaxSize() + l2Cache.getMaxSize(); 127 } 128 129 @Override 130 public long getCurrentDataSize() { 131 return l1Cache.getCurrentDataSize() + l2Cache.getCurrentDataSize(); 132 } 133 134 @Override 135 public long getFreeSize() { 136 return l1Cache.getFreeSize() + l2Cache.getFreeSize(); 137 } 138 139 @Override 140 public long getCurrentSize() { 141 return l1Cache.getCurrentSize() + l2Cache.getCurrentSize(); 142 } 143 144 @Override 145 public long getBlockCount() { 146 return l1Cache.getBlockCount() + l2Cache.getBlockCount(); 147 } 148 149 @Override 150 public long getDataBlockCount() { 151 return l1Cache.getDataBlockCount() + l2Cache.getDataBlockCount(); 152 } 153 154 public static class CombinedCacheStats extends CacheStats { 155 private final CacheStats lruCacheStats; 156 private final CacheStats bucketCacheStats; 157 158 CombinedCacheStats(CacheStats lbcStats, CacheStats fcStats) { 159 super("CombinedBlockCache"); 160 this.lruCacheStats = lbcStats; 161 this.bucketCacheStats = fcStats; 162 } 163 164 public CacheStats getLruCacheStats() { 165 return this.lruCacheStats; 166 } 167 168 public CacheStats getBucketCacheStats() { 169 return this.bucketCacheStats; 170 } 171 172 @Override 173 public long getDataMissCount() { 174 return lruCacheStats.getDataMissCount() + bucketCacheStats.getDataMissCount(); 175 } 176 177 @Override 178 public long getLeafIndexMissCount() { 179 return lruCacheStats.getLeafIndexMissCount() + bucketCacheStats.getLeafIndexMissCount(); 180 } 181 182 @Override 183 public long getBloomChunkMissCount() { 184 return lruCacheStats.getBloomChunkMissCount() + bucketCacheStats.getBloomChunkMissCount(); 185 } 186 187 @Override 188 public long getMetaMissCount() { 189 return lruCacheStats.getMetaMissCount() + bucketCacheStats.getMetaMissCount(); 190 } 191 192 @Override 193 public long getRootIndexMissCount() { 194 return lruCacheStats.getRootIndexMissCount() + bucketCacheStats.getRootIndexMissCount(); 195 } 196 197 @Override 198 public long getIntermediateIndexMissCount() { 199 return lruCacheStats.getIntermediateIndexMissCount() 200 + bucketCacheStats.getIntermediateIndexMissCount(); 201 } 202 203 @Override 204 public long getFileInfoMissCount() { 205 return lruCacheStats.getFileInfoMissCount() + bucketCacheStats.getFileInfoMissCount(); 206 } 207 208 @Override 209 public long getGeneralBloomMetaMissCount() { 210 return lruCacheStats.getGeneralBloomMetaMissCount() 211 + bucketCacheStats.getGeneralBloomMetaMissCount(); 212 } 213 214 @Override 215 public long getDeleteFamilyBloomMissCount() { 216 return lruCacheStats.getDeleteFamilyBloomMissCount() 217 + bucketCacheStats.getDeleteFamilyBloomMissCount(); 218 } 219 220 @Override 221 public long getTrailerMissCount() { 222 return lruCacheStats.getTrailerMissCount() + bucketCacheStats.getTrailerMissCount(); 223 } 224 225 @Override 226 public long getDataHitCount() { 227 return lruCacheStats.getDataHitCount() + bucketCacheStats.getDataHitCount(); 228 } 229 230 @Override 231 public long getLeafIndexHitCount() { 232 return lruCacheStats.getLeafIndexHitCount() + bucketCacheStats.getLeafIndexHitCount(); 233 } 234 235 @Override 236 public long getBloomChunkHitCount() { 237 return lruCacheStats.getBloomChunkHitCount() + bucketCacheStats.getBloomChunkHitCount(); 238 } 239 240 @Override 241 public long getMetaHitCount() { 242 return lruCacheStats.getMetaHitCount() + bucketCacheStats.getMetaHitCount(); 243 } 244 245 @Override 246 public long getRootIndexHitCount() { 247 return lruCacheStats.getRootIndexHitCount() + bucketCacheStats.getRootIndexHitCount(); 248 } 249 250 @Override 251 public long getIntermediateIndexHitCount() { 252 return lruCacheStats.getIntermediateIndexHitCount() 253 + bucketCacheStats.getIntermediateIndexHitCount(); 254 } 255 256 @Override 257 public long getFileInfoHitCount() { 258 return lruCacheStats.getFileInfoHitCount() + bucketCacheStats.getFileInfoHitCount(); 259 } 260 261 @Override 262 public long getGeneralBloomMetaHitCount() { 263 return lruCacheStats.getGeneralBloomMetaHitCount() 264 + bucketCacheStats.getGeneralBloomMetaHitCount(); 265 } 266 267 @Override 268 public long getDeleteFamilyBloomHitCount() { 269 return lruCacheStats.getDeleteFamilyBloomHitCount() 270 + bucketCacheStats.getDeleteFamilyBloomHitCount(); 271 } 272 273 @Override 274 public long getTrailerHitCount() { 275 return lruCacheStats.getTrailerHitCount() + bucketCacheStats.getTrailerHitCount(); 276 } 277 278 @Override 279 public long getRequestCount() { 280 return lruCacheStats.getRequestCount() + bucketCacheStats.getRequestCount(); 281 } 282 283 @Override 284 public long getRequestCachingCount() { 285 return lruCacheStats.getRequestCachingCount() + bucketCacheStats.getRequestCachingCount(); 286 } 287 288 @Override 289 public long getMissCount() { 290 return lruCacheStats.getMissCount() + bucketCacheStats.getMissCount(); 291 } 292 293 @Override 294 public long getPrimaryMissCount() { 295 return lruCacheStats.getPrimaryMissCount() + bucketCacheStats.getPrimaryMissCount(); 296 } 297 298 @Override 299 public long getMissCachingCount() { 300 return lruCacheStats.getMissCachingCount() + bucketCacheStats.getMissCachingCount(); 301 } 302 303 @Override 304 public long getHitCount() { 305 return lruCacheStats.getHitCount() + bucketCacheStats.getHitCount(); 306 } 307 308 @Override 309 public long getPrimaryHitCount() { 310 return lruCacheStats.getPrimaryHitCount() + bucketCacheStats.getPrimaryHitCount(); 311 } 312 313 @Override 314 public long getHitCachingCount() { 315 return lruCacheStats.getHitCachingCount() + bucketCacheStats.getHitCachingCount(); 316 } 317 318 @Override 319 public long getEvictionCount() { 320 return lruCacheStats.getEvictionCount() + bucketCacheStats.getEvictionCount(); 321 } 322 323 @Override 324 public long getEvictedCount() { 325 return lruCacheStats.getEvictedCount() + bucketCacheStats.getEvictedCount(); 326 } 327 328 @Override 329 public long getPrimaryEvictedCount() { 330 return lruCacheStats.getPrimaryEvictedCount() + bucketCacheStats.getPrimaryEvictedCount(); 331 } 332 333 @Override 334 public void rollMetricsPeriod() { 335 lruCacheStats.rollMetricsPeriod(); 336 bucketCacheStats.rollMetricsPeriod(); 337 } 338 339 @Override 340 public long getFailedInserts() { 341 return lruCacheStats.getFailedInserts() + bucketCacheStats.getFailedInserts(); 342 } 343 344 @Override 345 public long getSumHitCountsPastNPeriods() { 346 return lruCacheStats.getSumHitCountsPastNPeriods() 347 + bucketCacheStats.getSumHitCountsPastNPeriods(); 348 } 349 350 @Override 351 public long getSumRequestCountsPastNPeriods() { 352 return lruCacheStats.getSumRequestCountsPastNPeriods() 353 + bucketCacheStats.getSumRequestCountsPastNPeriods(); 354 } 355 356 @Override 357 public long getSumHitCachingCountsPastNPeriods() { 358 return lruCacheStats.getSumHitCachingCountsPastNPeriods() 359 + bucketCacheStats.getSumHitCachingCountsPastNPeriods(); 360 } 361 362 @Override 363 public long getSumRequestCachingCountsPastNPeriods() { 364 return lruCacheStats.getSumRequestCachingCountsPastNPeriods() 365 + bucketCacheStats.getSumRequestCachingCountsPastNPeriods(); 366 } 367 } 368 369 @Override 370 public Iterator<CachedBlock> iterator() { 371 return new BlockCachesIterator(getBlockCaches()); 372 } 373 374 @Override 375 public BlockCache[] getBlockCaches() { 376 return new BlockCache[] { this.l1Cache, this.l2Cache }; 377 } 378 379 @Override 380 public void setMaxSize(long size) { 381 this.l1Cache.setMaxSize(size); 382 } 383 384 public int getRpcRefCount(BlockCacheKey cacheKey) { 385 return (this.l2Cache instanceof BucketCache) 386 ? ((BucketCache) this.l2Cache).getRpcRefCount(cacheKey) 387 : 0; 388 } 389 390 public FirstLevelBlockCache getFirstLevelCache() { 391 return l1Cache; 392 } 393}