下面列出了怎么用org.apache.hadoop.hbase.filter.Filter.ReturnCode的API类实例代码及写法,或者点击链接到github查看源代码。
@SuppressWarnings("deprecation")
private boolean seekToNextUnfilteredKeyValue() throws IOException {
while (true) {
Cell peeked = delegate.peek();
// no more key values, so we are done
if (peeked == null) { return false; }
// filter the peeked value to see if it should be served
ReturnCode code = filter.filterKeyValue(peeked);
switch (code) {
// included, so we are done
case INCLUDE:
case INCLUDE_AND_NEXT_COL:
return true;
// not included, so we need to go to the next row
case SKIP:
case NEXT_COL:
case NEXT_ROW:
delegate.next();
break;
// use a seek hint to find out where we should go
case SEEK_NEXT_USING_HINT:
delegate.seek(KeyValueUtil.ensureKeyValue(filter.getNextCellHint(peeked)));
}
}
}
/**
* Point deletes should only cover the exact entry they are tied to. Earlier puts should always
* show up.
*/
@Test
public void testCoveringPointDelete() {
// start with doing a family delete, so we will seek to the next column
KeyValue kv = createKvForType(Type.Delete);
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
filter.filterKeyValue(kv);
KeyValue put = createKvForType(Type.Put);
assertEquals("Didn't filter out put with same timestamp!", ReturnCode.SKIP,
filter.filterKeyValue(put));
// we should filter out the exact same put again, which could occur with the kvs all kept in the
// same memstore
assertEquals("Didn't filter out put with same timestamp on second call!", ReturnCode.SKIP,
filter.filterKeyValue(put));
// ensure then that we don't filter out a put with an earlier timestamp (though everything else
// matches)
put = createKvForType(Type.Put, ts - 1);
assertEquals("Didn't accept put that has an earlier ts than the covering delete!",
ReturnCode.INCLUDE, filter.filterKeyValue(put));
}
/**
* DeleteFamily markers should delete everything from that timestamp backwards, but not hide
* anything forwards
*/
@Test
public void testDeleteFamilyCorrectlyCoversColumns() {
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
KeyValue df = createKvForType(Type.DeleteFamily, 11);
KeyValue put = createKvForType(Type.Put, 12);
assertEquals("Didn't filter out delete family", ReturnCode.SKIP, filter.filterKeyValue(df));
assertEquals("Filtered out put with newer TS than delete family", ReturnCode.INCLUDE,
filter.filterKeyValue(put));
// older kv shouldn't be visible
put = createKvForType(Type.Put, 10);
assertEquals("Didn't filter out older put, covered by DeleteFamily marker",
ReturnCode.SEEK_NEXT_USING_HINT, filter.filterKeyValue(put));
// next seek should be past the families
assertEquals(KeyValue.LOWESTKEY, filter.getNextCellHint(put));
}
/**
* Test that we don't cover other columns when we have a delete column.
*/
@Test
public void testDeleteColumnCorrectlyCoversColumns() {
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
KeyValue d = createKvForType(Type.DeleteColumn, 12);
byte[] qual2 = Bytes.add(qualifier, Bytes.toBytes("-other"));
KeyValue put = new KeyValue(row, family, qual2, 11, Type.Put, value);
assertEquals("Didn't filter out delete column", ReturnCode.SKIP, filter.filterKeyValue(d));
// different column put should still be visible
assertEquals("Filtered out put with different column than the delete", ReturnCode.INCLUDE,
filter.filterKeyValue(put));
// set a delete family, but in the past
d = createKvForType(Type.DeleteFamily, 10);
assertEquals("Didn't filter out delete column", ReturnCode.SKIP, filter.filterKeyValue(d));
// add back in the original delete column
d = createKvForType(Type.DeleteColumn, 11);
assertEquals("Didn't filter out delete column", ReturnCode.SKIP, filter.filterKeyValue(d));
// onto a different family, so that must be visible too
assertEquals("Filtered out put with different column than the delete", ReturnCode.INCLUDE,
filter.filterKeyValue(put));
}
/**
* When we do a "MUST_PASS_ONE" (a logical 'OR') of the two filters
* we expect to get the same result as the inclusive stop result.
* @throws Exception
*/
@Test
public void testFilterListWithInclusiveStopFilterMustPassOne() throws Exception {
byte[] r1 = Bytes.toBytes("Row1");
byte[] r11 = Bytes.toBytes("Row11");
byte[] r2 = Bytes.toBytes("Row2");
FilterList flist = new FilterList(FilterList.Operator.MUST_PASS_ONE);
flist.addFilter(new AlwaysNextColFilter());
flist.addFilter(new InclusiveStopFilter(r1));
flist.filterRowKey(KeyValueUtil.createFirstOnRow(r1));
assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r1, r1, r1)));
assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r11, r11, r11)));
flist.reset();
flist.filterRowKey(KeyValueUtil.createFirstOnRow(r2));
assertEquals(ReturnCode.NEXT_COL, flist.filterCell(new KeyValue(r2, r2, r2)));
}
@Test
public void testWithMultiVersionsInSameRow() throws Exception {
FilterList filterList01 =
new FilterList(Operator.MUST_PASS_ONE, new ColumnPaginationFilter(1, 0));
KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual"),
1, Bytes.toBytes("value"));
KeyValue kv2 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual"),
2, Bytes.toBytes("value"));
KeyValue kv3 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual"),
3, Bytes.toBytes("value"));
assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList01.filterCell(kv1));
assertEquals(ReturnCode.NEXT_COL, filterList01.filterCell(kv2));
assertEquals(ReturnCode.NEXT_COL, filterList01.filterCell(kv3));
FilterList filterList11 =
new FilterList(Operator.MUST_PASS_ONE, new ColumnPaginationFilter(1, 1));
assertEquals(ReturnCode.NEXT_COL, filterList11.filterCell(kv1));
assertEquals(ReturnCode.NEXT_COL, filterList11.filterCell(kv2));
assertEquals(ReturnCode.NEXT_COL, filterList11.filterCell(kv3));
}
@Test
public void testMPONEWithSeekNextUsingHint() throws Exception {
byte[] col = Bytes.toBytes("c");
FilterList filterList =
new FilterList(Operator.MUST_PASS_ONE, new ColumnPaginationFilter(1, col));
KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1,
Bytes.toBytes("value"));
KeyValue kv2 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("b"), 2,
Bytes.toBytes("value"));
KeyValue kv3 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("c"), 3,
Bytes.toBytes("value"));
KeyValue kv4 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("c"), 4,
Bytes.toBytes("value"));
assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, filterList.filterCell(kv1));
assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, filterList.filterCell(kv2));
assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv3));
assertEquals(ReturnCode.NEXT_COL, filterList.filterCell(kv4));
}
/**
* Point deletes should only cover the exact entry they are tied to. Earlier puts should always
* show up.
*/
@Test
public void testCoveringPointDelete() {
// start with doing a family delete, so we will seek to the next column
KeyValue kv = createKvForType(Type.Delete);
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
filter.filterKeyValue(kv);
KeyValue put = createKvForType(Type.Put);
assertEquals("Didn't filter out put with same timestamp!", ReturnCode.SKIP,
filter.filterKeyValue(put));
// we should filter out the exact same put again, which could occur with the kvs all kept in the
// same memstore
assertEquals("Didn't filter out put with same timestamp on second call!", ReturnCode.SKIP,
filter.filterKeyValue(put));
// ensure then that we don't filter out a put with an earlier timestamp (though everything else
// matches)
put = createKvForType(Type.Put, ts - 1);
assertEquals("Didn't accept put that has an earlier ts than the covering delete!",
ReturnCode.INCLUDE, filter.filterKeyValue(put));
}
/**
* DeleteFamily markers should delete everything from that timestamp backwards, but not hide
* anything forwards
*/
@Test
public void testDeleteFamilyCorrectlyCoversColumns() {
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
KeyValue df = createKvForType(Type.DeleteFamily, 11);
KeyValue put = createKvForType(Type.Put, 12);
assertEquals("Didn't filter out delete family", ReturnCode.SKIP, filter.filterKeyValue(df));
assertEquals("Filtered out put with newer TS than delete family", ReturnCode.INCLUDE,
filter.filterKeyValue(put));
// older kv shouldn't be visible
put = createKvForType(Type.Put, 10);
assertEquals("Didn't filter out older put, covered by DeleteFamily marker",
ReturnCode.SEEK_NEXT_USING_HINT, filter.filterKeyValue(put));
// next seek should be past the families
assertEquals(KeyValue.LOWESTKEY, filter.getNextCellHint(put));
}
/**
* Test that we don't cover other columns when we have a delete column.
*/
@Test
public void testDeleteColumnCorrectlyCoversColumns() {
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
KeyValue d = createKvForType(Type.DeleteColumn, 12);
byte[] qual2 = Bytes.add(qualifier, Bytes.toBytes("-other"));
KeyValue put = new KeyValue(row, family, qual2, 11, Type.Put, value);
assertEquals("Didn't filter out delete column", ReturnCode.SKIP, filter.filterKeyValue(d));
// different column put should still be visible
assertEquals("Filtered out put with different column than the delete", ReturnCode.INCLUDE,
filter.filterKeyValue(put));
// set a delete family, but in the past
d = createKvForType(Type.DeleteFamily, 10);
assertEquals("Didn't filter out delete column", ReturnCode.SKIP, filter.filterKeyValue(d));
// add back in the original delete column
d = createKvForType(Type.DeleteColumn, 11);
assertEquals("Didn't filter out delete column", ReturnCode.SKIP, filter.filterKeyValue(d));
// onto a different family, so that must be visible too
assertEquals("Filtered out put with different column than the delete", ReturnCode.INCLUDE,
filter.filterKeyValue(put));
}
private boolean seekToNextUnfilteredKeyValue() throws IOException {
while (true) {
KeyValue peeked = delegate.peek();
// no more key values, so we are done
if (peeked == null) { return false; }
// filter the peeked value to see if it should be served
ReturnCode code = filter.filterKeyValue(peeked);
switch (code) {
// included, so we are done
case INCLUDE:
case INCLUDE_AND_NEXT_COL:
return true;
// not included, so we need to go to the next row
case SKIP:
case NEXT_COL:
case NEXT_ROW:
delegate.next();
break;
// use a seek hint to find out where we should go
case SEEK_NEXT_USING_HINT:
delegate.seek(filter.getNextKeyHint(peeked));
}
}
}
/**
* Point deletes should only cover the exact entry they are tied to. Earlier puts should always
* show up.
*/
@Test
public void testCoveringPointDelete() {
// start with doing a family delete, so we will seek to the next column
KeyValue kv = createKvForType(Type.Delete);
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
filter.filterKeyValue(kv);
KeyValue put = createKvForType(Type.Put);
assertEquals("Didn't filter out put with same timestamp!", ReturnCode.SKIP,
filter.filterKeyValue(put));
// we should filter out the exact same put again, which could occur with the kvs all kept in the
// same memstore
assertEquals("Didn't filter out put with same timestamp on second call!", ReturnCode.SKIP,
filter.filterKeyValue(put));
// ensure then that we don't filter out a put with an earlier timestamp (though everything else
// matches)
put = createKvForType(Type.Put, ts - 1);
assertEquals("Didn't accept put that has an earlier ts than the covering delete!",
ReturnCode.INCLUDE, filter.filterKeyValue(put));
}
/**
* DeleteFamily markers should delete everything from that timestamp backwards, but not hide
* anything forwards
*/
@Test
public void testDeleteFamilyCorrectlyCoversColumns() {
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
KeyValue df = createKvForType(Type.DeleteFamily, 11);
KeyValue put = createKvForType(Type.Put, 12);
assertEquals("Didn't filter out delete family", ReturnCode.SKIP, filter.filterKeyValue(df));
assertEquals("Filtered out put with newer TS than delete family", ReturnCode.INCLUDE,
filter.filterKeyValue(put));
// older kv shouldn't be visible
put = createKvForType(Type.Put, 10);
assertEquals("Didn't filter out older put, covered by DeleteFamily marker",
ReturnCode.SEEK_NEXT_USING_HINT, filter.filterKeyValue(put));
// next seek should be past the families
assertEquals(KeyValue.LOWESTKEY, filter.getNextKeyHint(put));
}
/**
* Test that we don't cover other columns when we have a delete column.
*/
@Test
public void testDeleteColumnCorrectlyCoversColumns() {
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
KeyValue d = createKvForType(Type.DeleteColumn, 12);
byte[] qual2 = Bytes.add(qualifier, Bytes.toBytes("-other"));
KeyValue put =
new KeyValue(row, family, qual2, 0, qual2.length, 11, Type.Put, value, 0,
value.length);
assertEquals("Didn't filter out delete column", ReturnCode.SKIP, filter.filterKeyValue(d));
// different column put should still be visible
assertEquals("Filtered out put with different column than the delete", ReturnCode.INCLUDE,
filter.filterKeyValue(put));
// set a delete family, but in the past
d = createKvForType(Type.DeleteFamily, 10);
assertEquals("Didn't filter out delete column", ReturnCode.SKIP, filter.filterKeyValue(d));
// add back in the original delete column
d = createKvForType(Type.DeleteColumn, 11);
assertEquals("Didn't filter out delete column", ReturnCode.SKIP, filter.filterKeyValue(d));
// onto a different family, so that must be visible too
assertEquals("Filtered out put with different column than the delete", ReturnCode.INCLUDE,
filter.filterKeyValue(put));
}
@Test
public void testDeletesAreNotReturned() {
KeyValue kv = createKvForType(Type.Delete);
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
assertEquals("Didn't skip point delete!", ReturnCode.SKIP, filter.filterKeyValue(kv));
filter.reset();
kv = createKvForType(Type.DeleteColumn);
assertEquals("Didn't skip from column delete!", ReturnCode.SKIP, filter.filterKeyValue(kv));
filter.reset();
kv = createKvForType(Type.DeleteFamily);
assertEquals("Didn't skip from family delete!", ReturnCode.SKIP, filter.filterKeyValue(kv));
}
/**
* Hinting with this filter is a little convoluted as we binary search the list of families to
* attempt to find the right one to seek.
*/
@Test
public void testHintCorrectlyToNextFamily() {
// start with doing a family delete, so we will seek to the next column
KeyValue kv = createKvForType(Type.DeleteFamily);
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
assertEquals(ReturnCode.SKIP, filter.filterKeyValue(kv));
KeyValue next = createKvForType(Type.Put);
// make sure the hint is our attempt at the end key, because we have no more families to seek
assertEquals("Didn't get a hint from a family delete", ReturnCode.SEEK_NEXT_USING_HINT,
filter.filterKeyValue(next));
assertEquals("Didn't get END_KEY with no families to match", KeyValue.LOWESTKEY,
filter.getNextCellHint(next));
// check for a family that comes before our family, so we always seek to the end as well
filter = new ApplyAndFilterDeletesFilter(asSet(Bytes.toBytes("afamily")));
assertEquals(ReturnCode.SKIP, filter.filterKeyValue(kv));
// make sure the hint is our attempt at the end key, because we have no more families to seek
assertEquals("Didn't get a hint from a family delete", ReturnCode.SEEK_NEXT_USING_HINT,
filter.filterKeyValue(next));
assertEquals("Didn't get END_KEY with no families to match", KeyValue.LOWESTKEY,
filter.getNextCellHint(next));
// check that we seek to the correct family that comes after our family
byte[] laterFamily = Bytes.toBytes("zfamily");
filter = new ApplyAndFilterDeletesFilter(asSet(laterFamily));
assertEquals(ReturnCode.SKIP, filter.filterKeyValue(kv));
@SuppressWarnings("deprecation")
KeyValue expected = KeyValue.createFirstOnRow(kv.getRow(), laterFamily, new byte[0]);
assertEquals("Didn't get a hint from a family delete", ReturnCode.SEEK_NEXT_USING_HINT,
filter.filterKeyValue(next));
assertEquals("Didn't get correct next key with a next family", expected,
filter.getNextCellHint(next));
}
/**
* Test that when we do a column delete at a given timestamp that we delete the entire column.
* @throws Exception
*/
@Test
public void testCoverForDeleteColumn() throws Exception {
ApplyAndFilterDeletesFilter filter = new ApplyAndFilterDeletesFilter(EMPTY_SET);
KeyValue dc = createKvForType(Type.DeleteColumn, 11);
KeyValue put = createKvForType(Type.Put, 10);
assertEquals("Didn't filter out delete column.", ReturnCode.SKIP, filter.filterKeyValue(dc));
assertEquals("Didn't get a seek hint for the deleted column", ReturnCode.SEEK_NEXT_USING_HINT,
filter.filterKeyValue(put));
// seek past the given put
Cell seek = filter.getNextCellHint(put);
assertTrue("Seeked key wasn't past the expected put - didn't skip the column",
KeyValue.COMPARATOR.compare(seek, put) > 0);
}
@SuppressWarnings("deprecation")
@Override public void examine(SkipScanFilter skipper) throws IOException {
KeyValue kv = KeyValue.createFirstOnRow(rowkey);
skipper.reset();
assertFalse(skipper.filterAllRemaining());
assertFalse(skipper.filterRowKey(kv.getBuffer(), kv.getRowOffset(), kv.getRowLength()));
assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, skipper.filterKeyValue(kv));
assertEquals(KeyValue.createFirstOnRow(hint), skipper.getNextCellHint(kv));
}
@SuppressWarnings("deprecation")
@Override public void examine(SkipScanFilter skipper) throws IOException {
KeyValue kv = KeyValue.createFirstOnRow(rowkey);
skipper.reset();
assertFalse(skipper.filterAllRemaining());
assertFalse(skipper.filterRowKey(kv.getBuffer(), kv.getRowOffset(), kv.getRowLength()));
assertEquals(kv.toString(), ReturnCode.INCLUDE, skipper.filterKeyValue(kv));
}
@Override public void examine(SkipScanFilter skipper) throws IOException {
KeyValue kv = KeyValue.createFirstOnRow(rowkey);
skipper.reset();
assertEquals(ReturnCode.NEXT_ROW,skipper.filterKeyValue(kv));
skipper.reset();
assertTrue(skipper.filterAllRemaining());
}
/**
* When we do a "MUST_PASS_ONE" (a logical 'OR') of the above two filters
* we expect to get the same result as the 'prefix' only result.
* @throws Exception
*/
@Test
public void testFilterListTwoFiltersMustPassOne() throws Exception {
byte[] r1 = Bytes.toBytes("Row1");
byte[] r11 = Bytes.toBytes("Row11");
byte[] r2 = Bytes.toBytes("Row2");
FilterList flist = new FilterList(FilterList.Operator.MUST_PASS_ONE);
flist.addFilter(new PrefixFilter(r1));
flist.filterRowKey(KeyValueUtil.createFirstOnRow(r1));
assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r1, r1, r1)));
assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r11, r11, r11)));
flist.reset();
flist.filterRowKey(KeyValueUtil.createFirstOnRow(r2));
assertEquals(ReturnCode.SKIP, flist.filterCell(new KeyValue(r2, r2, r2)));
flist = new FilterList(FilterList.Operator.MUST_PASS_ONE);
flist.addFilter(new AlwaysNextColFilter());
flist.addFilter(new PrefixFilter(r1));
flist.filterRowKey(KeyValueUtil.createFirstOnRow(r1));
assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r1, r1, r1)));
assertEquals(ReturnCode.INCLUDE, flist.filterCell(new KeyValue(r11, r11, r11)));
flist.reset();
flist.filterRowKey(KeyValueUtil.createFirstOnRow(r2));
assertEquals(ReturnCode.NEXT_COL, flist.filterCell(new KeyValue(r2, r2, r2)));
}
/**
* Tests the behavior of transform() in a hierarchical filter.
*
* transform() only applies after a filterCell() whose return-code includes the KeyValue.
* Lazy evaluation of AND
*/
@Test
public void testTransformMPO() throws Exception {
// Apply the following filter:
// (family=fam AND qualifier=qual1 AND KeyOnlyFilter)
// OR (family=fam AND qualifier=qual2)
final FilterList flist = new FilterList(Operator.MUST_PASS_ONE, Lists.<Filter>newArrayList(
new FilterList(Operator.MUST_PASS_ALL, Lists.<Filter>newArrayList(
new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("fam"))),
new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("qual1"))),
new KeyOnlyFilter())),
new FilterList(Operator.MUST_PASS_ALL, Lists.<Filter>newArrayList(
new FamilyFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("fam"))),
new QualifierFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("qual2")))))));
final KeyValue kvQual1 = new KeyValue(
Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual1"), Bytes.toBytes("value"));
final KeyValue kvQual2 = new KeyValue(
Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual2"), Bytes.toBytes("value"));
final KeyValue kvQual3 = new KeyValue(
Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("qual3"), Bytes.toBytes("value"));
// Value for fam:qual1 should be stripped:
assertEquals(Filter.ReturnCode.INCLUDE, flist.filterCell(kvQual1));
final KeyValue transformedQual1 = KeyValueUtil.ensureKeyValue(flist.transformCell(kvQual1));
assertEquals(0, transformedQual1.getValueLength());
// Value for fam:qual2 should not be stripped:
assertEquals(Filter.ReturnCode.INCLUDE, flist.filterCell(kvQual2));
final KeyValue transformedQual2 = KeyValueUtil.ensureKeyValue(flist.transformCell(kvQual2));
assertEquals("value", Bytes.toString(transformedQual2.getValueArray(),
transformedQual2.getValueOffset(), transformedQual2.getValueLength()));
// Other keys should be skipped:
assertEquals(Filter.ReturnCode.SKIP, flist.filterCell(kvQual3));
}
@Test
public void testTheMaximalRule() throws IOException {
KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1,
Bytes.toBytes("value"));
MockFilter filter1 = new MockFilter(ReturnCode.INCLUDE);
MockFilter filter2 = new MockFilter(ReturnCode.INCLUDE_AND_NEXT_COL);
MockFilter filter3 = new MockFilter(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW);
MockFilter filter4 = new MockFilter(ReturnCode.NEXT_COL);
MockFilter filter5 = new MockFilter(ReturnCode.SKIP);
MockFilter filter6 = new MockFilter(ReturnCode.SEEK_NEXT_USING_HINT);
MockFilter filter7 = new MockFilter(ReturnCode.NEXT_ROW);
FilterList filterList = new FilterList(Operator.MUST_PASS_ALL, filter1, filter2);
assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ALL, filter2, filter3);
assertEquals(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ALL, filter4, filter5, filter6);
assertEquals(ReturnCode.NEXT_COL, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ALL, filter4, filter6);
assertEquals(ReturnCode.NEXT_COL, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ALL, filter3, filter1);
assertEquals(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ALL, filter3, filter2, filter1, filter5);
assertEquals(ReturnCode.NEXT_ROW, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ALL, filter2,
new FilterList(Operator.MUST_PASS_ALL, filter3, filter4));
assertEquals(ReturnCode.NEXT_ROW, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ALL, filter3, filter7);
assertEquals(ReturnCode.NEXT_ROW, filterList.filterCell(kv1));
}
@Test
public void testTheMinimalRule() throws IOException {
KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1,
Bytes.toBytes("value"));
MockFilter filter1 = new MockFilter(ReturnCode.INCLUDE);
MockFilter filter2 = new MockFilter(ReturnCode.INCLUDE_AND_NEXT_COL);
MockFilter filter3 = new MockFilter(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW);
MockFilter filter4 = new MockFilter(ReturnCode.NEXT_COL);
MockFilter filter5 = new MockFilter(ReturnCode.SKIP);
MockFilter filter6 = new MockFilter(ReturnCode.SEEK_NEXT_USING_HINT);
FilterList filterList = new FilterList(Operator.MUST_PASS_ONE, filter1, filter2);
assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ONE, filter2, filter3);
assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ONE, filter4, filter5, filter6);
assertEquals(ReturnCode.SKIP, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ONE, filter4, filter6);
assertEquals(ReturnCode.SKIP, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ONE, filter3, filter1);
assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ONE, filter3, filter2, filter1, filter5);
assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ONE, filter2,
new FilterList(Operator.MUST_PASS_ONE, filter3, filter4));
assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ONE, filter2,
new FilterList(Operator.MUST_PASS_ONE, filter3, filter4));
assertEquals(ReturnCode.INCLUDE_AND_NEXT_COL, filterList.filterCell(kv1));
filterList = new FilterList(Operator.MUST_PASS_ONE, filter6, filter6);
assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, filterList.filterCell(kv1));
}
@Test
public void testReversedFilterListWithMockSeekHintFilter() throws IOException {
KeyValue kv1 = new KeyValue(Bytes.toBytes("row1"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1,
Bytes.toBytes("value"));
KeyValue kv2 = new KeyValue(Bytes.toBytes("row2"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1,
Bytes.toBytes("value"));
KeyValue kv3 = new KeyValue(Bytes.toBytes("row3"), Bytes.toBytes("fam"), Bytes.toBytes("a"), 1,
Bytes.toBytes("value"));
Filter filter1 = new MockSeekHintFilter(kv1);
filter1.setReversed(true);
Filter filter2 = new MockSeekHintFilter(kv2);
filter2.setReversed(true);
Filter filter3 = new MockSeekHintFilter(kv3);
filter3.setReversed(true);
FilterList filterList = new FilterList(Operator.MUST_PASS_ONE);
filterList.setReversed(true);
filterList.addFilter(filter1);
filterList.addFilter(filter2);
filterList.addFilter(filter3);
Assert.assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, filterList.filterCell(kv1));
Assert.assertEquals(kv3, filterList.getNextCellHint(kv1));
filterList = new FilterList(Operator.MUST_PASS_ALL);
filterList.setReversed(true);
filterList.addFilter(filter1);
filterList.addFilter(filter2);
filterList.addFilter(filter3);
Assert.assertEquals(ReturnCode.SEEK_NEXT_USING_HINT, filterList.filterCell(kv1));
Assert.assertEquals(kv1, filterList.getNextCellHint(kv1));
}
@Test
public void testReversedFilterListWithOR() throws IOException {
byte[] r22 = Bytes.toBytes("Row22");
byte[] r2 = Bytes.toBytes("Row2");
byte[] r1 = Bytes.toBytes("Row1");
FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE);
filterList.setReversed(true);
PrefixFilter prefixFilter = new PrefixFilter(r2);
prefixFilter.setReversed(true);
filterList.addFilter(prefixFilter);
filterList.filterRowKey(KeyValueUtil.createFirstOnRow(r22));
assertEquals(ReturnCode.INCLUDE, filterList.filterCell(new KeyValue(r22, r22, r22)));
assertEquals(ReturnCode.INCLUDE, filterList.filterCell(new KeyValue(r2, r2, r2)));
filterList.reset();
filterList.filterRowKey(KeyValueUtil.createFirstOnRow(r1));
assertEquals(ReturnCode.SKIP, filterList.filterCell(new KeyValue(r1, r1, r1)));
filterList = new FilterList(FilterList.Operator.MUST_PASS_ONE);
filterList.setReversed(true);
AlwaysNextColFilter alwaysNextColFilter = new AlwaysNextColFilter();
alwaysNextColFilter.setReversed(true);
prefixFilter = new PrefixFilter(r2);
prefixFilter.setReversed(true);
filterList.addFilter(alwaysNextColFilter);
filterList.addFilter(prefixFilter);
filterList.filterRowKey(KeyValueUtil.createFirstOnRow(r22));
assertEquals(ReturnCode.INCLUDE, filterList.filterCell(new KeyValue(r22, r22, r22)));
assertEquals(ReturnCode.INCLUDE, filterList.filterCell(new KeyValue(r2, r2, r2)));
filterList.reset();
filterList.filterRowKey(KeyValueUtil.createFirstOnRow(r1));
assertEquals(ReturnCode.NEXT_COL, filterList.filterCell(new KeyValue(r1, r1, r1)));
}
@Test
public void testKeyOnlyFilterTransformCell() throws IOException {
Cell c;
KeyValue kv1 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("cf"), Bytes.toBytes("column1"),
1, Bytes.toBytes("value1"));
KeyValue kv2 = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("cf"), Bytes.toBytes("column1"),
2, Bytes.toBytes("value2"));
Filter filter1 = new SingleColumnValueFilter(Bytes.toBytes("cf"), Bytes.toBytes("column1"),
CompareOperator.EQUAL, Bytes.toBytes("value1"));
Filter filter2 = new SingleColumnValueFilter(Bytes.toBytes("cf"), Bytes.toBytes("column1"),
CompareOperator.EQUAL, Bytes.toBytes("value2"));
FilterList internalFilterList = new FilterList(Operator.MUST_PASS_ONE, filter1, filter2);
FilterList keyOnlyFilterFirst =
new FilterList(Operator.MUST_PASS_ALL, new KeyOnlyFilter(), internalFilterList);
assertEquals(ReturnCode.INCLUDE, keyOnlyFilterFirst.filterCell(kv1));
c = keyOnlyFilterFirst.transformCell(kv1);
assertEquals(0, c.getValueLength());
assertEquals(ReturnCode.INCLUDE, keyOnlyFilterFirst.filterCell(kv2));
c = keyOnlyFilterFirst.transformCell(kv2);
assertEquals(0, c.getValueLength());
internalFilterList.reset();
FilterList keyOnlyFilterLast =
new FilterList(Operator.MUST_PASS_ALL, new KeyOnlyFilter(), internalFilterList);
assertEquals(ReturnCode.INCLUDE, keyOnlyFilterLast.filterCell(kv1));
c = keyOnlyFilterLast.transformCell(kv1);
assertEquals(0, c.getValueLength());
assertEquals(ReturnCode.INCLUDE, keyOnlyFilterLast.filterCell(kv2));
c = keyOnlyFilterLast.transformCell(kv2);
assertEquals(0, c.getValueLength());
}
@Test
public void testEmptyFilterListTransformCell() throws IOException {
KeyValue kv = new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("cf"), Bytes.toBytes("column1"),
1, Bytes.toBytes("value"));
FilterList filterList = new FilterList(Operator.MUST_PASS_ALL);
assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv));
assertEquals(kv, filterList.transformCell(kv));
filterList = new FilterList(Operator.MUST_PASS_ONE);
assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv));
assertEquals(kv, filterList.transformCell(kv));
}
@Test
public void testTransformCell() throws IOException {
KeyValue kv =
new KeyValue(Bytes.toBytes("row"), Bytes.toBytes("cf"), Bytes.toBytes("column1"), 1,
Bytes.toBytes("value"));
// case MUST_PASS_ONE
TransformFilter filter1 = new TransformFilter(ReturnCode.INCLUDE);
TransformFilter filter2 = new TransformFilter(ReturnCode.NEXT_ROW);
TransformFilter filter3 = new TransformFilter(ReturnCode.SEEK_NEXT_USING_HINT);
FilterList filterList = new FilterList(Operator.MUST_PASS_ONE, filter1, filter2, filter3);
Assert.assertEquals(ReturnCode.INCLUDE, filterList.filterCell(kv));
Assert.assertEquals(kv, filterList.transformCell(kv));
Assert.assertEquals(true, filter1.getTransformed());
Assert.assertEquals(false, filter2.getTransformed());
Assert.assertEquals(false, filter3.getTransformed());
// case MUST_PASS_ALL
filter1 = new TransformFilter(ReturnCode.INCLUDE);
filter2 = new TransformFilter(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW);
filter3 = new TransformFilter(ReturnCode.INCLUDE_AND_NEXT_COL);
filterList = new FilterList(Operator.MUST_PASS_ALL, filter1, filter2, filter3);
Assert.assertEquals(ReturnCode.INCLUDE_AND_SEEK_NEXT_ROW, filterList.filterCell(kv));
Assert.assertEquals(kv, filterList.transformCell(kv));
Assert.assertEquals(true, filter1.getTransformed());
Assert.assertEquals(true, filter2.getTransformed());
Assert.assertEquals(true, filter3.getTransformed());
}
private boolean seekToNextUnfilteredKeyValue() throws IOException {
while (true) {
Cell peeked = delegate.peek();
// no more key values, so we are done
if (peeked == null) { return false; }
// filter the peeked value to see if it should be served
ReturnCode code = filter.filterKeyValue(peeked);
switch (code) {
// included, so we are done
case INCLUDE:
case INCLUDE_AND_NEXT_COL:
return true;
// not included, so we need to go to the next row
case SKIP:
case NEXT_COL:
case NEXT_ROW:
delegate.next();
break;
// use a seek hint to find out where we should go
case SEEK_NEXT_USING_HINT:
Cell nextCellHint = filter.getNextCellHint(peeked);
if(nextCellHint == KeyValue.LOWESTKEY) {
delegate.next();
} else {
delegate.seek(PhoenixKeyValueUtil.maybeCopyCell(nextCellHint));
}
}
}
}