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.nio.ByteBuffer;
024import java.util.ArrayList;
025import java.util.List;
026import org.apache.hadoop.hbase.Cell;
027import org.apache.hadoop.hbase.CellUtil;
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HBaseTestingUtility;
030import org.apache.hadoop.hbase.TableName;
031import org.apache.hadoop.hbase.client.Durability;
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.testclassification.FilterTests;
038import org.apache.hadoop.hbase.testclassification.MediumTests;
039import org.apache.hadoop.hbase.util.Bytes;
040import org.apache.hadoop.hbase.util.Pair;
041import org.junit.After;
042import org.junit.AfterClass;
043import org.junit.Before;
044import org.junit.BeforeClass;
045import org.junit.ClassRule;
046import org.junit.Rule;
047import org.junit.Test;
048import org.junit.experimental.categories.Category;
049import org.junit.rules.TestName;
050import org.slf4j.Logger;
051import org.slf4j.LoggerFactory;
052
053import org.apache.hbase.thirdparty.com.google.common.collect.Lists;
054
055/**
056 */
057@Category({FilterTests.class, MediumTests.class})
058public class TestFuzzyRowAndColumnRangeFilter {
059
060  @ClassRule
061  public static final HBaseClassTestRule CLASS_RULE =
062      HBaseClassTestRule.forClass(TestFuzzyRowAndColumnRangeFilter.class);
063
064  private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
065  private static final Logger LOG = LoggerFactory.getLogger(TestFuzzyRowAndColumnRangeFilter.class);
066
067  @Rule
068  public TestName name = new TestName();
069
070  /**
071   * @throws java.lang.Exception
072   */
073  @BeforeClass
074  public static void setUpBeforeClass() throws Exception {
075    TEST_UTIL.startMiniCluster();
076  }
077
078  /**
079   * @throws java.lang.Exception
080   */
081  @AfterClass
082  public static void tearDownAfterClass() throws Exception {
083    TEST_UTIL.shutdownMiniCluster();
084  }
085
086  /**
087   * @throws java.lang.Exception
088   */
089  @Before
090  public void setUp() throws Exception {
091    // Nothing to do.
092  }
093
094  /**
095   * @throws java.lang.Exception
096   */
097  @After
098  public void tearDown() throws Exception {
099    // Nothing to do.
100  }
101
102  @Test
103  public void Test() throws Exception {
104    String cf = "f";
105    Table ht = TEST_UTIL.createTable(TableName.valueOf(name.getMethodName()),
106            Bytes.toBytes(cf), Integer.MAX_VALUE);
107
108    // 10 byte row key - (2 bytes 4 bytes 4 bytes)
109    // 4 byte qualifier
110    // 4 byte value
111
112    for (int i1 = 0; i1 < 2; i1++) {
113      for (int i2 = 0; i2 < 5; i2++) {
114        byte[] rk = new byte[10];
115
116        ByteBuffer buf = ByteBuffer.wrap(rk);
117        buf.clear();
118        buf.putShort((short) 2);
119        buf.putInt(i1);
120        buf.putInt(i2);
121
122        for (int c = 0; c < 5; c++) {
123          byte[] cq = new byte[4];
124          Bytes.putBytes(cq, 0, Bytes.toBytes(c), 0, 4);
125
126          Put p = new Put(rk);
127          p.setDurability(Durability.SKIP_WAL);
128          p.addColumn(Bytes.toBytes(cf), cq, Bytes.toBytes(c));
129          ht.put(p);
130          LOG.info("Inserting: rk: " + Bytes.toStringBinary(rk) + " cq: "
131                  + Bytes.toStringBinary(cq));
132        }
133      }
134    }
135
136    TEST_UTIL.flush();
137
138    // test passes
139    runTest(ht, 0, 10);
140
141    // test fails
142    runTest(ht, 1, 8);
143  }
144
145  private void runTest(Table hTable, int cqStart, int expectedSize) throws IOException {
146    // [0, 2, ?, ?, ?, ?, 0, 0, 0, 1]
147    byte[] fuzzyKey = new byte[10];
148    ByteBuffer buf = ByteBuffer.wrap(fuzzyKey);
149    buf.clear();
150    buf.putShort((short) 2);
151    for (int i = 0; i < 4; i++)
152      buf.put((byte)63);
153    buf.putInt((short)1);
154
155    byte[] mask = new byte[] {0 , 0, 1, 1, 1, 1, 0, 0, 0, 0};
156
157    Pair<byte[], byte[]> pair = new Pair<>(fuzzyKey, mask);
158    FuzzyRowFilter fuzzyRowFilter = new FuzzyRowFilter(Lists.newArrayList(pair));
159    ColumnRangeFilter columnRangeFilter = new ColumnRangeFilter(Bytes.toBytes(cqStart), true
160            , Bytes.toBytes(4), true);
161    //regular test
162    runScanner(hTable, expectedSize, fuzzyRowFilter, columnRangeFilter);
163    //reverse filter order test
164    runScanner(hTable, expectedSize, columnRangeFilter, fuzzyRowFilter);
165  }
166
167  private void runScanner(Table hTable, int expectedSize, Filter... filters) throws IOException {
168    String cf = "f";
169    Scan scan = new Scan();
170    scan.addFamily(Bytes.toBytes(cf));
171    FilterList filterList = new FilterList(filters);
172    scan.setFilter(filterList);
173
174    ResultScanner scanner = hTable.getScanner(scan);
175    List<Cell> results = new ArrayList<>();
176    Result result;
177    long timeBeforeScan = System.currentTimeMillis();
178    while ((result = scanner.next()) != null) {
179      for (Cell kv : result.listCells()) {
180        LOG.info("Got rk: " + Bytes.toStringBinary(CellUtil.cloneRow(kv)) + " cq: "
181                + Bytes.toStringBinary(CellUtil.cloneQualifier(kv)));
182        results.add(kv);
183      }
184    }
185    long scanTime = System.currentTimeMillis() - timeBeforeScan;
186    scanner.close();
187
188    LOG.info("scan time = " + scanTime + "ms");
189    LOG.info("found " + results.size() + " results");
190
191    assertEquals(expectedSize, results.size());
192  }
193}