View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.filter;
19  
20  import static org.junit.Assert.*;
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.Set;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.hadoop.hbase.*;
33  import org.apache.hadoop.hbase.client.HTable;
34  import org.apache.hadoop.hbase.client.Put;
35  import org.apache.hadoop.hbase.client.Result;
36  import org.apache.hadoop.hbase.client.ResultScanner;
37  import org.apache.hadoop.hbase.client.Scan;
38  import org.apache.hadoop.hbase.client.Durability;
39  import org.apache.hadoop.hbase.regionserver.HRegion;
40  import org.apache.hadoop.hbase.regionserver.InternalScanner;
41  import org.apache.hadoop.hbase.util.Bytes;
42  import org.junit.Test;
43  import org.junit.After;
44  import org.junit.AfterClass;
45  import org.junit.Before;
46  import org.junit.BeforeClass;
47  import org.junit.experimental.categories.Category;
48  
49  
50  class StringRange {
51    private String start = null;
52    private String end = null;
53    private boolean startInclusive = true;
54    private boolean endInclusive = false;
55  
56    public StringRange(String start, boolean startInclusive, String end,
57        boolean endInclusive) {
58      this.start = start;
59      this.startInclusive = startInclusive;
60      this.end = end;
61      this.endInclusive = endInclusive;
62    }
63  
64    public String getStart() {
65      return this.start;
66    }
67  
68    public String getEnd() {
69      return this.end;
70    }
71  
72    public boolean isStartInclusive() {
73      return this.startInclusive;
74    }
75  
76    public boolean isEndInclusive() {
77      return this.endInclusive;
78    }
79  
80    @Override
81    public int hashCode() {
82      int hashCode = 0;
83      if (this.start != null) {
84        hashCode ^= this.start.hashCode();
85      }
86  
87      if (this.end != null) {
88        hashCode ^= this.end.hashCode();
89      }
90      return hashCode;
91    }
92  
93    @Override
94    public String toString() {
95      String result = (this.startInclusive ? "[" : "(")
96            + (this.start == null ? null : this.start) + ", "
97            + (this.end == null ? null : this.end)
98            + (this.endInclusive ? "]" : ")");
99      return result;
100   }
101 
102    public boolean inRange(String value) {
103     boolean afterStart = true;
104     if (this.start != null) {
105       int startCmp = value.compareTo(this.start);
106       afterStart = this.startInclusive ? startCmp >= 0 : startCmp > 0;
107     }
108 
109     boolean beforeEnd = true;
110     if (this.end != null) {
111       int endCmp = value.compareTo(this.end);
112       beforeEnd = this.endInclusive ? endCmp <= 0 : endCmp < 0;
113     }
114 
115     return afterStart && beforeEnd;
116   }
117 
118 }
119 
120 
121 @Category(MediumTests.class)
122 public class TestColumnRangeFilter {
123 
124   private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
125 
126   private final Log LOG = LogFactory.getLog(this.getClass());
127 
128   /**
129    * @throws java.lang.Exception
130    */
131   @BeforeClass
132   public static void setUpBeforeClass() throws Exception {
133     TEST_UTIL.startMiniCluster();
134   }
135 
136   /**
137    * @throws java.lang.Exception
138    */
139   @AfterClass
140   public static void tearDownAfterClass() throws Exception {
141     TEST_UTIL.shutdownMiniCluster();
142   }
143 
144   /**
145    * @throws java.lang.Exception
146    */
147   @Before
148   public void setUp() throws Exception {
149     // Nothing to do.
150   }
151 
152   /**
153    * @throws java.lang.Exception
154    */
155   @After
156   public void tearDown() throws Exception {
157     // Nothing to do.
158   }
159 
160   @Test
161   public void TestColumnRangeFilterClient() throws Exception {
162     String family = "Family";
163     String table = "TestColumnRangeFilterClient";
164     HTable ht = TEST_UTIL.createTable(Bytes.toBytes(table),
165         Bytes.toBytes(family), Integer.MAX_VALUE);
166 
167     List<String> rows = generateRandomWords(10, 8);
168     long maxTimestamp = 2;
169     List<String> columns = generateRandomWords(20000, 8);
170 
171     List<KeyValue> kvList = new ArrayList<KeyValue>();
172 
173     Map<StringRange, List<KeyValue>> rangeMap = new HashMap<StringRange, List<KeyValue>>();
174 
175     rangeMap.put(new StringRange(null, true, "b", false),
176         new ArrayList<KeyValue>());
177     rangeMap.put(new StringRange("p", true, "q", false),
178         new ArrayList<KeyValue>());
179     rangeMap.put(new StringRange("r", false, "s", true),
180         new ArrayList<KeyValue>());
181     rangeMap.put(new StringRange("z", false, null, false),
182         new ArrayList<KeyValue>());
183     String valueString = "ValueString";
184 
185     for (String row : rows) {
186       Put p = new Put(Bytes.toBytes(row));
187       p.setDurability(Durability.SKIP_WAL);
188       for (String column : columns) {
189         for (long timestamp = 1; timestamp <= maxTimestamp; timestamp++) {
190           KeyValue kv = KeyValueTestUtil.create(row, family, column, timestamp,
191               valueString);
192           p.add(kv);
193           kvList.add(kv);
194           for (StringRange s : rangeMap.keySet()) {
195             if (s.inRange(column)) {
196               rangeMap.get(s).add(kv);
197             }
198           }
199         }
200       }
201       ht.put(p);
202     }
203 
204     TEST_UTIL.flush();
205 
206     ColumnRangeFilter filter;
207     Scan scan = new Scan();
208     scan.setMaxVersions();
209     for (StringRange s : rangeMap.keySet()) {
210       filter = new ColumnRangeFilter(s.getStart() == null ? null
211           : Bytes.toBytes(s.getStart()), s.isStartInclusive(),
212           s.getEnd() == null ? null : Bytes.toBytes(s.getEnd()),
213           s.isEndInclusive());
214       scan.setFilter(filter);
215       ResultScanner scanner = ht.getScanner(scan);
216       List<Cell> results = new ArrayList<Cell>();
217       LOG.info("scan column range: " + s.toString());
218       long timeBeforeScan = System.currentTimeMillis();
219 
220       Result result;
221       while ((result = scanner.next()) != null) {
222         for (Cell kv : result.listCells()) {
223           results.add(kv);
224         }
225       }
226       long scanTime = System.currentTimeMillis() - timeBeforeScan;
227       scanner.close();
228       LOG.info("scan time = " + scanTime + "ms");
229       LOG.info("found " + results.size() + " results");
230       LOG.info("Expecting " + rangeMap.get(s).size() + " results");
231 
232       /*
233       for (KeyValue kv : results) {
234         LOG.info("found row " + Bytes.toString(kv.getRow()) + ", column "
235             + Bytes.toString(kv.getQualifier()));
236       }
237       */
238 
239       assertEquals(rangeMap.get(s).size(), results.size());
240     }
241     ht.close();
242   }
243 
244   List<String> generateRandomWords(int numberOfWords, int maxLengthOfWords) {
245     Set<String> wordSet = new HashSet<String>();
246     for (int i = 0; i < numberOfWords; i++) {
247       int lengthOfWords = (int) (Math.random() * maxLengthOfWords) + 1;
248       char[] wordChar = new char[lengthOfWords];
249       for (int j = 0; j < wordChar.length; j++) {
250         wordChar[j] = (char) (Math.random() * 26 + 97);
251       }
252       String word = new String(wordChar);
253       wordSet.add(word);
254     }
255     List<String> wordList = new ArrayList<String>(wordSet);
256     return wordList;
257   }
258 
259 }
260