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.assertArrayEquals;
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertFalse;
023
024import java.io.IOException;
025import java.util.ArrayList;
026import java.util.List;
027import org.apache.hadoop.hbase.Cell;
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HBaseTestingUtil;
030import org.apache.hadoop.hbase.HTestConst;
031import org.apache.hadoop.hbase.KeyValue;
032import org.apache.hadoop.hbase.TableName;
033import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
034import org.apache.hadoop.hbase.client.Put;
035import org.apache.hadoop.hbase.client.RegionInfo;
036import org.apache.hadoop.hbase.client.RegionInfoBuilder;
037import org.apache.hadoop.hbase.client.Scan;
038import org.apache.hadoop.hbase.client.TableDescriptor;
039import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
040import org.apache.hadoop.hbase.regionserver.HRegion;
041import org.apache.hadoop.hbase.regionserver.InternalScanner;
042import org.apache.hadoop.hbase.testclassification.SmallTests;
043import org.apache.hadoop.hbase.util.Bytes;
044import org.junit.AfterClass;
045import org.junit.BeforeClass;
046import org.junit.ClassRule;
047import org.junit.Test;
048import org.junit.experimental.categories.Category;
049
050/**
051 * To test behavior of filters at server from region side.
052 */
053@Category(SmallTests.class)
054public class TestFilterFromRegionSide {
055
056  @ClassRule
057  public static final HBaseClassTestRule CLASS_RULE =
058    HBaseClassTestRule.forClass(TestFilterFromRegionSide.class);
059
060  private final static HBaseTestingUtil TEST_UTIL = new HBaseTestingUtil();
061  private static HRegion REGION;
062
063  private static TableName TABLE_NAME = TableName.valueOf("TestFilterFromRegionSide");
064
065  private static int NUM_ROWS = 5;
066  private static byte[] ROW = Bytes.toBytes("testRow");
067  private static byte[][] ROWS = HTestConst.makeNAscii(ROW, NUM_ROWS);
068
069  // Should keep this value below 10 to keep generation of expected kv's simple. If above 10 then
070  // table/row/cf1/... will be followed by table/row/cf10/... instead of table/row/cf2/... which
071  // breaks the simple generation of expected kv's
072  private static int NUM_FAMILIES = 5;
073  private static byte[] FAMILY = Bytes.toBytes("testFamily");
074  private static byte[][] FAMILIES = HTestConst.makeNAscii(FAMILY, NUM_FAMILIES);
075
076  private static int NUM_QUALIFIERS = 5;
077  private static byte[] QUALIFIER = Bytes.toBytes("testQualifier");
078  private static byte[][] QUALIFIERS = HTestConst.makeNAscii(QUALIFIER, NUM_QUALIFIERS);
079
080  private static int VALUE_SIZE = 1024;
081  private static byte[] VALUE = Bytes.createMaxByteArray(VALUE_SIZE);
082
083  private static int NUM_COLS = NUM_FAMILIES * NUM_QUALIFIERS;
084
085  @BeforeClass
086  public static void setUpBeforeClass() throws Exception {
087    TableDescriptorBuilder builder = TableDescriptorBuilder.newBuilder(TABLE_NAME);
088
089    for (byte[] family : FAMILIES) {
090      builder.setColumnFamily(ColumnFamilyDescriptorBuilder.of(family));
091    }
092    TableDescriptor tableDescriptor = builder.build();
093    RegionInfo info = RegionInfoBuilder.newBuilder(tableDescriptor.getTableName()).build();
094    REGION = HBaseTestingUtil.createRegionAndWAL(info, TEST_UTIL.getDataTestDir(),
095      TEST_UTIL.getConfiguration(), tableDescriptor);
096    for (Put put : createPuts(ROWS, FAMILIES, QUALIFIERS, VALUE)) {
097      REGION.put(put);
098    }
099  }
100
101  private static ArrayList<Put> createPuts(byte[][] rows, byte[][] families, byte[][] qualifiers,
102    byte[] value) throws IOException {
103    Put put;
104    ArrayList<Put> puts = new ArrayList<>();
105
106    for (byte[] row1 : rows) {
107      put = new Put(row1);
108      for (byte[] family : families) {
109        for (int qual = 0; qual < qualifiers.length; qual++) {
110          KeyValue kv = new KeyValue(row1, family, qualifiers[qual], qual, value);
111          put.add(kv);
112        }
113      }
114      puts.add(put);
115    }
116
117    return puts;
118  }
119
120  @AfterClass
121  public static void tearDownAfterClass() throws Exception {
122    REGION.close();
123  }
124
125  @Test
126  public void testFirstKeyOnlyFilterAndBatch() throws IOException {
127    Scan scan = new Scan();
128    scan.setFilter(new FirstKeyOnlyFilter());
129    scan.setBatch(1);
130    InternalScanner scanner = REGION.getScanner(scan);
131    List<Cell> results = new ArrayList<>();
132    for (int i = 0; i < NUM_ROWS; i++) {
133      results.clear();
134      scanner.next(results);
135      assertEquals(1, results.size());
136      Cell cell = results.get(0);
137      assertArrayEquals(ROWS[i],
138        Bytes.copy(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
139    }
140    assertFalse(scanner.next(results));
141    scanner.close();
142  }
143
144  public static class FirstSeveralCellsFilter extends FilterBase {
145    private int count = 0;
146
147    @Override
148    public void reset() {
149      count = 0;
150    }
151
152    @Override
153    public boolean filterRowKey(Cell cell) throws IOException {
154      return false;
155    }
156
157    @Override
158    public ReturnCode filterCell(final Cell v) {
159      if (count++ < NUM_COLS) {
160        return ReturnCode.INCLUDE;
161      }
162      return ReturnCode.SKIP;
163    }
164
165    public static Filter parseFrom(final byte[] pbBytes) {
166      return new FirstSeveralCellsFilter();
167    }
168  }
169
170  @Test
171  public void testFirstSeveralCellsFilterAndBatch() throws IOException {
172    Scan scan = new Scan();
173    scan.setFilter(new FirstSeveralCellsFilter());
174    scan.setBatch(NUM_COLS);
175    InternalScanner scanner = REGION.getScanner(scan);
176    List<Cell> results = new ArrayList<>();
177    for (int i = 0; i < NUM_ROWS; i++) {
178      results.clear();
179      scanner.next(results);
180      assertEquals(NUM_COLS, results.size());
181      Cell cell = results.get(0);
182      assertArrayEquals(ROWS[i],
183        Bytes.copy(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()));
184      assertArrayEquals(FAMILIES[0],
185        Bytes.copy(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()));
186      assertArrayEquals(QUALIFIERS[0],
187        Bytes.copy(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()));
188    }
189    assertFalse(scanner.next(results));
190    scanner.close();
191  }
192}