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