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.regionserver;
019
020import static org.junit.jupiter.api.Assertions.assertEquals;
021
022import java.io.IOException;
023import org.apache.hadoop.conf.Configuration;
024import org.apache.hadoop.hbase.HBaseTestingUtil;
025import org.apache.hadoop.hbase.HConstants;
026import org.apache.hadoop.hbase.SingleProcessHBaseCluster.MiniHBaseClusterRegionServer;
027import org.apache.hadoop.hbase.TableName;
028import org.apache.hadoop.hbase.client.Put;
029import org.apache.hadoop.hbase.client.Result;
030import org.apache.hadoop.hbase.client.ResultScanner;
031import org.apache.hadoop.hbase.client.Scan;
032import org.apache.hadoop.hbase.client.Table;
033import org.apache.hadoop.hbase.testclassification.MediumTests;
034import org.apache.hadoop.hbase.testclassification.RegionServerTests;
035import org.apache.hadoop.hbase.util.Bytes;
036import org.junit.jupiter.api.AfterAll;
037import org.junit.jupiter.api.BeforeAll;
038import org.junit.jupiter.api.Tag;
039import org.junit.jupiter.api.Test;
040import org.junit.jupiter.api.TestInfo;
041import org.slf4j.Logger;
042import org.slf4j.LoggerFactory;
043
044@Tag(RegionServerTests.TAG)
045@Tag(MediumTests.TAG)
046public class TestScannerRPCScanMetrics {
047
048  private static final Logger LOG = LoggerFactory.getLogger(TestScannerRPCScanMetrics.class);
049  private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
050  private static final byte[] FAMILY = Bytes.toBytes("testFamily");
051  private static final byte[] QUALIFIER = Bytes.toBytes("testQualifier");
052  private static final byte[] VALUE = Bytes.toBytes("testValue");
053
054  @BeforeAll
055  public static void setupBeforeClass() throws Exception {
056    Configuration conf = TEST_UTIL.getConfiguration();
057    conf.setStrings(HConstants.REGION_SERVER_IMPL, RegionServerWithScanMetrics.class.getName());
058    TEST_UTIL.startMiniCluster(1);
059  }
060
061  @AfterAll
062  public static void tearDownAfterClass() throws Exception {
063    TEST_UTIL.shutdownMiniCluster();
064  }
065
066  @Test
067  public void testScannerRPCScanMetrics(TestInfo testInfo) throws Exception {
068    final TableName tableName = TableName.valueOf(testInfo.getTestMethod().get().getName());
069    byte[][] splits = new byte[1][];
070    splits[0] = Bytes.toBytes("row-4");
071    Table ht = TEST_UTIL.createTable(tableName, FAMILY, splits);
072    byte[] r0 = Bytes.toBytes("row-0");
073    byte[] r1 = Bytes.toBytes("row-1");
074    byte[] r2 = Bytes.toBytes("row-2");
075    byte[] r3 = Bytes.toBytes("row-3");
076    putToTable(ht, r0);
077    putToTable(ht, r1);
078    putToTable(ht, r2);
079    putToTable(ht, r3);
080    LOG.info("Wrote our four table entries");
081    Scan scan1 = new Scan();
082    scan1.withStartRow(r0);
083    // This scan should not increment rpc full scan count (start row specified)
084    scan1.withStopRow(Bytes.toBytes("row-4"));
085    scanNextIterate(ht, scan1);
086    Scan scan2 = new Scan();
087    scan2.withStartRow(r1);
088    // This scan should increment rpc full scan count by 1 (for second region only)
089    scanNextIterate(ht, scan2);
090    Scan scan3 = new Scan();
091    scan3.withStopRow(Bytes.toBytes("row-5"));
092    // This scan should increment rpc full scan count by 1 (for firts region only)
093    scanNextIterate(ht, scan3);
094    Scan scan4 = new Scan();
095    scan4.withStartRow(r1);
096    scan4.withStopRow(r2);
097    // This scan should not increment rpc full scan count (both start and stop row)
098    scanNextIterate(ht, scan4);
099    Scan dummyScan = new Scan();
100    // This scan should increment rpc full scan count by 2 (both regions - no stop/start row)
101    scanNextIterate(ht, dummyScan);
102
103    RSRpcServices testClusterRSRPCServices =
104      TEST_UTIL.getMiniHBaseCluster().getRegionServer(0).getRpcServices();
105    assertEquals(4, testClusterRSRPCServices.rpcFullScanRequestCount.intValue());
106  }
107
108  private void putToTable(Table ht, byte[] rowkey) throws IOException {
109    Put put = new Put(rowkey);
110    put.addColumn(FAMILY, QUALIFIER, VALUE);
111    ht.put(put);
112  }
113
114  private void scanNextIterate(Table ht, Scan scan) throws Exception {
115    ResultScanner scanner = ht.getScanner(scan);
116    for (Result result = scanner.next(); result != null; result = scanner.next()) {
117      // Use the result object
118    }
119    scanner.close();
120  }
121
122  private static class RegionServerWithScanMetrics extends MiniHBaseClusterRegionServer {
123    public RegionServerWithScanMetrics(Configuration conf)
124      throws IOException, InterruptedException {
125      super(conf);
126    }
127
128    protected RSRpcServices createRPCServices() throws IOException {
129      return new RSRPCServicesWithScanMetrics(this);
130    }
131  }
132
133  private static class RSRPCServicesWithScanMetrics extends RSRpcServices {
134    public long getScanRequestCount() {
135      return super.rpcScanRequestCount.longValue();
136    }
137
138    public long getFullScanRequestCount() {
139      return super.rpcFullScanRequestCount.longValue();
140    }
141
142    public RSRPCServicesWithScanMetrics(HRegionServer rs) throws IOException {
143      super(rs);
144    }
145  }
146
147}