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