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