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