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.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) this.ageAtEviction.update(t - this.startTime);
135     this.evictedBlockCount.incrementAndGet();
136   }
137 
138   public long getRequestCount() {
139     return getHitCount() + getMissCount();
140   }
141 
142   public long getRequestCachingCount() {
143     return getHitCachingCount() + getMissCachingCount();
144   }
145 
146   public long getMissCount() {
147     return missCount.get();
148   }
149 
150   public long getMissCachingCount() {
151     return missCachingCount.get();
152   }
153 
154   public long getHitCount() {
155     return hitCount.get();
156   }
157 
158   public long getHitCachingCount() {
159     return hitCachingCount.get();
160   }
161 
162   public long getEvictionCount() {
163     return evictionCount.get();
164   }
165 
166   public long getEvictedCount() {
167     return this.evictedBlockCount.get();
168   }
169 
170   public double getHitRatio() {
171     return ((float)getHitCount()/(float)getRequestCount());
172   }
173 
174   public double getHitCachingRatio() {
175     return ((float)getHitCachingCount()/(float)getRequestCachingCount());
176   }
177 
178   public double getMissRatio() {
179     return ((float)getMissCount()/(float)getRequestCount());
180   }
181 
182   public double getMissCachingRatio() {
183     return ((float)getMissCachingCount()/(float)getRequestCachingCount());
184   }
185 
186   public double evictedPerEviction() {
187     return ((float)getEvictedCount()/(float)getEvictionCount());
188   }
189 
190   public void rollMetricsPeriod() {
191     hitCounts[windowIndex] = getHitCount() - lastHitCount;
192     lastHitCount = getHitCount();
193     hitCachingCounts[windowIndex] =
194       getHitCachingCount() - lastHitCachingCount;
195     lastHitCachingCount = getHitCachingCount();
196     requestCounts[windowIndex] = getRequestCount() - lastRequestCount;
197     lastRequestCount = getRequestCount();
198     requestCachingCounts[windowIndex] =
199       getRequestCachingCount() - lastRequestCachingCount;
200     lastRequestCachingCount = getRequestCachingCount();
201     windowIndex = (windowIndex + 1) % numPeriodsInWindow;
202   }
203 
204   public long getSumHitCountsPastNPeriods() {
205     return sum(hitCounts);
206   }
207 
208   public long getSumRequestCountsPastNPeriods() {
209     return sum(requestCounts);
210   }
211 
212   public long getSumHitCachingCountsPastNPeriods() {
213     return sum(hitCachingCounts);
214   }
215 
216   public long getSumRequestCachingCountsPastNPeriods() {
217     return sum(requestCachingCounts);
218   }
219 
220   public double getHitRatioPastNPeriods() {
221     double ratio = ((double)sum(hitCounts)/(double)sum(requestCounts));
222     return Double.isNaN(ratio) ? 0 : ratio;
223   }
224 
225   public double getHitCachingRatioPastNPeriods() {
226     double ratio =
227       ((double)sum(hitCachingCounts)/(double)sum(requestCachingCounts));
228     return Double.isNaN(ratio) ? 0 : ratio;
229   }
230 
231   public AgeSnapshot getAgeAtEvictionSnapshot() {
232     return new AgeSnapshot(this.ageAtEviction);
233   }
234 
235   private static long sum(long [] counts) {
236     long sum = 0;
237     for (long count : counts) sum += count;
238     return sum;
239   }
240 
241   private static long [] initializeZeros(int n) {
242     long [] zeros = new long [n];
243     for (int i=0; i<n; i++) {
244       zeros[i] = 0L;
245     }
246     return zeros;
247   }
248 }