1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.filter;
19
20 import static org.junit.Assert.assertEquals;
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.List;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.hadoop.hbase.Cell;
30 import org.apache.hadoop.hbase.HBaseTestingUtility;
31 import org.apache.hadoop.hbase.HConstants;
32 import org.apache.hadoop.hbase.client.HTable;
33 import org.apache.hadoop.hbase.client.Put;
34 import org.apache.hadoop.hbase.client.Result;
35 import org.apache.hadoop.hbase.client.ResultScanner;
36 import org.apache.hadoop.hbase.client.Scan;
37 import org.apache.hadoop.hbase.filter.MultiRowRangeFilter.RowRange;
38 import org.apache.hadoop.hbase.testclassification.MediumTests;
39 import org.apache.hadoop.hbase.util.Bytes;
40 import org.junit.AfterClass;
41 import org.junit.Assert;
42 import org.junit.BeforeClass;
43 import org.junit.Test;
44 import org.junit.experimental.categories.Category;
45
46 @Category(MediumTests.class)
47 public class TestMultiRowRangeFilter {
48
49 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
50 private static final Log LOG = LogFactory.getLog(TestMultiRowRangeFilter.class);
51 private byte[] family = Bytes.toBytes("family");
52 private byte[] qf = Bytes.toBytes("qf");
53 private byte[] value = Bytes.toBytes("val");
54 private byte[] tableName;
55 private int numRows = 100;
56
57
58
59
60 @BeforeClass
61 public static void setUpBeforeClass() throws Exception {
62 TEST_UTIL.startMiniCluster();
63 }
64
65
66
67
68 @AfterClass
69 public static void tearDownAfterClass() throws Exception {
70 TEST_UTIL.shutdownMiniCluster();
71 }
72
73 @Test
74 public void testRowKeyPrefixWithEmptyPrefix() throws IOException {
75 byte[] prefix = {};
76 byte[][] rowKeyPrefixes = new byte[1][];
77 rowKeyPrefixes[0] = prefix;
78 MultiRowRangeFilter filter = new MultiRowRangeFilter(rowKeyPrefixes);
79 List<RowRange> actualRanges = filter.getRowRanges();
80 List<RowRange> expectedRanges = new ArrayList<>();
81 expectedRanges.add(
82 new RowRange(HConstants.EMPTY_START_ROW, true, HConstants.EMPTY_END_ROW, false)
83 );
84 assertRangesEqual(expectedRanges, actualRanges);
85 }
86
87 @Test
88 public void testRowKeyPrefixWithLastIncrementablePrefix() throws IOException {
89 byte[] prefix = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFE};
90 byte[][] rowKeyPrefixes = new byte[1][];
91 rowKeyPrefixes[0] = prefix;
92 MultiRowRangeFilter filter = new MultiRowRangeFilter(rowKeyPrefixes);
93 List<RowRange> actualRanges = filter.getRowRanges();
94 List<RowRange> expectedRanges = new ArrayList<>();
95 final byte[] expectedStop = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFF};
96 expectedRanges.add(new RowRange(prefix, true, expectedStop , false));
97 assertRangesEqual(expectedRanges, actualRanges);
98 }
99
100 @Test
101 public void testRowKeyPrefixWithoutLastIncrementablePrefix() throws IOException {
102 byte[] prefix = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFF};
103 byte[][] rowKeyPrefixes = new byte[1][];
104 rowKeyPrefixes[0] = prefix;
105 MultiRowRangeFilter filter = new MultiRowRangeFilter(rowKeyPrefixes);
106 List<RowRange> actualRanges = filter.getRowRanges();
107 List<RowRange> expectedRanges = new ArrayList<>();
108 final byte[] expectedStop = {(byte) 0x12, (byte) 0x24};
109 expectedRanges.add(new RowRange(prefix, true, expectedStop , false));
110 assertRangesEqual(expectedRanges, actualRanges);
111 }
112
113 @Test
114 public void testRowKeyPrefixWithMergablePrefix() throws IOException {
115 byte[] prefix1 = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFE};
116 byte[] prefix2 = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFF};
117 byte[][] rowKeyPrefixes = new byte[2][];
118 rowKeyPrefixes[0] = prefix1;
119 rowKeyPrefixes[1] = prefix2;
120 MultiRowRangeFilter filter = new MultiRowRangeFilter(rowKeyPrefixes);
121 List<RowRange> actualRanges = filter.getRowRanges();
122 List<RowRange> expectedRanges = new ArrayList<>();
123 final byte[] expectedStop = {(byte) 0x12, (byte) 0x24};
124 expectedRanges.add(new RowRange(prefix1, true, expectedStop , false));
125 assertRangesEqual(expectedRanges, actualRanges);
126 }
127
128 @Test
129 public void testRanges() throws IOException {
130 byte[] key1Start = new byte[] {-3};
131 byte[] key1End = new byte[] {-2};
132
133 byte[] key2Start = new byte[] {5};
134 byte[] key2End = new byte[] {6};
135
136 byte[] badKey = new byte[] {-10};
137
138 MultiRowRangeFilter filter = new MultiRowRangeFilter(Arrays.asList(
139 new MultiRowRangeFilter.RowRange(key1Start, true, key1End, false),
140 new MultiRowRangeFilter.RowRange(key2Start, true, key2End, false)
141 ));
142 filter.filterRowKey(badKey, 0, 1);
143 assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterKeyValue(null));
144 }
145
146 @Test
147 public void testOutOfOrderScannerNextException() throws Exception {
148 MultiRowRangeFilter filter = new MultiRowRangeFilter(Arrays.asList(
149 new MultiRowRangeFilter.RowRange(Bytes.toBytes("b"), true, Bytes.toBytes("c"), true),
150 new MultiRowRangeFilter.RowRange(Bytes.toBytes("d"), true, Bytes.toBytes("e"), true)
151 ));
152 filter.filterRowKey(Bytes.toBytes("a"), 0, 1);
153 assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterKeyValue(null));
154 filter.filterRowKey(Bytes.toBytes("b"), 0, 1);
155 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterKeyValue(null));
156 filter.filterRowKey(Bytes.toBytes("c"), 0, 1);
157 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterKeyValue(null));
158 filter.filterRowKey(Bytes.toBytes("d"), 0, 1);
159 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterKeyValue(null));
160 filter.filterRowKey(Bytes.toBytes("e"), 0, 1);
161 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterKeyValue(null));
162 }
163
164 @Test
165 public void testMergeAndSortWithEmptyStartRow() throws IOException {
166 List<RowRange> ranges = new ArrayList<RowRange>();
167 ranges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(20), false));
168 ranges.add(new RowRange(Bytes.toBytes(15), true, Bytes.toBytes(40), false));
169 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges);
170 List<RowRange> expectedRanges = new ArrayList<RowRange>();
171 expectedRanges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(40), false));
172 assertRangesEqual(expectedRanges, actualRanges);
173 }
174
175 @Test
176 public void testMergeAndSortWithEmptyStopRow() throws IOException {
177 List<RowRange> ranges = new ArrayList<RowRange>();
178 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
179 ranges.add(new RowRange(Bytes.toBytes(15), true, Bytes.toBytes(""), false));
180 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(70), false));
181 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges);
182 List<RowRange> expectedRanges = new ArrayList<RowRange>();
183 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(""), false));
184 assertRangesEqual(expectedRanges, actualRanges);
185 }
186
187 @Test
188 public void testMergeAndSortWithEmptyStartRowAndStopRow() throws IOException {
189 List<RowRange> ranges = new ArrayList<RowRange>();
190 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
191 ranges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(""), false));
192 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(70), false));
193 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges);
194 List<RowRange> expectedRanges = new ArrayList<RowRange>();
195 expectedRanges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(""), false));
196 assertRangesEqual(expectedRanges, actualRanges);
197 }
198
199 @Test(expected=IllegalArgumentException.class)
200 public void testMultiRowRangeWithoutRange() throws IOException {
201 List<RowRange> ranges = new ArrayList<RowRange>();
202 new MultiRowRangeFilter(ranges);
203 }
204
205 @Test(expected=IllegalArgumentException.class)
206 public void testMultiRowRangeWithInvalidRange() throws IOException {
207 List<RowRange> ranges = new ArrayList<RowRange>();
208 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
209
210 ranges.add(new RowRange(Bytes.toBytes(80), true, Bytes.toBytes(20), false));
211 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(70), false));
212 new MultiRowRangeFilter(ranges);
213 }
214
215 @Test
216 public void testMergeAndSortWithoutOverlap() throws IOException {
217 List<RowRange> ranges = new ArrayList<RowRange>();
218 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
219 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false));
220 ranges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false));
221 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges);
222 List<RowRange> expectedRanges = new ArrayList<RowRange>();
223 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
224 expectedRanges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false));
225 expectedRanges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false));
226 assertRangesEqual(expectedRanges, actualRanges);
227 }
228
229 @Test
230 public void testMergeAndSortWithOverlap() throws IOException {
231 List<RowRange> ranges = new ArrayList<RowRange>();
232 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
233 ranges.add(new RowRange(Bytes.toBytes(15), true, Bytes.toBytes(40), false));
234 ranges.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(30), false));
235 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(50), false));
236 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(70), false));
237 ranges.add(new RowRange(Bytes.toBytes(90), true, Bytes.toBytes(100), false));
238 ranges.add(new RowRange(Bytes.toBytes(95), true, Bytes.toBytes(100), false));
239 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges);
240 List<RowRange> expectedRanges = new ArrayList<RowRange>();
241 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(70), false));
242 expectedRanges.add(new RowRange(Bytes.toBytes(90), true, Bytes.toBytes(100), false));
243 assertRangesEqual(expectedRanges, actualRanges);
244 }
245
246 @Test
247 public void testMergeAndSortWithStartRowInclusive() throws IOException {
248 List<RowRange> ranges = new ArrayList<RowRange>();
249 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
250 ranges.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(""), false));
251 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges);
252 List<RowRange> expectedRanges = new ArrayList<RowRange>();
253 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(""), false));
254 assertRangesEqual(expectedRanges, actualRanges);
255 }
256
257 @Test
258 public void testMergeAndSortWithRowExclusive() throws IOException {
259 List<RowRange> ranges = new ArrayList<RowRange>();
260 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
261 ranges.add(new RowRange(Bytes.toBytes(20), false, Bytes.toBytes(""), false));
262 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges);
263 List<RowRange> expectedRanges = new ArrayList<RowRange>();
264 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
265 expectedRanges.add(new RowRange(Bytes.toBytes(20), false, Bytes.toBytes(""), false));
266 assertRangesEqual(expectedRanges, actualRanges);
267 }
268
269 @Test
270 public void testMergeAndSortWithRowInclusive() throws IOException {
271 List<RowRange> ranges = new ArrayList<RowRange>();
272 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), true));
273 ranges.add(new RowRange(Bytes.toBytes(20), false, Bytes.toBytes(""), false));
274 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges);
275 List<RowRange> expectedRanges = new ArrayList<RowRange>();
276 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(""), false));
277 assertRangesEqual(expectedRanges, actualRanges);
278 }
279
280 public void assertRangesEqual(List<RowRange> expected, List<RowRange> actual) {
281 assertEquals(expected.size(), actual.size());
282 for(int i = 0; i < expected.size(); i++) {
283 Assert.assertTrue(Bytes.equals(expected.get(i).getStartRow(), actual.get(i).getStartRow()));
284 Assert.assertTrue(expected.get(i).isStartRowInclusive() ==
285 actual.get(i).isStartRowInclusive());
286 Assert.assertTrue(Bytes.equals(expected.get(i).getStopRow(), actual.get(i).getStopRow()));
287 Assert.assertTrue(expected.get(i).isStopRowInclusive() ==
288 actual.get(i).isStopRowInclusive());
289 }
290 }
291
292 @Test
293 public void testMultiRowRangeFilterWithRangeOverlap() throws IOException {
294 tableName = Bytes.toBytes("testMultiRowRangeFilterWithRangeOverlap");
295 HTable ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE);
296 generateRows(numRows, ht, family, qf, value);
297
298 Scan scan = new Scan();
299 scan.setMaxVersions();
300
301 List<RowRange> ranges = new ArrayList<RowRange>();
302 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
303 ranges.add(new RowRange(Bytes.toBytes(15), true, Bytes.toBytes(40), false));
304 ranges.add(new RowRange(Bytes.toBytes(65), true, Bytes.toBytes(75), false));
305 ranges.add(new RowRange(Bytes.toBytes(60), true, null, false));
306 ranges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(80), false));
307
308 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
309 scan.setFilter(filter);
310 int resultsSize = getResultsSize(ht, scan);
311 LOG.info("found " + resultsSize + " results");
312 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(40), ht);
313 List<Cell> results2 = getScanResult(Bytes.toBytes(60), Bytes.toBytes(""), ht);
314
315 assertEquals(results1.size() + results2.size(), resultsSize);
316
317 ht.close();
318 }
319
320 @Test
321 public void testMultiRowRangeFilterWithoutRangeOverlap() throws IOException {
322 tableName = Bytes.toBytes("testMultiRowRangeFilterWithoutRangeOverlap");
323 HTable ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE);
324 generateRows(numRows, ht, family, qf, value);
325
326 Scan scan = new Scan();
327 scan.setMaxVersions();
328
329 List<RowRange> ranges = new ArrayList<RowRange>();
330 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false));
331 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
332 ranges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false));
333
334 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
335 scan.setFilter(filter);
336 int resultsSize = getResultsSize(ht, scan);
337 LOG.info("found " + resultsSize + " results");
338 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(20), ht);
339 List<Cell> results2 = getScanResult(Bytes.toBytes(30), Bytes.toBytes(40), ht);
340 List<Cell> results3 = getScanResult(Bytes.toBytes(60), Bytes.toBytes(70), ht);
341
342 assertEquals(results1.size() + results2.size() + results3.size(), resultsSize);
343
344 ht.close();
345 }
346
347 @Test
348 public void testMultiRowRangeFilterWithEmptyStartRow() throws IOException {
349 tableName = Bytes.toBytes("testMultiRowRangeFilterWithEmptyStartRow");
350 HTable ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE);
351 generateRows(numRows, ht, family, qf, value);
352 Scan scan = new Scan();
353 scan.setMaxVersions();
354
355 List<RowRange> ranges = new ArrayList<RowRange>();
356 ranges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(10), false));
357 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false));
358
359 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
360 scan.setFilter(filter);
361 int resultsSize = getResultsSize(ht, scan);
362 List<Cell> results1 = getScanResult(Bytes.toBytes(""), Bytes.toBytes(10), ht);
363 List<Cell> results2 = getScanResult(Bytes.toBytes(30), Bytes.toBytes(40), ht);
364 assertEquals(results1.size() + results2.size(), resultsSize);
365
366 ht.close();
367 }
368
369 @Test
370 public void testMultiRowRangeFilterWithEmptyStopRow() throws IOException {
371 tableName = Bytes.toBytes("testMultiRowRangeFilterWithEmptyStopRow");
372 HTable ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE);
373 generateRows(numRows, ht, family, qf, value);
374 Scan scan = new Scan();
375 scan.setMaxVersions();
376
377 List<RowRange> ranges = new ArrayList<RowRange>();
378 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(""), false));
379 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false));
380
381 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
382 scan.setFilter(filter);
383 int resultsSize = getResultsSize(ht, scan);
384 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(""), ht);
385 assertEquals(results1.size(), resultsSize);
386
387 ht.close();
388 }
389
390 @Test
391 public void testMultiRowRangeFilterWithInclusive() throws IOException {
392 tableName = Bytes.toBytes("testMultiRowRangeFilterWithInclusive");
393 HTable ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE);
394 generateRows(numRows, ht, family, qf, value);
395
396 Scan scan = new Scan();
397 scan.setMaxVersions();
398
399 List<RowRange> ranges = new ArrayList<RowRange>();
400 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
401 ranges.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(40), false));
402 ranges.add(new RowRange(Bytes.toBytes(65), true, Bytes.toBytes(75), false));
403 ranges.add(new RowRange(Bytes.toBytes(60), true, null, false));
404 ranges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(80), false));
405
406 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
407 scan.setFilter(filter);
408 int resultsSize = getResultsSize(ht, scan);
409 LOG.info("found " + resultsSize + " results");
410 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(40), ht);
411 List<Cell> results2 = getScanResult(Bytes.toBytes(60), Bytes.toBytes(""), ht);
412
413 assertEquals(results1.size() + results2.size(), resultsSize);
414
415 ht.close();
416 }
417
418 @Test
419 public void testMultiRowRangeFilterWithExclusive() throws IOException {
420 tableName = Bytes.toBytes("testMultiRowRangeFilterWithExclusive");
421 HTable ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE);
422 generateRows(numRows, ht, family, qf, value);
423
424 Scan scan = new Scan();
425 scan.setMaxVersions();
426
427 List<RowRange> ranges = new ArrayList<RowRange>();
428 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
429 ranges.add(new RowRange(Bytes.toBytes(20), false, Bytes.toBytes(40), false));
430 ranges.add(new RowRange(Bytes.toBytes(65), true, Bytes.toBytes(75), false));
431
432 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
433 scan.setFilter(filter);
434 int resultsSize = getResultsSize(ht, scan);
435 LOG.info("found " + resultsSize + " results");
436 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(40), ht);
437 List<Cell> results2 = getScanResult(Bytes.toBytes(65), Bytes.toBytes(75), ht);
438
439 assertEquals((results1.size() - 1) + results2.size(), resultsSize);
440
441 ht.close();
442 }
443
444 @Test
445 public void testMultiRowRangeWithFilterListAndOperator() throws IOException {
446 tableName = Bytes.toBytes("TestMultiRowRangeFilterWithFilterListAndOperator");
447 HTable ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE);
448 generateRows(numRows, ht, family, qf, value);
449
450 Scan scan = new Scan();
451 scan.setMaxVersions();
452
453 List<RowRange> ranges1 = new ArrayList<RowRange>();
454 ranges1.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
455 ranges1.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false));
456 ranges1.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false));
457
458 MultiRowRangeFilter filter1 = new MultiRowRangeFilter(ranges1);
459
460 List<RowRange> ranges2 = new ArrayList<RowRange>();
461 ranges2.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(40), false));
462 ranges2.add(new RowRange(Bytes.toBytes(80), true, Bytes.toBytes(90), false));
463
464 MultiRowRangeFilter filter2 = new MultiRowRangeFilter(ranges2);
465
466 FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
467 filterList.addFilter(filter1);
468 filterList.addFilter(filter2);
469 scan.setFilter(filterList);
470 int resultsSize = getResultsSize(ht, scan);
471 LOG.info("found " + resultsSize + " results");
472 List<Cell> results1 = getScanResult(Bytes.toBytes(30), Bytes.toBytes(40), ht);
473
474 assertEquals(results1.size(), resultsSize);
475
476 ht.close();
477 }
478
479 @Test
480 public void testMultiRowRangeWithFilterListOrOperator() throws IOException {
481 tableName = Bytes.toBytes("TestMultiRowRangeFilterWithFilterListOrOperator");
482 HTable ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE);
483 generateRows(numRows, ht, family, qf, value);
484
485 Scan scan = new Scan();
486 scan.setMaxVersions();
487
488 List<RowRange> ranges1 = new ArrayList<RowRange>();
489 ranges1.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false));
490 ranges1.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false));
491 ranges1.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false));
492
493 MultiRowRangeFilter filter1 = new MultiRowRangeFilter(ranges1);
494
495 List<RowRange> ranges2 = new ArrayList<RowRange>();
496 ranges2.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(40), false));
497 ranges2.add(new RowRange(Bytes.toBytes(80), true, Bytes.toBytes(90), false));
498
499 MultiRowRangeFilter filter2 = new MultiRowRangeFilter(ranges2);
500
501 FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE);
502 filterList.addFilter(filter1);
503 filterList.addFilter(filter2);
504 scan.setFilter(filterList);
505 int resultsSize = getResultsSize(ht, scan);
506 LOG.info("found " + resultsSize + " results");
507 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(40), ht);
508 List<Cell> results2 = getScanResult(Bytes.toBytes(60), Bytes.toBytes(70), ht);
509 List<Cell> results3 = getScanResult(Bytes.toBytes(80), Bytes.toBytes(90), ht);
510
511 assertEquals(results1.size() + results2.size() + results3.size(),resultsSize);
512
513 ht.close();
514 }
515
516 @Test
517 public void testOneRowRange() throws IOException {
518 tableName = Bytes.toBytes("testOneRowRange");
519 HTable ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE);
520 generateRows(numRows, ht, family, qf, value);
521 ArrayList<MultiRowRangeFilter.RowRange> rowRangesList = new ArrayList<>();
522 rowRangesList
523 .add(new MultiRowRangeFilter.RowRange(Bytes.toBytes(50), true, Bytes.toBytes(50), true));
524 Scan scan = new Scan();
525 scan.setFilter(new MultiRowRangeFilter(rowRangesList));
526 int resultsSize = getResultsSize(ht, scan);
527 assertEquals(1, resultsSize);
528 rowRangesList.clear();
529 rowRangesList
530 .add(new MultiRowRangeFilter.RowRange(Bytes.toBytes(50), true, Bytes.toBytes(51), false));
531 scan = new Scan();
532 scan.setFilter(new MultiRowRangeFilter(rowRangesList));
533 resultsSize = getResultsSize(ht, scan);
534 assertEquals(1, resultsSize);
535 rowRangesList.clear();
536 rowRangesList
537 .add(new MultiRowRangeFilter.RowRange(Bytes.toBytes(50), true, Bytes.toBytes(51), true));
538 scan = new Scan();
539 scan.setFilter(new MultiRowRangeFilter(rowRangesList));
540 resultsSize = getResultsSize(ht, scan);
541 assertEquals(2, resultsSize);
542 ht.close();
543 }
544
545 @Test
546 public void testReverseMultiRowRangeFilterWithinTable() throws IOException {
547 tableName = Bytes.toBytes("testReverseMultiRowRangeFilterWithinTable");
548 HTable ht = TEST_UTIL.createTable(tableName, family);
549 generateRows(numRows, ht, family, qf, value);
550
551 Scan scan = new Scan();
552 scan.setReversed(true);
553 List<RowRange> ranges = Arrays.asList(
554 new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(30), true),
555 new RowRange(Bytes.toBytes(50), true, Bytes.toBytes(60), true)
556 );
557 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
558 scan.setFilter(filter);
559
560 List<Integer> expectedResults = new ArrayList<>();
561 for (int i = 60; i >= 50; i--) {
562 expectedResults.add(i);
563 }
564 for (int i = 30; i >= 20; i--) {
565 expectedResults.add(i);
566 }
567
568 List<Cell> results = getResults(ht, scan);
569 List<Integer> actualResults = new ArrayList<>();
570 StringBuilder sb = new StringBuilder();
571 for (Cell result : results) {
572 int observedValue = Bytes.toInt(
573 result.getRowArray(), result.getRowOffset(), result.getRowLength());
574 actualResults.add(observedValue);
575 if (sb.length() > 0) {
576 sb.append(", ");
577 }
578 sb.append(observedValue);
579 }
580 assertEquals("Saw results: " + sb.toString(), 22, results.size());
581 }
582
583 @Test
584 public void testReverseMultiRowRangeFilterIncludingMaxRow() throws IOException {
585 tableName = Bytes.toBytes("testReverseMultiRowRangeFilterIncludingMaxRow");
586 HTable ht = TEST_UTIL.createTable(tableName, family);
587 for (String rowkey : Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h")) {
588 byte[] row = Bytes.toBytes(rowkey);
589 Put p = new Put(row);
590 p.addColumn(family, qf, value);
591 ht.put(p);
592 }
593 TEST_UTIL.flush();
594
595 Scan scan = new Scan();
596 scan.setReversed(true);
597 List<RowRange> ranges = Arrays.asList(
598 new RowRange(Bytes.toBytes("b"), true, Bytes.toBytes("c"), true),
599 new RowRange(Bytes.toBytes("f"), true, Bytes.toBytes("h"), true)
600 );
601 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
602 scan.setFilter(filter);
603
604 List<String> expected = Arrays.asList("h", "g", "f", "c", "b");
605 List<String> actual = new ArrayList<>();
606 for (Cell cell : getResults(ht, scan)) {
607 actual.add(Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
608 }
609
610 assertEquals(expected, actual);
611 }
612
613 @Test
614 public void testReverseMultiRowRangeFilterIncludingMinRow() throws IOException {
615 tableName = Bytes.toBytes("testReverseMultiRowRangeFilterIncludingMinRow");
616 HTable ht = TEST_UTIL.createTable(tableName, family);
617 for (String rowkey : Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h")) {
618 byte[] row = Bytes.toBytes(rowkey);
619 Put p = new Put(row);
620 p.addColumn(family, qf, value);
621 ht.put(p);
622 }
623 TEST_UTIL.flush();
624
625 Scan scan = new Scan();
626 scan.setReversed(true);
627 List<RowRange> ranges = Arrays.asList(
628 new RowRange(Bytes.toBytes("a"), true, Bytes.toBytes("c"), true),
629 new RowRange(Bytes.toBytes("f"), true, Bytes.toBytes("g"), true)
630 );
631 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
632 scan.setFilter(filter);
633
634 List<String> expected = Arrays.asList("g", "f", "c", "b", "a");
635 List<String> actual = new ArrayList<>();
636 for (Cell cell : getResults(ht, scan)) {
637 actual.add(Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
638 }
639
640 assertEquals(expected, actual);
641 }
642
643 @Test
644 public void testReverseMultiRowRangeFilterIncludingMinAndMaxRow() throws IOException {
645 tableName = Bytes.toBytes("testReverseMultiRowRangeFilterIncludingMinAndMaxRow");
646 HTable ht = TEST_UTIL.createTable(tableName, family);
647 for (String rowkey : Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h")) {
648 byte[] row = Bytes.toBytes(rowkey);
649 Put p = new Put(row);
650 p.addColumn(family, qf, value);
651 ht.put(p);
652 }
653 TEST_UTIL.flush();
654
655 Scan scan = new Scan();
656 scan.setReversed(true);
657 List<RowRange> ranges = Arrays.asList(
658 new RowRange(Bytes.toBytes("a"), true, Bytes.toBytes("c"), true),
659 new RowRange(Bytes.toBytes("f"), true, Bytes.toBytes("h"), true)
660 );
661 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges);
662 scan.setFilter(filter);
663
664 List<String> expected = Arrays.asList("h", "g", "f", "c", "b", "a");
665 List<String> actual = new ArrayList<>();
666 for (Cell cell : getResults(ht, scan)) {
667 actual.add(Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
668 }
669
670 assertEquals(expected, actual);
671 }
672
673 private void generateRows(int numberOfRows, HTable ht, byte[] family, byte[] qf, byte[] value)
674 throws IOException {
675 for (int i = 0; i < numberOfRows; i++) {
676 byte[] row = Bytes.toBytes(i);
677 Put p = new Put(row);
678 p.add(family, qf, value);
679 ht.put(p);
680 }
681 TEST_UTIL.flush();
682 }
683
684 private List<Cell> getScanResult(byte[] startRow, byte[] stopRow, HTable ht) throws IOException {
685 Scan scan = new Scan();
686 scan.setMaxVersions();
687 if(!Bytes.toString(startRow).isEmpty()) {
688 scan.setStartRow(startRow);
689 }
690 if(!Bytes.toString(stopRow).isEmpty()) {
691 scan.setStopRow(stopRow);
692 }
693 ResultScanner scanner = ht.getScanner(scan);
694 List<Cell> kvList = new ArrayList<Cell>();
695 Result r;
696 while ((r = scanner.next()) != null) {
697 for (Cell kv : r.listCells()) {
698 kvList.add(kv);
699 }
700 }
701 scanner.close();
702 return kvList;
703 }
704
705 private List<Cell> getResults(HTable ht, Scan scan) throws IOException {
706 ResultScanner scanner = ht.getScanner(scan);
707 List<Cell> results = new ArrayList<Cell>();
708 Result r;
709 while ((r = scanner.next()) != null) {
710 for (Cell kv : r.listCells()) {
711 results.add(kv);
712 }
713 }
714 scanner.close();
715 return results;
716 }
717
718 private int getResultsSize(HTable ht, Scan scan) throws IOException {
719 return getResults(ht, scan).size();
720 }
721 }