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