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