001/**
002 * Copyright The Apache Software Foundation
003 *
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements. See the NOTICE file distributed with this
006 * work for additional information regarding copyright ownership. The ASF
007 * licenses this file to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
015 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
016 * License for the specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.hadoop.hbase.io.hfile;
020
021import java.util.Iterator;
022
023import org.apache.yetus.audience.InterfaceAudience;
024import org.apache.hadoop.hbase.io.HeapSize;
025import org.apache.hadoop.hbase.io.hfile.BlockType.BlockCategory;
026import org.apache.hadoop.hbase.io.hfile.bucket.BucketCache;
027
028import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
029
030
031/**
032 * CombinedBlockCache is an abstraction layer that combines
033 * {@link LruBlockCache} and {@link BucketCache}. The smaller lruCache is used
034 * to cache bloom blocks and index blocks.  The larger Cache is used to
035 * cache data blocks. {@link #getBlock(BlockCacheKey, boolean, boolean, boolean)} reads
036 * first from the smaller lruCache before looking for the block in the l2Cache.
037 * Metrics are the combined size and hits and misses of both caches.
038 */
039@InterfaceAudience.Private
040public class CombinedBlockCache implements ResizableBlockCache, HeapSize {
041  protected final LruBlockCache onHeapCache;
042  protected final BlockCache l2Cache;
043  protected final CombinedCacheStats combinedCacheStats;
044
045  public CombinedBlockCache(LruBlockCache onHeapCache, BlockCache l2Cache) {
046    this.onHeapCache = onHeapCache;
047    this.l2Cache = l2Cache;
048    this.combinedCacheStats = new CombinedCacheStats(onHeapCache.getStats(),
049        l2Cache.getStats());
050  }
051
052  @Override
053  public long heapSize() {
054    long l2size = 0;
055    if (l2Cache instanceof HeapSize) {
056      l2size = ((HeapSize) l2Cache).heapSize();
057    }
058    return onHeapCache.heapSize() + l2size;
059  }
060
061  @Override
062  public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory) {
063    boolean metaBlock = buf.getBlockType().getCategory() != BlockCategory.DATA;
064    if (metaBlock) {
065      onHeapCache.cacheBlock(cacheKey, buf, inMemory);
066    } else {
067      l2Cache.cacheBlock(cacheKey, buf, inMemory);
068    }
069  }
070
071  @Override
072  public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf) {
073    cacheBlock(cacheKey, buf, false);
074  }
075
076  @Override
077  public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching,
078      boolean repeat, boolean updateCacheMetrics) {
079    // TODO: is there a hole here, or just awkwardness since in the lruCache getBlock
080    // we end up calling l2Cache.getBlock.
081    // We are not in a position to exactly look at LRU cache or BC as BlockType may not be getting
082    // passed always.
083    return onHeapCache.containsBlock(cacheKey)?
084        onHeapCache.getBlock(cacheKey, caching, repeat, updateCacheMetrics):
085        l2Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics);
086  }
087
088  @Override
089  public boolean evictBlock(BlockCacheKey cacheKey) {
090    return onHeapCache.evictBlock(cacheKey) || l2Cache.evictBlock(cacheKey);
091  }
092
093  @Override
094  public int evictBlocksByHfileName(String hfileName) {
095    return onHeapCache.evictBlocksByHfileName(hfileName)
096        + l2Cache.evictBlocksByHfileName(hfileName);
097  }
098
099  @Override
100  public CacheStats getStats() {
101    return this.combinedCacheStats;
102  }
103
104  @Override
105  public void shutdown() {
106    onHeapCache.shutdown();
107    l2Cache.shutdown();
108  }
109
110  @Override
111  public long size() {
112    return onHeapCache.size() + l2Cache.size();
113  }
114
115  @Override
116  public long getMaxSize() {
117    return onHeapCache.getMaxSize() + l2Cache.getMaxSize();
118  }
119
120  @Override
121  public long getCurrentDataSize() {
122    return onHeapCache.getCurrentDataSize() + l2Cache.getCurrentDataSize();
123  }
124
125  @Override
126  public long getFreeSize() {
127    return onHeapCache.getFreeSize() + l2Cache.getFreeSize();
128  }
129
130  @Override
131  public long getCurrentSize() {
132    return onHeapCache.getCurrentSize() + l2Cache.getCurrentSize();
133  }
134
135  @Override
136  public long getBlockCount() {
137    return onHeapCache.getBlockCount() + l2Cache.getBlockCount();
138  }
139
140  @Override
141  public long getDataBlockCount() {
142    return onHeapCache.getDataBlockCount() + l2Cache.getDataBlockCount();
143  }
144
145  public static class CombinedCacheStats extends CacheStats {
146    private final CacheStats lruCacheStats;
147    private final CacheStats bucketCacheStats;
148
149    CombinedCacheStats(CacheStats lbcStats, CacheStats fcStats) {
150      super("CombinedBlockCache");
151      this.lruCacheStats = lbcStats;
152      this.bucketCacheStats = fcStats;
153    }
154
155    public CacheStats getLruCacheStats() {
156      return this.lruCacheStats;
157    }
158
159    public CacheStats getBucketCacheStats() {
160      return this.bucketCacheStats;
161    }
162
163    @Override
164    public long getDataMissCount() {
165      return lruCacheStats.getDataMissCount() + bucketCacheStats.getDataMissCount();
166    }
167
168    @Override
169    public long getLeafIndexMissCount() {
170      return lruCacheStats.getLeafIndexMissCount() + bucketCacheStats.getLeafIndexMissCount();
171    }
172
173    @Override
174    public long getBloomChunkMissCount() {
175      return lruCacheStats.getBloomChunkMissCount() + bucketCacheStats.getBloomChunkMissCount();
176    }
177
178    @Override
179    public long getMetaMissCount() {
180      return lruCacheStats.getMetaMissCount() + bucketCacheStats.getMetaMissCount();
181    }
182
183    @Override
184    public long getRootIndexMissCount() {
185      return lruCacheStats.getRootIndexMissCount() + bucketCacheStats.getRootIndexMissCount();
186    }
187
188    @Override
189    public long getIntermediateIndexMissCount() {
190      return lruCacheStats.getIntermediateIndexMissCount() +
191          bucketCacheStats.getIntermediateIndexMissCount();
192    }
193
194    @Override
195    public long getFileInfoMissCount() {
196      return lruCacheStats.getFileInfoMissCount() + bucketCacheStats.getFileInfoMissCount();
197    }
198
199    @Override
200    public long getGeneralBloomMetaMissCount() {
201      return lruCacheStats.getGeneralBloomMetaMissCount() +
202          bucketCacheStats.getGeneralBloomMetaMissCount();
203    }
204
205    @Override
206    public long getDeleteFamilyBloomMissCount() {
207      return lruCacheStats.getDeleteFamilyBloomMissCount() +
208          bucketCacheStats.getDeleteFamilyBloomMissCount();
209    }
210
211    @Override
212    public long getTrailerMissCount() {
213      return lruCacheStats.getTrailerMissCount() + bucketCacheStats.getTrailerMissCount();
214    }
215
216    @Override
217    public long getDataHitCount() {
218      return lruCacheStats.getDataHitCount() + bucketCacheStats.getDataHitCount();
219    }
220
221    @Override
222    public long getLeafIndexHitCount() {
223      return lruCacheStats.getLeafIndexHitCount() + bucketCacheStats.getLeafIndexHitCount();
224    }
225
226    @Override
227    public long getBloomChunkHitCount() {
228      return lruCacheStats.getBloomChunkHitCount() + bucketCacheStats.getBloomChunkHitCount();
229    }
230
231    @Override
232    public long getMetaHitCount() {
233      return lruCacheStats.getMetaHitCount() + bucketCacheStats.getMetaHitCount();
234    }
235
236    @Override
237    public long getRootIndexHitCount() {
238      return lruCacheStats.getRootIndexHitCount() + bucketCacheStats.getRootIndexHitCount();
239    }
240
241    @Override
242    public long getIntermediateIndexHitCount() {
243      return lruCacheStats.getIntermediateIndexHitCount() +
244          bucketCacheStats.getIntermediateIndexHitCount();
245    }
246
247    @Override
248    public long getFileInfoHitCount() {
249      return lruCacheStats.getFileInfoHitCount() + bucketCacheStats.getFileInfoHitCount();
250    }
251
252    @Override
253    public long getGeneralBloomMetaHitCount() {
254      return lruCacheStats.getGeneralBloomMetaHitCount() +
255          bucketCacheStats.getGeneralBloomMetaHitCount();
256    }
257
258    @Override
259    public long getDeleteFamilyBloomHitCount() {
260      return lruCacheStats.getDeleteFamilyBloomHitCount() +
261          bucketCacheStats.getDeleteFamilyBloomHitCount();
262    }
263
264    @Override
265    public long getTrailerHitCount() {
266      return lruCacheStats.getTrailerHitCount() + bucketCacheStats.getTrailerHitCount();
267    }
268
269    @Override
270    public long getRequestCount() {
271      return lruCacheStats.getRequestCount()
272          + bucketCacheStats.getRequestCount();
273    }
274
275    @Override
276    public long getRequestCachingCount() {
277      return lruCacheStats.getRequestCachingCount()
278          + bucketCacheStats.getRequestCachingCount();
279    }
280
281    @Override
282    public long getMissCount() {
283      return lruCacheStats.getMissCount() + bucketCacheStats.getMissCount();
284    }
285
286    @Override
287    public long getPrimaryMissCount() {
288      return lruCacheStats.getPrimaryMissCount() + bucketCacheStats.getPrimaryMissCount();
289    }
290
291    @Override
292    public long getMissCachingCount() {
293      return lruCacheStats.getMissCachingCount()
294          + bucketCacheStats.getMissCachingCount();
295    }
296
297    @Override
298    public long getHitCount() {
299      return lruCacheStats.getHitCount() + bucketCacheStats.getHitCount();
300    }
301
302    @Override
303    public long getPrimaryHitCount() {
304      return lruCacheStats.getPrimaryHitCount() + bucketCacheStats.getPrimaryHitCount();
305    }
306    @Override
307    public long getHitCachingCount() {
308      return lruCacheStats.getHitCachingCount()
309          + bucketCacheStats.getHitCachingCount();
310    }
311
312    @Override
313    public long getEvictionCount() {
314      return lruCacheStats.getEvictionCount()
315          + bucketCacheStats.getEvictionCount();
316    }
317
318    @Override
319    public long getEvictedCount() {
320      return lruCacheStats.getEvictedCount()
321          + bucketCacheStats.getEvictedCount();
322    }
323
324    @Override
325    public long getPrimaryEvictedCount() {
326      return lruCacheStats.getPrimaryEvictedCount()
327          + bucketCacheStats.getPrimaryEvictedCount();
328    }
329
330    @Override
331    public void rollMetricsPeriod() {
332      lruCacheStats.rollMetricsPeriod();
333      bucketCacheStats.rollMetricsPeriod();
334    }
335    
336    @Override
337    public long getFailedInserts() {
338      return lruCacheStats.getFailedInserts() + bucketCacheStats.getFailedInserts();
339    }
340
341    @Override
342    public long getSumHitCountsPastNPeriods() {
343      return lruCacheStats.getSumHitCountsPastNPeriods()
344          + bucketCacheStats.getSumHitCountsPastNPeriods();
345    }
346    
347    @Override
348    public long getSumRequestCountsPastNPeriods() {
349      return lruCacheStats.getSumRequestCountsPastNPeriods()
350          + bucketCacheStats.getSumRequestCountsPastNPeriods();
351    }
352    
353    @Override
354    public long getSumHitCachingCountsPastNPeriods() {
355      return lruCacheStats.getSumHitCachingCountsPastNPeriods()
356          + bucketCacheStats.getSumHitCachingCountsPastNPeriods();
357    }
358
359    @Override
360    public long getSumRequestCachingCountsPastNPeriods() {
361      return lruCacheStats.getSumRequestCachingCountsPastNPeriods()
362          + bucketCacheStats.getSumRequestCachingCountsPastNPeriods();
363    }
364  }
365
366  @Override
367  public Iterator<CachedBlock> iterator() {
368    return new BlockCachesIterator(getBlockCaches());
369  }
370
371  @Override
372  public BlockCache[] getBlockCaches() {
373    return new BlockCache [] {this.onHeapCache, this.l2Cache};
374  }
375
376  @Override
377  public void setMaxSize(long size) {
378    this.onHeapCache.setMaxSize(size);
379  }
380
381  @Override
382  public void returnBlock(BlockCacheKey cacheKey, Cacheable block) {
383    // returnBlock is meaningful for L2 cache alone.
384    this.l2Cache.returnBlock(cacheKey, block);
385  }
386
387  @VisibleForTesting
388  public int getRefCount(BlockCacheKey cacheKey) {
389    return (this.l2Cache instanceof BucketCache)
390        ? ((BucketCache) this.l2Cache).getRefCount(cacheKey) : 0;
391  }
392
393  public LruBlockCache getOnHeapCache() {
394    return onHeapCache;
395  }
396}