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 /** 054 * number of rows filtered during scan RPC 055 */ 056 public final AtomicLong countOfRowsFiltered = 057 createCounter(COUNT_OF_ROWS_FILTERED_KEY_METRIC_NAME); 058 059 /** 060 * number of rows scanned during scan RPC. Not every row scanned will be returned to the client 061 * since rows may be filtered. 062 */ 063 public final AtomicLong countOfRowsScanned = createCounter(COUNT_OF_ROWS_SCANNED_KEY_METRIC_NAME); 064 065 public final AtomicLong countOfBlockBytesScanned = 066 createCounter(BLOCK_BYTES_SCANNED_KEY_METRIC_NAME); 067 068 public void setCounter(String counterName, long value) { 069 AtomicLong c = this.counters.get(counterName); 070 if (c != null) { 071 c.set(value); 072 } 073 } 074 075 /** Returns true if a counter exists with the counterName */ 076 public boolean hasCounter(String counterName) { 077 return this.counters.containsKey(counterName); 078 } 079 080 /** Returns {@link AtomicLong} instance for this counter name, null if counter does not exist. */ 081 public AtomicLong getCounter(String counterName) { 082 return this.counters.get(counterName); 083 } 084 085 public void addToCounter(String counterName, long delta) { 086 AtomicLong c = this.counters.get(counterName); 087 if (c != null) { 088 c.addAndGet(delta); 089 } 090 } 091 092 /** 093 * Get all of the values since the last time this function was called. Calling this function will 094 * reset all AtomicLongs in the instance back to 0. 095 * @return A Map of String -> Long for metrics 096 */ 097 public Map<String, Long> getMetricsMap() { 098 return getMetricsMap(true); 099 } 100 101 /** 102 * Get all of the values. If reset is true, we will reset the all AtomicLongs back to 0. 103 * @param reset whether to reset the AtomicLongs to 0. 104 * @return A Map of String -> Long for metrics 105 */ 106 public Map<String, Long> getMetricsMap(boolean reset) { 107 // Create a builder 108 ImmutableMap.Builder<String, Long> builder = ImmutableMap.builder(); 109 for (Map.Entry<String, AtomicLong> e : this.counters.entrySet()) { 110 long value = reset ? e.getValue().getAndSet(0) : e.getValue().get(); 111 builder.put(e.getKey(), value); 112 } 113 // Build the immutable map so that people can't mess around with it. 114 return builder.build(); 115 } 116}