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