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    @Override
156    public long getDataMissCount() {
157      return lruCacheStats.getDataMissCount() + bucketCacheStats.getDataMissCount();
158    }
159
160    @Override
161    public long getLeafIndexMissCount() {
162      return lruCacheStats.getLeafIndexMissCount() + bucketCacheStats.getLeafIndexMissCount();
163    }
164
165    @Override
166    public long getBloomChunkMissCount() {
167      return lruCacheStats.getBloomChunkMissCount() + bucketCacheStats.getBloomChunkMissCount();
168    }
169
170    @Override
171    public long getMetaMissCount() {
172      return lruCacheStats.getMetaMissCount() + bucketCacheStats.getMetaMissCount();
173    }
174
175    @Override
176    public long getRootIndexMissCount() {
177      return lruCacheStats.getRootIndexMissCount() + bucketCacheStats.getRootIndexMissCount();
178    }
179
180    @Override
181    public long getIntermediateIndexMissCount() {
182      return lruCacheStats.getIntermediateIndexMissCount() +
183          bucketCacheStats.getIntermediateIndexMissCount();
184    }
185
186    @Override
187    public long getFileInfoMissCount() {
188      return lruCacheStats.getFileInfoMissCount() + bucketCacheStats.getFileInfoMissCount();
189    }
190
191    @Override
192    public long getGeneralBloomMetaMissCount() {
193      return lruCacheStats.getGeneralBloomMetaMissCount() +
194          bucketCacheStats.getGeneralBloomMetaMissCount();
195    }
196
197    @Override
198    public long getDeleteFamilyBloomMissCount() {
199      return lruCacheStats.getDeleteFamilyBloomMissCount() +
200          bucketCacheStats.getDeleteFamilyBloomMissCount();
201    }
202
203    @Override
204    public long getTrailerMissCount() {
205      return lruCacheStats.getTrailerMissCount() + bucketCacheStats.getTrailerMissCount();
206    }
207
208    @Override
209    public long getDataHitCount() {
210      return lruCacheStats.getDataHitCount() + bucketCacheStats.getDataHitCount();
211    }
212
213    @Override
214    public long getLeafIndexHitCount() {
215      return lruCacheStats.getLeafIndexHitCount() + bucketCacheStats.getLeafIndexHitCount();
216    }
217
218    @Override
219    public long getBloomChunkHitCount() {
220      return lruCacheStats.getBloomChunkHitCount() + bucketCacheStats.getBloomChunkHitCount();
221    }
222
223    @Override
224    public long getMetaHitCount() {
225      return lruCacheStats.getMetaHitCount() + bucketCacheStats.getMetaHitCount();
226    }
227
228    @Override
229    public long getRootIndexHitCount() {
230      return lruCacheStats.getRootIndexHitCount() + bucketCacheStats.getRootIndexHitCount();
231    }
232
233    @Override
234    public long getIntermediateIndexHitCount() {
235      return lruCacheStats.getIntermediateIndexHitCount() +
236          bucketCacheStats.getIntermediateIndexHitCount();
237    }
238
239    @Override
240    public long getFileInfoHitCount() {
241      return lruCacheStats.getFileInfoHitCount() + bucketCacheStats.getFileInfoHitCount();
242    }
243
244    @Override
245    public long getGeneralBloomMetaHitCount() {
246      return lruCacheStats.getGeneralBloomMetaHitCount() +
247          bucketCacheStats.getGeneralBloomMetaHitCount();
248    }
249
250    @Override
251    public long getDeleteFamilyBloomHitCount() {
252      return lruCacheStats.getDeleteFamilyBloomHitCount() +
253          bucketCacheStats.getDeleteFamilyBloomHitCount();
254    }
255
256    @Override
257    public long getTrailerHitCount() {
258      return lruCacheStats.getTrailerHitCount() + bucketCacheStats.getTrailerHitCount();
259    }
260
261    @Override
262    public long getRequestCount() {
263      return lruCacheStats.getRequestCount()
264          + bucketCacheStats.getRequestCount();
265    }
266
267    @Override
268    public long getRequestCachingCount() {
269      return lruCacheStats.getRequestCachingCount()
270          + bucketCacheStats.getRequestCachingCount();
271    }
272
273    @Override
274    public long getMissCount() {
275      return lruCacheStats.getMissCount() + bucketCacheStats.getMissCount();
276    }
277
278    @Override
279    public long getPrimaryMissCount() {
280      return lruCacheStats.getPrimaryMissCount() + bucketCacheStats.getPrimaryMissCount();
281    }
282
283    @Override
284    public long getMissCachingCount() {
285      return lruCacheStats.getMissCachingCount()
286          + bucketCacheStats.getMissCachingCount();
287    }
288
289    @Override
290    public long getHitCount() {
291      return lruCacheStats.getHitCount() + bucketCacheStats.getHitCount();
292    }
293
294    @Override
295    public long getPrimaryHitCount() {
296      return lruCacheStats.getPrimaryHitCount() + bucketCacheStats.getPrimaryHitCount();
297    }
298    @Override
299    public long getHitCachingCount() {
300      return lruCacheStats.getHitCachingCount()
301          + bucketCacheStats.getHitCachingCount();
302    }
303
304    @Override
305    public long getEvictionCount() {
306      return lruCacheStats.getEvictionCount()
307          + bucketCacheStats.getEvictionCount();
308    }
309
310    @Override
311    public long getEvictedCount() {
312      return lruCacheStats.getEvictedCount()
313          + bucketCacheStats.getEvictedCount();
314    }
315
316    @Override
317    public long getPrimaryEvictedCount() {
318      return lruCacheStats.getPrimaryEvictedCount()
319          + bucketCacheStats.getPrimaryEvictedCount();
320    }
321
322    @Override
323    public void rollMetricsPeriod() {
324      lruCacheStats.rollMetricsPeriod();
325      bucketCacheStats.rollMetricsPeriod();
326    }
327    
328    @Override
329    public long getFailedInserts() {
330      return lruCacheStats.getFailedInserts() + bucketCacheStats.getFailedInserts();
331    }
332
333    @Override
334    public long getSumHitCountsPastNPeriods() {
335      return lruCacheStats.getSumHitCountsPastNPeriods()
336          + bucketCacheStats.getSumHitCountsPastNPeriods();
337    }
338    
339    @Override
340    public long getSumRequestCountsPastNPeriods() {
341      return lruCacheStats.getSumRequestCountsPastNPeriods()
342          + bucketCacheStats.getSumRequestCountsPastNPeriods();
343    }
344    
345    @Override
346    public long getSumHitCachingCountsPastNPeriods() {
347      return lruCacheStats.getSumHitCachingCountsPastNPeriods()
348          + bucketCacheStats.getSumHitCachingCountsPastNPeriods();
349    }
350
351    @Override
352    public long getSumRequestCachingCountsPastNPeriods() {
353      return lruCacheStats.getSumRequestCachingCountsPastNPeriods()
354          + bucketCacheStats.getSumRequestCachingCountsPastNPeriods();
355    }
356  }
357
358  @Override
359  public Iterator<CachedBlock> iterator() {
360    return new BlockCachesIterator(getBlockCaches());
361  }
362
363  @Override
364  public BlockCache[] getBlockCaches() {
365    return new BlockCache [] {this.onHeapCache, this.l2Cache};
366  }
367
368  @Override
369  public void setMaxSize(long size) {
370    this.onHeapCache.setMaxSize(size);
371  }
372
373  @Override
374  public void returnBlock(BlockCacheKey cacheKey, Cacheable block) {
375    // returnBlock is meaningful for L2 cache alone.
376    this.l2Cache.returnBlock(cacheKey, block);
377  }
378
379  @VisibleForTesting
380  public int getRefCount(BlockCacheKey cacheKey) {
381    return (this.l2Cache instanceof BucketCache)
382        ? ((BucketCache) this.l2Cache).getRefCount(cacheKey) : 0;
383  }
384}