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