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