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.yammer.metrics.core.Histogram;
26  import com.yammer.metrics.core.MetricsRegistry;
27  
28  /**
29   * Class that implements cache metrics.
30   */
31  @InterfaceAudience.Private
32  public class CacheStats {
33    /**
34     * Needed making histograms.
35     */
36    private static final MetricsRegistry METRICS = new MetricsRegistry();
37  
38    /** Sliding window statistics. The number of metric periods to include in
39     * sliding window hit ratio calculations.
40     */
41    static final int DEFAULT_WINDOW_PERIODS = 5;
42  
43    /** The number of getBlock requests that were cache hits */
44    private final AtomicLong hitCount = new AtomicLong(0);
45  
46    /**
47     * The number of getBlock requests that were cache hits, but only from
48     * requests that were set to use the block cache.  This is because all reads
49     * attempt to read from the block cache even if they will not put new blocks
50     * into the block cache.  See HBASE-2253 for more information.
51     */
52    private final AtomicLong hitCachingCount = new AtomicLong(0);
53  
54    /** The number of getBlock requests that were cache misses */
55    private final AtomicLong missCount = new AtomicLong(0);
56  
57    /**
58     * The number of getBlock requests that were cache misses, but only from
59     * requests that were set to use the block cache.
60     */
61    private final AtomicLong missCachingCount = new AtomicLong(0);
62  
63    /** The number of times an eviction has occurred */
64    private final AtomicLong evictionCount = new AtomicLong(0);
65  
66    /** The total number of blocks that have been evicted */
67    private final AtomicLong evictedBlockCount = new AtomicLong(0);
68  
69    /** The number of metrics periods to include in window */
70    private final int numPeriodsInWindow;
71    /** Hit counts for each period in window */
72    private final long [] hitCounts;
73    /** Caching hit counts for each period in window */
74    private final long [] hitCachingCounts;
75    /** Access counts for each period in window */
76    private final long [] requestCounts;
77    /** Caching access counts for each period in window */
78    private final long [] requestCachingCounts;
79    /** Last hit count read */
80    private long lastHitCount = 0;
81    /** Last hit caching count read */
82    private long lastHitCachingCount = 0;
83    /** Last request count read */
84    private long lastRequestCount = 0;
85    /** Last request caching count read */
86    private long lastRequestCachingCount = 0;
87    /** Current window index (next to be updated) */
88    private int windowIndex = 0;
89    /**
90     * Keep running age at eviction time
91     */
92    private Histogram ageAtEviction;
93    private long startTime = System.nanoTime();
94  
95    public CacheStats(final String name) {
96      this(name, DEFAULT_WINDOW_PERIODS);
97    }
98  
99    public CacheStats(final String name, int numPeriodsInWindow) {
100     this.numPeriodsInWindow = numPeriodsInWindow;
101     this.hitCounts = initializeZeros(numPeriodsInWindow);
102     this.hitCachingCounts = initializeZeros(numPeriodsInWindow);
103     this.requestCounts = initializeZeros(numPeriodsInWindow);
104     this.requestCachingCounts = initializeZeros(numPeriodsInWindow);
105     this.ageAtEviction = METRICS.newHistogram(CacheStats.class, name + ".ageAtEviction");
106   }
107 
108   @Override
109   public String toString() {
110     AgeSnapshot snapshot = getAgeAtEvictionSnapshot();
111     return "hitCount=" + getHitCount() + ", hitCachingCount=" + getHitCachingCount() +
112       ", missCount=" + getMissCount() + ", missCachingCount=" + getMissCachingCount() +
113       ", evictionCount=" + getEvictionCount() +
114       ", evictedBlockCount=" + getEvictedCount() +
115       ", evictedAgeMean=" + snapshot.getMean() +
116       ", evictedAgeStdDev=" + snapshot.getStdDev();
117   }
118 
119   public void miss(boolean caching) {
120     missCount.incrementAndGet();
121     if (caching) missCachingCount.incrementAndGet();
122   }
123 
124   public void hit(boolean caching) {
125     hitCount.incrementAndGet();
126     if (caching) hitCachingCount.incrementAndGet();
127   }
128 
129   public void evict() {
130     evictionCount.incrementAndGet();
131   }
132 
133   public void evicted(final long t) {
134     if (t > this.startTime) {
135       this.ageAtEviction.update((t - this.startTime)/BlockCacheUtil.NANOS_PER_SECOND);
136     }
137     this.evictedBlockCount.incrementAndGet();
138   }
139 
140   public long getRequestCount() {
141     return getHitCount() + getMissCount();
142   }
143 
144   public long getRequestCachingCount() {
145     return getHitCachingCount() + getMissCachingCount();
146   }
147 
148   public long getMissCount() {
149     return missCount.get();
150   }
151 
152   public long getMissCachingCount() {
153     return missCachingCount.get();
154   }
155 
156   public long getHitCount() {
157     return hitCount.get();
158   }
159 
160   public long getHitCachingCount() {
161     return hitCachingCount.get();
162   }
163 
164   public long getEvictionCount() {
165     return evictionCount.get();
166   }
167 
168   public long getEvictedCount() {
169     return this.evictedBlockCount.get();
170   }
171 
172   public double getHitRatio() {
173     return ((float)getHitCount()/(float)getRequestCount());
174   }
175 
176   public double getHitCachingRatio() {
177     return ((float)getHitCachingCount()/(float)getRequestCachingCount());
178   }
179 
180   public double getMissRatio() {
181     return ((float)getMissCount()/(float)getRequestCount());
182   }
183 
184   public double getMissCachingRatio() {
185     return ((float)getMissCachingCount()/(float)getRequestCachingCount());
186   }
187 
188   public double evictedPerEviction() {
189     return ((float)getEvictedCount()/(float)getEvictionCount());
190   }
191 
192   public void rollMetricsPeriod() {
193     hitCounts[windowIndex] = getHitCount() - lastHitCount;
194     lastHitCount = getHitCount();
195     hitCachingCounts[windowIndex] =
196       getHitCachingCount() - lastHitCachingCount;
197     lastHitCachingCount = getHitCachingCount();
198     requestCounts[windowIndex] = getRequestCount() - lastRequestCount;
199     lastRequestCount = getRequestCount();
200     requestCachingCounts[windowIndex] =
201       getRequestCachingCount() - lastRequestCachingCount;
202     lastRequestCachingCount = getRequestCachingCount();
203     windowIndex = (windowIndex + 1) % numPeriodsInWindow;
204   }
205 
206   public long getSumHitCountsPastNPeriods() {
207     return sum(hitCounts);
208   }
209 
210   public long getSumRequestCountsPastNPeriods() {
211     return sum(requestCounts);
212   }
213 
214   public long getSumHitCachingCountsPastNPeriods() {
215     return sum(hitCachingCounts);
216   }
217 
218   public long getSumRequestCachingCountsPastNPeriods() {
219     return sum(requestCachingCounts);
220   }
221 
222   public double getHitRatioPastNPeriods() {
223     double ratio = ((double)getSumHitCountsPastNPeriods() /
224         (double)getSumRequestCountsPastNPeriods());
225     return Double.isNaN(ratio) ? 0 : ratio;
226   }
227 
228   public double getHitCachingRatioPastNPeriods() {
229     double ratio = ((double)getSumHitCachingCountsPastNPeriods() /
230         (double)getSumRequestCachingCountsPastNPeriods());
231     return Double.isNaN(ratio) ? 0 : ratio;
232   }
233 
234   public AgeSnapshot getAgeAtEvictionSnapshot() {
235     return new AgeSnapshot(this.ageAtEviction);
236   }
237 
238   private static long sum(long [] counts) {
239     long sum = 0;
240     for (long count : counts) sum += count;
241     return sum;
242   }
243 
244   private static long [] initializeZeros(int n) {
245     long [] zeros = new long [n];
246     for (int i=0; i<n; i++) {
247       zeros[i] = 0L;
248     }
249     return zeros;
250   }
251 }