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; 019 020import static org.junit.jupiter.api.Assertions.assertEquals; 021import static org.junit.jupiter.api.Assertions.assertTrue; 022 023import com.codahale.metrics.Timer; 024import java.io.IOException; 025import java.util.Arrays; 026import org.apache.hadoop.conf.Configuration; 027import org.apache.hadoop.hbase.HBaseConfiguration; 028import org.apache.hadoop.hbase.HBaseTestingUtil; 029import org.apache.hadoop.hbase.TableName; 030import org.apache.hadoop.hbase.testclassification.ClientTests; 031import org.apache.hadoop.hbase.testclassification.MediumTests; 032import org.apache.hadoop.hbase.util.Bytes; 033import org.junit.jupiter.api.AfterAll; 034import org.junit.jupiter.api.BeforeAll; 035import org.junit.jupiter.api.Tag; 036import org.junit.jupiter.api.Test; 037 038import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ClientService; 039 040@Tag(MediumTests.TAG) 041@Tag(ClientTests.TAG) 042public class TestClientTableMetrics { 043 044 private static HBaseTestingUtil UTIL; 045 private static Connection CONN; 046 private static MetricsConnection METRICS; 047 private static final String tableName = "table_1"; 048 private static final TableName TABLE_1 = TableName.valueOf(tableName); 049 private static final byte[] FAMILY = Bytes.toBytes("f"); 050 051 @BeforeAll 052 public static void beforeClass() throws Exception { 053 Configuration conf = HBaseConfiguration.create(); 054 conf.setBoolean(MetricsConnection.CLIENT_SIDE_METRICS_ENABLED_KEY, true); 055 conf.setBoolean(MetricsConnection.CLIENT_SIDE_TABLE_METRICS_ENABLED_KEY, true); 056 UTIL = new HBaseTestingUtil(conf); 057 UTIL.startMiniCluster(2); 058 UTIL.createTable(TABLE_1, FAMILY); 059 UTIL.waitTableAvailable(TABLE_1); 060 CONN = UTIL.getConnection(); 061 METRICS = ((AsyncConnectionImpl) CONN.toAsyncConnection()).getConnectionMetrics().get(); 062 } 063 064 @AfterAll 065 public static void afterClass() throws Exception { 066 UTIL.deleteTableIfAny(TABLE_1); 067 UTIL.shutdownMiniCluster(); 068 } 069 070 @Test 071 public void testGetTableMetrics() throws IOException { 072 Table table = CONN.getTable(TABLE_1); 073 table.get(new Get(Bytes.toBytes("row1"))); 074 table.get(new Get(Bytes.toBytes("row2"))); 075 table.get(new Get(Bytes.toBytes("row3"))); 076 table.close(); 077 078 String metricKey = 079 "rpcCallDurationMs_" + ClientService.getDescriptor().getName() + "_Get_" + tableName; 080 verifyTableMetrics(metricKey, 3); 081 } 082 083 @Test 084 public void testMutateTableMetrics() throws IOException { 085 Table table = CONN.getTable(TABLE_1); 086 // PUT 087 Put put = new Put(Bytes.toBytes("row1")); 088 put.addColumn(FAMILY, Bytes.toBytes("name"), Bytes.toBytes("tom")); 089 table.put(put); 090 put = new Put(Bytes.toBytes("row2")); 091 put.addColumn(FAMILY, Bytes.toBytes("name"), Bytes.toBytes("jerry")); 092 table.put(put); 093 // DELETE 094 table.delete(new Delete(Bytes.toBytes("row1"))); 095 table.close(); 096 097 String metricKey = 098 "rpcCallDurationMs_" + ClientService.getDescriptor().getName() + "_Mutate(Put)_" + tableName; 099 verifyTableMetrics(metricKey, 2); 100 101 metricKey = "rpcCallDurationMs_" + ClientService.getDescriptor().getName() + "_Mutate(Delete)_" 102 + tableName; 103 verifyTableMetrics(metricKey, 1); 104 } 105 106 @Test 107 public void testScanTableMetrics() throws IOException { 108 Table table = CONN.getTable(TABLE_1); 109 table.getScanner(new Scan()); 110 table.close(); 111 112 String metricKey = 113 "rpcCallDurationMs_" + ClientService.getDescriptor().getName() + "_Scan_" + tableName; 114 verifyTableMetrics(metricKey, 1); 115 } 116 117 @Test 118 public void testMultiTableMetrics() throws IOException { 119 Table table = CONN.getTable(TABLE_1); 120 table.put(Arrays.asList( 121 new Put(Bytes.toBytes("row1")).addColumn(FAMILY, Bytes.toBytes("name"), Bytes.toBytes("tom")), 122 new Put(Bytes.toBytes("row2")).addColumn(FAMILY, Bytes.toBytes("name"), 123 Bytes.toBytes("jerry")))); 124 table.get(Arrays.asList(new Get(Bytes.toBytes("row1")), new Get(Bytes.toBytes("row2")))); 125 table.close(); 126 127 String metricKey = 128 "rpcCallDurationMs_" + ClientService.getDescriptor().getName() + "_Multi_" + tableName; 129 verifyTableMetrics(metricKey, 2); 130 } 131 132 private static void verifyTableMetrics(String metricKey, int expectedVal) { 133 String numOpsSuffix = "_num_ops"; 134 String p95Suffix = "_95th_percentile"; 135 String p99Suffix = "_99th_percentile"; 136 Timer timer = METRICS.getRpcTimers().get(metricKey); 137 long numOps = timer.getCount(); 138 double p95 = timer.getSnapshot().get95thPercentile(); 139 double p99 = timer.getSnapshot().get99thPercentile(); 140 assertEquals(expectedVal, numOps, "metric: " + metricKey + numOpsSuffix + " val: " + numOps); 141 assertTrue(p95 >= 0, "metric: " + metricKey + p95Suffix + " val: " + p95); 142 assertTrue(p99 >= 0, "metric: " + metricKey + p99Suffix + " val: " + p99); 143 } 144}