| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.tephra.hbase.coprocessor; |
| |
| import org.apache.hadoop.hbase.Cell; |
| import org.apache.hadoop.hbase.KeyValue; |
| import org.apache.hadoop.hbase.filter.Filter; |
| import org.apache.hadoop.hbase.filter.FilterBase; |
| import org.apache.hadoop.hbase.util.Bytes; |
| import org.junit.Test; |
| |
| import java.io.IOException; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import static org.junit.Assert.assertEquals; |
| |
| /** |
| * HBase 0.98 specific test for testing {@link CellSkipFilter}. |
| */ |
| public class CellSkipFilterTest { |
| |
| private static final String ROW1KEY = "row1"; |
| private static final String ROW2KEY = "row2"; |
| private static final String FAM1KEY = "fam1"; |
| private static final String COL1KEY = "col1"; |
| private static final String FAM2KEY = "fam2"; |
| private static final String COL2KEY = "col2"; |
| private static final String VALUE = "value"; |
| |
| @Test |
| public void testSkipFiltering() throws Exception { |
| long timestamp = System.currentTimeMillis(); |
| // Test to check that we get NEXT_COL once the INCLUDE_AND_NEXT_COL is returned for the same key |
| Filter filter = new CellSkipFilter(new MyFilter(0)); |
| assertEquals(Filter.ReturnCode.INCLUDE, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM1KEY, COL1KEY, VALUE, |
| timestamp))); |
| assertEquals(Filter.ReturnCode.INCLUDE_AND_NEXT_COL, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM1KEY, COL1KEY, |
| VALUE, timestamp - 1))); |
| |
| // Next call should get NEXT_COL instead of SKIP, as it would be returned by CellSkipFilter |
| assertEquals(Filter.ReturnCode.NEXT_COL, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM1KEY, COL1KEY, VALUE, |
| timestamp - 2))); |
| |
| // Next call with the same key should return the NEXT_COL again, as it would be returned by CellSkipFilter |
| assertEquals(Filter.ReturnCode.NEXT_COL, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM1KEY, COL1KEY, VALUE, |
| timestamp - 3))); |
| |
| // Since MyFilter counter is not incremented in the previous call, filtering for the different keyvalue should |
| // give SKIP from MyFilter |
| assertEquals(Filter.ReturnCode.SKIP, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM2KEY, COL1KEY, VALUE, |
| timestamp - 4))); |
| |
| // Test to check that we get NEXT_COL once the NEXT_COL is returned for the same key |
| filter = new CellSkipFilter(new MyFilter(2)); |
| assertEquals(Filter.ReturnCode.SKIP, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM1KEY, COL1KEY, VALUE, |
| timestamp))); |
| assertEquals(Filter.ReturnCode.NEXT_COL, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM1KEY, COL1KEY, VALUE, |
| timestamp - 1))); |
| |
| // Next call should get NEXT_COL instead of NEXT_ROW, as it would be returned by CellSkipFilter |
| assertEquals(Filter.ReturnCode.NEXT_COL, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM1KEY, COL1KEY, VALUE, |
| timestamp - 2))); |
| |
| // Next call with the same key should return the NEXT_COL again, as it would be returned by CellSkipFilter |
| assertEquals(Filter.ReturnCode.NEXT_COL, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM1KEY, COL1KEY, VALUE, |
| timestamp - 3))); |
| |
| // Since MyFilter counter is not incremented in the previous call, filtering for the different keyvalue should |
| // give NEXT_ROW from MyFilter |
| assertEquals(Filter.ReturnCode.NEXT_ROW, filter.filterKeyValue(newKeyValue(ROW1KEY, FAM1KEY, COL2KEY, VALUE, |
| timestamp - 4))); |
| |
| // Next call with the new key should returned the SEEK_NEXT_USING_HINT |
| assertEquals(Filter.ReturnCode.SEEK_NEXT_USING_HINT, filter.filterKeyValue(newKeyValue(ROW2KEY, FAM1KEY, COL1KEY, |
| VALUE, timestamp - 5))); |
| } |
| |
| private KeyValue newKeyValue(String rowkey, String family, String column, String value, long timestamp) { |
| return new KeyValue(Bytes.toBytes(rowkey), Bytes.toBytes(family), Bytes.toBytes(column), |
| timestamp, Bytes.toBytes(value)); |
| } |
| |
| /** |
| * Sample filter for testing. This filter maintains the {@link List} of {@link ReturnCode}s. It accepts the |
| * start index in the list and start serving the return codes corresponding that that index. Every time the |
| * return code is served, index is incremented. |
| */ |
| class MyFilter extends FilterBase { |
| |
| private final List<ReturnCode> returnCodes; |
| private int counter; |
| |
| public MyFilter(int startIndex) { |
| returnCodes = Arrays.asList(ReturnCode.INCLUDE, ReturnCode.INCLUDE_AND_NEXT_COL, ReturnCode.SKIP, |
| ReturnCode.NEXT_COL, ReturnCode.NEXT_ROW, ReturnCode.SEEK_NEXT_USING_HINT); |
| counter = startIndex; |
| } |
| |
| @Override |
| public ReturnCode filterKeyValue(Cell cell) throws IOException { |
| ReturnCode code = returnCodes.get(counter % returnCodes.size()); |
| counter++; |
| return code; |
| } |
| } |
| } |