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