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   public 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 getPrimaryMissCount() {
163       return lruCacheStats.getPrimaryMissCount() + bucketCacheStats.getPrimaryMissCount();
164     }
165 
166     @Override
167     public long getMissCachingCount() {
168       return lruCacheStats.getMissCachingCount()
169           + bucketCacheStats.getMissCachingCount();
170     }
171 
172     @Override
173     public long getHitCount() {
174       return lruCacheStats.getHitCount() + bucketCacheStats.getHitCount();
175     }
176 
177     @Override
178     public long getPrimaryHitCount() {
179       return lruCacheStats.getPrimaryHitCount() + bucketCacheStats.getPrimaryHitCount();
180     }
181     @Override
182     public long getHitCachingCount() {
183       return lruCacheStats.getHitCachingCount()
184           + bucketCacheStats.getHitCachingCount();
185     }
186 
187     @Override
188     public long getEvictionCount() {
189       return lruCacheStats.getEvictionCount()
190           + bucketCacheStats.getEvictionCount();
191     }
192 
193     @Override
194     public long getEvictedCount() {
195       return lruCacheStats.getEvictedCount()
196           + bucketCacheStats.getEvictedCount();
197     }
198 
199     @Override
200     public long getPrimaryEvictedCount() {
201       return lruCacheStats.getPrimaryEvictedCount()
202           + bucketCacheStats.getPrimaryEvictedCount();
203     }
204 
205     @Override
206     public void rollMetricsPeriod() {
207       lruCacheStats.rollMetricsPeriod();
208       bucketCacheStats.rollMetricsPeriod();
209     }
210     
211     @Override
212     public long getFailedInserts() {
213       return lruCacheStats.getFailedInserts() + bucketCacheStats.getFailedInserts();
214     }
215 
216     @Override
217     public long getSumHitCountsPastNPeriods() {
218       return lruCacheStats.getSumHitCountsPastNPeriods()
219           + bucketCacheStats.getSumHitCountsPastNPeriods();
220     }
221     
222     @Override
223     public long getSumRequestCountsPastNPeriods() {
224       return lruCacheStats.getSumRequestCountsPastNPeriods()
225           + bucketCacheStats.getSumRequestCountsPastNPeriods();
226     }
227     
228     @Override
229     public long getSumHitCachingCountsPastNPeriods() {
230       return lruCacheStats.getSumHitCachingCountsPastNPeriods()
231           + bucketCacheStats.getSumHitCachingCountsPastNPeriods();
232     }
233 
234     @Override
235     public long getSumRequestCachingCountsPastNPeriods() {
236       return lruCacheStats.getSumRequestCachingCountsPastNPeriods()
237           + bucketCacheStats.getSumRequestCachingCountsPastNPeriods();
238     }
239   }
240 
241   @Override
242   public Iterator<CachedBlock> iterator() {
243     return new BlockCachesIterator(getBlockCaches());
244   }
245 
246   @Override
247   public BlockCache[] getBlockCaches() {
248     return new BlockCache [] {this.lruCache, this.l2Cache};
249   }
250 
251   @Override
252   public void setMaxSize(long size) {
253     this.lruCache.setMaxSize(size);
254   }
255 
256   @Override
257   public void returnBlock(BlockCacheKey cacheKey, Cacheable block) {
258     // A noop
259     this.lruCache.returnBlock(cacheKey, block);
260     this.l2Cache.returnBlock(cacheKey, block);
261   }
262 
263   @VisibleForTesting
264   public int getRefCount(BlockCacheKey cacheKey) {
265     return ((BucketCache) this.l2Cache).getRefCount(cacheKey);
266   }
267 }