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 java.util.Optional; 021import org.apache.hadoop.conf.Configuration; 022import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor; 023import org.apache.hadoop.hbase.io.ByteBuffAllocator; 024import org.apache.hadoop.hbase.io.hfile.BlockType.BlockCategory; 025import org.apache.yetus.audience.InterfaceAudience; 026import org.slf4j.Logger; 027import org.slf4j.LoggerFactory; 028 029/** 030 * Stores all of the cache objects and configuration for a single HFile. 031 */ 032@InterfaceAudience.Private 033public class CacheConfig { 034 private static final Logger LOG = LoggerFactory.getLogger(CacheConfig.class.getName()); 035 036 /** 037 * Disabled cache configuration 038 */ 039 public static final CacheConfig DISABLED = new CacheConfig(); 040 041 /** 042 * Configuration key to cache data blocks on read. Bloom blocks and index blocks are always be 043 * cached if the block cache is enabled. 044 */ 045 public static final String CACHE_DATA_ON_READ_KEY = "hbase.block.data.cacheonread"; 046 047 /** 048 * Configuration key to cache data blocks on write. There are separate switches for bloom blocks 049 * and non-root index blocks. 050 */ 051 public static final String CACHE_BLOCKS_ON_WRITE_KEY = "hbase.rs.cacheblocksonwrite"; 052 053 /** 054 * Configuration key to cache leaf and intermediate-level index blocks on write. 055 */ 056 public static final String CACHE_INDEX_BLOCKS_ON_WRITE_KEY = "hfile.block.index.cacheonwrite"; 057 058 /** 059 * Configuration key to cache compound bloom filter blocks on write. 060 */ 061 public static final String CACHE_BLOOM_BLOCKS_ON_WRITE_KEY = "hfile.block.bloom.cacheonwrite"; 062 063 /** 064 * Configuration key to cache data blocks in compressed and/or encrypted format. 065 */ 066 public static final String CACHE_DATA_BLOCKS_COMPRESSED_KEY = "hbase.block.data.cachecompressed"; 067 068 /** 069 * Configuration key to evict all blocks of a given file from the block cache when the file is 070 * closed. 071 */ 072 public static final String EVICT_BLOCKS_ON_CLOSE_KEY = "hbase.rs.evictblocksonclose"; 073 074 /** 075 * Configuration key to prefetch all blocks of a given file into the block cache when the file is 076 * opened. 077 */ 078 public static final String PREFETCH_BLOCKS_ON_OPEN_KEY = "hbase.rs.prefetchblocksonopen"; 079 080 /** 081 * Configuration key to cache blocks when a compacted file is written 082 */ 083 public static final String CACHE_COMPACTED_BLOCKS_ON_WRITE_KEY = 084 "hbase.rs.cachecompactedblocksonwrite"; 085 086 /** 087 * Configuration key to determine total size in bytes of compacted files beyond which we do not 088 * cache blocks on compaction 089 */ 090 public static final String CACHE_COMPACTED_BLOCKS_ON_WRITE_THRESHOLD_KEY = 091 "hbase.rs.cachecompactedblocksonwrite.threshold"; 092 093 public static final String DROP_BEHIND_CACHE_COMPACTION_KEY = 094 "hbase.hfile.drop.behind.compaction"; 095 096 /** 097 * Configuration key to set interval for persisting bucket cache to disk. 098 */ 099 public static final String BUCKETCACHE_PERSIST_INTERVAL_KEY = 100 "hbase.bucketcache.persist.intervalinmillis"; 101 102 /** 103 * Configuration key to set the heap usage threshold limit once prefetch threads should be 104 * interrupted. 105 */ 106 public static final String PREFETCH_HEAP_USAGE_THRESHOLD = "hbase.rs.prefetchheapusage"; 107 108 // Defaults 109 public static final boolean DEFAULT_CACHE_DATA_ON_READ = true; 110 public static final boolean DEFAULT_CACHE_DATA_ON_WRITE = false; 111 public static final boolean DEFAULT_IN_MEMORY = false; 112 public static final boolean DEFAULT_CACHE_INDEXES_ON_WRITE = false; 113 public static final boolean DEFAULT_CACHE_BLOOMS_ON_WRITE = false; 114 public static final boolean DEFAULT_EVICT_ON_CLOSE = false; 115 public static final boolean DEFAULT_CACHE_DATA_COMPRESSED = false; 116 public static final boolean DEFAULT_PREFETCH_ON_OPEN = false; 117 public static final boolean DEFAULT_CACHE_COMPACTED_BLOCKS_ON_WRITE = false; 118 public static final boolean DROP_BEHIND_CACHE_COMPACTION_DEFAULT = true; 119 public static final long DEFAULT_CACHE_COMPACTED_BLOCKS_ON_WRITE_THRESHOLD = Long.MAX_VALUE; 120 public static final double DEFAULT_PREFETCH_HEAP_USAGE_THRESHOLD = 1d; 121 122 /** 123 * Whether blocks should be cached on read (default is on if there is a cache but this can be 124 * turned off on a per-family or per-request basis). If off we will STILL cache meta blocks; i.e. 125 * INDEX and BLOOM types. This cannot be disabled. 126 */ 127 private final boolean cacheDataOnRead; 128 129 /** Whether blocks should be flagged as in-memory when being cached */ 130 private final boolean inMemory; 131 132 /** Whether data blocks should be cached when new files are written */ 133 private boolean cacheDataOnWrite; 134 135 /** Whether index blocks should be cached when new files are written */ 136 private boolean cacheIndexesOnWrite; 137 138 /** Whether compound bloom filter blocks should be cached on write */ 139 private boolean cacheBloomsOnWrite; 140 141 /** Whether blocks of a file should be evicted when the file is closed */ 142 private boolean evictOnClose; 143 144 /** Whether data blocks should be stored in compressed and/or encrypted form in the cache */ 145 private final boolean cacheDataCompressed; 146 147 /** Whether data blocks should be prefetched into the cache */ 148 private final boolean prefetchOnOpen; 149 150 /** 151 * Whether data blocks should be cached when compacted file is written 152 */ 153 private final boolean cacheCompactedDataOnWrite; 154 155 /** 156 * Determine threshold beyond which we do not cache blocks on compaction 157 */ 158 private long cacheCompactedDataOnWriteThreshold; 159 160 private final boolean dropBehindCompaction; 161 162 // Local reference to the block cache 163 private final BlockCache blockCache; 164 165 private final ByteBuffAllocator byteBuffAllocator; 166 167 private final double heapUsageThreshold; 168 169 /** 170 * Create a cache configuration using the specified configuration object and defaults for family 171 * level settings. Only use if no column family context. 172 * @param conf hbase configuration 173 */ 174 public CacheConfig(Configuration conf) { 175 this(conf, null); 176 } 177 178 public CacheConfig(Configuration conf, BlockCache blockCache) { 179 this(conf, null, blockCache, ByteBuffAllocator.HEAP); 180 } 181 182 /** 183 * Create a cache configuration using the specified configuration object and family descriptor. 184 * @param conf hbase configuration 185 * @param family column family configuration 186 */ 187 public CacheConfig(Configuration conf, ColumnFamilyDescriptor family, BlockCache blockCache, 188 ByteBuffAllocator byteBuffAllocator) { 189 this.cacheDataOnRead = conf.getBoolean(CACHE_DATA_ON_READ_KEY, DEFAULT_CACHE_DATA_ON_READ) 190 && (family == null ? true : family.isBlockCacheEnabled()); 191 this.inMemory = family == null ? DEFAULT_IN_MEMORY : family.isInMemory(); 192 this.cacheDataCompressed = 193 conf.getBoolean(CACHE_DATA_BLOCKS_COMPRESSED_KEY, DEFAULT_CACHE_DATA_COMPRESSED); 194 this.dropBehindCompaction = 195 conf.getBoolean(DROP_BEHIND_CACHE_COMPACTION_KEY, DROP_BEHIND_CACHE_COMPACTION_DEFAULT); 196 // For the following flags we enable them regardless of per-schema settings 197 // if they are enabled in the global configuration. 198 this.cacheDataOnWrite = conf.getBoolean(CACHE_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_DATA_ON_WRITE) 199 || (family == null ? false : family.isCacheDataOnWrite()); 200 this.cacheIndexesOnWrite = 201 conf.getBoolean(CACHE_INDEX_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_INDEXES_ON_WRITE) 202 || (family == null ? false : family.isCacheIndexesOnWrite()); 203 this.cacheBloomsOnWrite = 204 conf.getBoolean(CACHE_BLOOM_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_BLOOMS_ON_WRITE) 205 || (family == null ? false : family.isCacheBloomsOnWrite()); 206 this.evictOnClose = conf.getBoolean(EVICT_BLOCKS_ON_CLOSE_KEY, DEFAULT_EVICT_ON_CLOSE) 207 || (family == null ? false : family.isEvictBlocksOnClose()); 208 this.prefetchOnOpen = conf.getBoolean(PREFETCH_BLOCKS_ON_OPEN_KEY, DEFAULT_PREFETCH_ON_OPEN) 209 || (family == null ? false : family.isPrefetchBlocksOnOpen()); 210 this.cacheCompactedDataOnWrite = 211 conf.getBoolean(CACHE_COMPACTED_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_COMPACTED_BLOCKS_ON_WRITE); 212 this.cacheCompactedDataOnWriteThreshold = getCacheCompactedBlocksOnWriteThreshold(conf); 213 this.heapUsageThreshold = 214 conf.getDouble(PREFETCH_HEAP_USAGE_THRESHOLD, DEFAULT_PREFETCH_HEAP_USAGE_THRESHOLD); 215 this.blockCache = blockCache; 216 this.byteBuffAllocator = byteBuffAllocator; 217 } 218 219 /** 220 * Constructs a cache configuration copied from the specified configuration. 221 */ 222 public CacheConfig(CacheConfig cacheConf) { 223 this.cacheDataOnRead = cacheConf.cacheDataOnRead; 224 this.inMemory = cacheConf.inMemory; 225 this.cacheDataOnWrite = cacheConf.cacheDataOnWrite; 226 this.cacheIndexesOnWrite = cacheConf.cacheIndexesOnWrite; 227 this.cacheBloomsOnWrite = cacheConf.cacheBloomsOnWrite; 228 this.evictOnClose = cacheConf.evictOnClose; 229 this.cacheDataCompressed = cacheConf.cacheDataCompressed; 230 this.prefetchOnOpen = cacheConf.prefetchOnOpen; 231 this.cacheCompactedDataOnWrite = cacheConf.cacheCompactedDataOnWrite; 232 this.cacheCompactedDataOnWriteThreshold = cacheConf.cacheCompactedDataOnWriteThreshold; 233 this.dropBehindCompaction = cacheConf.dropBehindCompaction; 234 this.blockCache = cacheConf.blockCache; 235 this.byteBuffAllocator = cacheConf.byteBuffAllocator; 236 this.heapUsageThreshold = cacheConf.heapUsageThreshold; 237 } 238 239 private CacheConfig() { 240 this.cacheDataOnRead = false; 241 this.inMemory = false; 242 this.cacheDataOnWrite = false; 243 this.cacheIndexesOnWrite = false; 244 this.cacheBloomsOnWrite = false; 245 this.evictOnClose = false; 246 this.cacheDataCompressed = false; 247 this.prefetchOnOpen = false; 248 this.cacheCompactedDataOnWrite = false; 249 this.dropBehindCompaction = false; 250 this.blockCache = null; 251 this.byteBuffAllocator = ByteBuffAllocator.HEAP; 252 this.heapUsageThreshold = DEFAULT_PREFETCH_HEAP_USAGE_THRESHOLD; 253 } 254 255 /** 256 * Returns whether the DATA blocks of this HFile should be cached on read or not (we always cache 257 * the meta blocks, the INDEX and BLOOM blocks). 258 * @return true if blocks should be cached on read, false if not 259 */ 260 public boolean shouldCacheDataOnRead() { 261 return cacheDataOnRead; 262 } 263 264 public boolean shouldDropBehindCompaction() { 265 return dropBehindCompaction; 266 } 267 268 /** 269 * Should we cache a block of a particular category? We always cache important blocks such as 270 * index blocks, as long as the block cache is available. 271 */ 272 public boolean shouldCacheBlockOnRead(BlockCategory category) { 273 return cacheDataOnRead || category == BlockCategory.INDEX || category == BlockCategory.BLOOM 274 || (prefetchOnOpen && (category != BlockCategory.META && category != BlockCategory.UNKNOWN)); 275 } 276 277 /** Returns true if blocks in this file should be flagged as in-memory */ 278 public boolean isInMemory() { 279 return this.inMemory; 280 } 281 282 /** 283 * @return true if data blocks should be written to the cache when an HFile is written, false if 284 * not 285 */ 286 public boolean shouldCacheDataOnWrite() { 287 return this.cacheDataOnWrite; 288 } 289 290 /** 291 * @param cacheDataOnWrite whether data blocks should be written to the cache when an HFile is 292 * written 293 */ 294 public void setCacheDataOnWrite(boolean cacheDataOnWrite) { 295 this.cacheDataOnWrite = cacheDataOnWrite; 296 } 297 298 /** 299 * Enable cache on write including: cacheDataOnWrite cacheIndexesOnWrite cacheBloomsOnWrite 300 */ 301 public void enableCacheOnWrite() { 302 this.cacheDataOnWrite = true; 303 this.cacheIndexesOnWrite = true; 304 this.cacheBloomsOnWrite = true; 305 } 306 307 /** 308 * @return true if index blocks should be written to the cache when an HFile is written, false if 309 * not 310 */ 311 public boolean shouldCacheIndexesOnWrite() { 312 return this.cacheIndexesOnWrite; 313 } 314 315 /** 316 * @return true if bloom blocks should be written to the cache when an HFile is written, false if 317 * not 318 */ 319 public boolean shouldCacheBloomsOnWrite() { 320 return this.cacheBloomsOnWrite; 321 } 322 323 /** 324 * @return true if blocks should be evicted from the cache when an HFile reader is closed, false 325 * if not 326 */ 327 public boolean shouldEvictOnClose() { 328 return this.evictOnClose; 329 } 330 331 /** 332 * Only used for testing. 333 * @param evictOnClose whether blocks should be evicted from the cache when an HFile reader is 334 * closed 335 */ 336 public void setEvictOnClose(boolean evictOnClose) { 337 this.evictOnClose = evictOnClose; 338 } 339 340 /** Returns true if data blocks should be compressed in the cache, false if not */ 341 public boolean shouldCacheDataCompressed() { 342 return this.cacheDataOnRead && this.cacheDataCompressed; 343 } 344 345 /** 346 * Returns true if this {@link BlockCategory} should be compressed in blockcache, false otherwise 347 */ 348 public boolean shouldCacheCompressed(BlockCategory category) { 349 switch (category) { 350 case DATA: 351 return this.cacheDataOnRead && this.cacheDataCompressed; 352 default: 353 return false; 354 } 355 } 356 357 /** Returns true if blocks should be prefetched into the cache on open, false if not */ 358 public boolean shouldPrefetchOnOpen() { 359 return this.prefetchOnOpen && this.cacheDataOnRead; 360 } 361 362 /** Returns true if blocks should be cached while writing during compaction, false if not */ 363 public boolean shouldCacheCompactedBlocksOnWrite() { 364 return this.cacheCompactedDataOnWrite; 365 } 366 367 /** Returns total file size in bytes threshold for caching while writing during compaction */ 368 public long getCacheCompactedBlocksOnWriteThreshold() { 369 return this.cacheCompactedDataOnWriteThreshold; 370 } 371 372 /** 373 * Return true if we may find this type of block in block cache. 374 * <p> 375 * TODO: today {@code family.isBlockCacheEnabled()} only means {@code cacheDataOnRead}, so here we 376 * consider lots of other configurations such as {@code cacheDataOnWrite}. We should fix this in 377 * the future, {@code cacheDataOnWrite} should honor the CF level {@code isBlockCacheEnabled} 378 * configuration. 379 */ 380 public boolean shouldReadBlockFromCache(BlockType blockType) { 381 if (cacheDataOnRead) { 382 return true; 383 } 384 if (prefetchOnOpen) { 385 return true; 386 } 387 if (cacheDataOnWrite) { 388 return true; 389 } 390 if (blockType == null) { 391 return true; 392 } 393 if ( 394 blockType.getCategory() == BlockCategory.BLOOM 395 || blockType.getCategory() == BlockCategory.INDEX 396 ) { 397 return true; 398 } 399 return false; 400 } 401 402 /** 403 * Checks if the current heap usage is below the threshold configured by 404 * "hbase.rs.prefetchheapusage" (0.8 by default). 405 */ 406 public boolean isHeapUsageBelowThreshold() { 407 double total = Runtime.getRuntime().maxMemory(); 408 double available = Runtime.getRuntime().freeMemory(); 409 double usedRatio = 1d - (available / total); 410 return heapUsageThreshold > usedRatio; 411 } 412 413 /** 414 * If we make sure the block could not be cached, we will not acquire the lock otherwise we will 415 * acquire lock 416 */ 417 public boolean shouldLockOnCacheMiss(BlockType blockType) { 418 if (blockType == null) { 419 return true; 420 } 421 return shouldCacheBlockOnRead(blockType.getCategory()); 422 } 423 424 /** 425 * Returns the block cache. 426 * @return the block cache, or null if caching is completely disabled 427 */ 428 public Optional<BlockCache> getBlockCache() { 429 return Optional.ofNullable(this.blockCache); 430 } 431 432 public boolean isCombinedBlockCache() { 433 return blockCache instanceof CombinedBlockCache; 434 } 435 436 public ByteBuffAllocator getByteBuffAllocator() { 437 return this.byteBuffAllocator; 438 } 439 440 public double getHeapUsageThreshold() { 441 return heapUsageThreshold; 442 } 443 444 private long getCacheCompactedBlocksOnWriteThreshold(Configuration conf) { 445 long cacheCompactedBlocksOnWriteThreshold = 446 conf.getLong(CACHE_COMPACTED_BLOCKS_ON_WRITE_THRESHOLD_KEY, 447 DEFAULT_CACHE_COMPACTED_BLOCKS_ON_WRITE_THRESHOLD); 448 449 if (cacheCompactedBlocksOnWriteThreshold < 0) { 450 LOG.warn( 451 "cacheCompactedBlocksOnWriteThreshold value : {} is less than 0, resetting it to: {}", 452 cacheCompactedBlocksOnWriteThreshold, DEFAULT_CACHE_COMPACTED_BLOCKS_ON_WRITE_THRESHOLD); 453 cacheCompactedBlocksOnWriteThreshold = DEFAULT_CACHE_COMPACTED_BLOCKS_ON_WRITE_THRESHOLD; 454 } 455 456 return cacheCompactedBlocksOnWriteThreshold; 457 } 458 459 @Override 460 public String toString() { 461 return "cacheDataOnRead=" + shouldCacheDataOnRead() + ", cacheDataOnWrite=" 462 + shouldCacheDataOnWrite() + ", cacheIndexesOnWrite=" + shouldCacheIndexesOnWrite() 463 + ", cacheBloomsOnWrite=" + shouldCacheBloomsOnWrite() + ", cacheEvictOnClose=" 464 + shouldEvictOnClose() + ", cacheDataCompressed=" + shouldCacheDataCompressed() 465 + ", prefetchOnOpen=" + shouldPrefetchOnOpen(); 466 } 467}