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.assertFalse; 022import static org.junit.Assert.assertTrue; 023 024import java.util.List; 025import java.util.concurrent.ExecutionException; 026import java.util.stream.Collectors; 027import java.util.stream.IntStream; 028import org.apache.hadoop.hbase.HBaseClassTestRule; 029import org.apache.hadoop.hbase.HBaseTestingUtility; 030import org.apache.hadoop.hbase.TableName; 031import org.apache.hadoop.hbase.testclassification.ClientTests; 032import org.apache.hadoop.hbase.testclassification.MediumTests; 033import org.apache.hadoop.hbase.util.Bytes; 034import org.junit.AfterClass; 035import org.junit.BeforeClass; 036import org.junit.ClassRule; 037import org.junit.Test; 038import org.junit.experimental.categories.Category; 039 040/** 041 * With filter we may stop at a middle of row and think that we still have more cells for the 042 * current row but actually all the remaining cells will be filtered out by the filter. So it will 043 * lead to a Result that mayHaveMoreCellsInRow is true but actually there are no cells for the same 044 * row. Here we want to test if our limited scan still works. 045 */ 046@Category({ MediumTests.class, ClientTests.class }) 047public class TestRawAsyncTableLimitedScanWithFilter { 048 049 @ClassRule 050 public static final HBaseClassTestRule CLASS_RULE = 051 HBaseClassTestRule.forClass(TestRawAsyncTableLimitedScanWithFilter.class); 052 053 private static final HBaseTestingUtility UTIL = new HBaseTestingUtility(); 054 055 private static final TableName TABLE_NAME = TableName.valueOf("TestRegionScanner"); 056 057 private static final byte[] FAMILY = Bytes.toBytes("cf"); 058 059 private static final byte[][] CQS = 060 { Bytes.toBytes("cq1"), Bytes.toBytes("cq2"), Bytes.toBytes("cq3"), Bytes.toBytes("cq4") }; 061 062 private static int ROW_COUNT = 10; 063 064 private static AsyncConnection CONN; 065 066 private static AsyncTable<?> TABLE; 067 068 @BeforeClass 069 public static void setUp() throws Exception { 070 UTIL.startMiniCluster(1); 071 UTIL.createTable(TABLE_NAME, FAMILY); 072 CONN = ConnectionFactory.createAsyncConnection(UTIL.getConfiguration()).get(); 073 TABLE = CONN.getTable(TABLE_NAME); 074 TABLE.putAll(IntStream.range(0, ROW_COUNT).mapToObj(i -> { 075 Put put = new Put(Bytes.toBytes(i)); 076 IntStream.range(0, CQS.length) 077 .forEach(j -> put.addColumn(FAMILY, CQS[j], Bytes.toBytes((j + 1) * i))); 078 return put; 079 }).collect(Collectors.toList())).get(); 080 } 081 082 @AfterClass 083 public static void tearDown() throws Exception { 084 if (CONN != null) { 085 CONN.close(); 086 } 087 UTIL.shutdownMiniCluster(); 088 } 089 090 @Test 091 public void testCompleteResult() throws InterruptedException, ExecutionException { 092 int limit = 5; 093 Scan scan = 094 new Scan().setFilter(new ColumnCountOnRowFilter(2)).setMaxResultSize(1).setLimit(limit); 095 List<Result> results = TABLE.scanAll(scan).get(); 096 assertEquals(limit, results.size()); 097 IntStream.range(0, limit).forEach(i -> { 098 Result result = results.get(i); 099 assertEquals(i, Bytes.toInt(result.getRow())); 100 assertEquals(2, result.size()); 101 assertFalse(result.mayHaveMoreCellsInRow()); 102 assertEquals(i, Bytes.toInt(result.getValue(FAMILY, CQS[0]))); 103 assertEquals(2 * i, Bytes.toInt(result.getValue(FAMILY, CQS[1]))); 104 }); 105 } 106 107 @Test 108 public void testAllowPartial() throws InterruptedException, ExecutionException { 109 int limit = 5; 110 Scan scan = new Scan().setFilter(new ColumnCountOnRowFilter(2)).setMaxResultSize(1) 111 .setAllowPartialResults(true).setLimit(limit); 112 List<Result> results = TABLE.scanAll(scan).get(); 113 assertEquals(2 * limit, results.size()); 114 IntStream.range(0, 2 * limit).forEach(i -> { 115 int key = i / 2; 116 Result result = results.get(i); 117 assertEquals(key, Bytes.toInt(result.getRow())); 118 assertEquals(1, result.size()); 119 assertTrue(result.mayHaveMoreCellsInRow()); 120 int cqIndex = i % 2; 121 assertEquals(key * (cqIndex + 1), Bytes.toInt(result.getValue(FAMILY, CQS[cqIndex]))); 122 }); 123 } 124 125 @Test 126 public void testBatchAllowPartial() throws InterruptedException, ExecutionException { 127 int limit = 5; 128 Scan scan = new Scan().setFilter(new ColumnCountOnRowFilter(3)).setBatch(2).setMaxResultSize(1) 129 .setAllowPartialResults(true).setLimit(limit); 130 List<Result> results = TABLE.scanAll(scan).get(); 131 assertEquals(3 * limit, results.size()); 132 IntStream.range(0, 3 * limit).forEach(i -> { 133 int key = i / 3; 134 Result result = results.get(i); 135 assertEquals(key, Bytes.toInt(result.getRow())); 136 assertEquals(1, result.size()); 137 assertTrue(result.mayHaveMoreCellsInRow()); 138 int cqIndex = i % 3; 139 assertEquals(key * (cqIndex + 1), Bytes.toInt(result.getValue(FAMILY, CQS[cqIndex]))); 140 }); 141 } 142 143 @Test 144 public void testBatch() throws InterruptedException, ExecutionException { 145 int limit = 5; 146 Scan scan = new Scan().setFilter(new ColumnCountOnRowFilter(2)).setBatch(2).setMaxResultSize(1) 147 .setLimit(limit); 148 List<Result> results = TABLE.scanAll(scan).get(); 149 assertEquals(limit, results.size()); 150 IntStream.range(0, limit).forEach(i -> { 151 Result result = results.get(i); 152 assertEquals(i, Bytes.toInt(result.getRow())); 153 assertEquals(2, result.size()); 154 assertTrue(result.mayHaveMoreCellsInRow()); 155 assertEquals(i, Bytes.toInt(result.getValue(FAMILY, CQS[0]))); 156 assertEquals(2 * i, Bytes.toInt(result.getValue(FAMILY, CQS[1]))); 157 }); 158 } 159 160 @Test 161 public void testBatchAndFilterDiffer() throws InterruptedException, ExecutionException { 162 int limit = 5; 163 Scan scan = new Scan().setFilter(new ColumnCountOnRowFilter(3)).setBatch(2).setMaxResultSize(1) 164 .setLimit(limit); 165 List<Result> results = TABLE.scanAll(scan).get(); 166 assertEquals(2 * limit, results.size()); 167 IntStream.range(0, limit).forEach(i -> { 168 Result result = results.get(2 * i); 169 assertEquals(i, Bytes.toInt(result.getRow())); 170 assertEquals(2, result.size()); 171 assertTrue(result.mayHaveMoreCellsInRow()); 172 assertEquals(i, Bytes.toInt(result.getValue(FAMILY, CQS[0]))); 173 assertEquals(2 * i, Bytes.toInt(result.getValue(FAMILY, CQS[1]))); 174 result = results.get(2 * i + 1); 175 assertEquals(i, Bytes.toInt(result.getRow())); 176 assertEquals(1, result.size()); 177 assertFalse(result.mayHaveMoreCellsInRow()); 178 assertEquals(3 * i, Bytes.toInt(result.getValue(FAMILY, CQS[2]))); 179 }); 180 } 181}