View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  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,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.io.hfile;
20  
21  import java.util.concurrent.atomic.AtomicLong;
22  
23  import org.apache.hadoop.hbase.classification.InterfaceAudience;
24  
25  import com.codahale.metrics.Histogram;
26  import com.codahale.metrics.MetricRegistry;
27  
28  import static com.codahale.metrics.MetricRegistry.name;
29  
30  /**
31   * Class that implements cache metrics.
32   */
33  @InterfaceAudience.Private
34  public class CacheStats {
35    /**
36     * Needed making histograms.
37     */
38    private static final MetricRegistry METRICS = new MetricRegistry();
39  
40    /** Sliding window statistics. The number of metric periods to include in
41     * sliding window hit ratio calculations.
42     */
43    static final int DEFAULT_WINDOW_PERIODS = 5;
44  
45    /** The number of getBlock requests that were cache hits */
46    private final AtomicLong hitCount = new AtomicLong(0);
47  
48    /** The number of getBlock requests that were cache hits from primary replica */
49    private final AtomicLong primaryHitCount = new AtomicLong(0);
50    
51    /**
52     * The number of getBlock requests that were cache hits, but only from
53     * requests that were set to use the block cache.  This is because all reads
54     * attempt to read from the block cache even if they will not put new blocks
55     * into the block cache.  See HBASE-2253 for more information.
56     */
57    private final AtomicLong hitCachingCount = new AtomicLong(0);
58  
59    /** The number of getBlock requests that were cache misses */
60    private final AtomicLong missCount = new AtomicLong(0);
61  
62    /** The number of getBlock requests for primary replica that were cache misses */
63    private final AtomicLong primaryMissCount = new AtomicLong(0);
64    /**
65     * The number of getBlock requests that were cache misses, but only from
66     * requests that were set to use the block cache.
67     */
68    private final AtomicLong missCachingCount = new AtomicLong(0);
69  
70    /** The number of times an eviction has occurred */
71    private final AtomicLong evictionCount = new AtomicLong(0);
72  
73    /** The total number of blocks that have been evicted */
74    private final AtomicLong evictedBlockCount = new AtomicLong(0);
75  
76    /** The total number of blocks for primary replica that have been evicted */
77    private final AtomicLong primaryEvictedBlockCount = new AtomicLong(0);
78  
79    /** The total number of blocks that were not inserted. */
80    private final AtomicLong failedInserts = new AtomicLong(0);
81  
82    /** The number of metrics periods to include in window */
83    private final int numPeriodsInWindow;
84    /** Hit counts for each period in window */
85    private final long [] hitCounts;
86    /** Caching hit counts for each period in window */
87    private final long [] hitCachingCounts;
88    /** Access counts for each period in window */
89    private final long [] requestCounts;
90    /** Caching access counts for each period in window */
91    private final long [] requestCachingCounts;
92    /** Last hit count read */
93    private long lastHitCount = 0;
94    /** Last hit caching count read */
95    private long lastHitCachingCount = 0;
96    /** Last request count read */
97    private long lastRequestCount = 0;
98    /** Last request caching count read */
99    private long lastRequestCachingCount = 0;
100   /** Current window index (next to be updated) */
101   private int windowIndex = 0;
102   /**
103    * Keep running age at eviction time
104    */
105   private Histogram ageAtEviction;
106   private long startTime = System.nanoTime();
107 
108   public CacheStats(final String name) {
109     this(name, DEFAULT_WINDOW_PERIODS);
110   }
111 
112   public CacheStats(final String name, int numPeriodsInWindow) {
113     this.numPeriodsInWindow = numPeriodsInWindow;
114     this.hitCounts = initializeZeros(numPeriodsInWindow);
115     this.hitCachingCounts = initializeZeros(numPeriodsInWindow);
116     this.requestCounts = initializeZeros(numPeriodsInWindow);
117     this.requestCachingCounts = initializeZeros(numPeriodsInWindow);
118     this.ageAtEviction = METRICS.histogram(name(CacheStats.class, name + ".ageAtEviction"));
119   }
120 
121   @Override
122   public String toString() {
123     AgeSnapshot snapshot = getAgeAtEvictionSnapshot();
124     return "hitCount=" + getHitCount() + ", hitCachingCount=" + getHitCachingCount() +
125       ", missCount=" + getMissCount() + ", missCachingCount=" + getMissCachingCount() +
126       ", evictionCount=" + getEvictionCount() +
127       ", evictedBlockCount=" + getEvictedCount() +
128       ", primaryMissCount=" + getPrimaryMissCount() +
129       ", primaryHitCount=" + getPrimaryHitCount() +
130       ", evictedAgeMean=" + snapshot.getMean() +
131       ", evictedAgeStdDev=" + snapshot.getStdDev();
132   }
133 
134   public void miss(boolean caching, boolean primary) {
135     missCount.incrementAndGet();
136     if (primary) primaryMissCount.incrementAndGet();
137     if (caching) missCachingCount.incrementAndGet();
138   }
139 
140   public void hit(boolean caching) {
141     hit(caching, true);
142   }
143 
144   public void hit(boolean caching, boolean primary) {
145     hitCount.incrementAndGet();
146     if (primary) primaryHitCount.incrementAndGet();
147     if (caching) hitCachingCount.incrementAndGet();
148   }
149 
150   public void evict() {
151     evictionCount.incrementAndGet();
152   }
153 
154   public void evicted(final long t, boolean primary) {
155     if (t > this.startTime) this.ageAtEviction.update(t - this.startTime);
156     this.evictedBlockCount.incrementAndGet();
157     if (primary) {
158       primaryEvictedBlockCount.incrementAndGet();
159     }
160   }
161 
162   public long failInsert() {
163     return failedInserts.incrementAndGet();
164   }
165 
166   public long getRequestCount() {
167     return getHitCount() + getMissCount();
168   }
169 
170   public long getRequestCachingCount() {
171     return getHitCachingCount() + getMissCachingCount();
172   }
173 
174   public long getMissCount() {
175     return missCount.get();
176   }
177 
178   public long getPrimaryMissCount() {
179     return primaryMissCount.get();
180   }
181 
182   public long getMissCachingCount() {
183     return missCachingCount.get();
184   }
185 
186   public long getHitCount() {
187     return hitCount.get();
188   }
189 
190   public long getPrimaryHitCount() {
191     return primaryHitCount.get();
192   }
193 
194   public long getHitCachingCount() {
195     return hitCachingCount.get();
196   }
197 
198   public long getEvictionCount() {
199     return evictionCount.get();
200   }
201 
202   public long getEvictedCount() {
203     return this.evictedBlockCount.get();
204   }
205 
206   public long getPrimaryEvictedCount() {
207     return primaryEvictedBlockCount.get();
208   }
209 
210   public double getHitRatio() {
211     return ((float)getHitCount()/(float)getRequestCount());
212   }
213 
214   public double getHitCachingRatio() {
215     return ((float)getHitCachingCount()/(float)getRequestCachingCount());
216   }
217 
218   public double getMissRatio() {
219     return ((float)getMissCount()/(float)getRequestCount());
220   }
221 
222   public double getMissCachingRatio() {
223     return ((float)getMissCachingCount()/(float)getRequestCachingCount());
224   }
225 
226   public double evictedPerEviction() {
227     return ((float)getEvictedCount()/(float)getEvictionCount());
228   }
229 
230   public long getFailedInserts() {
231     return failedInserts.get();
232   }
233 
234   public void rollMetricsPeriod() {
235     hitCounts[windowIndex] = getHitCount() - lastHitCount;
236     lastHitCount = getHitCount();
237     hitCachingCounts[windowIndex] =
238       getHitCachingCount() - lastHitCachingCount;
239     lastHitCachingCount = getHitCachingCount();
240     requestCounts[windowIndex] = getRequestCount() - lastRequestCount;
241     lastRequestCount = getRequestCount();
242     requestCachingCounts[windowIndex] =
243       getRequestCachingCount() - lastRequestCachingCount;
244     lastRequestCachingCount = getRequestCachingCount();
245     windowIndex = (windowIndex + 1) % numPeriodsInWindow;
246   }
247 
248   public long getSumHitCountsPastNPeriods() {
249     return sum(hitCounts);
250   }
251 
252   public long getSumRequestCountsPastNPeriods() {
253     return sum(requestCounts);
254   }
255 
256   public long getSumHitCachingCountsPastNPeriods() {
257     return sum(hitCachingCounts);
258   }
259 
260   public long getSumRequestCachingCountsPastNPeriods() {
261     return sum(requestCachingCounts);
262   }
263 
264   public double getHitRatioPastNPeriods() {
265     double ratio = ((double)getSumHitCountsPastNPeriods() /
266         (double)getSumRequestCountsPastNPeriods());
267     return Double.isNaN(ratio) ? 0 : ratio;
268   }
269 
270   public double getHitCachingRatioPastNPeriods() {
271     double ratio = ((double)getSumHitCachingCountsPastNPeriods() /
272         (double)getSumRequestCachingCountsPastNPeriods());
273     return Double.isNaN(ratio) ? 0 : ratio;
274   }
275 
276   public AgeSnapshot getAgeAtEvictionSnapshot() {
277     return new AgeSnapshot(this.ageAtEviction);
278   }
279 
280   private static long sum(long [] counts) {
281     long sum = 0;
282     for (long count : counts) sum += count;
283     return sum;
284   }
285 
286   private static long [] initializeZeros(int n) {
287     long [] zeros = new long [n];
288     for (int i=0; i<n; i++) {
289       zeros[i] = 0L;
290     }
291     return zeros;
292   }
293 }