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.lang.management.ManagementFactory;
21  import java.lang.management.MemoryUsage;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.hadoop.conf.Configuration;
26  import org.apache.hadoop.hbase.HColumnDescriptor;
27  import org.apache.hadoop.hbase.regionserver.StoreFile;
28  import org.apache.hadoop.hbase.util.DirectMemoryUtils;
29  import org.apache.hadoop.util.StringUtils;
30  
31  /**
32   * Stores all of the cache objects and configuration for a single HFile.
33   */
34  public class CacheConfig {
35    private static final Log LOG = LogFactory.getLog(CacheConfig.class.getName());
36  
37    /**
38     * Configuration key for the size of the block cache, in bytes.
39     */
40    public static final String HFILE_BLOCK_CACHE_SIZE_KEY =
41      "hfile.block.cache.size";
42  
43    /**
44     * Configuration key to cache data blocks on write. There are separate
45     * switches for bloom blocks and non-root index blocks.
46     */
47    public static final String CACHE_BLOCKS_ON_WRITE_KEY =
48        "hbase.rs.cacheblocksonwrite";
49  
50    /**
51     * Configuration key to cache leaf and intermediate-level index blocks on
52     * write.
53     */
54    public static final String CACHE_INDEX_BLOCKS_ON_WRITE_KEY =
55        "hfile.block.index.cacheonwrite";
56  
57    /**
58     * Configuration key to cache compound bloom filter blocks on write.
59     */
60    public static final String CACHE_BLOOM_BLOCKS_ON_WRITE_KEY =
61        "hfile.block.bloom.cacheonwrite";
62  
63    /**
64     * TODO: Implement this (jgray)
65     * Configuration key to cache data blocks in compressed format.
66     */
67    public static final String CACHE_DATA_BLOCKS_COMPRESSED_KEY =
68        "hbase.rs.blockcache.cachedatacompressed";
69  
70    /**
71     * Configuration key to evict all blocks of a given file from the block cache
72     * when the file is closed.
73     */
74    public static final String EVICT_BLOCKS_ON_CLOSE_KEY =
75        "hbase.rs.evictblocksonclose";
76  
77    // Defaults
78  
79    public static final boolean DEFAULT_CACHE_DATA_ON_READ = true;
80    public static final boolean DEFAULT_CACHE_DATA_ON_WRITE = false;
81    public static final boolean DEFAULT_IN_MEMORY = false;
82    public static final boolean DEFAULT_CACHE_INDEXES_ON_WRITE = false;
83    public static final boolean DEFAULT_CACHE_BLOOMS_ON_WRITE = false;
84    public static final boolean DEFAULT_EVICT_ON_CLOSE = false;
85    public static final boolean DEFAULT_COMPRESSED_CACHE = false;
86  
87    /** Local reference to the block cache, null if completely disabled */
88    private final BlockCache blockCache;
89  
90    /**
91     * Whether blocks should be cached on read (default is on if there is a
92     * cache but this can be turned off on a per-family or per-request basis)
93     */
94    private boolean cacheDataOnRead;
95  
96    /** Whether blocks should be flagged as in-memory when being cached */
97    private final boolean inMemory;
98  
99    /** Whether data blocks should be cached when new files are written */
100   private boolean cacheDataOnWrite;
101 
102   /** Whether index blocks should be cached when new files are written */
103   private final boolean cacheIndexesOnWrite;
104 
105   /** Whether compound bloom filter blocks should be cached on write */
106   private final boolean cacheBloomsOnWrite;
107 
108   /** Whether blocks of a file should be evicted when the file is closed */
109   private boolean evictOnClose;
110 
111   /** Whether data blocks should be stored in compressed form in the cache */
112   private final boolean cacheCompressed;
113 
114   /**
115    * Create a cache configuration using the specified configuration object and
116    * family descriptor.
117    * @param conf hbase configuration
118    * @param family column family configuration
119    */
120   public CacheConfig(Configuration conf, HColumnDescriptor family) {
121     this(CacheConfig.instantiateBlockCache(conf),
122         family.isBlockCacheEnabled(), family.isInMemory(),
123         conf.getBoolean(CACHE_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_DATA_ON_WRITE),
124         conf.getBoolean(CACHE_INDEX_BLOCKS_ON_WRITE_KEY,
125             DEFAULT_CACHE_INDEXES_ON_WRITE),
126         conf.getBoolean(CACHE_BLOOM_BLOCKS_ON_WRITE_KEY,
127             DEFAULT_CACHE_BLOOMS_ON_WRITE),
128         conf.getBoolean(EVICT_BLOCKS_ON_CLOSE_KEY, DEFAULT_EVICT_ON_CLOSE),
129         conf.getBoolean(CACHE_DATA_BLOCKS_COMPRESSED_KEY, DEFAULT_COMPRESSED_CACHE)
130      );
131   }
132 
133   /**
134    * Create a cache configuration using the specified configuration object and
135    * defaults for family level settings.
136    * @param conf hbase configuration
137    */
138   public CacheConfig(Configuration conf) {
139     this(CacheConfig.instantiateBlockCache(conf),
140         DEFAULT_CACHE_DATA_ON_READ,
141         DEFAULT_IN_MEMORY, // This is a family-level setting so can't be set
142                            // strictly from conf
143         conf.getBoolean(CACHE_BLOCKS_ON_WRITE_KEY, DEFAULT_CACHE_DATA_ON_WRITE),
144         conf.getBoolean(CACHE_INDEX_BLOCKS_ON_WRITE_KEY,
145             DEFAULT_CACHE_INDEXES_ON_WRITE),
146             conf.getBoolean(CACHE_BLOOM_BLOCKS_ON_WRITE_KEY,
147                 DEFAULT_CACHE_BLOOMS_ON_WRITE),
148         conf.getBoolean(EVICT_BLOCKS_ON_CLOSE_KEY, DEFAULT_EVICT_ON_CLOSE),
149         conf.getBoolean(CACHE_DATA_BLOCKS_COMPRESSED_KEY,
150             DEFAULT_COMPRESSED_CACHE)
151      );
152   }
153 
154   /**
155    * Create a block cache configuration with the specified cache and
156    * configuration parameters.
157    * @param blockCache reference to block cache, null if completely disabled
158    * @param cacheDataOnRead whether data blocks should be cached on read
159    * @param inMemory whether blocks should be flagged as in-memory
160    * @param cacheDataOnWrite whether data blocks should be cached on write
161    * @param cacheIndexesOnWrite whether index blocks should be cached on write
162    * @param cacheBloomsOnWrite whether blooms should be cached on write
163    * @param evictOnClose whether blocks should be evicted when HFile is closed
164    * @param cacheCompressed whether to store blocks as compressed in the cache
165    */
166   CacheConfig(final BlockCache blockCache,
167       final boolean cacheDataOnRead, final boolean inMemory,
168       final boolean cacheDataOnWrite, final boolean cacheIndexesOnWrite,
169       final boolean cacheBloomsOnWrite, final boolean evictOnClose,
170       final boolean cacheCompressed) {
171     this.blockCache = blockCache;
172     this.cacheDataOnRead = cacheDataOnRead;
173     this.inMemory = inMemory;
174     this.cacheDataOnWrite = cacheDataOnWrite;
175     this.cacheIndexesOnWrite = cacheIndexesOnWrite;
176     this.cacheBloomsOnWrite = cacheBloomsOnWrite;
177     this.evictOnClose = evictOnClose;
178     this.cacheCompressed = cacheCompressed;
179   }
180 
181   /**
182    * Constructs a cache configuration copied from the specified configuration.
183    * @param cacheConf
184    */
185   public CacheConfig(CacheConfig cacheConf) {
186     this(cacheConf.blockCache, cacheConf.cacheDataOnRead, cacheConf.inMemory,
187         cacheConf.cacheDataOnWrite, cacheConf.cacheIndexesOnWrite,
188         cacheConf.cacheBloomsOnWrite, cacheConf.evictOnClose,
189         cacheConf.cacheCompressed);
190   }
191 
192   /**
193    * Checks whether the block cache is enabled.
194    */
195   public boolean isBlockCacheEnabled() {
196     return this.blockCache != null;
197   }
198 
199   /**
200    * Returns the block cache.
201    * @return the block cache, or null if caching is completely disabled
202    */
203   public BlockCache getBlockCache() {
204     return this.blockCache;
205   }
206 
207   /**
208    * Returns whether the blocks of this HFile should be cached on read or not.
209    * @return true if blocks should be cached on read, false if not
210    */
211   public boolean shouldCacheDataOnRead() {
212     return isBlockCacheEnabled() && cacheDataOnRead;
213   }
214 
215   /**
216    * @return true if blocks in this file should be flagged as in-memory
217    */
218   public boolean isInMemory() {
219     return isBlockCacheEnabled() && this.inMemory;
220   }
221 
222   /**
223    * @return true if data blocks should be written to the cache when an HFile is
224    *         written, false if not
225    */
226   public boolean shouldCacheDataOnWrite() {
227     return isBlockCacheEnabled() && this.cacheDataOnWrite;
228   }
229 
230   /**
231    * Only used for testing.
232    * @param cacheDataOnWrite whether data blocks should be written to the cache
233    *                         when an HFile is written
234    */
235   public void forTestsOnly_setCacheDataOnWrite(boolean cacheDataOnWrite) {
236     this.cacheDataOnWrite = cacheDataOnWrite;
237   }
238 
239   /**
240    * @return true if index blocks should be written to the cache when an HFile
241    *         is written, false if not
242    */
243   public boolean shouldCacheIndexesOnWrite() {
244     return isBlockCacheEnabled() && this.cacheIndexesOnWrite;
245   }
246 
247   /**
248    * @return true if bloom blocks should be written to the cache when an HFile
249    *         is written, false if not
250    */
251   public boolean shouldCacheBloomsOnWrite() {
252     return isBlockCacheEnabled() && this.cacheBloomsOnWrite;
253   }
254 
255   /**
256    * @return true if blocks should be evicted from the cache when an HFile
257    *         reader is closed, false if not
258    */
259   public boolean shouldEvictOnClose() {
260     return isBlockCacheEnabled() && this.evictOnClose;
261   }
262 
263   /**
264    * Only used for testing.
265    * @param evictOnClose whether blocks should be evicted from the cache when an
266    *                     HFile reader is closed
267    */
268   public void forTestsOnly_setEvictOnClose(boolean evictOnClose) {
269     this.evictOnClose = evictOnClose;
270   }
271 
272   /**
273    * @return true if blocks should be compressed in the cache, false if not
274    */
275   public boolean shouldCacheCompressed() {
276     return isBlockCacheEnabled() && this.cacheCompressed;
277   }
278 
279   @Override
280   public String toString() {
281     if (!isBlockCacheEnabled()) {
282       return "CacheConfig:disabled";
283     }
284     return "CacheConfig:enabled " +
285       "[cacheDataOnRead=" + shouldCacheDataOnRead() + "] " +
286       "[cacheDataOnWrite=" + shouldCacheDataOnWrite() + "] " +
287       "[cacheIndexesOnWrite=" + shouldCacheIndexesOnWrite() + "] " +
288       "[cacheBloomsOnWrite=" + shouldCacheBloomsOnWrite() + "] " +
289       "[cacheEvictOnClose=" + shouldEvictOnClose() + "] " +
290       "[cacheCompressed=" + shouldCacheCompressed() + "]";
291   }
292 
293   // Static block cache reference and methods
294 
295   /**
296    * Static reference to the block cache, or null if no caching should be used
297    * at all.
298    */
299   private static BlockCache globalBlockCache;
300 
301   /** Boolean whether we have disabled the block cache entirely. */
302   private static boolean blockCacheDisabled = false;
303 
304   /**
305    * Returns the block cache or <code>null</code> in case none should be used.
306    *
307    * @param conf  The current configuration.
308    * @return The block cache or <code>null</code>.
309    */
310   private static synchronized BlockCache instantiateBlockCache(
311       Configuration conf) {
312     if (globalBlockCache != null) return globalBlockCache;
313     if (blockCacheDisabled) return null;
314 
315     float cachePercentage = conf.getFloat(HFILE_BLOCK_CACHE_SIZE_KEY, 0.2f);
316     if (cachePercentage == 0L) {
317       blockCacheDisabled = true;
318       return null;
319     }
320     if (cachePercentage > 1.0) {
321       throw new IllegalArgumentException(HFILE_BLOCK_CACHE_SIZE_KEY +
322         " must be between 0.0 and 1.0, not > 1.0");
323     }
324 
325     // Calculate the amount of heap to give the heap.
326     MemoryUsage mu = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
327     long cacheSize = (long)(mu.getMax() * cachePercentage);
328     int blockSize = conf.getInt("hbase.offheapcache.minblocksize",
329         HFile.DEFAULT_BLOCKSIZE);
330     long offHeapCacheSize =
331       (long) (conf.getFloat("hbase.offheapcache.percentage", (float) 0.95) *
332           DirectMemoryUtils.getDirectMemorySize());
333     LOG.info("Allocating LruBlockCache with maximum size " +
334       StringUtils.humanReadableInt(cacheSize));
335     if (offHeapCacheSize <= 0) {
336       globalBlockCache = new LruBlockCache(cacheSize,
337           StoreFile.DEFAULT_BLOCKSIZE_SMALL);
338     } else {
339       globalBlockCache = new DoubleBlockCache(cacheSize, offHeapCacheSize,
340           StoreFile.DEFAULT_BLOCKSIZE_SMALL, blockSize, conf);
341     }
342     return globalBlockCache;
343   }
344 }