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 * 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.setMaxVersions(); 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.setMaxVersions(); 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.setMaxVersions(); 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.setMaxVersions(); 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.setMaxVersions(); 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 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 434 ht.setReadRpcTimeout(600000); 435 ht.setOperationTimeout(6000000); 436 generateRows(numRows, ht, family, qf, value); 437 438 Scan scan = new Scan(); 439 scan.setMaxVersions(); 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 ht.close(); 456 } 457 458 @Test 459 public void testMultiRowRangeWithFilterListAndOperator() throws IOException { 460 tableName = TableName.valueOf(name.getMethodName()); 461 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 462 generateRows(numRows, ht, family, qf, value); 463 464 Scan scan = new Scan(); 465 scan.setMaxVersions(); 466 467 List<RowRange> ranges1 = new ArrayList<>(); 468 ranges1.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 469 ranges1.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false)); 470 ranges1.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false)); 471 472 MultiRowRangeFilter filter1 = new MultiRowRangeFilter(ranges1); 473 474 List<RowRange> ranges2 = new ArrayList<>(); 475 ranges2.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(40), false)); 476 ranges2.add(new RowRange(Bytes.toBytes(80), true, Bytes.toBytes(90), false)); 477 478 MultiRowRangeFilter filter2 = new MultiRowRangeFilter(ranges2); 479 480 FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL); 481 filterList.addFilter(filter1); 482 filterList.addFilter(filter2); 483 scan.setFilter(filterList); 484 int resultsSize = getResultsSize(ht, scan); 485 LOG.info("found " + resultsSize + " results"); 486 List<Cell> results1 = getScanResult(Bytes.toBytes(30), Bytes.toBytes(40), ht); 487 488 assertEquals(results1.size(), resultsSize); 489 490 ht.close(); 491 } 492 493 @Test 494 public void testMultiRowRangeWithFilterListOrOperator() throws IOException { 495 tableName = TableName.valueOf(name.getMethodName()); 496 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 497 generateRows(numRows, ht, family, qf, value); 498 499 Scan scan = new Scan(); 500 scan.setMaxVersions(); 501 502 List<RowRange> ranges1 = new ArrayList<>(); 503 ranges1.add(new RowRange(Bytes.toBytes(30), true, Bytes.toBytes(40), false)); 504 ranges1.add(new RowRange(Bytes.toBytes(10), true, Bytes.toBytes(20), false)); 505 ranges1.add(new RowRange(Bytes.toBytes(60), true, Bytes.toBytes(70), false)); 506 507 MultiRowRangeFilter filter1 = new MultiRowRangeFilter(ranges1); 508 509 List<RowRange> ranges2 = new ArrayList<>(); 510 ranges2.add(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(40), false)); 511 ranges2.add(new RowRange(Bytes.toBytes(80), true, Bytes.toBytes(90), false)); 512 513 MultiRowRangeFilter filter2 = new MultiRowRangeFilter(ranges2); 514 515 FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE); 516 filterList.addFilter(filter1); 517 filterList.addFilter(filter2); 518 scan.setFilter(filterList); 519 int resultsSize = getResultsSize(ht, scan); 520 LOG.info("found " + resultsSize + " results"); 521 List<Cell> results1 = getScanResult(Bytes.toBytes(10), Bytes.toBytes(40), ht); 522 List<Cell> results2 = getScanResult(Bytes.toBytes(60), Bytes.toBytes(70), ht); 523 List<Cell> results3 = getScanResult(Bytes.toBytes(80), Bytes.toBytes(90), ht); 524 525 assertEquals(results1.size() + results2.size() + results3.size(), resultsSize); 526 527 ht.close(); 528 } 529 530 @Test 531 public void testOneRowRange() throws IOException { 532 tableName = TableName.valueOf(name.getMethodName()); 533 Table ht = TEST_UTIL.createTable(tableName, family, Integer.MAX_VALUE); 534 generateRows(numRows, ht, family, qf, value); 535 ArrayList<MultiRowRangeFilter.RowRange> rowRangesList = new ArrayList<>(); 536 rowRangesList 537 .add(new MultiRowRangeFilter.RowRange(Bytes.toBytes(50), true, Bytes.toBytes(50), true)); 538 Scan scan = new Scan(); 539 scan.setFilter(new MultiRowRangeFilter(rowRangesList)); 540 int resultsSize = getResultsSize(ht, scan); 541 assertEquals(1, resultsSize); 542 rowRangesList.clear(); 543 rowRangesList 544 .add(new MultiRowRangeFilter.RowRange(Bytes.toBytes(50), true, Bytes.toBytes(51), false)); 545 scan = new Scan(); 546 scan.setFilter(new MultiRowRangeFilter(rowRangesList)); 547 resultsSize = getResultsSize(ht, scan); 548 assertEquals(1, resultsSize); 549 rowRangesList.clear(); 550 rowRangesList 551 .add(new MultiRowRangeFilter.RowRange(Bytes.toBytes(50), true, Bytes.toBytes(51), true)); 552 scan = new Scan(); 553 scan.setFilter(new MultiRowRangeFilter(rowRangesList)); 554 resultsSize = getResultsSize(ht, scan); 555 assertEquals(2, resultsSize); 556 ht.close(); 557 } 558 559 @Test 560 public void testReverseMultiRowRangeFilterWithinTable() throws IOException { 561 tableName = TableName.valueOf(name.getMethodName()); 562 Table ht = TEST_UTIL.createTable(tableName, family); 563 generateRows(numRows, ht, family, qf, value); 564 565 Scan scan = new Scan(); 566 scan.setReversed(true); 567 List<RowRange> ranges = 568 Arrays.asList(new RowRange(Bytes.toBytes(20), true, Bytes.toBytes(30), true), 569 new RowRange(Bytes.toBytes(50), true, Bytes.toBytes(60), true)); 570 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 571 scan.setFilter(filter); 572 573 List<Integer> expectedResults = new ArrayList<>(); 574 for (int i = 60; i >= 50; i--) { 575 expectedResults.add(i); 576 } 577 for (int i = 30; i >= 20; i--) { 578 expectedResults.add(i); 579 } 580 581 List<Cell> results = getResults(ht, scan); 582 List<Integer> actualResults = new ArrayList<>(); 583 StringBuilder sb = new StringBuilder(); 584 for (Cell result : results) { 585 int observedValue = 586 Bytes.toInt(result.getRowArray(), result.getRowOffset(), result.getRowLength()); 587 actualResults.add(observedValue); 588 if (sb.length() > 0) { 589 sb.append(", "); 590 } 591 sb.append(observedValue); 592 } 593 assertEquals("Saw results: " + sb.toString(), 22, results.size()); 594 } 595 596 @Test 597 public void testReverseMultiRowRangeFilterIncludingMaxRow() throws IOException { 598 tableName = TableName.valueOf(name.getMethodName()); 599 Table ht = TEST_UTIL.createTable(tableName, family); 600 for (String rowkey : Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h")) { 601 byte[] row = Bytes.toBytes(rowkey); 602 Put p = new Put(row); 603 p.addColumn(family, qf, value); 604 ht.put(p); 605 } 606 TEST_UTIL.flush(); 607 608 Scan scan = new Scan(); 609 scan.setReversed(true); 610 List<RowRange> ranges = 611 Arrays.asList(new RowRange(Bytes.toBytes("b"), true, Bytes.toBytes("c"), true), 612 new RowRange(Bytes.toBytes("f"), true, Bytes.toBytes("h"), true)); 613 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 614 scan.setFilter(filter); 615 616 List<String> expected = Arrays.asList("h", "g", "f", "c", "b"); 617 List<String> actual = new ArrayList<>(); 618 for (Cell cell : getResults(ht, scan)) { 619 actual.add(Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())); 620 } 621 622 assertEquals(expected, actual); 623 } 624 625 @Test 626 public void testReverseMultiRowRangeFilterIncludingMinRow() throws IOException { 627 tableName = TableName.valueOf(name.getMethodName()); 628 Table ht = TEST_UTIL.createTable(tableName, family); 629 for (String rowkey : Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h")) { 630 byte[] row = Bytes.toBytes(rowkey); 631 Put p = new Put(row); 632 p.addColumn(family, qf, value); 633 ht.put(p); 634 } 635 TEST_UTIL.flush(); 636 637 Scan scan = new Scan(); 638 scan.setReversed(true); 639 List<RowRange> ranges = 640 Arrays.asList(new RowRange(Bytes.toBytes("a"), true, Bytes.toBytes("c"), true), 641 new RowRange(Bytes.toBytes("f"), true, Bytes.toBytes("g"), true)); 642 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 643 scan.setFilter(filter); 644 645 List<String> expected = Arrays.asList("g", "f", "c", "b", "a"); 646 List<String> actual = new ArrayList<>(); 647 for (Cell cell : getResults(ht, scan)) { 648 actual.add(Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())); 649 } 650 651 assertEquals(expected, actual); 652 } 653 654 @Test 655 public void testReverseMultiRowRangeFilterIncludingMinAndMaxRow() throws IOException { 656 tableName = TableName.valueOf(name.getMethodName()); 657 Table ht = TEST_UTIL.createTable(tableName, family); 658 for (String rowkey : Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h")) { 659 byte[] row = Bytes.toBytes(rowkey); 660 Put p = new Put(row); 661 p.addColumn(family, qf, value); 662 ht.put(p); 663 } 664 TEST_UTIL.flush(); 665 666 Scan scan = new Scan(); 667 scan.setReversed(true); 668 List<RowRange> ranges = 669 Arrays.asList(new RowRange(Bytes.toBytes("a"), true, Bytes.toBytes("c"), true), 670 new RowRange(Bytes.toBytes("f"), true, Bytes.toBytes("h"), true)); 671 MultiRowRangeFilter filter = new MultiRowRangeFilter(ranges); 672 scan.setFilter(filter); 673 674 List<String> expected = Arrays.asList("h", "g", "f", "c", "b", "a"); 675 List<String> actual = new ArrayList<>(); 676 for (Cell cell : getResults(ht, scan)) { 677 actual.add(Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength())); 678 } 679 680 assertEquals(expected, actual); 681 } 682 683 private void generateRows(int numberOfRows, Table ht, byte[] family, byte[] qf, byte[] value) 684 throws IOException { 685 for (int i = 0; i < numberOfRows; i++) { 686 byte[] row = Bytes.toBytes(i); 687 Put p = new Put(row); 688 p.addColumn(family, qf, value); 689 ht.put(p); 690 } 691 TEST_UTIL.flush(); 692 } 693 694 private List<Cell> getScanResult(byte[] startRow, byte[] stopRow, Table ht) throws IOException { 695 Scan scan = new Scan(); 696 scan.setMaxVersions(); 697 if (!Bytes.toString(startRow).isEmpty()) { 698 scan.setStartRow(startRow); 699 } 700 if (!Bytes.toString(stopRow).isEmpty()) { 701 scan.setStopRow(stopRow); 702 } 703 ResultScanner scanner = ht.getScanner(scan); 704 List<Cell> kvList = new ArrayList<>(); 705 Result r; 706 while ((r = scanner.next()) != null) { 707 for (Cell kv : r.listCells()) { 708 kvList.add(kv); 709 } 710 } 711 scanner.close(); 712 return kvList; 713 } 714 715 private List<Cell> getResults(Table ht, Scan scan) throws IOException { 716 ResultScanner scanner = ht.getScanner(scan); 717 List<Cell> results = new ArrayList<>(); 718 Result r; 719 while ((r = scanner.next()) != null) { 720 for (Cell kv : r.listCells()) { 721 results.add(kv); 722 } 723 } 724 scanner.close(); 725 return results; 726 } 727 728 private int getResultsSize(Table ht, Scan scan) throws IOException { 729 return getResults(ht, scan).size(); 730 } 731}