View Javadoc

1   /**
2    * Copyright The Apache Software Foundation
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements. See the NOTICE file distributed with this
6    * work for additional information regarding copyright ownership. The ASF
7    * licenses this file to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16   * License for the specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.hadoop.hbase.io.hfile;
20  
21  import java.util.Iterator;
22  
23  import org.apache.hadoop.hbase.classification.InterfaceAudience;
24  import org.apache.hadoop.hbase.io.HeapSize;
25  import org.apache.hadoop.hbase.io.hfile.BlockType.BlockCategory;
26  import org.apache.hadoop.hbase.io.hfile.bucket.BucketCache;
27  
28  import com.google.common.annotations.VisibleForTesting;
29  
30  
31  /**
32   * CombinedBlockCache is an abstraction layer that combines
33   * {@link LruBlockCache} and {@link BucketCache}. The smaller lruCache is used
34   * to cache bloom blocks and index blocks.  The larger l2Cache is used to
35   * cache data blocks. {@link #getBlock(BlockCacheKey, boolean, boolean, boolean)} reads
36   * first from the smaller lruCache before looking for the block in the l2Cache.  Blocks evicted
37   * from lruCache are put into the bucket cache. 
38   * Metrics are the combined size and hits and misses of both caches.
39   * 
40   */
41  @InterfaceAudience.Private
42  public class CombinedBlockCache implements ResizableBlockCache, HeapSize {
43    protected final LruBlockCache lruCache;
44    protected final BlockCache l2Cache;
45    protected final CombinedCacheStats combinedCacheStats;
46  
47    public CombinedBlockCache(LruBlockCache lruCache, BlockCache l2Cache) {
48      this.lruCache = lruCache;
49      this.l2Cache = l2Cache;
50      this.combinedCacheStats = new CombinedCacheStats(lruCache.getStats(),
51          l2Cache.getStats());
52    }
53  
54    @Override
55    public long heapSize() {
56      long l2size = 0;
57      if (l2Cache instanceof HeapSize) {
58        l2size = ((HeapSize) l2Cache).heapSize();
59      }
60      return lruCache.heapSize() + l2size;
61    }
62  
63    @Override
64    public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory,
65        final boolean cacheDataInL1) {
66      boolean isMetaBlock = buf.getBlockType().getCategory() != BlockCategory.DATA;
67      if (isMetaBlock || cacheDataInL1) {
68        lruCache.cacheBlock(cacheKey, buf, inMemory, cacheDataInL1);
69      } else {
70        l2Cache.cacheBlock(cacheKey, buf, inMemory, false);
71      }
72    }
73  
74    @Override
75    public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf) {
76      cacheBlock(cacheKey, buf, false, false);
77    }
78  
79    @Override
80    public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching,
81        boolean repeat, boolean updateCacheMetrics) {
82      // TODO: is there a hole here, or just awkwardness since in the lruCache getBlock
83      // we end up calling l2Cache.getBlock.
84      if (lruCache.containsBlock(cacheKey)) {
85        return lruCache.getBlock(cacheKey, caching, repeat, updateCacheMetrics);
86      }
87      Cacheable result = l2Cache.getBlock(cacheKey, caching, repeat, updateCacheMetrics);
88  
89      return result;
90    }
91  
92    @Override
93    public boolean evictBlock(BlockCacheKey cacheKey) {
94      return lruCache.evictBlock(cacheKey) || l2Cache.evictBlock(cacheKey);
95    }
96  
97    @Override
98    public int evictBlocksByHfileName(String hfileName) {
99      return lruCache.evictBlocksByHfileName(hfileName)
100         + l2Cache.evictBlocksByHfileName(hfileName);
101   }
102 
103   @Override
104   public CacheStats getStats() {
105     return this.combinedCacheStats;
106   }
107 
108   @Override
109   public void shutdown() {
110     lruCache.shutdown();
111     l2Cache.shutdown();
112   }
113 
114   @Override
115   public long size() {
116     return lruCache.size() + l2Cache.size();
117   }
118 
119   @Override
120   public long getFreeSize() {
121     return lruCache.getFreeSize() + l2Cache.getFreeSize();
122   }
123 
124   @Override
125   public long getCurrentSize() {
126     return lruCache.getCurrentSize() + l2Cache.getCurrentSize();
127   }
128 
129   @Override
130   public long getBlockCount() {
131     return lruCache.getBlockCount() + l2Cache.getBlockCount();
132   }
133 
134   private static class CombinedCacheStats extends CacheStats {
135     private final CacheStats lruCacheStats;
136     private final CacheStats bucketCacheStats;
137 
138     CombinedCacheStats(CacheStats lbcStats, CacheStats fcStats) {
139       super("CombinedBlockCache");
140       this.lruCacheStats = lbcStats;
141       this.bucketCacheStats = fcStats;
142     }
143 
144     @Override
145     public long getRequestCount() {
146       return lruCacheStats.getRequestCount()
147           + bucketCacheStats.getRequestCount();
148     }
149 
150     @Override
151     public long getRequestCachingCount() {
152       return lruCacheStats.getRequestCachingCount()
153           + bucketCacheStats.getRequestCachingCount();
154     }
155 
156     @Override
157     public long getMissCount() {
158       return lruCacheStats.getMissCount() + bucketCacheStats.getMissCount();
159     }
160 
161     @Override
162     public long getMissCachingCount() {
163       return lruCacheStats.getMissCachingCount()
164           + bucketCacheStats.getMissCachingCount();
165     }
166 
167     @Override
168     public long getHitCount() {
169       return lruCacheStats.getHitCount() + bucketCacheStats.getHitCount();
170     }
171 
172     @Override
173     public long getHitCachingCount() {
174       return lruCacheStats.getHitCachingCount()
175           + bucketCacheStats.getHitCachingCount();
176     }
177 
178     @Override
179     public long getEvictionCount() {
180       return lruCacheStats.getEvictionCount()
181           + bucketCacheStats.getEvictionCount();
182     }
183 
184     @Override
185     public long getEvictedCount() {
186       return lruCacheStats.getEvictedCount()
187           + bucketCacheStats.getEvictedCount();
188     }
189 
190     @Override
191     public double getHitRatioPastNPeriods() {
192       double ratio = ((double) (lruCacheStats.getSumHitCountsPastNPeriods() + bucketCacheStats
193           .getSumHitCountsPastNPeriods()) / (double) (lruCacheStats
194           .getSumRequestCountsPastNPeriods() + bucketCacheStats
195           .getSumRequestCountsPastNPeriods()));
196       return Double.isNaN(ratio) ? 0 : ratio;
197     }
198 
199     @Override
200     public double getHitCachingRatioPastNPeriods() {
201       double ratio = ((double) (lruCacheStats
202           .getSumHitCachingCountsPastNPeriods() + bucketCacheStats
203           .getSumHitCachingCountsPastNPeriods()) / (double) (lruCacheStats
204           .getSumRequestCachingCountsPastNPeriods() + bucketCacheStats
205           .getSumRequestCachingCountsPastNPeriods()));
206       return Double.isNaN(ratio) ? 0 : ratio;
207     }
208   }
209 
210   @Override
211   public Iterator<CachedBlock> iterator() {
212     return new BlockCachesIterator(getBlockCaches());
213   }
214 
215   @Override
216   public BlockCache[] getBlockCaches() {
217     return new BlockCache [] {this.lruCache, this.l2Cache};
218   }
219 
220   @Override
221   public void setMaxSize(long size) {
222     this.lruCache.setMaxSize(size);
223   }
224 
225   @Override
226   public void returnBlock(BlockCacheKey cacheKey, Cacheable block) {
227     // A noop
228     this.lruCache.returnBlock(cacheKey, block);
229     this.l2Cache.returnBlock(cacheKey, block);
230   }
231 
232   @VisibleForTesting
233   public int getRefCount(BlockCacheKey cacheKey) {
234     return ((BucketCache) this.l2Cache).getRefCount(cacheKey);
235   }
236 }