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 FirstLevelBlockCache} 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 l1Cache before looking for the block in the l2Cache.  Blocks evicted
037 * from l1Cache are put into the bucket cache.
038 * Metrics are the combined size and hits and misses of both caches.
039 */
040@InterfaceAudience.Private
041public class CombinedBlockCache implements ResizableBlockCache, HeapSize {
042  protected final FirstLevelBlockCache l1Cache;
043  protected final BlockCache l2Cache;
044  protected final CombinedCacheStats combinedCacheStats;
045
046  public CombinedBlockCache(FirstLevelBlockCache l1Cache, BlockCache l2Cache) {
047    this.l1Cache = l1Cache;
048    this.l2Cache = l2Cache;
049    this.combinedCacheStats = new CombinedCacheStats(l1Cache.getStats(),
050        l2Cache.getStats());
051  }
052
053  @Override
054  public long heapSize() {
055    long l2size = 0;
056    if (l2Cache instanceof HeapSize) {
057      l2size = ((HeapSize) l2Cache).heapSize();
058    }
059    return l1Cache.heapSize() + l2size;
060  }
061
062  @Override
063  public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory) {
064    boolean metaBlock = buf.getBlockType().getCategory() != BlockCategory.DATA;
065    if (metaBlock) {
066      l1Cache.cacheBlock(cacheKey, buf, inMemory);
067    } else {
068      l2Cache.cacheBlock(cacheKey, buf, inMemory);
069    }
070  }
071
072  @Override
073  public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf) {
074    cacheBlock(cacheKey, buf, false);
075  }
076
077  @Override
078  public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching,
079      boolean repeat, boolean updateCacheMetrics) {
080    // TODO: is there a hole here, or just awkwardness since in the lruCache getBlock
081    // we end up calling l2Cache.getBlock.
082    // We are not in a position to exactly look at LRU cache or BC as BlockType may not be getting
083    // passed always.
084    return l1Cache.containsBlock(cacheKey)?
085        l1Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics):
086        l2Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics);
087  }
088
089  @Override
090  public boolean evictBlock(BlockCacheKey cacheKey) {
091    return l1Cache.evictBlock(cacheKey) || l2Cache.evictBlock(cacheKey);
092  }
093
094  @Override
095  public int evictBlocksByHfileName(String hfileName) {
096    return l1Cache.evictBlocksByHfileName(hfileName)
097        + l2Cache.evictBlocksByHfileName(hfileName);
098  }
099
100  @Override
101  public CacheStats getStats() {
102    return this.combinedCacheStats;
103  }
104
105  @Override
106  public void shutdown() {
107    l1Cache.shutdown();
108    l2Cache.shutdown();
109  }
110
111  @Override
112  public long size() {
113    return l1Cache.size() + l2Cache.size();
114  }
115
116  @Override
117  public long getMaxSize() {
118    return l1Cache.getMaxSize() + l2Cache.getMaxSize();
119  }
120
121  @Override
122  public long getCurrentDataSize() {
123    return l1Cache.getCurrentDataSize() + l2Cache.getCurrentDataSize();
124  }
125
126  @Override
127  public long getFreeSize() {
128    return l1Cache.getFreeSize() + l2Cache.getFreeSize();
129  }
130
131  @Override
132  public long getCurrentSize() {
133    return l1Cache.getCurrentSize() + l2Cache.getCurrentSize();
134  }
135
136  @Override
137  public long getBlockCount() {
138    return l1Cache.getBlockCount() + l2Cache.getBlockCount();
139  }
140
141  @Override
142  public long getDataBlockCount() {
143    return l1Cache.getDataBlockCount() + l2Cache.getDataBlockCount();
144  }
145
146  public static class CombinedCacheStats extends CacheStats {
147    private final CacheStats lruCacheStats;
148    private final CacheStats bucketCacheStats;
149
150    CombinedCacheStats(CacheStats lbcStats, CacheStats fcStats) {
151      super("CombinedBlockCache");
152      this.lruCacheStats = lbcStats;
153      this.bucketCacheStats = fcStats;
154    }
155
156    public CacheStats getLruCacheStats() {
157      return this.lruCacheStats;
158    }
159
160    public CacheStats getBucketCacheStats() {
161      return this.bucketCacheStats;
162    }
163
164    @Override
165    public long getDataMissCount() {
166      return lruCacheStats.getDataMissCount() + bucketCacheStats.getDataMissCount();
167    }
168
169    @Override
170    public long getLeafIndexMissCount() {
171      return lruCacheStats.getLeafIndexMissCount() + bucketCacheStats.getLeafIndexMissCount();
172    }
173
174    @Override
175    public long getBloomChunkMissCount() {
176      return lruCacheStats.getBloomChunkMissCount() + bucketCacheStats.getBloomChunkMissCount();
177    }
178
179    @Override
180    public long getMetaMissCount() {
181      return lruCacheStats.getMetaMissCount() + bucketCacheStats.getMetaMissCount();
182    }
183
184    @Override
185    public long getRootIndexMissCount() {
186      return lruCacheStats.getRootIndexMissCount() + bucketCacheStats.getRootIndexMissCount();
187    }
188
189    @Override
190    public long getIntermediateIndexMissCount() {
191      return lruCacheStats.getIntermediateIndexMissCount() +
192          bucketCacheStats.getIntermediateIndexMissCount();
193    }
194
195    @Override
196    public long getFileInfoMissCount() {
197      return lruCacheStats.getFileInfoMissCount() + bucketCacheStats.getFileInfoMissCount();
198    }
199
200    @Override
201    public long getGeneralBloomMetaMissCount() {
202      return lruCacheStats.getGeneralBloomMetaMissCount() +
203          bucketCacheStats.getGeneralBloomMetaMissCount();
204    }
205
206    @Override
207    public long getDeleteFamilyBloomMissCount() {
208      return lruCacheStats.getDeleteFamilyBloomMissCount() +
209          bucketCacheStats.getDeleteFamilyBloomMissCount();
210    }
211
212    @Override
213    public long getTrailerMissCount() {
214      return lruCacheStats.getTrailerMissCount() + bucketCacheStats.getTrailerMissCount();
215    }
216
217    @Override
218    public long getDataHitCount() {
219      return lruCacheStats.getDataHitCount() + bucketCacheStats.getDataHitCount();
220    }
221
222    @Override
223    public long getLeafIndexHitCount() {
224      return lruCacheStats.getLeafIndexHitCount() + bucketCacheStats.getLeafIndexHitCount();
225    }
226
227    @Override
228    public long getBloomChunkHitCount() {
229      return lruCacheStats.getBloomChunkHitCount() + bucketCacheStats.getBloomChunkHitCount();
230    }
231
232    @Override
233    public long getMetaHitCount() {
234      return lruCacheStats.getMetaHitCount() + bucketCacheStats.getMetaHitCount();
235    }
236
237    @Override
238    public long getRootIndexHitCount() {
239      return lruCacheStats.getRootIndexHitCount() + bucketCacheStats.getRootIndexHitCount();
240    }
241
242    @Override
243    public long getIntermediateIndexHitCount() {
244      return lruCacheStats.getIntermediateIndexHitCount() +
245          bucketCacheStats.getIntermediateIndexHitCount();
246    }
247
248    @Override
249    public long getFileInfoHitCount() {
250      return lruCacheStats.getFileInfoHitCount() + bucketCacheStats.getFileInfoHitCount();
251    }
252
253    @Override
254    public long getGeneralBloomMetaHitCount() {
255      return lruCacheStats.getGeneralBloomMetaHitCount() +
256          bucketCacheStats.getGeneralBloomMetaHitCount();
257    }
258
259    @Override
260    public long getDeleteFamilyBloomHitCount() {
261      return lruCacheStats.getDeleteFamilyBloomHitCount() +
262          bucketCacheStats.getDeleteFamilyBloomHitCount();
263    }
264
265    @Override
266    public long getTrailerHitCount() {
267      return lruCacheStats.getTrailerHitCount() + bucketCacheStats.getTrailerHitCount();
268    }
269
270    @Override
271    public long getRequestCount() {
272      return lruCacheStats.getRequestCount()
273          + bucketCacheStats.getRequestCount();
274    }
275
276    @Override
277    public long getRequestCachingCount() {
278      return lruCacheStats.getRequestCachingCount()
279          + bucketCacheStats.getRequestCachingCount();
280    }
281
282    @Override
283    public long getMissCount() {
284      return lruCacheStats.getMissCount() + bucketCacheStats.getMissCount();
285    }
286
287    @Override
288    public long getPrimaryMissCount() {
289      return lruCacheStats.getPrimaryMissCount() + bucketCacheStats.getPrimaryMissCount();
290    }
291
292    @Override
293    public long getMissCachingCount() {
294      return lruCacheStats.getMissCachingCount()
295          + bucketCacheStats.getMissCachingCount();
296    }
297
298    @Override
299    public long getHitCount() {
300      return lruCacheStats.getHitCount() + bucketCacheStats.getHitCount();
301    }
302
303    @Override
304    public long getPrimaryHitCount() {
305      return lruCacheStats.getPrimaryHitCount() + bucketCacheStats.getPrimaryHitCount();
306    }
307    @Override
308    public long getHitCachingCount() {
309      return lruCacheStats.getHitCachingCount()
310          + bucketCacheStats.getHitCachingCount();
311    }
312
313    @Override
314    public long getEvictionCount() {
315      return lruCacheStats.getEvictionCount()
316          + bucketCacheStats.getEvictionCount();
317    }
318
319    @Override
320    public long getEvictedCount() {
321      return lruCacheStats.getEvictedCount()
322          + bucketCacheStats.getEvictedCount();
323    }
324
325    @Override
326    public long getPrimaryEvictedCount() {
327      return lruCacheStats.getPrimaryEvictedCount()
328          + bucketCacheStats.getPrimaryEvictedCount();
329    }
330
331    @Override
332    public void rollMetricsPeriod() {
333      lruCacheStats.rollMetricsPeriod();
334      bucketCacheStats.rollMetricsPeriod();
335    }
336
337    @Override
338    public long getFailedInserts() {
339      return lruCacheStats.getFailedInserts() + bucketCacheStats.getFailedInserts();
340    }
341
342    @Override
343    public long getSumHitCountsPastNPeriods() {
344      return lruCacheStats.getSumHitCountsPastNPeriods()
345          + bucketCacheStats.getSumHitCountsPastNPeriods();
346    }
347
348    @Override
349    public long getSumRequestCountsPastNPeriods() {
350      return lruCacheStats.getSumRequestCountsPastNPeriods()
351          + bucketCacheStats.getSumRequestCountsPastNPeriods();
352    }
353
354    @Override
355    public long getSumHitCachingCountsPastNPeriods() {
356      return lruCacheStats.getSumHitCachingCountsPastNPeriods()
357          + bucketCacheStats.getSumHitCachingCountsPastNPeriods();
358    }
359
360    @Override
361    public long getSumRequestCachingCountsPastNPeriods() {
362      return lruCacheStats.getSumRequestCachingCountsPastNPeriods()
363          + bucketCacheStats.getSumRequestCachingCountsPastNPeriods();
364    }
365  }
366
367  @Override
368  public Iterator<CachedBlock> iterator() {
369    return new BlockCachesIterator(getBlockCaches());
370  }
371
372  @Override
373  public BlockCache[] getBlockCaches() {
374    return new BlockCache [] {this.l1Cache, this.l2Cache};
375  }
376
377  @Override
378  public void setMaxSize(long size) {
379    this.l1Cache.setMaxSize(size);
380  }
381
382  @VisibleForTesting
383  public int getRpcRefCount(BlockCacheKey cacheKey) {
384    return (this.l2Cache instanceof BucketCache)
385        ? ((BucketCache) this.l2Cache).getRpcRefCount(cacheKey)
386        : 0;
387  }
388
389  public FirstLevelBlockCache getFirstLevelCache() {
390    return l1Cache;
391  }
392}