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.client.metrics; 019 020import java.util.HashMap; 021import java.util.Map; 022import java.util.concurrent.atomic.AtomicLong; 023import org.apache.yetus.audience.InterfaceAudience; 024 025import org.apache.hbase.thirdparty.com.google.common.collect.ImmutableMap; 026 027/** 028 * Provides server side metrics related to scan operations. 029 */ 030@InterfaceAudience.Public 031@SuppressWarnings("checkstyle:VisibilityModifier") // See HBASE-27757 032public class ServerSideScanMetrics { 033 /** 034 * Hash to hold the String -> Atomic Long mappings for each metric 035 */ 036 private final Map<String, AtomicLong> counters = new HashMap<>(); 037 038 /** 039 * Create a new counter with the specified name 040 * @return {@link AtomicLong} instance for the counter with counterName 041 */ 042 protected AtomicLong createCounter(String counterName) { 043 AtomicLong c = new AtomicLong(0); 044 counters.put(counterName, c); 045 return c; 046 } 047 048 public static final String COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME = "ROWS_SCANNED"; 049 public static final String COUNT_OF_ROWS_FILTERED_KEY_METRIC_NAME = "ROWS_FILTERED"; 050 051 public static final String BLOCK_BYTES_SCANNED_KEY_METRIC_NAME = "BLOCK_BYTES_SCANNED"; 052 053 public static final String FS_READ_TIME_METRIC_NAME = "FS_READ_TIME"; 054 055 /** 056 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0 057 * (<a href="https://issues.apache.org/jira/browse/HBASE-17886">HBASE-17886</a>). Use 058 * {@link #COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME}. 059 */ 060 @Deprecated 061 public static final String COUNT_OF_ROWS_SCANNED_KEY = COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME; 062 063 /** 064 * @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0 065 * (<a href="https://issues.apache.org/jira/browse/HBASE-17886">HBASE-17886</a>). Use 066 * {@link #COUNT_OF_ROWS_FILTERED_KEY_METRIC_NAME}. 067 */ 068 @Deprecated 069 public static final String COUNT_OF_ROWS_FILTERED_KEY = COUNT_OF_ROWS_FILTERED_KEY_METRIC_NAME; 070 071 /** 072 * number of rows filtered during scan RPC 073 */ 074 public final AtomicLong countOfRowsFiltered = 075 createCounter(COUNT_OF_ROWS_FILTERED_KEY_METRIC_NAME); 076 077 /** 078 * number of rows scanned during scan RPC. Not every row scanned will be returned to the client 079 * since rows may be filtered. 080 */ 081 public final AtomicLong countOfRowsScanned = createCounter(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME); 082 083 public final AtomicLong countOfBlockBytesScanned = 084 createCounter(BLOCK_BYTES_SCANNED_KEY_METRIC_NAME); 085 086 public final AtomicLong fsReadTime = createCounter(FS_READ_TIME_METRIC_NAME); 087 088 public void setCounter(String counterName, long value) { 089 AtomicLong c = this.counters.get(counterName); 090 if (c != null) { 091 c.set(value); 092 } 093 } 094 095 /** Returns true if a counter exists with the counterName */ 096 public boolean hasCounter(String counterName) { 097 return this.counters.containsKey(counterName); 098 } 099 100 /** Returns {@link AtomicLong} instance for this counter name, null if counter does not exist. */ 101 public AtomicLong getCounter(String counterName) { 102 return this.counters.get(counterName); 103 } 104 105 public void addToCounter(String counterName, long delta) { 106 AtomicLong c = this.counters.get(counterName); 107 if (c != null) { 108 c.addAndGet(delta); 109 } 110 } 111 112 /** 113 * Get all of the values since the last time this function was called. Calling this function will 114 * reset all AtomicLongs in the instance back to 0. 115 * @return A Map of String -> Long for metrics 116 */ 117 public Map<String, Long> getMetricsMap() { 118 return getMetricsMap(true); 119 } 120 121 /** 122 * Get all of the values. If reset is true, we will reset the all AtomicLongs back to 0. 123 * @param reset whether to reset the AtomicLongs to 0. 124 * @return A Map of String -> Long for metrics 125 */ 126 public Map<String, Long> getMetricsMap(boolean reset) { 127 // Create a builder 128 ImmutableMap.Builder<String, Long> builder = ImmutableMap.builder(); 129 for (Map.Entry<String, AtomicLong> e : this.counters.entrySet()) { 130 long value = reset ? e.getValue().getAndSet(0) : e.getValue().get(); 131 builder.put(e.getKey(), value); 132 } 133 // Build the immutable map so that people can't mess around with it. 134 return builder.build(); 135 } 136}