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