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