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.filter; 019 020import static org.junit.Assert.assertEquals; 021 022import java.io.IOException; 023import java.util.ArrayList; 024import java.util.Arrays; 025import java.util.List; 026import org.apache.hadoop.hbase.Cell; 027import org.apache.hadoop.hbase.HBaseClassTestRule; 028import org.apache.hadoop.hbase.HBaseTestingUtility; 029import org.apache.hadoop.hbase.HConstants; 030import org.apache.hadoop.hbase.KeyValueUtil; 031import org.apache.hadoop.hbase.TableName; 032import org.apache.hadoop.hbase.client.Put; 033import org.apache.hadoop.hbase.client.Result; 034import org.apache.hadoop.hbase.client.ResultScanner; 035import org.apache.hadoop.hbase.client.Scan; 036import org.apache.hadoop.hbase.client.Table; 037import org.apache.hadoop.hbase.filter.MultiRowRangeFilter.RowRange; 038import org.apache.hadoop.hbase.testclassification.LargeTests; 039import org.apache.hadoop.hbase.util.Bytes; 040import org.junit.AfterClass; 041import org.junit.Assert; 042import org.junit.BeforeClass; 043import org.junit.ClassRule; 044import org.junit.Rule; 045import org.junit.Test; 046import org.junit.experimental.categories.Category; 047import org.junit.rules.TestName; 048import org.slf4j.Logger; 049import org.slf4j.LoggerFactory; 050 051@Category(LargeTests.class) 052public class TestMultiRowRangeFilter { 053 054 @ClassRule 055 public static final HBaseClassTestRule CLASS_RULE = 056 HBaseClassTestRule.forClass(TestMultiRowRangeFilter.class); 057 058 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility(); 059 private static final Logger LOG = LoggerFactory.getLogger(TestMultiRowRangeFilter.class); 060 private byte[] family = Bytes.toBytes("family"); 061 private byte[] qf = Bytes.toBytes("qf"); 062 private byte[] value = Bytes.toBytes("val"); 063 private TableName tableName; 064 private int numRows = 100; 065 066 @Rule 067 public TestName name = new TestName(); 068 069 /** 070 * @throws Exception 071 */ 072 @BeforeClass 073 public static void setUpBeforeClass() throws Exception { 074 TEST_UTIL.startMiniCluster(); 075 } 076 077 /** 078 * @throws Exception 079 */ 080 @AfterClass 081 public static void tearDownAfterClass() throws Exception { 082 TEST_UTIL.shutdownMiniCluster(); 083 } 084 085 @Test 086 public void testRowKeyPrefixWithEmptyPrefix() throws IOException { 087 byte[] prefix = {}; 088 byte[][] rowKeyPrefixes = new byte[1][]; 089 rowKeyPrefixes[0] = prefix; 090 MultiRowRangeFilter filter = new MultiRowRangeFilter(rowKeyPrefixes); 091 List<RowRange> actualRanges = filter.getRowRanges(); 092 List<RowRange> expectedRanges = new ArrayList<>(); 093 expectedRanges.add( 094 new RowRange(HConstants.EMPTY_START_ROW, true, HConstants.EMPTY_END_ROW, false) 095 ); 096 assertRangesEqual(expectedRanges, actualRanges); 097 } 098 099 @Test 100 public void testRowKeyPrefixWithLastIncrementablePrefix() throws IOException { 101 byte[] prefix = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFE}; 102 byte[][] rowKeyPrefixes = new byte[1][]; 103 rowKeyPrefixes[0] = prefix; 104 MultiRowRangeFilter filter = new MultiRowRangeFilter(rowKeyPrefixes); 105 List<RowRange> actualRanges = filter.getRowRanges(); 106 List<RowRange> expectedRanges = new ArrayList<>(); 107 final byte[] expectedStop = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFF}; 108 expectedRanges.add(new RowRange(prefix, true, expectedStop , false)); 109 assertRangesEqual(expectedRanges, actualRanges); 110 } 111 112 @Test 113 public void testRowKeyPrefixWithoutLastIncrementablePrefix() throws IOException { 114 byte[] prefix = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFF}; 115 byte[][] rowKeyPrefixes = new byte[1][]; 116 rowKeyPrefixes[0] = prefix; 117 MultiRowRangeFilter filter = new MultiRowRangeFilter(rowKeyPrefixes); 118 List<RowRange> actualRanges = filter.getRowRanges(); 119 List<RowRange> expectedRanges = new ArrayList<>(); 120 final byte[] expectedStop = {(byte) 0x12, (byte) 0x24}; 121 expectedRanges.add(new RowRange(prefix, true, expectedStop , false)); 122 assertRangesEqual(expectedRanges, actualRanges); 123 } 124 125 @Test 126 public void testRowKeyPrefixWithMergablePrefix() throws IOException { 127 byte[] prefix1 = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFE}; 128 byte[] prefix2 = {(byte) 0x12, (byte) 0x23, (byte) 0xFF, (byte) 0xFF}; 129 byte[][] rowKeyPrefixes = new byte[2][]; 130 rowKeyPrefixes[0] = prefix1; 131 rowKeyPrefixes[1] = prefix2; 132 MultiRowRangeFilter filter = new MultiRowRangeFilter(rowKeyPrefixes); 133 List<RowRange> actualRanges = filter.getRowRanges(); 134 List<RowRange> expectedRanges = new ArrayList<>(); 135 final byte[] expectedStop = {(byte) 0x12, (byte) 0x24}; 136 expectedRanges.add(new RowRange(prefix1, true, expectedStop , false)); 137 assertRangesEqual(expectedRanges, actualRanges); 138 } 139 140 @Test 141 public void testRanges() throws IOException { 142 byte[] key1Start = new byte[] {-3}; 143 byte[] key1End = new byte[] {-2}; 144 145 byte[] key2Start = new byte[] {5}; 146 byte[] key2End = new byte[] {6}; 147 148 byte[] badKey = new byte[] {-10}; 149 150 MultiRowRangeFilter filter = new MultiRowRangeFilter(Arrays.asList( 151 new MultiRowRangeFilter.RowRange(key1Start, true, key1End, false), 152 new MultiRowRangeFilter.RowRange(key2Start, true, key2End, false) 153 )); 154 filter.filterRowKey(KeyValueUtil.createFirstOnRow(badKey)); 155 /* 156 * FAILS -- includes BAD key! 157 * Expected :SEEK_NEXT_USING_HINT 158 * Actual :INCLUDE 159 * */ 160 assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterCell(null)); 161 } 162 163 @Test 164 public void testOutOfOrderScannerNextException() throws Exception { 165 MultiRowRangeFilter filter = new MultiRowRangeFilter(Arrays.asList( 166 new MultiRowRangeFilter.RowRange(Bytes.toBytes("b"), true, Bytes.toBytes("c"), true), 167 new MultiRowRangeFilter.RowRange(Bytes.toBytes("d"), true, Bytes.toBytes("e"), true) 168 )); 169 filter.filterRowKey(KeyValueUtil.createFirstOnRow(Bytes.toBytes("a"))); 170 assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterCell(null)); 171 filter.filterRowKey(KeyValueUtil.createFirstOnRow(Bytes.toBytes("b"))); 172 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(null)); 173 filter.filterRowKey(KeyValueUtil.createFirstOnRow(Bytes.toBytes("c"))); 174 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(null)); 175 filter.filterRowKey(KeyValueUtil.createFirstOnRow(Bytes.toBytes("d"))); 176 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(null)); 177 filter.filterRowKey(KeyValueUtil.createFirstOnRow(Bytes.toBytes("e"))); 178 assertEquals(Filter.ReturnCode.INCLUDE, filter.filterCell(null)); 179 } 180 181 @Test 182 public void testMergeAndSortWithEmptyStartRow() throws IOException { 183 List<RowRange> ranges = new ArrayList<>(); 184 ranges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(20), false)); 185 ranges.add(new RowRange(Bytes.toBytes(15), true, Bytes.toBytes(40), false)); 186 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges); 187 List<RowRange> expectedRanges = new ArrayList<>(); 188 expectedRanges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(40), false)); 189 assertRangesEqual(expectedRanges, actualRanges); 190 } 191 192 @Test 193 public void testMergeAndSortWithEmptyStopRow() throws IOException { 194 List<RowRange> ranges = new ArrayList<>(); 195 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 196 ranges.add(new RowRange(Bytes.toBytes(15), true, Bytes.toBytes(""), false)); 197 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(70), false)); 198 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges); 199 List<RowRange> expectedRanges = new ArrayList<>(); 200 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(""), false)); 201 assertRangesEqual(expectedRanges, actualRanges); 202 } 203 204 @Test 205 public void testMergeAndSortWithEmptyStartRowAndStopRow() throws IOException { 206 List<RowRange> ranges = new ArrayList<>(); 207 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 208 ranges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(""), false)); 209 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(70), false)); 210 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges); 211 List<RowRange> expectedRanges = new ArrayList<>(); 212 expectedRanges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(""), false)); 213 assertRangesEqual(expectedRanges, actualRanges); 214 } 215 216 @Test(expected=IllegalArgumentException.class) 217 public void testMultiRowRangeWithoutRange() throws IOException { 218 List<RowRange> ranges = new ArrayList<>(); 219 new MultiRowRangeFilter(ranges); 220 } 221 222 @Test(expected=IllegalArgumentException.class) 223 public void testMultiRowRangeWithInvalidRange() throws IOException { 224 List<RowRange> ranges = new ArrayList<>(); 225 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 226 // the start row larger than the stop row 227 ranges.add(new RowRange(Bytes.toBytes(80), true, Bytes.toBytes(20), false)); 228 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(70), false)); 229 new MultiRowRangeFilter(ranges); 230 } 231 232 @Test 233 public void testMergeAndSortWithoutOverlap() throws IOException { 234 List<RowRange> ranges = new ArrayList<>(); 235 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 236 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false)); 237 ranges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false)); 238 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges); 239 List<RowRange> expectedRanges = new ArrayList<>(); 240 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 241 expectedRanges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false)); 242 expectedRanges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false)); 243 assertRangesEqual(expectedRanges, actualRanges); 244 } 245 246 @Test 247 public void testMergeAndSortWithOverlap() throws IOException { 248 List<RowRange> ranges = new ArrayList<>(); 249 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 250 ranges.add(new RowRange(Bytes.toBytes(15), true, Bytes.toBytes(40), false)); 251 ranges.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(30), false)); 252 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(50), false)); 253 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(70), false)); 254 ranges.add(new RowRange(Bytes.toBytes(90), true, Bytes.toBytes(100), false)); 255 ranges.add(new RowRange(Bytes.toBytes(95), true, Bytes.toBytes(100), false)); 256 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges); 257 List<RowRange> expectedRanges = new ArrayList<>(); 258 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(70), false)); 259 expectedRanges.add(new RowRange(Bytes.toBytes(90), true, Bytes.toBytes(100), false)); 260 assertRangesEqual(expectedRanges, actualRanges); 261 } 262 263 @Test 264 public void testMergeAndSortWithStartRowInclusive() throws IOException { 265 List<RowRange> ranges = new ArrayList<>(); 266 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 267 ranges.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(""), false)); 268 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges); 269 List<RowRange> expectedRanges = new ArrayList<>(); 270 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(""), false)); 271 assertRangesEqual(expectedRanges, actualRanges); 272 } 273 274 @Test 275 public void testMergeAndSortWithRowExclusive() throws IOException { 276 List<RowRange> ranges = new ArrayList<>(); 277 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 278 ranges.add(new RowRange(Bytes.toBytes(20), false, Bytes.toBytes(""), false)); 279 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges); 280 List<RowRange> expectedRanges = new ArrayList<>(); 281 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 282 expectedRanges.add(new RowRange(Bytes.toBytes(20), false, Bytes.toBytes(""), false)); 283 assertRangesEqual(expectedRanges, actualRanges); 284 } 285 286 @Test 287 public void testMergeAndSortWithRowInclusive() throws IOException { 288 List<RowRange> ranges = new ArrayList<>(); 289 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), true)); 290 ranges.add(new RowRange(Bytes.toBytes(20), false, Bytes.toBytes(""), false)); 291 List<RowRange> actualRanges = MultiRowRangeFilter.sortAndMerge(ranges); 292 List<RowRange> expectedRanges = new ArrayList<>(); 293 expectedRanges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(""), false)); 294 assertRangesEqual(expectedRanges, actualRanges); 295 } 296 297 public void assertRangesEqual(List<RowRange> expected, List<RowRange> actual) { 298 assertEquals(expected.size(), actual.size()); 299 for(int i = 0; i < expected.size(); i++) { 300 Assert.assertTrue(Bytes.equals(expected.get(i).getStartRow(), actual.get(i).getStartRow())); 301 Assert.assertTrue(expected.get(i).isStartRowInclusive() == 302 actual.get(i).isStartRowInclusive()); 303 Assert.assertTrue(Bytes.equals(expected.get(i).getStopRow(), actual.get(i).getStopRow())); 304 Assert.assertTrue(expected.get(i).isStopRowInclusive() == 305 actual.get(i).isStopRowInclusive()); 306 } 307 } 308 309 @Test 310 public void testMultiRowRangeFilterWithRangeOverlap() throws IOException { 311 tableName = TableName.valueOf(name.getMethodName()); 312 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 313 generateRows(numRows, ht, family, qf, value); 314 315 Scan scan = new Scan(); 316 scan.setMaxVersions(); 317 318 List<RowRange> ranges = new ArrayList<>(); 319 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 320 ranges.add(new RowRange(Bytes.toBytes(15), true, Bytes.toBytes(40), false)); 321 ranges.add(new RowRange(Bytes.toBytes(65), true, Bytes.toBytes(75), false)); 322 ranges.add(new RowRange(Bytes.toBytes(60), true, null, false)); 323 ranges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(80), false)); 324 325 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 326 scan.setFilter(filter); 327 int resultsSize = getResultsSize(ht, scan); 328 LOG.info("found " + resultsSize + " results"); 329 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(40), ht); 330 List<Cell> results2 = getScanResult(Bytes.toBytes(60), Bytes.toBytes(""), ht); 331 332 assertEquals(results1.size() + results2.size(), resultsSize); 333 334 ht.close(); 335 } 336 337 @Test 338 public void testMultiRowRangeFilterWithoutRangeOverlap() throws IOException { 339 tableName = TableName.valueOf(name.getMethodName()); 340 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 341 generateRows(numRows, ht, family, qf, value); 342 343 Scan scan = new Scan(); 344 scan.setMaxVersions(); 345 346 List<RowRange> ranges = new ArrayList<>(); 347 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false)); 348 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 349 ranges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false)); 350 351 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 352 scan.setFilter(filter); 353 int resultsSize = getResultsSize(ht, scan); 354 LOG.info("found " + resultsSize + " results"); 355 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(20), ht); 356 List<Cell> results2 = getScanResult(Bytes.toBytes(30), Bytes.toBytes(40), ht); 357 List<Cell> results3 = getScanResult(Bytes.toBytes(60), Bytes.toBytes(70), ht); 358 359 assertEquals(results1.size() + results2.size() + results3.size(), resultsSize); 360 361 ht.close(); 362 } 363 364 @Test 365 public void testMultiRowRangeFilterWithEmptyStartRow() throws IOException { 366 tableName = TableName.valueOf(name.getMethodName()); 367 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 368 generateRows(numRows, ht, family, qf, value); 369 Scan scan = new Scan(); 370 scan.setMaxVersions(); 371 372 List<RowRange> ranges = new ArrayList<>(); 373 ranges.add(new RowRange(Bytes.toBytes(""), true, Bytes.toBytes(10), false)); 374 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false)); 375 376 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 377 scan.setFilter(filter); 378 int resultsSize = getResultsSize(ht, scan); 379 List<Cell> results1 = getScanResult(Bytes.toBytes(""), Bytes.toBytes(10), ht); 380 List<Cell> results2 = getScanResult(Bytes.toBytes(30), Bytes.toBytes(40), ht); 381 assertEquals(results1.size() + results2.size(), resultsSize); 382 383 ht.close(); 384 } 385 386 @Test 387 public void testMultiRowRangeFilterWithEmptyStopRow() throws IOException { 388 tableName = TableName.valueOf(name.getMethodName()); 389 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 390 generateRows(numRows, ht, family, qf, value); 391 Scan scan = new Scan(); 392 scan.setMaxVersions(); 393 394 List<RowRange> ranges = new ArrayList<>(); 395 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(""), false)); 396 ranges.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false)); 397 398 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 399 scan.setFilter(filter); 400 int resultsSize = getResultsSize(ht, scan); 401 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(""), ht); 402 assertEquals(results1.size(), resultsSize); 403 404 ht.close(); 405 } 406 407 @Test 408 public void testMultiRowRangeFilterWithInclusive() throws IOException { 409 tableName = TableName.valueOf(name.getMethodName()); 410 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 411 generateRows(numRows, ht, family, qf, value); 412 413 Scan scan = new Scan(); 414 scan.setMaxVersions(); 415 416 List<RowRange> ranges = new ArrayList<>(); 417 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 418 ranges.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(40), false)); 419 ranges.add(new RowRange(Bytes.toBytes(65), true, Bytes.toBytes(75), false)); 420 ranges.add(new RowRange(Bytes.toBytes(60), true, null, false)); 421 ranges.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(80), false)); 422 423 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 424 scan.setFilter(filter); 425 int resultsSize = getResultsSize(ht, scan); 426 LOG.info("found " + resultsSize + " results"); 427 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(40), ht); 428 List<Cell> results2 = getScanResult(Bytes.toBytes(60), Bytes.toBytes(""), ht); 429 430 assertEquals(results1.size() + results2.size(), resultsSize); 431 432 ht.close(); 433 } 434 435 @Test 436 public void testMultiRowRangeFilterWithExclusive() throws IOException { 437 tableName = TableName.valueOf(name.getMethodName()); 438 TEST_UTIL.getConfiguration().setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, 6000000); 439 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 440 ht.setReadRpcTimeout(600000); 441 ht.setOperationTimeout(6000000); 442 generateRows(numRows, ht, family, qf, value); 443 444 Scan scan = new Scan(); 445 scan.setMaxVersions(); 446 447 List<RowRange> ranges = new ArrayList<>(); 448 ranges.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 449 ranges.add(new RowRange(Bytes.toBytes(20), false, Bytes.toBytes(40), false)); 450 ranges.add(new RowRange(Bytes.toBytes(65), true, Bytes.toBytes(75), false)); 451 452 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 453 scan.setFilter(filter); 454 int resultsSize = getResultsSize(ht, scan); 455 LOG.info("found " + resultsSize + " results"); 456 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(40), ht); 457 List<Cell> results2 = getScanResult(Bytes.toBytes(65), Bytes.toBytes(75), ht); 458 459 assertEquals((results1.size() - 1) + results2.size(), resultsSize); 460 461 ht.close(); 462 } 463 464 @Test 465 public void testMultiRowRangeWithFilterListAndOperator() throws IOException { 466 tableName = TableName.valueOf(name.getMethodName()); 467 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 468 generateRows(numRows, ht, family, qf, value); 469 470 Scan scan = new Scan(); 471 scan.setMaxVersions(); 472 473 List<RowRange> ranges1 = new ArrayList<>(); 474 ranges1.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 475 ranges1.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false)); 476 ranges1.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false)); 477 478 MultiRowRangeFilter filter1 = new MultiRowRangeFilter(ranges1); 479 480 List<RowRange> ranges2 = new ArrayList<>(); 481 ranges2.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(40), false)); 482 ranges2.add(new RowRange(Bytes.toBytes(80), true, Bytes.toBytes(90), false)); 483 484 MultiRowRangeFilter filter2 = new MultiRowRangeFilter(ranges2); 485 486 FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL); 487 filterList.addFilter(filter1); 488 filterList.addFilter(filter2); 489 scan.setFilter(filterList); 490 int resultsSize = getResultsSize(ht, scan); 491 LOG.info("found " + resultsSize + " results"); 492 List<Cell> results1 = getScanResult(Bytes.toBytes(30), Bytes.toBytes(40), ht); 493 494 assertEquals(results1.size(), resultsSize); 495 496 ht.close(); 497 } 498 499 @Test 500 public void testMultiRowRangeWithFilterListOrOperator() throws IOException { 501 tableName = TableName.valueOf(name.getMethodName()); 502 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 503 generateRows(numRows, ht, family, qf, value); 504 505 Scan scan = new Scan(); 506 scan.setMaxVersions(); 507 508 List<RowRange> ranges1 = new ArrayList<>(); 509 ranges1.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false)); 510 ranges1.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 511 ranges1.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false)); 512 513 MultiRowRangeFilter filter1 = new MultiRowRangeFilter(ranges1); 514 515 List<RowRange> ranges2 = new ArrayList<>(); 516 ranges2.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(40), false)); 517 ranges2.add(new RowRange(Bytes.toBytes(80), true, Bytes.toBytes(90), false)); 518 519 MultiRowRangeFilter filter2 = new MultiRowRangeFilter(ranges2); 520 521 FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE); 522 filterList.addFilter(filter1); 523 filterList.addFilter(filter2); 524 scan.setFilter(filterList); 525 int resultsSize = getResultsSize(ht, scan); 526 LOG.info("found " + resultsSize + " results"); 527 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(40), ht); 528 List<Cell> results2 = getScanResult(Bytes.toBytes(60), Bytes.toBytes(70), ht); 529 List<Cell> results3 = getScanResult(Bytes.toBytes(80), Bytes.toBytes(90), ht); 530 531 assertEquals(results1.size() + results2.size() + results3.size(),resultsSize); 532 533 ht.close(); 534 } 535 536 @Test 537 public void testOneRowRange() throws IOException { 538 tableName = TableName.valueOf(name.getMethodName()); 539 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 540 generateRows(numRows, ht, family, qf, value); 541 ArrayList<MultiRowRangeFilter.RowRange> rowRangesList = new ArrayList<>(); 542 rowRangesList 543 .add(new MultiRowRangeFilter.RowRange(Bytes.toBytes(50), true, Bytes.toBytes(50), true)); 544 Scan scan = new Scan(); 545 scan.setFilter(new MultiRowRangeFilter(rowRangesList)); 546 int resultsSize = getResultsSize(ht, scan); 547 assertEquals(1, resultsSize); 548 rowRangesList.clear(); 549 rowRangesList 550 .add(new MultiRowRangeFilter.RowRange(Bytes.toBytes(50), true, Bytes.toBytes(51), false)); 551 scan = new Scan(); 552 scan.setFilter(new MultiRowRangeFilter(rowRangesList)); 553 resultsSize = getResultsSize(ht, scan); 554 assertEquals(1, resultsSize); 555 rowRangesList.clear(); 556 rowRangesList 557 .add(new MultiRowRangeFilter.RowRange(Bytes.toBytes(50), true, Bytes.toBytes(51), true)); 558 scan = new Scan(); 559 scan.setFilter(new MultiRowRangeFilter(rowRangesList)); 560 resultsSize = getResultsSize(ht, scan); 561 assertEquals(2, resultsSize); 562 ht.close(); 563 } 564 565 @Test 566 public void testReverseMultiRowRangeFilterWithinTable() throws IOException { 567 tableName = TableName.valueOf(name.getMethodName()); 568 Table ht = TEST_UTIL.createTable(tableName, family); 569 generateRows(numRows, ht, family, qf, value); 570 571 Scan scan = new Scan(); 572 scan.setReversed(true); 573 List<RowRange> ranges = Arrays.asList( 574 new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(30), true), 575 new RowRange(Bytes.toBytes(50), true, Bytes.toBytes(60), true) 576 ); 577 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 578 scan.setFilter(filter); 579 580 List<Integer> expectedResults = new ArrayList<>(); 581 for (int i = 60; i >= 50; i--) { 582 expectedResults.add(i); 583 } 584 for (int i = 30; i >= 20; i--) { 585 expectedResults.add(i); 586 } 587 588 List<Cell> results = getResults(ht, scan); 589 List<Integer> actualResults = new ArrayList<>(); 590 StringBuilder sb = new StringBuilder(); 591 for (Cell result : results) { 592 int observedValue = Bytes.toInt( 593 result.getRowArray(), result.getRowOffset(), result.getRowLength()); 594 actualResults.add(observedValue); 595 if (sb.length() > 0) { 596 sb.append(", "); 597 } 598 sb.append(observedValue); 599 } 600 assertEquals("Saw results: " + sb.toString(), 22, results.size()); 601 } 602 603 @Test 604 public void testReverseMultiRowRangeFilterIncludingMaxRow() throws IOException { 605 tableName = TableName.valueOf(name.getMethodName()); 606 Table ht = TEST_UTIL.createTable(tableName, family); 607 for (String rowkey : Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h")) { 608 byte[] row = Bytes.toBytes(rowkey); 609 Put p = new Put(row); 610 p.addColumn(family, qf, value); 611 ht.put(p); 612 } 613 TEST_UTIL.flush(); 614 615 Scan scan = new Scan(); 616 scan.setReversed(true); 617 List<RowRange> ranges = Arrays.asList( 618 new RowRange(Bytes.toBytes("b"), true, Bytes.toBytes("c"), true), 619 new RowRange(Bytes.toBytes("f"), true, Bytes.toBytes("h"), true) 620 ); 621 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 622 scan.setFilter(filter); 623 624 List<String> expected = Arrays.asList("h", "g", "f", "c", "b"); 625 List<String> actual = new ArrayList<>(); 626 for (Cell cell : getResults(ht, scan)) { 627 actual.add(Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())); 628 } 629 630 assertEquals(expected, actual); 631 } 632 633 @Test 634 public void testReverseMultiRowRangeFilterIncludingMinRow() throws IOException { 635 tableName = TableName.valueOf(name.getMethodName()); 636 Table ht = TEST_UTIL.createTable(tableName, family); 637 for (String rowkey : Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h")) { 638 byte[] row = Bytes.toBytes(rowkey); 639 Put p = new Put(row); 640 p.addColumn(family, qf, value); 641 ht.put(p); 642 } 643 TEST_UTIL.flush(); 644 645 Scan scan = new Scan(); 646 scan.setReversed(true); 647 List<RowRange> ranges = Arrays.asList( 648 new RowRange(Bytes.toBytes("a"), true, Bytes.toBytes("c"), true), 649 new RowRange(Bytes.toBytes("f"), true, Bytes.toBytes("g"), true) 650 ); 651 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 652 scan.setFilter(filter); 653 654 List<String> expected = Arrays.asList("g", "f", "c", "b", "a"); 655 List<String> actual = new ArrayList<>(); 656 for (Cell cell : getResults(ht, scan)) { 657 actual.add(Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())); 658 } 659 660 assertEquals(expected, actual); 661 } 662 663 @Test 664 public void testReverseMultiRowRangeFilterIncludingMinAndMaxRow() throws IOException { 665 tableName = TableName.valueOf(name.getMethodName()); 666 Table ht = TEST_UTIL.createTable(tableName, family); 667 for (String rowkey : Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h")) { 668 byte[] row = Bytes.toBytes(rowkey); 669 Put p = new Put(row); 670 p.addColumn(family, qf, value); 671 ht.put(p); 672 } 673 TEST_UTIL.flush(); 674 675 Scan scan = new Scan(); 676 scan.setReversed(true); 677 List<RowRange> ranges = Arrays.asList( 678 new RowRange(Bytes.toBytes("a"), true, Bytes.toBytes("c"), true), 679 new RowRange(Bytes.toBytes("f"), true, Bytes.toBytes("h"), true) 680 ); 681 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 682 scan.setFilter(filter); 683 684 List<String> expected = Arrays.asList("h", "g", "f", "c", "b", "a"); 685 List<String> actual = new ArrayList<>(); 686 for (Cell cell : getResults(ht, scan)) { 687 actual.add(Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())); 688 } 689 690 assertEquals(expected, actual); 691 } 692 693 private void generateRows(int numberOfRows, Table ht, byte[] family, byte[] qf, byte[] value) 694 throws IOException { 695 for (int i = 0; i < numberOfRows; i++) { 696 byte[] row = Bytes.toBytes(i); 697 Put p = new Put(row); 698 p.addColumn(family, qf, value); 699 ht.put(p); 700 } 701 TEST_UTIL.flush(); 702 } 703 704 private List<Cell> getScanResult(byte[] startRow, byte[] stopRow, Table ht) throws IOException { 705 Scan scan = new Scan(); 706 scan.setMaxVersions(); 707 if(!Bytes.toString(startRow).isEmpty()) { 708 scan.setStartRow(startRow); 709 } 710 if(!Bytes.toString(stopRow).isEmpty()) { 711 scan.setStopRow(stopRow); 712 } 713 ResultScanner scanner = ht.getScanner(scan); 714 List<Cell> kvList = new ArrayList<>(); 715 Result r; 716 while ((r = scanner.next()) != null) { 717 for (Cell kv : r.listCells()) { 718 kvList.add(kv); 719 } 720 } 721 scanner.close(); 722 return kvList; 723 } 724 725 private List<Cell> getResults(Table ht, Scan scan) throws IOException { 726 ResultScanner scanner = ht.getScanner(scan); 727 List<Cell> results = new ArrayList<>(); 728 Result r; 729 while ((r = scanner.next()) != null) { 730 for (Cell kv : r.listCells()) { 731 results.add(kv); 732 } 733 } 734 scanner.close(); 735 return results; 736 } 737 738 private int getResultsSize(Table ht, Scan scan) throws IOException { 739 return getResults(ht, scan).size(); 740 } 741}