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