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