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