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; 021import static org.junit.Assert.assertFalse; 022import static org.junit.Assert.assertNull; 023import static org.junit.Assert.assertTrue; 024import static org.junit.Assert.fail; 025 026import java.io.IOException; 027import java.util.ArrayList; 028import java.util.Arrays; 029import java.util.List; 030import org.apache.hadoop.hbase.Cell; 031import org.apache.hadoop.hbase.CellComparator; 032import org.apache.hadoop.hbase.CompareOperator; 033import org.apache.hadoop.hbase.HBaseClassTestRule; 034import org.apache.hadoop.hbase.KeyValue; 035import org.apache.hadoop.hbase.KeyValueUtil; 036import org.apache.hadoop.hbase.exceptions.DeserializationException; 037import org.apache.hadoop.hbase.filter.Filter.ReturnCode; 038import org.apache.hadoop.hbase.filter.FilterList.Operator; 039import org.apache.hadoop.hbase.testclassification.FilterTests; 040import org.apache.hadoop.hbase.testclassification.SmallTests; 041import org.apache.hadoop.hbase.util.Bytes; 042import org.junit.Assert; 043import org.junit.ClassRule; 044import org.junit.Test; 045import org.junit.experimental.categories.Category; 046 047import org.apache.hbase.thirdparty.com.google.common.collect.Lists; 048 049import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; 050 051@Category({FilterTests.class, SmallTests.class}) 052public class TestFilterList { 053 054 @ClassRule 055 public static final HBaseClassTestRule CLASS_RULE = 056 HBaseClassTestRule.forClass(TestFilterList.class); 057 058 static final int MAX_PAGES = 2; 059 060 @Test 061 public void testAddFilter() throws Exception { 062 Filter filter1 = new FirstKeyOnlyFilter(); 063 Filter filter2 = new FirstKeyOnlyFilter(); 064 065 FilterList filterList = new FilterList(filter1, filter2); 066 filterList.addFilter(new FirstKeyOnlyFilter()); 067 068 filterList = new FilterList(Arrays.asList(filter1, filter2)); 069 filterList.addFilter(new FirstKeyOnlyFilter()); 070 071 filterList = new FilterList(Operator.MUST_PASS_ALL, filter1, filter2); 072 filterList.addFilter(new FirstKeyOnlyFilter()); 073 074 filterList = new FilterList(Operator.MUST_PASS_ALL, Arrays.asList(filter1, filter2)); 075 filterList.addFilter(new FirstKeyOnlyFilter()); 076 077 filterList.setReversed(false); 078 FirstKeyOnlyFilter f = new FirstKeyOnlyFilter(); 079 f.setReversed(true); 080 try { 081 filterList.addFilter(f); 082 fail("The IllegalArgumentException should be thrown because the added filter is reversed"); 083 } catch (IllegalArgumentException e) { 084 } 085 086 } 087 088 @Test 089 public void testConstruction() { 090 FirstKeyOnlyFilter f1 = new FirstKeyOnlyFilter(); 091 FirstKeyOnlyFilter f2 = new FirstKeyOnlyFilter(); 092 f1.setReversed(true); 093 f2.setReversed(false); 094 095 try { 096 FilterList ff = new FilterList(f1, f2); 097 fail("The IllegalArgumentException should be thrown"); 098 } catch (IllegalArgumentException e) { 099 } 100 101 try { 102 FilterList ff = new FilterList(Arrays.asList(f1, f2)); 103 fail("The IllegalArgumentException should be thrown because the added filter is reversed"); 104 } catch (IllegalArgumentException e) { 105 } 106 107 try { 108 FilterList ff = new FilterList(FilterList.Operator.MUST_PASS_ALL, Arrays.asList(f1, f2)); 109 fail("The IllegalArgumentException should be thrown because the added filter is reversed"); 110 } catch (IllegalArgumentException e) { 111 } 112 113 try { 114 FilterList ff = new FilterList(FilterList.Operator.MUST_PASS_ALL, f1, f2); 115 fail("The IllegalArgumentException should be thrown because the added filter is reversed"); 116 } catch (IllegalArgumentException e) { 117 } 118 } 119 /** 120 * Test "must pass one" 121 * @throws Exception 122 */ 123 @Test 124 public void testMPONE() throws Exception { 125 mpOneTest(getFilterMPONE()); 126 } 127 128 private Filter getFilterMPONE() { 129 List<Filter> filters = new ArrayList<>(); 130 filters.add(new PageFilter(MAX_PAGES)); 131 filters.add(new WhileMatchFilter(new PrefixFilter(Bytes.toBytes("yyy")))); 132 Filter filterMPONE = 133 new FilterList(FilterList.Operator.MUST_PASS_ONE, filters); 134 return filterMPONE; 135 } 136 137 private void mpOneTest(Filter filterMPONE) throws Exception { 138 /* Filter must do all below steps: 139 * <ul> 140 * <li>{@link #reset()}</li> 141 * <li>{@link #filterAllRemaining()} -> true indicates scan is over, false, keep going on.</li> 142 * <li>{@link #filterRowKey(byte[],int,int)} -> true to drop this row, 143 * if false, we will also call</li> 144 * <li>{@link #filterCell(org.apache.hadoop.hbase.KeyValue)} -> true to drop this cell</li> 145 * <li>{@link #filterRow()} -> last chance to drop entire row based on the sequence of 146 * filterValue() calls. Eg: filter a row if it doesn't contain a specified column. 147 * </li> 148 * </ul> 149 */ 150 filterMPONE.reset(); 151 assertFalse(filterMPONE.filterAllRemaining()); 152 153 /* Will pass both */ 154 byte [] rowkey = Bytes.toBytes("yyyyyyyyy"); 155 for (int i = 0; i < MAX_PAGES - 1; i++) { 156 assertFalse(filterMPONE.filterRowKey(KeyValueUtil.createFirstOnRow(rowkey))); 157 KeyValue kv = new KeyValue(rowkey, rowkey, Bytes.toBytes(i), 158 Bytes.toBytes(i)); 159 assertTrue(Filter.ReturnCode.INCLUDE == filterMPONE.filterCell(kv)); 160 assertFalse(filterMPONE.filterRow()); 161 } 162 163 /* Only pass PageFilter */ 164 rowkey = Bytes.toBytes("z"); 165 assertFalse(filterMPONE.filterRowKey(KeyValueUtil.createFirstOnRow(rowkey))); 166 KeyValue kv = new KeyValue(rowkey, rowkey, Bytes.toBytes(0), 167 Bytes.toBytes(0)); 168 assertTrue(Filter.ReturnCode.INCLUDE == filterMPONE.filterCell(kv)); 169 assertFalse(filterMPONE.filterRow()); 170 171 /* reach MAX_PAGES already, should filter any rows */ 172 rowkey = Bytes.toBytes("yyy"); 173 assertTrue(filterMPONE.filterRowKey(KeyValueUtil.createFirstOnRow(rowkey))); 174 kv = new KeyValue(rowkey, rowkey, Bytes.toBytes(0), 175 Bytes.toBytes(0)); 176 assertFalse(Filter.ReturnCode.INCLUDE == filterMPONE.filterCell(kv)); 177 assertFalse(filterMPONE.filterRow()); 178 179 /* We should filter any row */ 180 rowkey = Bytes.toBytes("z"); 181 assertTrue(filterMPONE.filterRowKey(KeyValueUtil.createFirstOnRow(rowkey))); 182 assertTrue(filterMPONE.filterAllRemaining()); 183 } 184 185 /** 186 * Test "must pass all" 187 * @throws Exception 188 */ 189 @Test 190 public void testMPALL() throws Exception { 191 mpAllTest(getMPALLFilter()); 192 } 193 194 private Filter getMPALLFilter() { 195 List<Filter> filters = new ArrayList<>(); 196 filters.add(new PageFilter(MAX_PAGES)); 197 filters.add(new WhileMatchFilter(new PrefixFilter(Bytes.toBytes("yyy")))); 198 Filter filterMPALL = 199 new FilterList(FilterList.Operator.MUST_PASS_ALL, filters); 200 return filterMPALL; 201 } 202 203 private void mpAllTest(Filter filterMPALL) throws Exception { 204 /* Filter must do all below steps: 205 * <ul> 206 * <li>{@link #reset()}</li> 207 * <li>{@link #filterAllRemaining()} -> true indicates scan is over, false, keep going on.</li> 208 * <li>{@link #filterRowKey(byte[],int,int)} -> true to drop this row, 209 * if false, we will also call</li> 210 * <li>{@link #filterCell(org.apache.hadoop.hbase.KeyValue)} -> true to drop this cell</li> 211 * <li>{@link #filterRow()} -> last chance to drop entire row based on the sequence of 212 * filterValue() calls. Eg: filter a row if it doesn't contain a specified column. 213 * </li> 214 * </ul> 215 */ 216 filterMPALL.reset(); 217 assertFalse(filterMPALL.filterAllRemaining()); 218 byte [] rowkey = Bytes.toBytes("yyyyyyyyy"); 219 for (int i = 0; i < MAX_PAGES - 1; i++) { 220 assertFalse(filterMPALL.filterRowKey(KeyValueUtil.createFirstOnRow(rowkey))); 221 KeyValue kv = new KeyValue(rowkey, rowkey, Bytes.toBytes(i), 222 Bytes.toBytes(i)); 223 assertTrue(Filter.ReturnCode.INCLUDE == filterMPALL.filterCell(kv)); 224 } 225 filterMPALL.reset(); 226 rowkey = Bytes.toBytes("z"); 227 assertTrue(filterMPALL.filterRowKey(KeyValueUtil.createFirstOnRow(rowkey))); 228 // Should fail here; row should be filtered out. 229 KeyValue kv = new KeyValue(rowkey, rowkey, rowkey, rowkey); 230 assertTrue(Filter.ReturnCode.NEXT_ROW == filterMPALL.filterCell(kv)); 231 } 232 233 /** 234 * Test list ordering 235 * @throws Exception 236 */ 237 @Test 238 public void testOrdering() throws Exception { 239 orderingTest(getOrderingFilter()); 240 } 241 242 public Filter getOrderingFilter() { 243 List<Filter> filters = new ArrayList<>(); 244 filters.add(new PrefixFilter(Bytes.toBytes("yyy"))); 245 filters.add(new PageFilter(MAX_PAGES)); 246 Filter filterMPONE = 247 new FilterList(FilterList.Operator.MUST_PASS_ONE, filters); 248 return filterMPONE; 249 } 250 251 public void orderingTest(Filter filterMPONE) throws Exception { 252 /* Filter must do all below steps: 253 * <ul> 254 * <li>{@link #reset()}</li> 255 * <li>{@link #filterAllRemaining()} -> true indicates scan is over, false, keep going on.</li> 256 * <li>{@link #filterRowKey(byte[],int,int)} -> true to drop this row, 257 * if false, we will also call</li> 258 * <li>{@link #filterCell(org.apache.hadoop.hbase.KeyValue)} -> true to drop this key/value</li> 259 * <li>{@link #filterRow()} -> last chance to drop entire row based on the sequence of 260 * filterValue() calls. Eg: filter a row if it doesn't contain a specified column. 261 * </li> 262 * </ul> 263 */ 264 filterMPONE.reset(); 265 assertFalse(filterMPONE.filterAllRemaining()); 266 267 /* We should be able to fill MAX_PAGES without incrementing page counter */ 268 byte [] rowkey = Bytes.toBytes("yyyyyyyy"); 269 for (int i = 0; i < MAX_PAGES; i++) { 270 assertFalse(filterMPONE.filterRowKey(KeyValueUtil.createFirstOnRow(rowkey))); 271 KeyValue kv = new KeyValue(rowkey, rowkey, Bytes.toBytes(i), 272 Bytes.toBytes(i)); 273 assertTrue(Filter.ReturnCode.INCLUDE == filterMPONE.filterCell(kv)); 274 assertFalse(filterMPONE.filterRow()); 275 } 276 277 /* Now let's fill the page filter */ 278 rowkey = Bytes.toBytes("xxxxxxx"); 279 for (int i = 0; i < MAX_PAGES; i++) { 280 assertFalse(filterMPONE.filterRowKey(KeyValueUtil.createFirstOnRow(rowkey))); 281 KeyValue kv = new KeyValue(rowkey, rowkey, Bytes.toBytes(i), 282 Bytes.toBytes(i)); 283 assertTrue(Filter.ReturnCode.INCLUDE == filterMPONE.filterCell(kv)); 284 assertFalse(filterMPONE.filterRow()); 285 } 286 287 /* We should still be able to include even though page filter is at max */ 288 rowkey = Bytes.toBytes("yyy"); 289 for (int i = 0; i < MAX_PAGES; i++) { 290 assertFalse(filterMPONE.filterRowKey(KeyValueUtil.createFirstOnRow(rowkey))); 291 KeyValue kv = new KeyValue(rowkey, rowkey, Bytes.toBytes(i), 292 Bytes.toBytes(i)); 293 assertTrue(Filter.ReturnCode.INCLUDE == filterMPONE.filterCell(kv)); 294 assertFalse(filterMPONE.filterRow()); 295 } 296 } 297 298 /** 299 * When we do a "MUST_PASS_ONE" (a logical 'OR') of the above two filters 300 * we expect to get the same result as the 'prefix' only result. 301 * @throws Exception 302 */ 303 @Test 304 public void testFilterListTwoFiltersMustPassOne() throws Exception { 305 byte[] r1 = Bytes.toBytes("Row1"); 306 byte[] r11 = Bytes.toBytes("Row11"); 307 byte[] r2 = Bytes.toBytes("Row2"); 308 309 FilterList flist = new FilterList(FilterList.Operator.MUST_PASS_ONE); 310 flist.addFilter(new PrefixFilter(r1)); 311 flist.filterRowKey(KeyValueUtil.createFirstOnRow(r1)); 312 assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r1, r1, r1))); 313 assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r11, r11, r11))); 314 315 flist.reset(); 316 flist.filterRowKey(KeyValueUtil.createFirstOnRow(r2)); 317 assertEquals(ReturnCode.SKIP, flist.filterCell(new KeyValue(r2, r2, r2))); 318 319 flist = new FilterList(FilterList.Operator.MUST_PASS_ONE); 320 flist.addFilter(new AlwaysNextColFilter()); 321 flist.addFilter(new PrefixFilter(r1)); 322 flist.filterRowKey(KeyValueUtil.createFirstOnRow(r1)); 323 assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r1, r1, r1))); 324 assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r11, r11, r11))); 325 326 flist.reset(); 327 flist.filterRowKey(KeyValueUtil.createFirstOnRow(r2)); 328 assertEquals(ReturnCode.NEXT_COL, flist.filterCell(new KeyValue(r2, r2, r2))); 329 } 330 331 /** 332 * When we do a "MUST_PASS_ONE" (a logical 'OR') of the two filters 333 * we expect to get the same result as the inclusive stop result. 334 * @throws Exception 335 */ 336 @Test 337 public void testFilterListWithInclusiveStopFilterMustPassOne() throws Exception { 338 byte[] r1 = Bytes.toBytes("Row1"); 339 byte[] r11 = Bytes.toBytes("Row11"); 340 byte[] r2 = Bytes.toBytes("Row2"); 341 342 FilterList flist = new FilterList(FilterList.Operator.MUST_PASS_ONE); 343 flist.addFilter(new AlwaysNextColFilter()); 344 flist.addFilter(new InclusiveStopFilter(r1)); 345 flist.filterRowKey(KeyValueUtil.createFirstOnRow(r1)); 346 assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r1, r1, r1))); 347 assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r11, r11, r11))); 348 349 flist.reset(); 350 flist.filterRowKey(KeyValueUtil.createFirstOnRow(r2)); 351 assertEquals(ReturnCode.NEXT_COL, flist.filterCell(new KeyValue(r2, r2, r2))); 352 } 353 354 public static class AlwaysNextColFilter extends FilterBase { 355 public AlwaysNextColFilter() { 356 super(); 357 } 358 359 @Override 360 public ReturnCode filterCell(final Cell v) { 361 return ReturnCode.NEXT_COL; 362 } 363 364 public static AlwaysNextColFilter parseFrom(final byte[] pbBytes) 365 throws DeserializationException { 366 return new AlwaysNextColFilter(); 367 } 368 } 369 370 /** 371 * Test serialization 372 * @throws Exception 373 */ 374 @Test 375 public void testSerialization() throws Exception { 376 List<Filter> filters = new ArrayList<>(); 377 filters.add(new PageFilter(MAX_PAGES)); 378 filters.add(new WhileMatchFilter(new PrefixFilter(Bytes.toBytes("yyy")))); 379 Filter filterMPALL = 380 new FilterList(FilterList.Operator.MUST_PASS_ALL, filters); 381 382 // Decompose filterMPALL to bytes. 383 byte[] buffer = filterMPALL.toByteArray(); 384 385 // Recompose filterMPALL. 386 FilterList newFilter = FilterList.parseFrom(buffer); 387 388 // Run tests 389 mpOneTest(ProtobufUtil.toFilter(ProtobufUtil.toFilter(getFilterMPONE()))); 390 mpAllTest(ProtobufUtil.toFilter(ProtobufUtil.toFilter(getMPALLFilter()))); 391 orderingTest(ProtobufUtil.toFilter(ProtobufUtil.toFilter(getOrderingFilter()))); 392 } 393 394 /** 395 * Test filterCell logic. 396 * @throws Exception 397 */ 398 @Test 399 public void testFilterCell() throws Exception { 400 Filter includeFilter = new FilterBase() { 401 @Override 402 public Filter.ReturnCode filterCell(final Cell v) { 403 return Filter.ReturnCode.INCLUDE; 404 } 405 }; 406 407 Filter alternateFilter = new FilterBase() { 408 boolean returnInclude = true; 409 410 @Override 411 public Filter.ReturnCode filterCell(final Cell v) { 412 Filter.ReturnCode returnCode = returnInclude ? Filter.ReturnCode.INCLUDE : 413 Filter.ReturnCode.SKIP; 414 returnInclude = !returnInclude; 415 return returnCode; 416 } 417 }; 418 419 Filter alternateIncludeFilter = new FilterBase() { 420 boolean returnIncludeOnly = false; 421 422 @Override 423 public Filter.ReturnCode filterCell(final Cell v) { 424 Filter.ReturnCode returnCode = returnIncludeOnly ? Filter.ReturnCode.INCLUDE : 425 Filter.ReturnCode.INCLUDE_AND_NEXT_COL; 426 returnIncludeOnly = !returnIncludeOnly; 427 return returnCode; 428 } 429 }; 430 431 // Check must pass one filter. 432 FilterList mpOnefilterList = new FilterList(Operator.MUST_PASS_ONE, 433 Arrays.asList(new Filter[] { includeFilter, alternateIncludeFilter, alternateFilter })); 434 // INCLUDE, INCLUDE, INCLUDE_AND_NEXT_COL. 435 assertEquals(ReturnCode.INCLUDE, mpOnefilterList.filterCell(null)); 436 // INCLUDE, SKIP, INCLUDE. 437 assertEquals(Filter.ReturnCode.INCLUDE, mpOnefilterList.filterCell(null)); 438 439 // Check must pass all filter. 440 FilterList mpAllfilterList = new FilterList(Operator.MUST_PASS_ALL, 441 Arrays.asList(new Filter[] { includeFilter, alternateIncludeFilter, alternateFilter })); 442 // INCLUDE, INCLUDE, INCLUDE_AND_NEXT_COL. 443 assertEquals(Filter.ReturnCode.INCLUDE_AND_NEXT_COL, mpAllfilterList.filterCell(null)); 444 // INCLUDE, SKIP, INCLUDE. 445 assertEquals(Filter.ReturnCode.SKIP, mpAllfilterList.filterCell(null)); 446 } 447 448 /** 449 * Test pass-thru of hints. 450 */ 451 @Test 452 public void testHintPassThru() throws Exception { 453 454 final KeyValue minKeyValue = new KeyValue(Bytes.toBytes(0L), null, null); 455 final KeyValue maxKeyValue = new KeyValue(Bytes.toBytes(Long.MAX_VALUE), 456 null, null); 457 458 Filter filterNoHint = new FilterBase() { 459 @Override 460 public byte [] toByteArray() { 461 return null; 462 } 463 464 @Override 465 public ReturnCode filterCell(final Cell ignored) throws IOException { 466 return ReturnCode.INCLUDE; 467 } 468 }; 469 470 Filter filterMinHint = new FilterBase() { 471 @Override 472 public ReturnCode filterCell(final Cell ignored) { 473 return ReturnCode.SEEK_NEXT_USING_HINT; 474 } 475 476 @Override 477 public Cell getNextCellHint(Cell currentKV) { 478 return minKeyValue; 479 } 480 481 @Override 482 public byte [] toByteArray() {return null;} 483 }; 484 485 Filter filterMaxHint = new FilterBase() { 486 @Override 487 public ReturnCode filterCell(final Cell ignored) { 488 return ReturnCode.SEEK_NEXT_USING_HINT; 489 } 490 491 @Override 492 public Cell getNextCellHint(Cell cell) { 493 return new KeyValue(Bytes.toBytes(Long.MAX_VALUE), null, null); 494 } 495 496 @Override 497 public byte [] toByteArray() {return null;} 498 }; 499 500 CellComparator comparator = CellComparator.getInstance(); 501 // MUST PASS ONE 502 503 // Should take the min if given two hints 504 FilterList filterList = new FilterList(Operator.MUST_PASS_ONE, 505 Arrays.asList(new Filter [] { filterMinHint, filterMaxHint } )); 506 assertEquals(0, comparator.compare(filterList.getNextCellHint(null), minKeyValue)); 507 508 // Should have no hint if any filter has no hint 509 filterList = new FilterList(Operator.MUST_PASS_ONE, 510 Arrays.asList( 511 new Filter [] { filterMinHint, filterMaxHint, filterNoHint } )); 512 assertNull(filterList.getNextCellHint(null)); 513 filterList = new FilterList(Operator.MUST_PASS_ONE, 514 Arrays.asList(new Filter [] { filterNoHint, filterMaxHint } )); 515 assertNull(filterList.getNextCellHint(null)); 516 517 // Should give max hint if its the only one 518 filterList = new FilterList(Operator.MUST_PASS_ONE, 519 Arrays.asList(new Filter[] { filterMaxHint, filterMaxHint })); 520 assertEquals(0, comparator.compare(filterList.getNextCellHint(null), maxKeyValue)); 521 522 // MUST PASS ALL 523 524 // Should take the first hint 525 filterList = new FilterList(Operator.MUST_PASS_ALL, 526 Arrays.asList(new Filter [] { filterMinHint, filterMaxHint } )); 527 filterList.filterCell(null); 528 assertEquals(0, comparator.compare(filterList.getNextCellHint(null), minKeyValue)); 529 530 filterList = new FilterList(Operator.MUST_PASS_ALL, 531 Arrays.asList(new Filter [] { filterMaxHint, filterMinHint } )); 532 filterList.filterCell(null); 533 assertEquals(0, comparator.compare(filterList.getNextCellHint(null), maxKeyValue)); 534 535 // Should have first hint even if a filter has no hint 536 filterList = new FilterList(Operator.MUST_PASS_ALL, 537 Arrays.asList(new Filter[] { filterNoHint, filterMinHint, filterMaxHint })); 538 filterList.filterCell(null); 539 assertEquals(0, comparator.compare(filterList.getNextCellHint(null), minKeyValue)); 540 filterList = new FilterList(Operator.MUST_PASS_ALL, 541 Arrays.asList(new Filter[] { filterNoHint, filterMaxHint })); 542 filterList.filterCell(null); 543 assertEquals(0, comparator.compare(filterList.getNextCellHint(null), maxKeyValue)); 544 filterList = new FilterList(Operator.MUST_PASS_ALL, 545 Arrays.asList(new Filter[] { filterNoHint, filterMinHint })); 546 filterList.filterCell(null); 547 assertEquals(0, comparator.compare(filterList.getNextCellHint(null), minKeyValue)); 548 } 549 550 /** 551 * Tests the behavior of transform() in a hierarchical filter. 552 * 553 * transform() only applies after a filterCell() whose return-code includes the KeyValue. 554 * Lazy evaluation of AND 555 */ 556 @Test 557 public void testTransformMPO() throws Exception { 558 // Apply the following filter: 559 // (family=fam AND qualifier=qual1 AND KeyOnlyFilter) 560 // OR (family=fam AND qualifier=qual2) 561 final FilterList flist = new FilterList(Operator.MUST_PASS_ONE, Lists.<Filter>newArrayList( 562 new FilterList(Operator.MUST_PASS_ALL, Lists.<Filter>newArrayList( 563 new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("fam"))), 564 new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("qual1"))), 565 new KeyOnlyFilter())), 566 new FilterList(Operator.MUST_PASS_ALL, Lists.<Filter>newArrayList( 567 new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("fam"))), 568 new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("qual2"))))))); 569 570 final KeyValue kvQual1 = new KeyValue( 571 Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual1"), Bytes.toBytes("value")); 572 final KeyValue kvQual2 = new KeyValue( 573 Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual2"), Bytes.toBytes("value")); 574 final KeyValue kvQual3 = new KeyValue( 575 Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual3"), Bytes.toBytes("value")); 576 577 // Value for fam:qual1 should be stripped: 578 assertEquals(Filter.ReturnCode.INCLUDE, flist.filterCell(kvQual1)); 579 final KeyValue transformedQual1 = KeyValueUtil.ensureKeyValue(flist.transformCell(kvQual1)); 580 assertEquals(0, transformedQual1.getValueLength()); 581 582 // Value for fam:qual2 should not be stripped: 583 assertEquals(Filter.ReturnCode.INCLUDE, flist.filterCell(kvQual2)); 584 final KeyValue transformedQual2 = KeyValueUtil.ensureKeyValue(flist.transformCell(kvQual2)); 585 assertEquals("value", Bytes.toString(transformedQual2.getValueArray(), 586 transformedQual2.getValueOffset(), transformedQual2.getValueLength())); 587 588 // Other keys should be skipped: 589 assertEquals(Filter.ReturnCode.SKIP, flist.filterCell(kvQual3)); 590 } 591 592 @Test 593 public void testWithMultiVersionsInSameRow() throws Exception { 594 FilterList filterList01 = 595 new FilterList(Operator.MUST_PASS_ONE, new ColumnPaginationFilter(1, 0)); 596 597 KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual"), 598 1, Bytes.toBytes("value")); 599 KeyValue kv2 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual"), 600 2, Bytes.toBytes("value")); 601 KeyValue kv3 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual"), 602 3, Bytes.toBytes("value")); 603 604 assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList01.filterCell(kv1)); 605 assertEquals(ReturnCode.SKIP, filterList01.filterCell(kv2)); 606 assertEquals(ReturnCode.SKIP, filterList01.filterCell(kv3)); 607 608 FilterList filterList11 = 609 new FilterList(Operator.MUST_PASS_ONE, new ColumnPaginationFilter(1, 1)); 610 611 assertEquals(ReturnCode.NEXT_COL, filterList11.filterCell(kv1)); 612 assertEquals(ReturnCode.SKIP, filterList11.filterCell(kv2)); 613 assertEquals(ReturnCode.SKIP, filterList11.filterCell(kv3)); 614 } 615 616 @Test 617 public void testMPONEWithSeekNextUsingHint() throws Exception { 618 byte[] col = Bytes.toBytes("c"); 619 FilterList filterList = 620 new FilterList(Operator.MUST_PASS_ONE, new ColumnPaginationFilter(1, col)); 621 622 KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1, 623 Bytes.toBytes("value")); 624 KeyValue kv2 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("b"), 2, 625 Bytes.toBytes("value")); 626 KeyValue kv3 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("c"), 3, 627 Bytes.toBytes("value")); 628 KeyValue kv4 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("c"), 4, 629 Bytes.toBytes("value")); 630 631 assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, filterList.filterCell(kv1)); 632 assertEquals(ReturnCode.SKIP, filterList.filterCell(kv2)); 633 assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv3)); 634 assertEquals(ReturnCode.SKIP, filterList.filterCell(kv4)); 635 } 636 637 private static class MockFilter extends FilterBase { 638 private ReturnCode targetRetCode; 639 public boolean didCellPassToTheFilter = false; 640 641 public MockFilter(ReturnCode targetRetCode) { 642 this.targetRetCode = targetRetCode; 643 } 644 645 @Override 646 public ReturnCode filterCell(final Cell v) throws IOException { 647 this.didCellPassToTheFilter = true; 648 return targetRetCode; 649 } 650 } 651 652 @Test 653 public void testShouldPassCurrentCellToFilter() throws IOException { 654 KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1, 655 Bytes.toBytes("value")); 656 KeyValue kv2 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 2, 657 Bytes.toBytes("value")); 658 KeyValue kv3 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("b"), 3, 659 Bytes.toBytes("value")); 660 KeyValue kv4 = new KeyValue(Bytes.toBytes("row1"), Bytes.toBytes("fam"), Bytes.toBytes("c"), 4, 661 Bytes.toBytes("value")); 662 663 MockFilter mockFilter = new MockFilter(ReturnCode.NEXT_COL); 664 FilterList filter = new FilterList(Operator.MUST_PASS_ONE, mockFilter); 665 666 filter.filterCell(kv1); 667 assertTrue(mockFilter.didCellPassToTheFilter); 668 669 mockFilter.didCellPassToTheFilter = false; 670 filter.filterCell(kv2); 671 assertFalse(mockFilter.didCellPassToTheFilter); 672 673 mockFilter.didCellPassToTheFilter = false; 674 filter.filterCell(kv3); 675 assertTrue(mockFilter.didCellPassToTheFilter); 676 677 mockFilter = new MockFilter(ReturnCode.INCLUDE_AND_NEXT_COL); 678 filter = new FilterList(Operator.MUST_PASS_ONE, mockFilter); 679 680 filter.filterCell(kv1); 681 assertTrue(mockFilter.didCellPassToTheFilter); 682 683 mockFilter.didCellPassToTheFilter = false; 684 filter.filterCell(kv2); 685 assertFalse(mockFilter.didCellPassToTheFilter); 686 687 mockFilter.didCellPassToTheFilter = false; 688 filter.filterCell(kv3); 689 assertTrue(mockFilter.didCellPassToTheFilter); 690 691 mockFilter = new MockFilter(ReturnCode.NEXT_ROW); 692 filter = new FilterList(Operator.MUST_PASS_ONE, mockFilter); 693 filter.filterCell(kv1); 694 assertTrue(mockFilter.didCellPassToTheFilter); 695 696 mockFilter.didCellPassToTheFilter = false; 697 filter.filterCell(kv2); 698 assertFalse(mockFilter.didCellPassToTheFilter); 699 700 mockFilter.didCellPassToTheFilter = false; 701 filter.filterCell(kv3); 702 assertFalse(mockFilter.didCellPassToTheFilter); 703 704 filter.reset(); 705 mockFilter.didCellPassToTheFilter = false; 706 filter.filterCell(kv4); 707 assertTrue(mockFilter.didCellPassToTheFilter); 708 709 mockFilter = new MockFilter(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW); 710 filter = new FilterList(Operator.MUST_PASS_ONE, mockFilter); 711 filter.filterCell(kv1); 712 assertTrue(mockFilter.didCellPassToTheFilter); 713 714 mockFilter.didCellPassToTheFilter = false; 715 filter.filterCell(kv2); 716 assertFalse(mockFilter.didCellPassToTheFilter); 717 718 mockFilter.didCellPassToTheFilter = false; 719 filter.filterCell(kv3); 720 assertFalse(mockFilter.didCellPassToTheFilter); 721 722 filter.reset(); 723 mockFilter.didCellPassToTheFilter = false; 724 filter.filterCell(kv4); 725 assertTrue(mockFilter.didCellPassToTheFilter); 726 } 727 728 @Test 729 public void testTheMaximalRule() throws IOException { 730 KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1, 731 Bytes.toBytes("value")); 732 MockFilter filter1 = new MockFilter(ReturnCode.INCLUDE); 733 MockFilter filter2 = new MockFilter(ReturnCode.INCLUDE_AND_NEXT_COL); 734 MockFilter filter3 = new MockFilter(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW); 735 MockFilter filter4 = new MockFilter(ReturnCode.NEXT_COL); 736 MockFilter filter5 = new MockFilter(ReturnCode.SKIP); 737 MockFilter filter6 = new MockFilter(ReturnCode.SEEK_NEXT_USING_HINT); 738 MockFilter filter7 = new MockFilter(ReturnCode.NEXT_ROW); 739 740 FilterList filterList = new FilterList(Operator.MUST_PASS_ALL, filter1, filter2); 741 assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv1)); 742 743 filterList = new FilterList(Operator.MUST_PASS_ALL, filter2, filter3); 744 assertEquals(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW, filterList.filterCell(kv1)); 745 746 filterList = new FilterList(Operator.MUST_PASS_ALL, filter4, filter5, filter6); 747 assertEquals(ReturnCode.NEXT_COL, filterList.filterCell(kv1)); 748 749 filterList = new FilterList(Operator.MUST_PASS_ALL, filter4, filter6); 750 assertEquals(ReturnCode.NEXT_COL, filterList.filterCell(kv1)); 751 752 filterList = new FilterList(Operator.MUST_PASS_ALL, filter3, filter1); 753 assertEquals(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW, filterList.filterCell(kv1)); 754 755 filterList = new FilterList(Operator.MUST_PASS_ALL, filter3, filter2, filter1, filter5); 756 assertEquals(ReturnCode.NEXT_ROW, filterList.filterCell(kv1)); 757 758 filterList = new FilterList(Operator.MUST_PASS_ALL, filter2, 759 new FilterList(Operator.MUST_PASS_ALL, filter3, filter4)); 760 assertEquals(ReturnCode.NEXT_ROW, filterList.filterCell(kv1)); 761 762 filterList = new FilterList(Operator.MUST_PASS_ALL, filter3, filter7); 763 assertEquals(ReturnCode.NEXT_ROW, filterList.filterCell(kv1)); 764 } 765 766 @Test 767 public void testTheMinimalRule() throws IOException { 768 KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1, 769 Bytes.toBytes("value")); 770 MockFilter filter1 = new MockFilter(ReturnCode.INCLUDE); 771 MockFilter filter2 = new MockFilter(ReturnCode.INCLUDE_AND_NEXT_COL); 772 MockFilter filter3 = new MockFilter(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW); 773 MockFilter filter4 = new MockFilter(ReturnCode.NEXT_COL); 774 MockFilter filter5 = new MockFilter(ReturnCode.SKIP); 775 MockFilter filter6 = new MockFilter(ReturnCode.SEEK_NEXT_USING_HINT); 776 FilterList filterList = new FilterList(Operator.MUST_PASS_ONE, filter1, filter2); 777 assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv1)); 778 779 filterList = new FilterList(Operator.MUST_PASS_ONE, filter2, filter3); 780 assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv1)); 781 782 filterList = new FilterList(Operator.MUST_PASS_ONE, filter4, filter5, filter6); 783 assertEquals(ReturnCode.SKIP, filterList.filterCell(kv1)); 784 785 filterList = new FilterList(Operator.MUST_PASS_ONE, filter4, filter6); 786 assertEquals(ReturnCode.SKIP, filterList.filterCell(kv1)); 787 788 filterList = new FilterList(Operator.MUST_PASS_ONE, filter3, filter1); 789 assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv1)); 790 791 filterList = new FilterList(Operator.MUST_PASS_ONE, filter3, filter2, filter1, filter5); 792 assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv1)); 793 794 filterList = new FilterList(Operator.MUST_PASS_ONE, filter2, 795 new FilterList(Operator.MUST_PASS_ONE, filter3, filter4)); 796 assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv1)); 797 798 filterList = new FilterList(Operator.MUST_PASS_ONE, filter2, 799 new FilterList(Operator.MUST_PASS_ONE, filter3, filter4)); 800 assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv1)); 801 802 filterList = new FilterList(Operator.MUST_PASS_ONE, filter6, filter6); 803 assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, filterList.filterCell(kv1)); 804 } 805 806 static class MockSeekHintFilter extends FilterBase { 807 private Cell returnCell; 808 809 public MockSeekHintFilter(Cell returnCell) { 810 this.returnCell = returnCell; 811 } 812 813 @Override 814 public ReturnCode filterCell(final Cell v) throws IOException { 815 return ReturnCode.SEEK_NEXT_USING_HINT; 816 } 817 818 @Override 819 public Cell getNextCellHint(Cell currentCell) throws IOException { 820 return this.returnCell; 821 } 822 } 823 824 @Test 825 public void testReversedFilterListWithMockSeekHintFilter() throws IOException { 826 KeyValue kv1 = new KeyValue(Bytes.toBytes("row1"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1, 827 Bytes.toBytes("value")); 828 KeyValue kv2 = new KeyValue(Bytes.toBytes("row2"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1, 829 Bytes.toBytes("value")); 830 KeyValue kv3 = new KeyValue(Bytes.toBytes("row3"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1, 831 Bytes.toBytes("value")); 832 Filter filter1 = new MockSeekHintFilter(kv1); 833 filter1.setReversed(true); 834 Filter filter2 = new MockSeekHintFilter(kv2); 835 filter2.setReversed(true); 836 Filter filter3 = new MockSeekHintFilter(kv3); 837 filter3.setReversed(true); 838 839 FilterList filterList = new FilterList(Operator.MUST_PASS_ONE); 840 filterList.setReversed(true); 841 filterList.addFilter(filter1); 842 filterList.addFilter(filter2); 843 filterList.addFilter(filter3); 844 845 Assert.assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, filterList.filterCell(kv1)); 846 Assert.assertEquals(kv3, filterList.getNextCellHint(kv1)); 847 848 filterList = new FilterList(Operator.MUST_PASS_ALL); 849 filterList.setReversed(true); 850 filterList.addFilter(filter1); 851 filterList.addFilter(filter2); 852 filterList.addFilter(filter3); 853 854 Assert.assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, filterList.filterCell(kv1)); 855 Assert.assertEquals(kv1, filterList.getNextCellHint(kv1)); 856 } 857 858 @Test 859 public void testReversedFilterListWithOR() throws IOException { 860 byte[] r22 = Bytes.toBytes("Row22"); 861 byte[] r2 = Bytes.toBytes("Row2"); 862 byte[] r1 = Bytes.toBytes("Row1"); 863 864 FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE); 865 filterList.setReversed(true); 866 PrefixFilter prefixFilter = new PrefixFilter(r2); 867 prefixFilter.setReversed(true); 868 filterList.addFilter(prefixFilter); 869 filterList.filterRowKey(KeyValueUtil.createFirstOnRow(r22)); 870 assertEquals(ReturnCode.INCLUDE, filterList.filterCell(new KeyValue(r22, r22, r22))); 871 assertEquals(ReturnCode.INCLUDE, filterList.filterCell(new KeyValue(r2, r2, r2))); 872 873 filterList.reset(); 874 filterList.filterRowKey(KeyValueUtil.createFirstOnRow(r1)); 875 assertEquals(ReturnCode.SKIP, filterList.filterCell(new KeyValue(r1, r1, r1))); 876 877 filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE); 878 filterList.setReversed(true); 879 AlwaysNextColFilter alwaysNextColFilter = new AlwaysNextColFilter(); 880 alwaysNextColFilter.setReversed(true); 881 prefixFilter = new PrefixFilter(r2); 882 prefixFilter.setReversed(true); 883 filterList.addFilter(alwaysNextColFilter); 884 filterList.addFilter(prefixFilter); 885 filterList.filterRowKey(KeyValueUtil.createFirstOnRow(r22)); 886 assertEquals(ReturnCode.INCLUDE, filterList.filterCell(new KeyValue(r22, r22, r22))); 887 assertEquals(ReturnCode.INCLUDE, filterList.filterCell(new KeyValue(r2, r2, r2))); 888 889 filterList.reset(); 890 filterList.filterRowKey(KeyValueUtil.createFirstOnRow(r1)); 891 assertEquals(ReturnCode.NEXT_COL, filterList.filterCell(new KeyValue(r1, r1, r1))); 892 } 893 894 @Test 895 public void testKeyOnlyFilterTransformCell() throws IOException { 896 Cell c; 897 KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("cf"), Bytes.toBytes("column1"), 898 1, Bytes.toBytes("value1")); 899 KeyValue kv2 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("cf"), Bytes.toBytes("column1"), 900 2, Bytes.toBytes("value2")); 901 902 Filter filter1 = new SingleColumnValueFilter(Bytes.toBytes("cf"), Bytes.toBytes("column1"), 903 CompareOperator.EQUAL, Bytes.toBytes("value1")); 904 Filter filter2 = new SingleColumnValueFilter(Bytes.toBytes("cf"), Bytes.toBytes("column1"), 905 CompareOperator.EQUAL, Bytes.toBytes("value2")); 906 FilterList internalFilterList = new FilterList(Operator.MUST_PASS_ONE, filter1, filter2); 907 908 FilterList keyOnlyFilterFirst = 909 new FilterList(Operator.MUST_PASS_ALL, new KeyOnlyFilter(), internalFilterList); 910 911 assertEquals(ReturnCode.INCLUDE, keyOnlyFilterFirst.filterCell(kv1)); 912 c = keyOnlyFilterFirst.transformCell(kv1); 913 assertEquals(0, c.getValueLength()); 914 assertEquals(ReturnCode.INCLUDE, keyOnlyFilterFirst.filterCell(kv2)); 915 c = keyOnlyFilterFirst.transformCell(kv2); 916 assertEquals(0, c.getValueLength()); 917 918 internalFilterList.reset(); 919 FilterList keyOnlyFilterLast = 920 new FilterList(Operator.MUST_PASS_ALL, new KeyOnlyFilter(), internalFilterList); 921 assertEquals(ReturnCode.INCLUDE, keyOnlyFilterLast.filterCell(kv1)); 922 c = keyOnlyFilterLast.transformCell(kv1); 923 assertEquals(0, c.getValueLength()); 924 assertEquals(ReturnCode.INCLUDE, keyOnlyFilterLast.filterCell(kv2)); 925 c = keyOnlyFilterLast.transformCell(kv2); 926 assertEquals(0, c.getValueLength()); 927 } 928 929 @Test 930 public void testEmptyFilterListTransformCell() throws IOException { 931 KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("cf"), Bytes.toBytes("column1"), 932 1, Bytes.toBytes("value")); 933 FilterList filterList = new FilterList(Operator.MUST_PASS_ALL); 934 assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv)); 935 assertEquals(kv, filterList.transformCell(kv)); 936 937 filterList = new FilterList(Operator.MUST_PASS_ONE); 938 assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv)); 939 assertEquals(kv, filterList.transformCell(kv)); 940 } 941 942 private static class MockNextRowFilter extends FilterBase { 943 private int hitCount = 0; 944 945 @Override 946 public ReturnCode filterCell(final Cell v) throws IOException { 947 hitCount++; 948 return ReturnCode.NEXT_ROW; 949 } 950 951 public int getHitCount() { 952 return hitCount; 953 } 954 } 955 956 @Test 957 public void testRowCountFilter() throws IOException { 958 KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam1"), Bytes.toBytes("a"), 1, 959 Bytes.toBytes("value")); 960 KeyValue kv2 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam2"), Bytes.toBytes("a"), 2, 961 Bytes.toBytes("value")); 962 MockNextRowFilter mockNextRowFilter = new MockNextRowFilter(); 963 FilterList filter = new FilterList(Operator.MUST_PASS_ONE, mockNextRowFilter); 964 filter.filterCell(kv1); 965 filter.filterCell(kv2); 966 assertEquals(2, mockNextRowFilter.getHitCount()); 967 } 968 969 private static class TransformFilter extends FilterBase { 970 private ReturnCode targetRetCode; 971 private boolean transformed = false; 972 973 public TransformFilter(ReturnCode targetRetCode) { 974 this.targetRetCode = targetRetCode; 975 } 976 977 @Override 978 public ReturnCode filterCell(final Cell v) throws IOException { 979 return targetRetCode; 980 } 981 982 @Override 983 public Cell transformCell(Cell c) throws IOException { 984 transformed = true; 985 return super.transformCell(c); 986 } 987 988 public boolean getTransformed() { 989 return this.transformed; 990 } 991 } 992 993 @Test 994 public void testTransformCell() throws IOException { 995 KeyValue kv = 996 new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("cf"), Bytes.toBytes("column1"), 1, 997 Bytes.toBytes("value")); 998 999 // case MUST_PASS_ONE 1000 TransformFilter filter1 = new TransformFilter(ReturnCode.INCLUDE); 1001 TransformFilter filter2 = new TransformFilter(ReturnCode.NEXT_ROW); 1002 TransformFilter filter3 = new TransformFilter(ReturnCode.SEEK_NEXT_USING_HINT); 1003 FilterList filterList = new FilterList(Operator.MUST_PASS_ONE, filter1, filter2, filter3); 1004 Assert.assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv)); 1005 Assert.assertEquals(kv, filterList.transformCell(kv)); 1006 Assert.assertEquals(true, filter1.getTransformed()); 1007 Assert.assertEquals(false, filter2.getTransformed()); 1008 Assert.assertEquals(false, filter3.getTransformed()); 1009 1010 // case MUST_PASS_ALL 1011 filter1 = new TransformFilter(ReturnCode.INCLUDE); 1012 filter2 = new TransformFilter(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW); 1013 filter3 = new TransformFilter(ReturnCode.INCLUDE_AND_NEXT_COL); 1014 filterList = new FilterList(Operator.MUST_PASS_ALL, filter1, filter2, filter3); 1015 1016 Assert.assertEquals(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW, filterList.filterCell(kv)); 1017 Assert.assertEquals(kv, filterList.transformCell(kv)); 1018 Assert.assertEquals(true, filter1.getTransformed()); 1019 Assert.assertEquals(true, filter2.getTransformed()); 1020 Assert.assertEquals(true, filter3.getTransformed()); 1021 } 1022} 1023