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 java.io.IOException;
024import org.apache.hadoop.hbase.HBaseTestingUtil;
025import org.apache.hadoop.hbase.TableName;
026import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
027import org.apache.hadoop.hbase.ipc.HBaseRpcController;
028import org.apache.hadoop.hbase.ipc.HBaseRpcControllerImpl;
029import org.apache.hadoop.hbase.testclassification.MediumTests;
030import org.apache.hadoop.hbase.testclassification.RegionServerTests;
031import org.apache.hadoop.hbase.util.Bytes;
032import org.junit.jupiter.api.AfterAll;
033import org.junit.jupiter.api.BeforeAll;
034import org.junit.jupiter.api.Tag;
035import org.junit.jupiter.api.Test;
036
037import org.apache.hbase.thirdparty.com.google.protobuf.ServiceException;
038
039import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
040import org.apache.hadoop.hbase.shaded.protobuf.ResponseConverter;
041import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos;
042import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ScanRequest;
043import org.apache.hadoop.hbase.shaded.protobuf.generated.ClientProtos.ScanResponse;
044
045/**
046 * Testcase to make sure that we do not close scanners if ScanRequest.numberOfRows is zero. See
047 * HBASE-18042 for more details.
048 */
049@Tag(RegionServerTests.TAG)
050@Tag(MediumTests.TAG)
051public class TestScanWithoutFetchingData {
052
053  private static final HBaseTestingUtil UTIL = new HBaseTestingUtil();
054
055  private static final TableName TABLE_NAME = TableName.valueOf("test");
056
057  private static final byte[] CF = Bytes.toBytes("cf");
058
059  private static final byte[] CQ = Bytes.toBytes("cq");
060
061  private static final int COUNT = 10;
062
063  private static RegionInfo HRI;
064
065  private static AsyncConnectionImpl CONN;
066
067  private static ClientProtos.ClientService.Interface STUB;
068
069  @BeforeAll
070  public static void setUp() throws Exception {
071    UTIL.startMiniCluster(1);
072    try (Table table = UTIL.createTable(TABLE_NAME, CF)) {
073      for (int i = 0; i < COUNT; i++) {
074        table.put(new Put(Bytes.toBytes(i)).addColumn(CF, CQ, Bytes.toBytes(i)));
075      }
076    }
077    HRI = UTIL.getAdmin().getRegions(TABLE_NAME).get(0);
078    CONN =
079      (AsyncConnectionImpl) ConnectionFactory.createAsyncConnection(UTIL.getConfiguration()).get();
080    STUB = CONN.getRegionServerStub(UTIL.getHBaseCluster().getRegionServer(0).getServerName());
081  }
082
083  @AfterAll
084  public static void tearDown() throws Exception {
085    UTIL.shutdownMiniCluster();
086  }
087
088  private ScanResponse scan(HBaseRpcController hrc, ScanRequest req) throws IOException {
089    BlockingRpcCallback<ScanResponse> callback = new BlockingRpcCallback<>();
090    STUB.scan(hrc, req, callback);
091    return callback.get();
092  }
093
094  private void assertResult(int row, Result result) {
095    assertEquals(row, Bytes.toInt(result.getRow()));
096    assertEquals(row, Bytes.toInt(result.getValue(CF, CQ)));
097  }
098
099  @Test
100  public void test() throws ServiceException, IOException {
101    Scan scan = new Scan();
102    ScanRequest req = RequestConverter.buildScanRequest(HRI.getRegionName(), scan, 0, false);
103    HBaseRpcController hrc = new HBaseRpcControllerImpl();
104    ScanResponse resp = scan(hrc, req);
105    assertTrue(resp.getMoreResults());
106    assertTrue(resp.getMoreResultsInRegion());
107    assertEquals(0, ResponseConverter.getResults(hrc.cellScanner(), resp).length);
108    long scannerId = resp.getScannerId();
109    int nextCallSeq = 0;
110    // test normal next
111    for (int i = 0; i < COUNT / 2; i++) {
112      req = RequestConverter.buildScanRequest(scannerId, 1, false, nextCallSeq++, false, false, -1);
113      hrc.reset();
114      resp = scan(hrc, req);
115      assertTrue(resp.getMoreResults());
116      assertTrue(resp.getMoreResultsInRegion());
117      Result[] results = ResponseConverter.getResults(hrc.cellScanner(), resp);
118      assertEquals(1, results.length);
119      assertResult(i, results[0]);
120    }
121    // test zero next
122    req = RequestConverter.buildScanRequest(scannerId, 0, false, nextCallSeq++, false, false, -1);
123    hrc.reset();
124    resp = scan(hrc, req);
125    assertTrue(resp.getMoreResults());
126    assertTrue(resp.getMoreResultsInRegion());
127    assertEquals(0, ResponseConverter.getResults(hrc.cellScanner(), resp).length);
128    for (int i = COUNT / 2; i < COUNT; i++) {
129      req = RequestConverter.buildScanRequest(scannerId, 1, false, nextCallSeq++, false, false, -1);
130      hrc.reset();
131      resp = scan(hrc, req);
132      assertTrue(resp.getMoreResults());
133      assertEquals(i != COUNT - 1, resp.getMoreResultsInRegion());
134      Result[] results = ResponseConverter.getResults(hrc.cellScanner(), resp);
135      assertEquals(1, results.length);
136      assertResult(i, results[0]);
137    }
138    // close
139    req = RequestConverter.buildScanRequest(scannerId, 0, true, false);
140    hrc.reset();
141    resp = scan(hrc, req);
142  }
143}