001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.io.hfile;
020
021import java.util.Arrays;
022import java.util.concurrent.atomic.AtomicLong;
023import java.util.concurrent.atomic.LongAdder;
024
025import org.apache.yetus.audience.InterfaceAudience;
026import org.apache.hadoop.hbase.metrics.impl.FastLongHistogram;
027
028
029/**
030 * Class that implements cache metrics.
031 */
032@InterfaceAudience.Private
033public class CacheStats {
034
035  /** Sliding window statistics. The number of metric periods to include in
036   * sliding window hit ratio calculations.
037   */
038  static final int DEFAULT_WINDOW_PERIODS = 5;
039
040  /** The number of getBlock requests that were cache hits */
041  private final LongAdder hitCount = new LongAdder();
042
043  /** The number of getBlock requests that were cache hits from primary replica */
044  private final LongAdder primaryHitCount = new LongAdder();
045
046  /**
047   * The number of getBlock requests that were cache hits, but only from
048   * requests that were set to use the block cache.  This is because all reads
049   * attempt to read from the block cache even if they will not put new blocks
050   * into the block cache.  See HBASE-2253 for more information.
051   */
052  private final LongAdder hitCachingCount = new LongAdder();
053
054  /** The number of getBlock requests that were cache misses */
055  private final LongAdder missCount = new LongAdder();
056
057  /** The number of getBlock requests for primary replica that were cache misses */
058  private final LongAdder primaryMissCount = new LongAdder();
059  /**
060   * The number of getBlock requests that were cache misses, but only from
061   * requests that were set to use the block cache.
062   */
063  private final LongAdder missCachingCount = new LongAdder();
064
065  /** The number of times an eviction has occurred */
066  private final LongAdder evictionCount = new LongAdder();
067
068  /** The total number of blocks that have been evicted */
069  private final LongAdder evictedBlockCount = new LongAdder();
070
071  /** The total number of blocks for primary replica that have been evicted */
072  private final LongAdder primaryEvictedBlockCount = new LongAdder();
073
074  /** The total number of blocks that were not inserted. */
075  private final AtomicLong failedInserts = new AtomicLong(0);
076
077  /** Per Block Type Counts */
078  private final LongAdder dataMissCount = new LongAdder();
079  private final LongAdder leafIndexMissCount = new LongAdder();
080  private final LongAdder bloomChunkMissCount = new LongAdder();
081  private final LongAdder metaMissCount = new LongAdder();
082  private final LongAdder rootIndexMissCount = new LongAdder();
083  private final LongAdder intermediateIndexMissCount = new LongAdder();
084  private final LongAdder fileInfoMissCount = new LongAdder();
085  private final LongAdder generalBloomMetaMissCount = new LongAdder();
086  private final LongAdder deleteFamilyBloomMissCount = new LongAdder();
087  private final LongAdder trailerMissCount = new LongAdder();
088
089  private final LongAdder dataHitCount = new LongAdder();
090  private final LongAdder leafIndexHitCount = new LongAdder();
091  private final LongAdder bloomChunkHitCount = new LongAdder();
092  private final LongAdder metaHitCount = new LongAdder();
093  private final LongAdder rootIndexHitCount = new LongAdder();
094  private final LongAdder intermediateIndexHitCount = new LongAdder();
095  private final LongAdder fileInfoHitCount = new LongAdder();
096  private final LongAdder generalBloomMetaHitCount = new LongAdder();
097  private final LongAdder deleteFamilyBloomHitCount = new LongAdder();
098  private final LongAdder trailerHitCount = new LongAdder();
099
100  /** The number of metrics periods to include in window */
101  private final int numPeriodsInWindow;
102  /** Hit counts for each period in window */
103  private final long [] hitCounts;
104  /** Caching hit counts for each period in window */
105  private final long [] hitCachingCounts;
106  /** Access counts for each period in window */
107  private final long [] requestCounts;
108  /** Caching access counts for each period in window */
109  private final long [] requestCachingCounts;
110  /** Last hit count read */
111  private long lastHitCount = 0;
112  /** Last hit caching count read */
113  private long lastHitCachingCount = 0;
114  /** Last request count read */
115  private long lastRequestCount = 0;
116  /** Last request caching count read */
117  private long lastRequestCachingCount = 0;
118  /** Current window index (next to be updated) */
119  private int windowIndex = 0;
120  /**
121   * Keep running age at eviction time
122   */
123  private FastLongHistogram ageAtEviction;
124  private long startTime = System.nanoTime();
125
126  public CacheStats(final String name) {
127    this(name, DEFAULT_WINDOW_PERIODS);
128  }
129
130  public CacheStats(final String name, int numPeriodsInWindow) {
131    this.numPeriodsInWindow = numPeriodsInWindow;
132    this.hitCounts = new long[numPeriodsInWindow];
133    this.hitCachingCounts =  new long[numPeriodsInWindow];
134    this.requestCounts =  new long[numPeriodsInWindow];
135    this.requestCachingCounts =  new long[numPeriodsInWindow];
136    this.ageAtEviction = new FastLongHistogram();
137  }
138
139  @Override
140  public String toString() {
141    AgeSnapshot snapshot = getAgeAtEvictionSnapshot();
142    return "hitCount=" + getHitCount() + ", hitCachingCount=" + getHitCachingCount() +
143      ", missCount=" + getMissCount() + ", missCachingCount=" + getMissCachingCount() +
144      ", evictionCount=" + getEvictionCount() +
145      ", evictedBlockCount=" + getEvictedCount() +
146      ", primaryMissCount=" + getPrimaryMissCount() +
147      ", primaryHitCount=" + getPrimaryHitCount() +
148      ", evictedAgeMean=" + snapshot.getMean();
149  }
150
151
152  public void miss(boolean caching, boolean primary, BlockType type) {
153    missCount.increment();
154    if (primary) primaryMissCount.increment();
155    if (caching) missCachingCount.increment();
156    if (type == null) {
157      return;
158    }
159    switch (type) {
160      case DATA:
161      case ENCODED_DATA:
162        dataMissCount.increment();
163        break;
164      case LEAF_INDEX:
165        leafIndexMissCount.increment();
166        break;
167      case BLOOM_CHUNK:
168        bloomChunkMissCount.increment();
169        break;
170      case META:
171        metaMissCount.increment();
172        break;
173      case INTERMEDIATE_INDEX:
174        intermediateIndexMissCount.increment();
175        break;
176      case ROOT_INDEX:
177        rootIndexMissCount.increment();
178        break;
179      case FILE_INFO:
180        fileInfoMissCount.increment();
181        break;
182      case GENERAL_BLOOM_META:
183        generalBloomMetaMissCount.increment();
184        break;
185      case DELETE_FAMILY_BLOOM_META:
186        deleteFamilyBloomMissCount.increment();
187        break;
188      case TRAILER:
189        trailerMissCount.increment();
190        break;
191      default:
192        // If there's a new type that's fine
193        // Ignore it for now. This is metrics don't exception.
194        break;
195    }
196  }
197
198  public void hit(boolean caching, boolean primary, BlockType type) {
199    hitCount.increment();
200    if (primary) primaryHitCount.increment();
201    if (caching) hitCachingCount.increment();
202
203
204    if (type == null) {
205      return;
206    }
207    switch (type) {
208      case DATA:
209      case ENCODED_DATA:
210        dataHitCount.increment();
211        break;
212      case LEAF_INDEX:
213        leafIndexHitCount.increment();
214        break;
215      case BLOOM_CHUNK:
216        bloomChunkHitCount.increment();
217        break;
218      case META:
219        metaHitCount.increment();
220        break;
221      case INTERMEDIATE_INDEX:
222        intermediateIndexHitCount.increment();
223        break;
224      case ROOT_INDEX:
225        rootIndexHitCount.increment();
226        break;
227      case FILE_INFO:
228        fileInfoHitCount.increment();
229        break;
230      case GENERAL_BLOOM_META:
231        generalBloomMetaHitCount.increment();
232        break;
233      case DELETE_FAMILY_BLOOM_META:
234        deleteFamilyBloomHitCount.increment();
235        break;
236      case TRAILER:
237        trailerHitCount.increment();
238        break;
239      default:
240        // If there's a new type that's fine
241        // Ignore it for now. This is metrics don't exception.
242        break;
243    }
244  }
245
246  public void evict() {
247    evictionCount.increment();
248  }
249
250  public void evicted(final long t, boolean primary) {
251    if (t > this.startTime) {
252      this.ageAtEviction.add((t - this.startTime) / BlockCacheUtil.NANOS_PER_SECOND, 1);
253    }
254    this.evictedBlockCount.increment();
255    if (primary) {
256      primaryEvictedBlockCount.increment();
257    }
258  }
259
260  public long failInsert() {
261    return failedInserts.incrementAndGet();
262  }
263
264
265  // All of the counts of misses and hits.
266  public long getDataMissCount() {
267    return dataMissCount.sum();
268  }
269
270  public long getLeafIndexMissCount() {
271    return leafIndexMissCount.sum();
272  }
273
274  public long getBloomChunkMissCount() {
275    return bloomChunkMissCount.sum();
276  }
277
278  public long getMetaMissCount() {
279    return metaMissCount.sum();
280  }
281
282  public long getRootIndexMissCount() {
283    return rootIndexMissCount.sum();
284  }
285
286  public long getIntermediateIndexMissCount() {
287    return intermediateIndexMissCount.sum();
288  }
289
290  public long getFileInfoMissCount() {
291    return fileInfoMissCount.sum();
292  }
293
294  public long getGeneralBloomMetaMissCount() {
295    return generalBloomMetaMissCount.sum();
296  }
297
298  public long getDeleteFamilyBloomMissCount() {
299    return deleteFamilyBloomMissCount.sum();
300  }
301
302  public long getTrailerMissCount() {
303    return trailerMissCount.sum();
304  }
305
306  public long getDataHitCount() {
307    return dataHitCount.sum();
308  }
309
310  public long getLeafIndexHitCount() {
311    return leafIndexHitCount.sum();
312  }
313
314  public long getBloomChunkHitCount() {
315    return bloomChunkHitCount.sum();
316  }
317
318  public long getMetaHitCount() {
319    return metaHitCount.sum();
320  }
321
322  public long getRootIndexHitCount() {
323    return rootIndexHitCount.sum();
324  }
325
326  public long getIntermediateIndexHitCount() {
327    return intermediateIndexHitCount.sum();
328  }
329
330  public long getFileInfoHitCount() {
331    return fileInfoHitCount.sum();
332  }
333
334  public long getGeneralBloomMetaHitCount() {
335    return generalBloomMetaHitCount.sum();
336  }
337
338  public long getDeleteFamilyBloomHitCount() {
339    return deleteFamilyBloomHitCount.sum();
340  }
341
342  public long getTrailerHitCount() {
343    return trailerHitCount.sum();
344  }
345
346  public long getRequestCount() {
347    return getHitCount() + getMissCount();
348  }
349
350  public long getRequestCachingCount() {
351    return getHitCachingCount() + getMissCachingCount();
352  }
353
354  public long getMissCount() {
355    return missCount.sum();
356  }
357
358  public long getPrimaryMissCount() {
359    return primaryMissCount.sum();
360  }
361
362  public long getMissCachingCount() {
363    return missCachingCount.sum();
364  }
365
366  public long getHitCount() {
367    return hitCount.sum();
368  }
369
370  public long getPrimaryHitCount() {
371    return primaryHitCount.sum();
372  }
373
374  public long getHitCachingCount() {
375    return hitCachingCount.sum();
376  }
377
378  public long getEvictionCount() {
379    return evictionCount.sum();
380  }
381
382  public long getEvictedCount() {
383    return this.evictedBlockCount.sum();
384  }
385
386  public long getPrimaryEvictedCount() {
387    return primaryEvictedBlockCount.sum();
388  }
389
390  public double getHitRatio() {
391    double requestCount = getRequestCount();
392
393    if (requestCount == 0) {
394      return 0;
395    }
396
397    return getHitCount() / requestCount;
398  }
399
400  public double getHitCachingRatio() {
401    double requestCachingCount = getRequestCachingCount();
402
403    if (requestCachingCount == 0) {
404      return 0;
405    }
406
407    return getHitCachingCount() / requestCachingCount;
408  }
409
410  public double getMissRatio() {
411    double requestCount = getRequestCount();
412
413    if (requestCount == 0) {
414      return 0;
415    }
416
417    return getMissCount() / requestCount;
418  }
419
420  public double getMissCachingRatio() {
421    double requestCachingCount = getRequestCachingCount();
422
423    if (requestCachingCount == 0) {
424      return 0;
425    }
426
427    return getMissCachingCount() / requestCachingCount;
428  }
429
430  public double evictedPerEviction() {
431    double evictionCount = getEvictionCount();
432
433    if (evictionCount == 0) {
434      return 0;
435    }
436
437    return getEvictedCount() / evictionCount;
438  }
439
440  public long getFailedInserts() {
441    return failedInserts.get();
442  }
443
444  public void rollMetricsPeriod() {
445    hitCounts[windowIndex] = getHitCount() - lastHitCount;
446    lastHitCount = getHitCount();
447    hitCachingCounts[windowIndex] =
448      getHitCachingCount() - lastHitCachingCount;
449    lastHitCachingCount = getHitCachingCount();
450    requestCounts[windowIndex] = getRequestCount() - lastRequestCount;
451    lastRequestCount = getRequestCount();
452    requestCachingCounts[windowIndex] =
453      getRequestCachingCount() - lastRequestCachingCount;
454    lastRequestCachingCount = getRequestCachingCount();
455    windowIndex = (windowIndex + 1) % numPeriodsInWindow;
456  }
457
458  public long getSumHitCountsPastNPeriods() {
459    return sum(hitCounts);
460  }
461
462  public long getSumRequestCountsPastNPeriods() {
463    return sum(requestCounts);
464  }
465
466  public long getSumHitCachingCountsPastNPeriods() {
467    return sum(hitCachingCounts);
468  }
469
470  public long getSumRequestCachingCountsPastNPeriods() {
471    return sum(requestCachingCounts);
472  }
473
474  public double getHitRatioPastNPeriods() {
475    double ratio = ((double)getSumHitCountsPastNPeriods() /
476        (double)getSumRequestCountsPastNPeriods());
477    return Double.isNaN(ratio) ? 0 : ratio;
478  }
479
480  public double getHitCachingRatioPastNPeriods() {
481    double ratio = ((double)getSumHitCachingCountsPastNPeriods() /
482        (double)getSumRequestCachingCountsPastNPeriods());
483    return Double.isNaN(ratio) ? 0 : ratio;
484  }
485
486  public AgeSnapshot getAgeAtEvictionSnapshot() {
487    return new AgeSnapshot(this.ageAtEviction);
488  }
489
490  private static long sum(long[] counts) {
491    return Arrays.stream(counts).sum();
492  }
493}