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