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 static org.apache.hadoop.hbase.HConstants.BUCKET_CACHE_IOENGINE_KEY; 021import static org.apache.hadoop.hbase.HConstants.BUCKET_CACHE_SIZE_KEY; 022 023import java.io.IOException; 024 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.hbase.HConstants; 027import org.apache.yetus.audience.InterfaceAudience; 028import org.slf4j.Logger; 029import org.slf4j.LoggerFactory; 030import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 031import org.apache.hadoop.hbase.io.hfile.BlockType.BlockCategory; 032import org.apache.hadoop.hbase.io.hfile.bucket.BucketCache; 033import org.apache.hadoop.hbase.io.util.MemorySizeUtil; 034import org.apache.hadoop.hbase.util.ReflectionUtils; 035import org.apache.hadoop.util.StringUtils; 036 037import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; 038 039 040/** 041 * Stores all of the cache objects and configuration for a single HFile. 042 */ 043@InterfaceAudience.Private 044public class CacheConfig { 045 private static final Logger LOG = LoggerFactory.getLogger(CacheConfig.class.getName()); 046 047 048 /** 049 * Disabled cache configuration 050 */ 051 052 public static final CacheConfig DISABLED = new CacheConfig(); 053 054 055 /** 056 * Configuration key to cache data blocks on read. Bloom blocks and index blocks are always be 057 * cached if the block cache is enabled. 058 */ 059 public static final String CACHE_DATA_ON_READ_KEY = "hbase.block.data.cacheonread"; 060 061 /** 062 * Configuration key to cache data blocks on write. There are separate 063 * switches for bloom blocks and non-root index blocks. 064 */ 065 public static final String CACHE_BLOCKS_ON_WRITE_KEY = 066 "hbase.rs.cacheblocksonwrite"; 067 068 /** 069 * Configuration key to cache leaf and intermediate-level index blocks on 070 * write. 071 */ 072 public static final String CACHE_INDEX_BLOCKS_ON_WRITE_KEY = 073 "hfile.block.index.cacheonwrite"; 074 075 /** 076 * Configuration key to cache compound bloom filter blocks on write. 077 */ 078 public static final String CACHE_BLOOM_BLOCKS_ON_WRITE_KEY = 079 "hfile.block.bloom.cacheonwrite"; 080 081 /** 082 * Configuration key to cache data blocks in compressed and/or encrypted format. 083 */ 084 public static final String CACHE_DATA_BLOCKS_COMPRESSED_KEY = 085 "hbase.block.data.cachecompressed"; 086 087 /** 088 * Configuration key to evict all blocks of a given file from the block cache 089 * when the file is closed. 090 */ 091 public static final String EVICT_BLOCKS_ON_CLOSE_KEY = 092 "hbase.rs.evictblocksonclose"; 093 094 /** 095 * Configuration keys for Bucket cache 096 */ 097 098 /** 099 * If the chosen ioengine can persist its state across restarts, the path to the file to persist 100 * to. This file is NOT the data file. It is a file into which we will serialize the map of 101 * what is in the data file. For example, if you pass the following argument as 102 * BUCKET_CACHE_IOENGINE_KEY ("hbase.bucketcache.ioengine"), 103 * <code>file:/tmp/bucketcache.data </code>, then we will write the bucketcache data to the file 104 * <code>/tmp/bucketcache.data</code> but the metadata on where the data is in the supplied file 105 * is an in-memory map that needs to be persisted across restarts. Where to store this 106 * in-memory state is what you supply here: e.g. <code>/tmp/bucketcache.map</code>. 107 */ 108 public static final String BUCKET_CACHE_PERSISTENT_PATH_KEY = 109 "hbase.bucketcache.persistent.path"; 110 111 public static final String BUCKET_CACHE_WRITER_THREADS_KEY = "hbase.bucketcache.writer.threads"; 112 public static final String BUCKET_CACHE_WRITER_QUEUE_KEY = 113 "hbase.bucketcache.writer.queuelength"; 114 115 /** 116 * A comma-delimited array of values for use as bucket sizes. 117 */ 118 public static final String BUCKET_CACHE_BUCKETS_KEY = "hbase.bucketcache.bucket.sizes"; 119 120 /** 121 * Defaults for Bucket cache 122 */ 123 public static final int DEFAULT_BUCKET_CACHE_WRITER_THREADS = 3; 124 public static final int DEFAULT_BUCKET_CACHE_WRITER_QUEUE = 64; 125 126 /** 127 * Configuration key to prefetch all blocks of a given file into the block cache 128 * when the file is opened. 129 */ 130 public static final String PREFETCH_BLOCKS_ON_OPEN_KEY = 131 "hbase.rs.prefetchblocksonopen"; 132 133 /** 134 * The target block size used by blockcache instances. Defaults to 135 * {@link HConstants#DEFAULT_BLOCKSIZE}. 136 * TODO: this config point is completely wrong, as it's used to determine the 137 * target block size of BlockCache instances. Rename. 138 */ 139 public static final String BLOCKCACHE_BLOCKSIZE_KEY = "hbase.offheapcache.minblocksize"; 140 141 private static final String EXTERNAL_BLOCKCACHE_KEY = "hbase.blockcache.use.external"; 142 private static final boolean EXTERNAL_BLOCKCACHE_DEFAULT = false; 143 144 private static final String EXTERNAL_BLOCKCACHE_CLASS_KEY = "hbase.blockcache.external.class"; 145 private static final String DROP_BEHIND_CACHE_COMPACTION_KEY = 146 "hbase.hfile.drop.behind.compaction"; 147 private static final boolean DROP_BEHIND_CACHE_COMPACTION_DEFAULT = true; 148 149 /** 150 * Enum of all built in external block caches. 151 * This is used for config. 152 */ 153 private static enum ExternalBlockCaches { 154 memcached("org.apache.hadoop.hbase.io.hfile.MemcachedBlockCache"); 155 // TODO(eclark): Consider more. Redis, etc. 156 Class<? extends BlockCache> clazz; 157 ExternalBlockCaches(String clazzName) { 158 try { 159 clazz = (Class<? extends BlockCache>) Class.forName(clazzName); 160 } catch (ClassNotFoundException cnef) { 161 clazz = null; 162 } 163 } 164 ExternalBlockCaches(Class<? extends BlockCache> clazz) { 165 this.clazz = clazz; 166 } 167 } 168 169 // Defaults 170 public static final boolean DEFAULT_CACHE_DATA_ON_READ = true; 171 public static final boolean DEFAULT_CACHE_DATA_ON_WRITE = false; 172 public static final boolean DEFAULT_IN_MEMORY = false; 173 public static final boolean DEFAULT_CACHE_INDEXES_ON_WRITE = false; 174 public static final boolean DEFAULT_CACHE_BLOOMS_ON_WRITE = false; 175 public static final boolean DEFAULT_EVICT_ON_CLOSE = false; 176 public static final boolean DEFAULT_CACHE_DATA_COMPRESSED = false; 177 public static final boolean DEFAULT_PREFETCH_ON_OPEN = false; 178 179 /** Local reference to the block cache, null if completely disabled */ 180 private final BlockCache blockCache; 181 182 /** 183 * Whether blocks should be cached on read (default is on if there is a 184 * cache but this can be turned off on a per-family or per-request basis). 185 * If off we will STILL cache meta blocks; i.e. INDEX and BLOOM types. 186 * This cannot be disabled. 187 */ 188 private boolean cacheDataOnRead; 189 190 /** Whether blocks should be flagged as in-memory when being cached */ 191 private final boolean inMemory; 192 193 /** Whether data blocks should be cached when new files are written */ 194 private boolean cacheDataOnWrite; 195 196 /** Whether index blocks should be cached when new files are written */ 197 private final boolean cacheIndexesOnWrite; 198 199 /** Whether compound bloom filter blocks should be cached on write */ 200 private final boolean cacheBloomsOnWrite; 201 202 /** Whether blocks of a file should be evicted when the file is closed */ 203 private boolean evictOnClose; 204 205 /** Whether data blocks should be stored in compressed and/or encrypted form in the cache */ 206 private final boolean cacheDataCompressed; 207 208 /** Whether data blocks should be prefetched into the cache */ 209 private final boolean prefetchOnOpen; 210 211 private final boolean dropBehindCompaction; 212 213 /** 214 * Create a cache configuration using the specified configuration object and 215 * family descriptor. 216 * @param conf hbase configuration 217 * @param family column family configuration 218 */ 219 public CacheConfig(Configuration conf, ColumnFamilyDescriptor family) { 220 this(CacheConfig.instantiateBlockCache(conf), 221 conf.getBoolean(CACHE_DATA_ON_READ_KEY, DEFAULT_CACHE_DATA_ON_READ) 222 && family.isBlockCacheEnabled(), 223 family.isInMemory(), 224 // For the following flags we enable them regardless of per-schema settings 225 // if they are enabled in the global configuration. 226 conf.getBoolean(CACHE_BLOCKS_ON_WRITE_KEY, 227 DEFAULT_CACHE_DATA_ON_WRITE) || family.isCacheDataOnWrite(), 228 conf.getBoolean(CACHE_INDEX_BLOCKS_ON_WRITE_KEY, 229 DEFAULT_CACHE_INDEXES_ON_WRITE) || family.isCacheIndexesOnWrite(), 230 conf.getBoolean(CACHE_BLOOM_BLOCKS_ON_WRITE_KEY, 231 DEFAULT_CACHE_BLOOMS_ON_WRITE) || family.isCacheBloomsOnWrite(), 232 conf.getBoolean(EVICT_BLOCKS_ON_CLOSE_KEY, 233 DEFAULT_EVICT_ON_CLOSE) || family.isEvictBlocksOnClose(), 234 conf.getBoolean(CACHE_DATA_BLOCKS_COMPRESSED_KEY, DEFAULT_CACHE_DATA_COMPRESSED), 235 conf.getBoolean(PREFETCH_BLOCKS_ON_OPEN_KEY, 236 DEFAULT_PREFETCH_ON_OPEN) || family.isPrefetchBlocksOnOpen(), 237 conf.getBoolean(DROP_BEHIND_CACHE_COMPACTION_KEY, DROP_BEHIND_CACHE_COMPACTION_DEFAULT) 238 ); 239 LOG.info("Created cacheConfig for " + family.getNameAsString() + ": " + this); 240 } 241 242 /** 243 * Create a cache configuration using the specified configuration object and 244 * defaults for family level settings. Only use if no column family context. Prefer 245 * {@link CacheConfig#CacheConfig(Configuration, ColumnFamilyDescriptor)} 246 * @see #CacheConfig(Configuration, ColumnFamilyDescriptor) 247 * @param conf hbase configuration 248 */ 249 public CacheConfig(Configuration conf) { 250 this(CacheConfig.instantiateBlockCache(conf), 251 conf.getBoolean(CACHE_DATA_ON_READ_KEY, DEFAULT_CACHE_DATA_ON_READ), 252 DEFAULT_IN_MEMORY, // This is a family-level setting so can't be set 253 // strictly from conf 254 conf.getBoolean(CACHE_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_DATA_ON_WRITE), 255 conf.getBoolean(CACHE_INDEX_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_INDEXES_ON_WRITE), 256 conf.getBoolean(CACHE_BLOOM_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_BLOOMS_ON_WRITE), 257 conf.getBoolean(EVICT_BLOCKS_ON_CLOSE_KEY, DEFAULT_EVICT_ON_CLOSE), 258 conf.getBoolean(CACHE_DATA_BLOCKS_COMPRESSED_KEY, DEFAULT_CACHE_DATA_COMPRESSED), 259 conf.getBoolean(PREFETCH_BLOCKS_ON_OPEN_KEY, DEFAULT_PREFETCH_ON_OPEN), 260 conf.getBoolean(DROP_BEHIND_CACHE_COMPACTION_KEY, DROP_BEHIND_CACHE_COMPACTION_DEFAULT) 261 ); 262 LOG.info("Created cacheConfig: " + this); 263 } 264 265 /** 266 * Create a block cache configuration with the specified cache and configuration parameters. 267 * @param blockCache reference to block cache, null if completely disabled 268 * @param cacheDataOnRead whether DATA blocks should be cached on read (we always cache INDEX 269 * blocks and BLOOM blocks; this cannot be disabled). 270 * @param inMemory whether blocks should be flagged as in-memory 271 * @param cacheDataOnWrite whether data blocks should be cached on write 272 * @param cacheIndexesOnWrite whether index blocks should be cached on write 273 * @param cacheBloomsOnWrite whether blooms should be cached on write 274 * @param evictOnClose whether blocks should be evicted when HFile is closed 275 * @param cacheDataCompressed whether to store blocks as compressed in the cache 276 * @param prefetchOnOpen whether to prefetch blocks upon open 277 * @param cacheDataInL1 If more than one cache tier deployed, if true, cache this column families 278 * data blocks up in the L1 tier. 279 * @param dropBehindCompaction indicate that we should set drop behind to true when open a store 280 * file reader for compaction 281 */ 282 CacheConfig(final BlockCache blockCache, 283 final boolean cacheDataOnRead, final boolean inMemory, 284 final boolean cacheDataOnWrite, final boolean cacheIndexesOnWrite, 285 final boolean cacheBloomsOnWrite, final boolean evictOnClose, 286 final boolean cacheDataCompressed, final boolean prefetchOnOpen, 287 final boolean dropBehindCompaction) { 288 this.blockCache = blockCache; 289 this.cacheDataOnRead = cacheDataOnRead; 290 this.inMemory = inMemory; 291 this.cacheDataOnWrite = cacheDataOnWrite; 292 this.cacheIndexesOnWrite = cacheIndexesOnWrite; 293 this.cacheBloomsOnWrite = cacheBloomsOnWrite; 294 this.evictOnClose = evictOnClose; 295 this.cacheDataCompressed = cacheDataCompressed; 296 this.prefetchOnOpen = prefetchOnOpen; 297 this.dropBehindCompaction = dropBehindCompaction; 298 } 299 300 /** 301 * Constructs a cache configuration copied from the specified configuration. 302 * @param cacheConf 303 */ 304 public CacheConfig(CacheConfig cacheConf) { 305 this(cacheConf.blockCache, cacheConf.cacheDataOnRead, cacheConf.inMemory, 306 cacheConf.cacheDataOnWrite, cacheConf.cacheIndexesOnWrite, 307 cacheConf.cacheBloomsOnWrite, cacheConf.evictOnClose, 308 cacheConf.cacheDataCompressed, cacheConf.prefetchOnOpen, 309 cacheConf.dropBehindCompaction); 310 } 311 312 private CacheConfig() { 313 this(null, false, false, false, false, false, false, false, false, false); 314 } 315 316 /** 317 * Checks whether the block cache is enabled. 318 */ 319 public boolean isBlockCacheEnabled() { 320 return this.blockCache != null; 321 } 322 323 /** 324 * Returns the block cache. 325 * @return the block cache, or null if caching is completely disabled 326 */ 327 public BlockCache getBlockCache() { 328 return this.blockCache; 329 } 330 331 /** 332 * Returns whether the DATA blocks of this HFile should be cached on read or not (we always 333 * cache the meta blocks, the INDEX and BLOOM blocks). 334 * @return true if blocks should be cached on read, false if not 335 */ 336 public boolean shouldCacheDataOnRead() { 337 return isBlockCacheEnabled() && cacheDataOnRead; 338 } 339 340 public boolean shouldDropBehindCompaction() { 341 return dropBehindCompaction; 342 } 343 344 /** 345 * Should we cache a block of a particular category? We always cache 346 * important blocks such as index blocks, as long as the block cache is 347 * available. 348 */ 349 public boolean shouldCacheBlockOnRead(BlockCategory category) { 350 return isBlockCacheEnabled() 351 && (cacheDataOnRead || 352 category == BlockCategory.INDEX || 353 category == BlockCategory.BLOOM || 354 (prefetchOnOpen && 355 (category != BlockCategory.META && 356 category != BlockCategory.UNKNOWN))); 357 } 358 359 /** 360 * @return true if blocks in this file should be flagged as in-memory 361 */ 362 public boolean isInMemory() { 363 return isBlockCacheEnabled() && this.inMemory; 364 } 365 366 /** 367 * @return true if data blocks should be written to the cache when an HFile is 368 * written, false if not 369 */ 370 public boolean shouldCacheDataOnWrite() { 371 return isBlockCacheEnabled() && this.cacheDataOnWrite; 372 } 373 374 /** 375 * Only used for testing. 376 * @param cacheDataOnWrite whether data blocks should be written to the cache 377 * when an HFile is written 378 */ 379 @VisibleForTesting 380 public void setCacheDataOnWrite(boolean cacheDataOnWrite) { 381 this.cacheDataOnWrite = cacheDataOnWrite; 382 } 383 384 /** 385 * @return true if index blocks should be written to the cache when an HFile 386 * is written, false if not 387 */ 388 public boolean shouldCacheIndexesOnWrite() { 389 return isBlockCacheEnabled() && this.cacheIndexesOnWrite; 390 } 391 392 /** 393 * @return true if bloom blocks should be written to the cache when an HFile 394 * is written, false if not 395 */ 396 public boolean shouldCacheBloomsOnWrite() { 397 return isBlockCacheEnabled() && this.cacheBloomsOnWrite; 398 } 399 400 /** 401 * @return true if blocks should be evicted from the cache when an HFile 402 * reader is closed, false if not 403 */ 404 public boolean shouldEvictOnClose() { 405 return isBlockCacheEnabled() && this.evictOnClose; 406 } 407 408 /** 409 * Only used for testing. 410 * @param evictOnClose whether blocks should be evicted from the cache when an 411 * HFile reader is closed 412 */ 413 public void setEvictOnClose(boolean evictOnClose) { 414 this.evictOnClose = evictOnClose; 415 } 416 417 /** 418 * @return true if data blocks should be compressed in the cache, false if not 419 */ 420 public boolean shouldCacheDataCompressed() { 421 return isBlockCacheEnabled() && this.cacheDataOnRead && this.cacheDataCompressed; 422 } 423 424 /** 425 * @return true if this {@link BlockCategory} should be compressed in blockcache, false otherwise 426 */ 427 public boolean shouldCacheCompressed(BlockCategory category) { 428 if (!isBlockCacheEnabled()) return false; 429 switch (category) { 430 case DATA: 431 return this.cacheDataOnRead && this.cacheDataCompressed; 432 default: 433 return false; 434 } 435 } 436 437 /** 438 * @return true if blocks should be prefetched into the cache on open, false if not 439 */ 440 public boolean shouldPrefetchOnOpen() { 441 return isBlockCacheEnabled() && this.prefetchOnOpen; 442 } 443 444 /** 445 * Return true if we may find this type of block in block cache. 446 * <p> 447 * TODO: today {@code family.isBlockCacheEnabled()} only means {@code cacheDataOnRead}, so here we 448 * consider lots of other configurations such as {@code cacheDataOnWrite}. We should fix this in 449 * the future, {@code cacheDataOnWrite} should honor the CF level {@code isBlockCacheEnabled} 450 * configuration. 451 */ 452 public boolean shouldReadBlockFromCache(BlockType blockType) { 453 if (!isBlockCacheEnabled()) { 454 return false; 455 } 456 if (cacheDataOnRead) { 457 return true; 458 } 459 if (prefetchOnOpen) { 460 return true; 461 } 462 if (cacheDataOnWrite) { 463 return true; 464 } 465 if (blockType == null) { 466 return true; 467 } 468 if (blockType.getCategory() == BlockCategory.BLOOM || 469 blockType.getCategory() == BlockCategory.INDEX) { 470 return true; 471 } 472 return false; 473 } 474 475 /** 476 * If we make sure the block could not be cached, we will not acquire the lock 477 * otherwise we will acquire lock 478 */ 479 public boolean shouldLockOnCacheMiss(BlockType blockType) { 480 if (blockType == null) { 481 return true; 482 } 483 return shouldCacheBlockOnRead(blockType.getCategory()); 484 } 485 486 @Override 487 public String toString() { 488 if (!isBlockCacheEnabled()) { 489 return "CacheConfig:disabled"; 490 } 491 return "blockCache=" + getBlockCache() + 492 ", cacheDataOnRead=" + shouldCacheDataOnRead() + 493 ", cacheDataOnWrite=" + shouldCacheDataOnWrite() + 494 ", cacheIndexesOnWrite=" + shouldCacheIndexesOnWrite() + 495 ", cacheBloomsOnWrite=" + shouldCacheBloomsOnWrite() + 496 ", cacheEvictOnClose=" + shouldEvictOnClose() + 497 ", cacheDataCompressed=" + shouldCacheDataCompressed() + 498 ", prefetchOnOpen=" + shouldPrefetchOnOpen(); 499 } 500 501 // Static block cache reference and methods 502 503 /** 504 * Static reference to the block cache, or null if no caching should be used 505 * at all. 506 */ 507 // Clear this if in tests you'd make more than one block cache instance. 508 @VisibleForTesting 509 static BlockCache GLOBAL_BLOCK_CACHE_INSTANCE; 510 private static LruBlockCache ONHEAP_CACHE_INSTANCE = null; 511 private static BlockCache L2_CACHE_INSTANCE = null;// Can be BucketCache or External cache. 512 513 /** Boolean whether we have disabled the block cache entirely. */ 514 @VisibleForTesting 515 static boolean blockCacheDisabled = false; 516 517 /** 518 * @param c Configuration to use. 519 * @return An L1 instance. Currently an instance of LruBlockCache. 520 */ 521 public static LruBlockCache getOnHeapCache(final Configuration c) { 522 return getOnHeapCacheInternal(c); 523 } 524 525 public CacheStats getOnHeapCacheStats() { 526 if (ONHEAP_CACHE_INSTANCE != null) { 527 return ONHEAP_CACHE_INSTANCE.getStats(); 528 } 529 return null; 530 } 531 532 public CacheStats getL2CacheStats() { 533 if (L2_CACHE_INSTANCE != null) { 534 return L2_CACHE_INSTANCE.getStats(); 535 } 536 return null; 537 } 538 539 /** 540 * @param c Configuration to use. 541 * @return An L1 instance. Currently an instance of LruBlockCache. 542 */ 543 private synchronized static LruBlockCache getOnHeapCacheInternal(final Configuration c) { 544 if (ONHEAP_CACHE_INSTANCE != null) { 545 return ONHEAP_CACHE_INSTANCE; 546 } 547 final long cacheSize = MemorySizeUtil.getOnHeapCacheSize(c); 548 if (cacheSize < 0) { 549 blockCacheDisabled = true; 550 } 551 if (blockCacheDisabled) return null; 552 int blockSize = c.getInt(BLOCKCACHE_BLOCKSIZE_KEY, HConstants.DEFAULT_BLOCKSIZE); 553 LOG.info("Allocating onheap LruBlockCache size=" + 554 StringUtils.byteDesc(cacheSize) + ", blockSize=" + StringUtils.byteDesc(blockSize)); 555 ONHEAP_CACHE_INSTANCE = new LruBlockCache(cacheSize, blockSize, true, c); 556 return ONHEAP_CACHE_INSTANCE; 557 } 558 559 private static BlockCache getExternalBlockcache(Configuration c) { 560 if (LOG.isDebugEnabled()) { 561 LOG.debug("Trying to use External l2 cache"); 562 } 563 Class klass = null; 564 565 // Get the class, from the config. s 566 try { 567 klass = ExternalBlockCaches.valueOf(c.get(EXTERNAL_BLOCKCACHE_CLASS_KEY, "memcache")).clazz; 568 } catch (IllegalArgumentException exception) { 569 try { 570 klass = c.getClass(EXTERNAL_BLOCKCACHE_CLASS_KEY, Class.forName( 571 "org.apache.hadoop.hbase.io.hfile.MemcachedBlockCache")); 572 } catch (ClassNotFoundException e) { 573 return null; 574 } 575 } 576 577 // Now try and create an instance of the block cache. 578 try { 579 LOG.info("Creating external block cache of type: " + klass); 580 return (BlockCache) ReflectionUtils.newInstance(klass, c); 581 } catch (Exception e) { 582 LOG.warn("Error creating external block cache", e); 583 } 584 return null; 585 586 } 587 588 @VisibleForTesting 589 static BucketCache getBucketCache(Configuration c) { 590 // Check for L2. ioengine name must be non-null. 591 String bucketCacheIOEngineName = c.get(BUCKET_CACHE_IOENGINE_KEY, null); 592 if (bucketCacheIOEngineName == null || bucketCacheIOEngineName.length() <= 0) return null; 593 594 int blockSize = c.getInt(BLOCKCACHE_BLOCKSIZE_KEY, HConstants.DEFAULT_BLOCKSIZE); 595 final long bucketCacheSize = MemorySizeUtil.getBucketCacheSize(c); 596 if (bucketCacheSize <= 0) { 597 throw new IllegalStateException("bucketCacheSize <= 0; Check " + 598 BUCKET_CACHE_SIZE_KEY + " setting and/or server java heap size"); 599 } 600 if (c.get("hbase.bucketcache.percentage.in.combinedcache") != null) { 601 LOG.warn("Configuration 'hbase.bucketcache.percentage.in.combinedcache' is no longer " 602 + "respected. See comments in http://hbase.apache.org/book.html#_changes_of_note"); 603 } 604 int writerThreads = c.getInt(BUCKET_CACHE_WRITER_THREADS_KEY, 605 DEFAULT_BUCKET_CACHE_WRITER_THREADS); 606 int writerQueueLen = c.getInt(BUCKET_CACHE_WRITER_QUEUE_KEY, 607 DEFAULT_BUCKET_CACHE_WRITER_QUEUE); 608 String persistentPath = c.get(BUCKET_CACHE_PERSISTENT_PATH_KEY); 609 String[] configuredBucketSizes = c.getStrings(BUCKET_CACHE_BUCKETS_KEY); 610 int [] bucketSizes = null; 611 if (configuredBucketSizes != null) { 612 bucketSizes = new int[configuredBucketSizes.length]; 613 for (int i = 0; i < configuredBucketSizes.length; i++) { 614 int bucketSize = Integer.parseInt(configuredBucketSizes[i].trim()); 615 if (bucketSize % 256 != 0) { 616 // We need all the bucket sizes to be multiples of 256. Having all the configured bucket 617 // sizes to be multiples of 256 will ensure that the block offsets within buckets, 618 // that are calculated, will also be multiples of 256. 619 // See BucketEntry where offset to each block is represented using 5 bytes (instead of 8 620 // bytes long). We would like to save heap overhead as less as possible. 621 throw new IllegalArgumentException("Illegal value: " + bucketSize + " configured for '" 622 + BUCKET_CACHE_BUCKETS_KEY + "'. All bucket sizes to be multiples of 256"); 623 } 624 bucketSizes[i] = bucketSize; 625 } 626 } 627 BucketCache bucketCache = null; 628 try { 629 int ioErrorsTolerationDuration = c.getInt( 630 "hbase.bucketcache.ioengine.errors.tolerated.duration", 631 BucketCache.DEFAULT_ERROR_TOLERATION_DURATION); 632 // Bucket cache logs its stats on creation internal to the constructor. 633 bucketCache = new BucketCache(bucketCacheIOEngineName, 634 bucketCacheSize, blockSize, bucketSizes, writerThreads, writerQueueLen, persistentPath, 635 ioErrorsTolerationDuration, c); 636 } catch (IOException ioex) { 637 LOG.error("Can't instantiate bucket cache", ioex); throw new RuntimeException(ioex); 638 } 639 return bucketCache; 640 } 641 642 /** 643 * Returns the block cache or <code>null</code> in case none should be used. 644 * Sets GLOBAL_BLOCK_CACHE_INSTANCE 645 * 646 * @param conf The current configuration. 647 * @return The block cache or <code>null</code>. 648 */ 649 public static synchronized BlockCache instantiateBlockCache(Configuration conf) { 650 if (GLOBAL_BLOCK_CACHE_INSTANCE != null) return GLOBAL_BLOCK_CACHE_INSTANCE; 651 if (blockCacheDisabled) return null; 652 LruBlockCache onHeapCache = getOnHeapCacheInternal(conf); 653 // blockCacheDisabled is set as a side-effect of getL1Internal(), so check it again after the 654 // call. 655 if (blockCacheDisabled) return null; 656 boolean useExternal = conf.getBoolean(EXTERNAL_BLOCKCACHE_KEY, EXTERNAL_BLOCKCACHE_DEFAULT); 657 if (useExternal) { 658 L2_CACHE_INSTANCE = getExternalBlockcache(conf); 659 GLOBAL_BLOCK_CACHE_INSTANCE = L2_CACHE_INSTANCE == null ? onHeapCache 660 : new InclusiveCombinedBlockCache(onHeapCache, L2_CACHE_INSTANCE); 661 } else { 662 // otherwise use the bucket cache. 663 L2_CACHE_INSTANCE = getBucketCache(conf); 664 if (!conf.getBoolean("hbase.bucketcache.combinedcache.enabled", true)) { 665 // Non combined mode is off from 2.0 666 LOG.warn( 667 "From HBase 2.0 onwards only combined mode of LRU cache and bucket cache is available"); 668 } 669 GLOBAL_BLOCK_CACHE_INSTANCE = L2_CACHE_INSTANCE == null ? onHeapCache 670 : new CombinedBlockCache(onHeapCache, L2_CACHE_INSTANCE); 671 } 672 return GLOBAL_BLOCK_CACHE_INSTANCE; 673 } 674 675 // Supposed to use only from tests. Some tests want to reinit the Global block cache instance 676 @VisibleForTesting 677 static synchronized void clearGlobalInstances() { 678 ONHEAP_CACHE_INSTANCE = null; 679 L2_CACHE_INSTANCE = null; 680 GLOBAL_BLOCK_CACHE_INSTANCE = null; 681 } 682}