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  /**
29   * CombinedBlockCache is an abstraction layer that combines
30   * {@link LruBlockCache} and {@link BucketCache}. The smaller lruCache is used
31   * to cache bloom blocks and index blocks.  The larger bucketCache is used to
32   * cache data blocks. {@link #getBlock(BlockCacheKey, boolean, boolean, boolean)} reads
33   * first from the smaller lruCache before looking for the block in the bucketCache.  Blocks evicted
34   * from lruCache are put into the bucket cache. 
35   * Metrics are the combined size and hits and misses of both caches.
36   * 
37   */
38  @InterfaceAudience.Private
39  public class CombinedBlockCache implements ResizableBlockCache, HeapSize {
40    private final LruBlockCache lruCache;
41    private final BucketCache bucketCache;
42    private final CombinedCacheStats combinedCacheStats;
43  
44    public CombinedBlockCache(LruBlockCache lruCache, BucketCache bucketCache) {
45      this.lruCache = lruCache;
46      this.bucketCache = bucketCache;
47      this.combinedCacheStats = new CombinedCacheStats(lruCache.getStats(),
48          bucketCache.getStats());
49    }
50  
51    @Override
52    public long heapSize() {
53      return lruCache.heapSize() + bucketCache.heapSize();
54    }
55  
56    @Override
57    public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory,
58        final boolean cacheDataInL1) {
59      boolean isMetaBlock = buf.getBlockType().getCategory() != BlockCategory.DATA;
60      if (isMetaBlock || cacheDataInL1) {
61        lruCache.cacheBlock(cacheKey, buf, inMemory, cacheDataInL1);
62      } else {
63        bucketCache.cacheBlock(cacheKey, buf, inMemory, cacheDataInL1);
64      }
65    }
66  
67    @Override
68    public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf) {
69      cacheBlock(cacheKey, buf, false, false);
70    }
71  
72    @Override
73    public Cacheable getBlock(BlockCacheKey cacheKey, boolean caching,
74        boolean repeat, boolean updateCacheMetrics) {
75      // TODO: is there a hole here, or just awkwardness since in the lruCache getBlock
76      // we end up calling bucketCache.getBlock.
77      if (lruCache.containsBlock(cacheKey)) {
78        return lruCache.getBlock(cacheKey, caching, repeat, updateCacheMetrics);
79      }
80      return bucketCache.getBlock(cacheKey, caching, repeat, updateCacheMetrics);
81    }
82  
83    @Override
84    public boolean evictBlock(BlockCacheKey cacheKey) {
85      return lruCache.evictBlock(cacheKey) || bucketCache.evictBlock(cacheKey);
86    }
87  
88    @Override
89    public int evictBlocksByHfileName(String hfileName) {
90      return lruCache.evictBlocksByHfileName(hfileName)
91          + bucketCache.evictBlocksByHfileName(hfileName);
92    }
93  
94    @Override
95    public CacheStats getStats() {
96      return this.combinedCacheStats;
97    }
98  
99    @Override
100   public void shutdown() {
101     lruCache.shutdown();
102     bucketCache.shutdown();
103   }
104 
105   @Override
106   public long size() {
107     return lruCache.size() + bucketCache.size();
108   }
109 
110   @Override
111   public long getFreeSize() {
112     return lruCache.getFreeSize() + bucketCache.getFreeSize();
113   }
114 
115   @Override
116   public long getCurrentSize() {
117     return lruCache.getCurrentSize() + bucketCache.getCurrentSize();
118   }
119 
120   @Override
121   public long getBlockCount() {
122     return lruCache.getBlockCount() + bucketCache.getBlockCount();
123   }
124 
125   private static class CombinedCacheStats extends CacheStats {
126     private final CacheStats lruCacheStats;
127     private final CacheStats bucketCacheStats;
128 
129     CombinedCacheStats(CacheStats lbcStats, CacheStats fcStats) {
130       super("CombinedBlockCache");
131       this.lruCacheStats = lbcStats;
132       this.bucketCacheStats = fcStats;
133     }
134 
135     @Override
136     public long getRequestCount() {
137       return lruCacheStats.getRequestCount()
138           + bucketCacheStats.getRequestCount();
139     }
140 
141     @Override
142     public long getRequestCachingCount() {
143       return lruCacheStats.getRequestCachingCount()
144           + bucketCacheStats.getRequestCachingCount();
145     }
146 
147     @Override
148     public long getMissCount() {
149       return lruCacheStats.getMissCount() + bucketCacheStats.getMissCount();
150     }
151 
152     @Override
153     public long getMissCachingCount() {
154       return lruCacheStats.getMissCachingCount()
155           + bucketCacheStats.getMissCachingCount();
156     }
157 
158     @Override
159     public long getHitCount() {
160       return lruCacheStats.getHitCount() + bucketCacheStats.getHitCount();
161     }
162 
163     @Override
164     public long getHitCachingCount() {
165       return lruCacheStats.getHitCachingCount()
166           + bucketCacheStats.getHitCachingCount();
167     }
168 
169     @Override
170     public long getEvictionCount() {
171       return lruCacheStats.getEvictionCount()
172           + bucketCacheStats.getEvictionCount();
173     }
174 
175     @Override
176     public long getEvictedCount() {
177       return lruCacheStats.getEvictedCount()
178           + bucketCacheStats.getEvictedCount();
179     }
180 
181     @Override
182     public double getHitRatioPastNPeriods() {
183       double ratio = ((double) (lruCacheStats.getSumHitCountsPastNPeriods() + bucketCacheStats
184           .getSumHitCountsPastNPeriods()) / (double) (lruCacheStats
185           .getSumRequestCountsPastNPeriods() + bucketCacheStats
186           .getSumRequestCountsPastNPeriods()));
187       return Double.isNaN(ratio) ? 0 : ratio;
188     }
189 
190     @Override
191     public double getHitCachingRatioPastNPeriods() {
192       double ratio = ((double) (lruCacheStats
193           .getSumHitCachingCountsPastNPeriods() + bucketCacheStats
194           .getSumHitCachingCountsPastNPeriods()) / (double) (lruCacheStats
195           .getSumRequestCachingCountsPastNPeriods() + bucketCacheStats
196           .getSumRequestCachingCountsPastNPeriods()));
197       return Double.isNaN(ratio) ? 0 : ratio;
198     }
199   }
200 
201   @Override
202   public Iterator<CachedBlock> iterator() {
203     return new BlockCachesIterator(getBlockCaches());
204   }
205 
206   @Override
207   public BlockCache[] getBlockCaches() {
208     return new BlockCache [] {this.lruCache, this.bucketCache};
209   }
210 
211   @Override
212   public void setMaxSize(long size) {
213     this.lruCache.setMaxSize(size);
214   }
215 }