View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.io.hfile;
19  
20  import java.io.IOException;
21  import java.lang.management.ManagementFactory;
22  import java.lang.management.MemoryUsage;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.hadoop.classification.InterfaceAudience;
27  import org.apache.hadoop.conf.Configuration;
28  import org.apache.hadoop.hbase.HColumnDescriptor;
29  import org.apache.hadoop.hbase.HConstants;
30  import org.apache.hadoop.hbase.io.hfile.BlockType.BlockCategory;
31  import org.apache.hadoop.hbase.io.hfile.bucket.BucketCache;
32  import org.apache.hadoop.hbase.io.hfile.slab.SlabCache;
33  import org.apache.hadoop.hbase.util.DirectMemoryUtils;
34  import org.apache.hadoop.util.StringUtils;
35  
36  import com.google.common.annotations.VisibleForTesting;
37  
38  /**
39   * Stores all of the cache objects and configuration for a single HFile.
40   */
41  @InterfaceAudience.Private
42  public class CacheConfig {
43    private static final Log LOG = LogFactory.getLog(CacheConfig.class.getName());
44  
45    /**
46     * Configuration key to cache data blocks on write. There are separate
47     * switches for bloom blocks and non-root index blocks.
48     */
49    public static final String CACHE_BLOCKS_ON_WRITE_KEY =
50        "hbase.rs.cacheblocksonwrite";
51  
52    /**
53     * Configuration key to cache leaf and intermediate-level index blocks on
54     * write.
55     */
56    public static final String CACHE_INDEX_BLOCKS_ON_WRITE_KEY =
57        "hfile.block.index.cacheonwrite";
58  
59    /**
60     * Configuration key to cache compound bloom filter blocks on write.
61     */
62    public static final String CACHE_BLOOM_BLOCKS_ON_WRITE_KEY =
63        "hfile.block.bloom.cacheonwrite";
64  
65    /**
66     * TODO: Implement this (jgray)
67     * Configuration key to cache data blocks in compressed format.
68     */
69    public static final String CACHE_DATA_BLOCKS_COMPRESSED_KEY =
70        "hbase.rs.blockcache.cachedatacompressed";
71  
72    /**
73     * Configuration key to evict all blocks of a given file from the block cache
74     * when the file is closed.
75     */
76    public static final String EVICT_BLOCKS_ON_CLOSE_KEY =
77        "hbase.rs.evictblocksonclose";
78  
79    /**
80     * Configuration keys for Bucket cache
81     */
82  
83    /**
84     * Current ioengine options in include: heap, offheap and file:PATH (where PATH is the path
85     * to the file that will host the file-based cache.  See BucketCache#getIOEngineFromName() for
86     * list of supported ioengine options.
87     * 
88     * <p>Set this option and a non-zero {@link #BUCKET_CACHE_SIZE_KEY} to enable bucket cache.
89     */
90    public static final String BUCKET_CACHE_IOENGINE_KEY = "hbase.bucketcache.ioengine";
91  
92    /**
93     * When using bucket cache, this is a float that EITHER represents a percentage of total heap
94     * memory size to give to the cache (if < 1.0) OR, it is the capacity in megabytes of the cache.
95     * 
96     * <p>The resultant size is further divided if {@link #BUCKET_CACHE_COMBINED_KEY} is set (It is
97     * set by default. When false, bucket cache serves as an "L2" cache to the "L1"
98     * {@link LruBlockCache}).  The percentage is set in
99     * with {@link #BUCKET_CACHE_COMBINED_PERCENTAGE_KEY} float.
100    */
101   public static final String BUCKET_CACHE_SIZE_KEY = "hbase.bucketcache.size";
102 
103   /**
104    * If the chosen ioengine can persist its state across restarts, the path to the file to
105    * persist to.
106    */
107   public static final String BUCKET_CACHE_PERSISTENT_PATH_KEY = 
108       "hbase.bucketcache.persistent.path";
109 
110   /**
111    * If the bucket cache is used in league with the lru on-heap block cache (meta blocks such
112    * as indices and blooms are kept in the lru blockcache and the data blocks in the
113    * bucket cache).
114    */
115   public static final String BUCKET_CACHE_COMBINED_KEY = 
116       "hbase.bucketcache.combinedcache.enabled";
117 
118   /**
119    * A float which designates how much of the overall cache to give to bucket cache
120    * and how much to on-heap lru cache when {@link #BUCKET_CACHE_COMBINED_KEY} is set.
121    */
122   public static final String BUCKET_CACHE_COMBINED_PERCENTAGE_KEY = 
123       "hbase.bucketcache.percentage.in.combinedcache";
124 
125   public static final String BUCKET_CACHE_WRITER_THREADS_KEY = "hbase.bucketcache.writer.threads";
126   public static final String BUCKET_CACHE_WRITER_QUEUE_KEY = 
127       "hbase.bucketcache.writer.queuelength";
128 
129   /**
130    * A comma-delimited array of values for use as bucket sizes.
131    */
132   public static final String BUCKET_CACHE_BUCKETS_KEY = "hbase.bucketcache.bucket.sizes";
133 
134   /**
135    * Defaults for Bucket cache
136    */
137   public static final boolean DEFAULT_BUCKET_CACHE_COMBINED = true;
138   public static final int DEFAULT_BUCKET_CACHE_WRITER_THREADS = 3;
139   public static final int DEFAULT_BUCKET_CACHE_WRITER_QUEUE = 64;
140   public static final float DEFAULT_BUCKET_CACHE_COMBINED_PERCENTAGE = 0.9f;
141 
142   /**
143    * Setting this float to a non-null value turns on {@link DoubleBlockCache}
144    * which makes use of the {@link LruBlockCache} and {@link SlabCache}.
145    * 
146    * The float value of between 0 and 1 will be multiplied against the setting for
147    * <code>-XX:MaxDirectMemorySize</code> to figure what size of the offheap allocation to give
148    * over to slab cache.
149    * 
150    * Slab cache has been little used and is likely to be deprecated in the near future.
151    */
152   public static final String SLAB_CACHE_OFFHEAP_PERCENTAGE_KEY =
153     "hbase.offheapcache.percentage";
154 
155  /**
156    * Configuration key to prefetch all blocks of a given file into the block cache
157    * when the file is opened.
158    */
159   public static final String PREFETCH_BLOCKS_ON_OPEN_KEY =
160       "hbase.rs.prefetchblocksonopen";
161 
162   // Defaults
163 
164   public static final boolean DEFAULT_CACHE_DATA_ON_READ = true;
165   public static final boolean DEFAULT_CACHE_DATA_ON_WRITE = false;
166   public static final boolean DEFAULT_IN_MEMORY = false;
167   public static final boolean DEFAULT_CACHE_INDEXES_ON_WRITE = false;
168   public static final boolean DEFAULT_CACHE_BLOOMS_ON_WRITE = false;
169   public static final boolean DEFAULT_EVICT_ON_CLOSE = false;
170   public static final boolean DEFAULT_COMPRESSED_CACHE = false;
171   public static final boolean DEFAULT_PREFETCH_ON_OPEN = false;
172 
173   /** Local reference to the block cache, null if completely disabled */
174   private final BlockCache blockCache;
175 
176   /**
177    * Whether blocks should be cached on read (default is on if there is a
178    * cache but this can be turned off on a per-family or per-request basis).
179    * If off we will STILL cache meta blocks; i.e. INDEX and BLOOM types.
180    * This cannot be disabled.
181    */
182   private boolean cacheDataOnRead;
183 
184   /** Whether blocks should be flagged as in-memory when being cached */
185   private final boolean inMemory;
186 
187   /** Whether data blocks should be cached when new files are written */
188   private boolean cacheDataOnWrite;
189 
190   /** Whether index blocks should be cached when new files are written */
191   private final boolean cacheIndexesOnWrite;
192 
193   /** Whether compound bloom filter blocks should be cached on write */
194   private final boolean cacheBloomsOnWrite;
195 
196   /** Whether blocks of a file should be evicted when the file is closed */
197   private boolean evictOnClose;
198 
199   /** Whether data blocks should be stored in compressed form in the cache */
200   private final boolean cacheCompressed;
201 
202   /** Whether data blocks should be prefetched into the cache */
203   private final boolean prefetchOnOpen;
204 
205   /**
206    * If true and if more than one tier in this cache deploy -- e.g. CombinedBlockCache has an L1
207    * and an L2 tier -- then cache data blocks up in the L1 tier (The meta blocks are likely being
208    * cached up in L1 already.  At least this is the case if CombinedBlockCache).
209    */
210   private boolean cacheDataInL1;
211 
212   /**
213    * Create a cache configuration using the specified configuration object and
214    * family descriptor.
215    * @param conf hbase configuration
216    * @param family column family configuration
217    */
218   public CacheConfig(Configuration conf, HColumnDescriptor family) {
219     this(CacheConfig.instantiateBlockCache(conf),
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.shouldCacheDataOnWrite(),
226         conf.getBoolean(CACHE_INDEX_BLOCKS_ON_WRITE_KEY,
227             DEFAULT_CACHE_INDEXES_ON_WRITE) || family.shouldCacheIndexesOnWrite(),
228         conf.getBoolean(CACHE_BLOOM_BLOCKS_ON_WRITE_KEY,
229             DEFAULT_CACHE_BLOOMS_ON_WRITE) || family.shouldCacheBloomsOnWrite(),
230         conf.getBoolean(EVICT_BLOCKS_ON_CLOSE_KEY,
231             DEFAULT_EVICT_ON_CLOSE) || family.shouldEvictBlocksOnClose(),
232         conf.getBoolean(CACHE_DATA_BLOCKS_COMPRESSED_KEY, DEFAULT_COMPRESSED_CACHE),
233         conf.getBoolean(PREFETCH_BLOCKS_ON_OPEN_KEY,
234             DEFAULT_PREFETCH_ON_OPEN) || family.shouldPrefetchBlocksOnOpen(),
235         conf.getBoolean(HColumnDescriptor.CACHE_DATA_IN_L1,
236             HColumnDescriptor.DEFAULT_CACHE_DATA_IN_L1) || family.shouldCacheDataInL1()
237      );
238   }
239 
240   /**
241    * Create a cache configuration using the specified configuration object and
242    * defaults for family level settings.
243    * @param conf hbase configuration
244    */
245   public CacheConfig(Configuration conf) {
246     this(CacheConfig.instantiateBlockCache(conf),
247         DEFAULT_CACHE_DATA_ON_READ,
248         DEFAULT_IN_MEMORY, // This is a family-level setting so can't be set
249                            // strictly from conf
250         conf.getBoolean(CACHE_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_DATA_ON_WRITE),
251         conf.getBoolean(CACHE_INDEX_BLOCKS_ON_WRITE_KEY,
252             DEFAULT_CACHE_INDEXES_ON_WRITE),
253             conf.getBoolean(CACHE_BLOOM_BLOCKS_ON_WRITE_KEY,
254                 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,
257             DEFAULT_COMPRESSED_CACHE),
258         conf.getBoolean(PREFETCH_BLOCKS_ON_OPEN_KEY, DEFAULT_PREFETCH_ON_OPEN),
259         conf.getBoolean(HColumnDescriptor.CACHE_DATA_IN_L1,
260           HColumnDescriptor.DEFAULT_CACHE_DATA_IN_L1)
261      );
262   }
263 
264   /**
265    * Create a block cache configuration with the specified cache and
266    * 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 cacheCompressed 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    */
280   CacheConfig(final BlockCache blockCache,
281       final boolean cacheDataOnRead, final boolean inMemory,
282       final boolean cacheDataOnWrite, final boolean cacheIndexesOnWrite,
283       final boolean cacheBloomsOnWrite, final boolean evictOnClose,
284       final boolean cacheCompressed, final boolean prefetchOnOpen,
285       final boolean cacheDataInL1) {
286     this.blockCache = blockCache;
287     this.cacheDataOnRead = cacheDataOnRead;
288     this.inMemory = inMemory;
289     this.cacheDataOnWrite = cacheDataOnWrite;
290     this.cacheIndexesOnWrite = cacheIndexesOnWrite;
291     this.cacheBloomsOnWrite = cacheBloomsOnWrite;
292     this.evictOnClose = evictOnClose;
293     this.cacheCompressed = cacheCompressed;
294     this.prefetchOnOpen = prefetchOnOpen;
295     this.cacheDataInL1 = cacheDataInL1;
296     LOG.info(this);
297   }
298 
299   /**
300    * Constructs a cache configuration copied from the specified configuration.
301    * @param cacheConf
302    */
303   public CacheConfig(CacheConfig cacheConf) {
304     this(cacheConf.blockCache, cacheConf.cacheDataOnRead, cacheConf.inMemory,
305         cacheConf.cacheDataOnWrite, cacheConf.cacheIndexesOnWrite,
306         cacheConf.cacheBloomsOnWrite, cacheConf.evictOnClose,
307         cacheConf.cacheCompressed, cacheConf.prefetchOnOpen,
308         cacheConf.cacheDataInL1);
309   }
310 
311   /**
312    * Checks whether the block cache is enabled.
313    */
314   public boolean isBlockCacheEnabled() {
315     return this.blockCache != null;
316   }
317 
318   /**
319    * Returns the block cache.
320    * @return the block cache, or null if caching is completely disabled
321    */
322   public BlockCache getBlockCache() {
323     return this.blockCache;
324   }
325 
326   /**
327    * Returns whether the DATA blocks of this HFile should be cached on read or not (we always
328    * cache the meta blocks, the INDEX and BLOOM blocks).
329    * @return true if blocks should be cached on read, false if not
330    */
331   public boolean shouldCacheDataOnRead() {
332     return isBlockCacheEnabled() && cacheDataOnRead;
333   }
334 
335   /**
336    * Should we cache a block of a particular category? We always cache
337    * important blocks such as index blocks, as long as the block cache is
338    * available.
339    */
340   public boolean shouldCacheBlockOnRead(BlockCategory category) {
341     boolean shouldCache = isBlockCacheEnabled()
342         && (cacheDataOnRead ||
343             category == BlockCategory.INDEX ||
344             category == BlockCategory.BLOOM ||
345             (prefetchOnOpen &&
346                 (category != BlockCategory.META &&
347                  category != BlockCategory.UNKNOWN)));
348     return shouldCache;
349   }
350 
351   /**
352    * @return true if blocks in this file should be flagged as in-memory
353    */
354   public boolean isInMemory() {
355     return isBlockCacheEnabled() && this.inMemory;
356   }
357 
358   /**
359    * @return True if cache data blocks in L1 tier (if more than one tier in block cache deploy).
360    */
361   public boolean isCacheDataInL1() {
362     return isBlockCacheEnabled() && this.cacheDataInL1;
363   }
364 
365   /**
366    * @return true if data blocks should be written to the cache when an HFile is
367    *         written, false if not
368    */
369   public boolean shouldCacheDataOnWrite() {
370     return isBlockCacheEnabled() && this.cacheDataOnWrite;
371   }
372 
373   /**
374    * Only used for testing.
375    * @param cacheDataOnWrite whether data blocks should be written to the cache
376    *                         when an HFile is written
377    */
378   @VisibleForTesting
379   public void setCacheDataOnWrite(boolean cacheDataOnWrite) {
380     this.cacheDataOnWrite = cacheDataOnWrite;
381   }
382 
383   /**
384    * Only used for testing.
385    * @param cacheDataInL1 Whether to cache data blocks up in l1 (if a multi-tier cache
386    * implementation).
387    */
388   @VisibleForTesting
389   public void setCacheDataInL1(boolean cacheDataInL1) {
390     this.cacheDataInL1 = cacheDataInL1;
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 blocks should be compressed in the cache, false if not
428    */
429   public boolean shouldCacheCompressed() {
430     return isBlockCacheEnabled() && this.cacheCompressed;
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   @Override
441   public String toString() {
442     if (!isBlockCacheEnabled()) {
443       return "CacheConfig:disabled";
444     }
445     return "blockCache=" + getBlockCache() +
446       ", cacheDataOnRead=" + shouldCacheDataOnRead() +
447       ", cacheDataOnWrite=" + shouldCacheDataOnWrite() +
448       ", cacheIndexesOnWrite=" + shouldCacheIndexesOnWrite() +
449       ", cacheBloomsOnWrite=" + shouldCacheBloomsOnWrite() +
450       ", cacheEvictOnClose=" + shouldEvictOnClose() +
451       ", cacheCompressed=" + shouldCacheCompressed() +
452       ", prefetchOnOpen=" + shouldPrefetchOnOpen();
453   }
454 
455   // Static block cache reference and methods
456 
457   /**
458    * Static reference to the block cache, or null if no caching should be used
459    * at all.
460    */
461   // Clear this if in tests you'd make more than one block cache instance.
462   @VisibleForTesting
463   static BlockCache GLOBAL_BLOCK_CACHE_INSTANCE;
464 
465   /** Boolean whether we have disabled the block cache entirely. */
466   @VisibleForTesting
467   static boolean blockCacheDisabled = false;
468 
469   /**
470    * Returns the block cache or <code>null</code> in case none should be used.
471    *
472    * @param conf  The current configuration.
473    * @return The block cache or <code>null</code>.
474    */
475   public static synchronized BlockCache instantiateBlockCache(Configuration conf) {
476     if (GLOBAL_BLOCK_CACHE_INSTANCE != null) return GLOBAL_BLOCK_CACHE_INSTANCE;
477     if (blockCacheDisabled) return null;
478 
479     float cachePercentage = conf.getFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY,
480       HConstants.HFILE_BLOCK_CACHE_SIZE_DEFAULT);
481     if (cachePercentage <= 0.0001f) {
482       blockCacheDisabled = true;
483       return null;
484     }
485     if (cachePercentage > 1.0) {
486       throw new IllegalArgumentException(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY +
487         " must be between 0.0 and 1.0, and not > 1.0");
488     }
489 
490     // Calculate the amount of heap to give the heap.
491     MemoryUsage mu = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
492     long lruCacheSize = (long) (mu.getMax() * cachePercentage);
493     int blockSize = conf.getInt("hbase.offheapcache.minblocksize", HConstants.DEFAULT_BLOCKSIZE);
494     long slabCacheOffHeapCacheSize =
495       conf.getFloat(SLAB_CACHE_OFFHEAP_PERCENTAGE_KEY, 0) == 0?
496       0:
497       (long) (conf.getFloat(SLAB_CACHE_OFFHEAP_PERCENTAGE_KEY, (float) 0) *
498           DirectMemoryUtils.getDirectMemorySize());
499     if (slabCacheOffHeapCacheSize <= 0) {
500       String bucketCacheIOEngineName = conf.get(BUCKET_CACHE_IOENGINE_KEY, null);
501       float bucketCachePercentage = conf.getFloat(BUCKET_CACHE_SIZE_KEY, 0F);
502       // A percentage of max heap size or a absolute value with unit megabytes
503       long bucketCacheSize = (long) (bucketCachePercentage < 1 ? mu.getMax()
504           * bucketCachePercentage : bucketCachePercentage * 1024 * 1024);
505 
506       boolean combinedWithLru = conf.getBoolean(BUCKET_CACHE_COMBINED_KEY,
507           DEFAULT_BUCKET_CACHE_COMBINED);
508       BucketCache bucketCache = null;
509       if (bucketCacheIOEngineName != null && bucketCacheSize > 0) {
510         int writerThreads = conf.getInt(BUCKET_CACHE_WRITER_THREADS_KEY,
511             DEFAULT_BUCKET_CACHE_WRITER_THREADS);
512         int writerQueueLen = conf.getInt(BUCKET_CACHE_WRITER_QUEUE_KEY,
513             DEFAULT_BUCKET_CACHE_WRITER_QUEUE);
514         String persistentPath = conf.get(BUCKET_CACHE_PERSISTENT_PATH_KEY);
515         float combinedPercentage = conf.getFloat(
516             BUCKET_CACHE_COMBINED_PERCENTAGE_KEY,
517             DEFAULT_BUCKET_CACHE_COMBINED_PERCENTAGE);
518         String[] configuredBucketSizes = conf.getStrings(BUCKET_CACHE_BUCKETS_KEY);
519         int[] bucketSizes = null;
520         if (configuredBucketSizes != null) {
521           bucketSizes = new int[configuredBucketSizes.length];
522           for (int i = 0; i < configuredBucketSizes.length; i++) {
523             bucketSizes[i] = Integer.parseInt(configuredBucketSizes[i]);
524           }
525         }
526         if (combinedWithLru) {
527           lruCacheSize = (long) ((1 - combinedPercentage) * bucketCacheSize);
528           bucketCacheSize = (long) (combinedPercentage * bucketCacheSize);
529         }
530         try {
531           int ioErrorsTolerationDuration = conf.getInt(
532               "hbase.bucketcache.ioengine.errors.tolerated.duration",
533               BucketCache.DEFAULT_ERROR_TOLERATION_DURATION);
534           bucketCache = new BucketCache(bucketCacheIOEngineName,
535               bucketCacheSize, blockSize, bucketSizes, writerThreads, writerQueueLen, persistentPath,
536               ioErrorsTolerationDuration);
537         } catch (IOException ioex) {
538           LOG.error("Can't instantiate bucket cache", ioex);
539           throw new RuntimeException(ioex);
540         }
541       }
542       LOG.info("Allocating LruBlockCache size=" +
543         StringUtils.byteDesc(lruCacheSize) + ", blockSize=" + StringUtils.byteDesc(blockSize));
544       LruBlockCache lruCache = new LruBlockCache(lruCacheSize, blockSize);
545       lruCache.setVictimCache(bucketCache);
546       if (bucketCache != null && combinedWithLru) {
547         GLOBAL_BLOCK_CACHE_INSTANCE = new CombinedBlockCache(lruCache, bucketCache);
548       } else {
549         GLOBAL_BLOCK_CACHE_INSTANCE = lruCache;
550       }
551     } else {
552       LOG.warn("SlabCache is deprecated. Consider BucketCache as a replacement.");
553       GLOBAL_BLOCK_CACHE_INSTANCE = new DoubleBlockCache(
554           lruCacheSize, slabCacheOffHeapCacheSize, blockSize, blockSize, conf);
555     }
556     return GLOBAL_BLOCK_CACHE_INSTANCE;
557   }
558 }