1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.client;
19
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertFalse;
22 import static org.junit.Assert.assertTrue;
23
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.List;
27
28 import org.apache.hadoop.hbase.HBaseTestingUtility;
29 import org.apache.hadoop.hbase.TableName;
30 import org.apache.hadoop.hbase.testclassification.ClientTests;
31 import org.apache.hadoop.hbase.testclassification.MediumTests;
32 import org.apache.hadoop.hbase.util.Bytes;
33 import org.junit.AfterClass;
34 import org.junit.BeforeClass;
35 import org.junit.Test;
36 import org.junit.experimental.categories.Category;
37 import org.junit.runner.RunWith;
38 import org.junit.runners.Parameterized;
39 import org.junit.runners.Parameterized.Parameter;
40 import org.junit.runners.Parameterized.Parameters;
41
42
43
44
45
46 @RunWith(Parameterized.class)
47 @Category({ MediumTests.class, ClientTests.class })
48 public class TestScannersFromClientSide2 {
49
50 private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
51
52 private static TableName TABLE_NAME = TableName.valueOf("scan");
53
54 private static byte[] FAMILY = Bytes.toBytes("cf");
55
56 private static byte[] CQ1 = Bytes.toBytes("cq1");
57
58 private static byte[] CQ2 = Bytes.toBytes("cq2");
59
60 @Parameter(0)
61 public boolean batch;
62
63 @Parameter(1)
64 public boolean smallResultSize;
65
66 @Parameter(2)
67 public boolean allowPartial;
68
69 @Parameters(name = "{index}: batch={0}, smallResultSize={1}, allowPartial={2}")
70 public static List<Object[]> params() {
71 List<Object[]> params = new ArrayList<>();
72 boolean[] values = new boolean[] { false, true };
73 for (int i = 0; i < 2; i++) {
74 for (int j = 0; j < 2; j++) {
75 for (int k = 0; k < 2; k++) {
76 params.add(new Object[] { values[i], values[j], values[k] });
77 }
78 }
79 }
80 return params;
81 }
82
83 @BeforeClass
84 public static void setUp() throws Exception {
85 TEST_UTIL.startMiniCluster(3);
86 byte[][] splitKeys = new byte[8][];
87 for (int i = 111; i < 999; i += 111) {
88 splitKeys[i / 111 - 1] = Bytes.toBytes(String.format("%03d", i));
89 }
90 Table table = TEST_UTIL.createTable(TABLE_NAME, FAMILY, splitKeys);
91 List<Put> puts = new ArrayList<>();
92 for (int i = 0; i < 1000; i++) {
93 puts.add(new Put(Bytes.toBytes(String.format("%03d", i)))
94 .addColumn(FAMILY, CQ1, Bytes.toBytes(i)).addColumn(FAMILY, CQ2, Bytes.toBytes(i * i)));
95 }
96 TEST_UTIL.waitTableAvailable(TABLE_NAME);
97 table.put(puts);
98 }
99
100 @AfterClass
101 public static void tearDown() throws Exception {
102 TEST_UTIL.shutdownMiniCluster();
103 }
104
105 private Scan createScan() {
106 Scan scan = new Scan();
107 if (batch) {
108 scan.setBatch(1);
109 }
110 if (smallResultSize) {
111 scan.setMaxResultSize(1);
112 }
113 if (allowPartial) {
114 scan.setAllowPartialResults(true);
115 }
116 return scan;
117 }
118
119 private void assertResultEquals(Result result, int i) {
120 assertEquals(String.format("%03d", i), Bytes.toString(result.getRow()));
121 assertEquals(i, Bytes.toInt(result.getValue(FAMILY, CQ1)));
122 assertEquals(i * i, Bytes.toInt(result.getValue(FAMILY, CQ2)));
123 }
124
125 private List<Result> doScan(Scan scan) throws IOException {
126 List<Result> results = new ArrayList<>();
127 try (Table table = TEST_UTIL.getConnection().getTable(TABLE_NAME);
128 ResultScanner scanner = table.getScanner(scan)) {
129 for (Result r; (r = scanner.next()) != null;) {
130 results.add(r);
131 }
132 }
133 return assertAndCreateCompleteResults(results);
134 }
135
136 private List<Result> assertAndCreateCompleteResults(List<Result> results) throws IOException {
137 if ((!batch && !allowPartial) || (allowPartial && !batch && !smallResultSize)) {
138 for (Result result : results) {
139 assertFalse("Should not have partial result", result.mayHaveMoreCellsInRow());
140 }
141 return results;
142 }
143 List<Result> completeResults = new ArrayList<>();
144 List<Result> partialResults = new ArrayList<>();
145 for (Result result : results) {
146 if (!result.mayHaveMoreCellsInRow()) {
147 assertFalse("Should have partial result", partialResults.isEmpty());
148 partialResults.add(result);
149 completeResults.add(Result.createCompleteResult(partialResults));
150 partialResults.clear();
151 } else {
152 partialResults.add(result);
153 }
154 }
155 assertTrue("Should not have orphan partial result", partialResults.isEmpty());
156 return completeResults;
157 }
158
159 private void testScan(int start, boolean startInclusive, int stop, boolean stopInclusive,
160 int limit) throws Exception {
161 Scan scan =
162 createScan().withStartRow(Bytes.toBytes(String.format("%03d", start)), startInclusive)
163 .withStopRow(Bytes.toBytes(String.format("%03d", stop)), stopInclusive);
164 if (limit > 0) {
165 scan.setLimit(limit);
166 }
167 List<Result> results = doScan(scan);
168 int actualStart = startInclusive ? start : start + 1;
169 int actualStop = stopInclusive ? stop + 1 : stop;
170 int count = actualStop - actualStart;
171 if (limit > 0) {
172 count = Math.min(count, limit);
173 }
174 assertEquals(count, results.size());
175 for (int i = 0; i < count; i++) {
176 assertResultEquals(results.get(i), actualStart + i);
177 }
178 }
179
180 private void testReversedScan(int start, boolean startInclusive, int stop, boolean stopInclusive,
181 int limit) throws Exception {
182 Scan scan = createScan()
183 .withStartRow(Bytes.toBytes(String.format("%03d", start)), startInclusive)
184 .withStopRow(Bytes.toBytes(String.format("%03d", stop)), stopInclusive).setReversed(true);
185 if (limit > 0) {
186 scan.setLimit(limit);
187 }
188 List<Result> results = doScan(scan);
189 int actualStart = startInclusive ? start : start - 1;
190 int actualStop = stopInclusive ? stop - 1 : stop;
191 int count = actualStart - actualStop;
192 if (limit > 0) {
193 count = Math.min(count, limit);
194 }
195 assertEquals(count, results.size());
196 for (int i = 0; i < count; i++) {
197 assertResultEquals(results.get(i), actualStart - i);
198 }
199 }
200
201 @Test
202 public void testScanWithLimit() throws Exception {
203 testScan(1, true, 998, false, 900);
204 testScan(123, true, 345, true, 100);
205 testScan(234, true, 456, false, 100);
206 testScan(345, false, 567, true, 100);
207 testScan(456, false, 678, false, 100);
208
209 }
210
211 @Test
212 public void testScanWithLimitGreaterThanActualCount() throws Exception {
213 testScan(1, true, 998, false, 1000);
214 testScan(123, true, 345, true, 200);
215 testScan(234, true, 456, false, 200);
216 testScan(345, false, 567, true, 200);
217 testScan(456, false, 678, false, 200);
218 }
219
220 @Test
221 public void testReversedScanWithLimit() throws Exception {
222 testReversedScan(998, true, 1, false, 900);
223 testReversedScan(543, true, 321, true, 100);
224 testReversedScan(654, true, 432, false, 100);
225 testReversedScan(765, false, 543, true, 100);
226 testReversedScan(876, false, 654, false, 100);
227 }
228
229 @Test
230 public void testReversedScanWithLimitGreaterThanActualCount() throws Exception {
231 testReversedScan(998, true, 1, false, 1000);
232 testReversedScan(543, true, 321, true, 200);
233 testReversedScan(654, true, 432, false, 200);
234 testReversedScan(765, false, 543, true, 200);
235 testReversedScan(876, false, 654, false, 200);
236 }
237
238 @Test
239 public void testStartRowStopRowInclusive() throws Exception {
240 testScan(1, true, 998, false, -1);
241 testScan(123, true, 345, true, -1);
242 testScan(234, true, 456, false, -1);
243 testScan(345, false, 567, true, -1);
244 testScan(456, false, 678, false, -1);
245 }
246
247 @Test
248 public void testReversedStartRowStopRowInclusive() throws Exception {
249 testReversedScan(998, true, 1, false, -1);
250 testReversedScan(543, true, 321, true, -1);
251 testReversedScan(654, true, 432, false, -1);
252 testReversedScan(765, false, 543, true, -1);
253 testReversedScan(876, false, 654, false, -1);
254 }
255 }