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 @Override 156 public long getDataMissCount() { 157 return lruCacheStats.getDataMissCount() + bucketCacheStats.getDataMissCount(); 158 } 159 160 @Override 161 public long getLeafIndexMissCount() { 162 return lruCacheStats.getLeafIndexMissCount() + bucketCacheStats.getLeafIndexMissCount(); 163 } 164 165 @Override 166 public long getBloomChunkMissCount() { 167 return lruCacheStats.getBloomChunkMissCount() + bucketCacheStats.getBloomChunkMissCount(); 168 } 169 170 @Override 171 public long getMetaMissCount() { 172 return lruCacheStats.getMetaMissCount() + bucketCacheStats.getMetaMissCount(); 173 } 174 175 @Override 176 public long getRootIndexMissCount() { 177 return lruCacheStats.getRootIndexMissCount() + bucketCacheStats.getRootIndexMissCount(); 178 } 179 180 @Override 181 public long getIntermediateIndexMissCount() { 182 return lruCacheStats.getIntermediateIndexMissCount() + 183 bucketCacheStats.getIntermediateIndexMissCount(); 184 } 185 186 @Override 187 public long getFileInfoMissCount() { 188 return lruCacheStats.getFileInfoMissCount() + bucketCacheStats.getFileInfoMissCount(); 189 } 190 191 @Override 192 public long getGeneralBloomMetaMissCount() { 193 return lruCacheStats.getGeneralBloomMetaMissCount() + 194 bucketCacheStats.getGeneralBloomMetaMissCount(); 195 } 196 197 @Override 198 public long getDeleteFamilyBloomMissCount() { 199 return lruCacheStats.getDeleteFamilyBloomMissCount() + 200 bucketCacheStats.getDeleteFamilyBloomMissCount(); 201 } 202 203 @Override 204 public long getTrailerMissCount() { 205 return lruCacheStats.getTrailerMissCount() + bucketCacheStats.getTrailerMissCount(); 206 } 207 208 @Override 209 public long getDataHitCount() { 210 return lruCacheStats.getDataHitCount() + bucketCacheStats.getDataHitCount(); 211 } 212 213 @Override 214 public long getLeafIndexHitCount() { 215 return lruCacheStats.getLeafIndexHitCount() + bucketCacheStats.getLeafIndexHitCount(); 216 } 217 218 @Override 219 public long getBloomChunkHitCount() { 220 return lruCacheStats.getBloomChunkHitCount() + bucketCacheStats.getBloomChunkHitCount(); 221 } 222 223 @Override 224 public long getMetaHitCount() { 225 return lruCacheStats.getMetaHitCount() + bucketCacheStats.getMetaHitCount(); 226 } 227 228 @Override 229 public long getRootIndexHitCount() { 230 return lruCacheStats.getRootIndexHitCount() + bucketCacheStats.getRootIndexHitCount(); 231 } 232 233 @Override 234 public long getIntermediateIndexHitCount() { 235 return lruCacheStats.getIntermediateIndexHitCount() + 236 bucketCacheStats.getIntermediateIndexHitCount(); 237 } 238 239 @Override 240 public long getFileInfoHitCount() { 241 return lruCacheStats.getFileInfoHitCount() + bucketCacheStats.getFileInfoHitCount(); 242 } 243 244 @Override 245 public long getGeneralBloomMetaHitCount() { 246 return lruCacheStats.getGeneralBloomMetaHitCount() + 247 bucketCacheStats.getGeneralBloomMetaHitCount(); 248 } 249 250 @Override 251 public long getDeleteFamilyBloomHitCount() { 252 return lruCacheStats.getDeleteFamilyBloomHitCount() + 253 bucketCacheStats.getDeleteFamilyBloomHitCount(); 254 } 255 256 @Override 257 public long getTrailerHitCount() { 258 return lruCacheStats.getTrailerHitCount() + bucketCacheStats.getTrailerHitCount(); 259 } 260 261 @Override 262 public long getRequestCount() { 263 return lruCacheStats.getRequestCount() 264 + bucketCacheStats.getRequestCount(); 265 } 266 267 @Override 268 public long getRequestCachingCount() { 269 return lruCacheStats.getRequestCachingCount() 270 + bucketCacheStats.getRequestCachingCount(); 271 } 272 273 @Override 274 public long getMissCount() { 275 return lruCacheStats.getMissCount() + bucketCacheStats.getMissCount(); 276 } 277 278 @Override 279 public long getPrimaryMissCount() { 280 return lruCacheStats.getPrimaryMissCount() + bucketCacheStats.getPrimaryMissCount(); 281 } 282 283 @Override 284 public long getMissCachingCount() { 285 return lruCacheStats.getMissCachingCount() 286 + bucketCacheStats.getMissCachingCount(); 287 } 288 289 @Override 290 public long getHitCount() { 291 return lruCacheStats.getHitCount() + bucketCacheStats.getHitCount(); 292 } 293 294 @Override 295 public long getPrimaryHitCount() { 296 return lruCacheStats.getPrimaryHitCount() + bucketCacheStats.getPrimaryHitCount(); 297 } 298 @Override 299 public long getHitCachingCount() { 300 return lruCacheStats.getHitCachingCount() 301 + bucketCacheStats.getHitCachingCount(); 302 } 303 304 @Override 305 public long getEvictionCount() { 306 return lruCacheStats.getEvictionCount() 307 + bucketCacheStats.getEvictionCount(); 308 } 309 310 @Override 311 public long getEvictedCount() { 312 return lruCacheStats.getEvictedCount() 313 + bucketCacheStats.getEvictedCount(); 314 } 315 316 @Override 317 public long getPrimaryEvictedCount() { 318 return lruCacheStats.getPrimaryEvictedCount() 319 + bucketCacheStats.getPrimaryEvictedCount(); 320 } 321 322 @Override 323 public void rollMetricsPeriod() { 324 lruCacheStats.rollMetricsPeriod(); 325 bucketCacheStats.rollMetricsPeriod(); 326 } 327 328 @Override 329 public long getFailedInserts() { 330 return lruCacheStats.getFailedInserts() + bucketCacheStats.getFailedInserts(); 331 } 332 333 @Override 334 public long getSumHitCountsPastNPeriods() { 335 return lruCacheStats.getSumHitCountsPastNPeriods() 336 + bucketCacheStats.getSumHitCountsPastNPeriods(); 337 } 338 339 @Override 340 public long getSumRequestCountsPastNPeriods() { 341 return lruCacheStats.getSumRequestCountsPastNPeriods() 342 + bucketCacheStats.getSumRequestCountsPastNPeriods(); 343 } 344 345 @Override 346 public long getSumHitCachingCountsPastNPeriods() { 347 return lruCacheStats.getSumHitCachingCountsPastNPeriods() 348 + bucketCacheStats.getSumHitCachingCountsPastNPeriods(); 349 } 350 351 @Override 352 public long getSumRequestCachingCountsPastNPeriods() { 353 return lruCacheStats.getSumRequestCachingCountsPastNPeriods() 354 + bucketCacheStats.getSumRequestCachingCountsPastNPeriods(); 355 } 356 } 357 358 @Override 359 public Iterator<CachedBlock> iterator() { 360 return new BlockCachesIterator(getBlockCaches()); 361 } 362 363 @Override 364 public BlockCache[] getBlockCaches() { 365 return new BlockCache [] {this.onHeapCache, this.l2Cache}; 366 } 367 368 @Override 369 public void setMaxSize(long size) { 370 this.onHeapCache.setMaxSize(size); 371 } 372 373 @Override 374 public void returnBlock(BlockCacheKey cacheKey, Cacheable block) { 375 // returnBlock is meaningful for L2 cache alone. 376 this.l2Cache.returnBlock(cacheKey, block); 377 } 378 379 @VisibleForTesting 380 public int getRefCount(BlockCacheKey cacheKey) { 381 return (this.l2Cache instanceof BucketCache) 382 ? ((BucketCache) this.l2Cache).getRefCount(cacheKey) : 0; 383 } 384}