1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.filter;
19
20 import com.google.common.collect.Lists;
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.hadoop.conf.Configuration;
24 import org.apache.hadoop.hbase.Cell;
25 import org.apache.hadoop.hbase.CellUtil;
26 import org.apache.hadoop.hbase.HBaseTestingUtility;
27 import org.apache.hadoop.hbase.HConstants;
28 import org.apache.hadoop.hbase.TableName;
29 import org.apache.hadoop.hbase.client.Durability;
30 import org.apache.hadoop.hbase.client.HTable;
31 import org.apache.hadoop.hbase.client.Put;
32 import org.apache.hadoop.hbase.client.Result;
33 import org.apache.hadoop.hbase.client.ResultScanner;
34 import org.apache.hadoop.hbase.client.Scan;
35 import org.apache.hadoop.hbase.client.Table;
36 import org.apache.hadoop.hbase.filter.FilterList.Operator;
37 import org.apache.hadoop.hbase.regionserver.ConstantSizeRegionSplitPolicy;
38 import org.apache.hadoop.hbase.regionserver.HRegion;
39 import org.apache.hadoop.hbase.regionserver.RegionScanner;
40 import org.apache.hadoop.hbase.testclassification.MediumTests;
41 import org.apache.hadoop.hbase.util.Bytes;
42 import org.apache.hadoop.hbase.util.Pair;
43 import org.junit.After;
44 import org.junit.AfterClass;
45 import org.junit.Before;
46 import org.junit.BeforeClass;
47 import org.junit.Test;
48 import org.junit.experimental.categories.Category;
49
50 import java.io.IOException;
51 import java.nio.ByteBuffer;
52 import java.util.ArrayList;
53 import java.util.Arrays;
54 import java.util.List;
55
56 import static org.junit.Assert.assertEquals;
57
58
59
60 @Category(MediumTests.class)
61 public class TestFuzzyRowFilterEndToEnd {
62 private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
63 private final static byte fuzzyValue = (byte) 63;
64 private static final Log LOG = LogFactory.getLog(TestFuzzyRowFilterEndToEnd.class);
65
66 private static int firstPartCardinality = 50;
67 private static int secondPartCardinality = 50;
68 private static int thirdPartCardinality = 50;
69 private static int colQualifiersTotal = 5;
70 private static int totalFuzzyKeys = thirdPartCardinality / 2;
71
72 private static String table = "TestFuzzyRowFilterEndToEnd";
73
74
75
76
77 @BeforeClass
78 public static void setUpBeforeClass() throws Exception {
79 Configuration conf = TEST_UTIL.getConfiguration();
80 conf.setInt("hbase.client.scanner.caching", 1000);
81 conf.set(HConstants.HBASE_REGION_SPLIT_POLICY_KEY,
82 ConstantSizeRegionSplitPolicy.class.getName());
83
84 conf.setLong(HConstants.HREGION_MAX_FILESIZE, ((long) 1024) * 1024 * 1024 * 10);
85
86 TEST_UTIL.startMiniCluster();
87 }
88
89
90
91
92 @AfterClass
93 public static void tearDownAfterClass() throws Exception {
94 TEST_UTIL.shutdownMiniCluster();
95 }
96
97
98
99
100 @Before
101 public void setUp() throws Exception {
102
103 }
104
105
106
107
108 @After
109 public void tearDown() throws Exception {
110
111 }
112
113
114 @Test
115 public void testAllFixedBits() throws IOException {
116 String cf = "f";
117 String cq = "q";
118 String table = "testAllFixedBits";
119
120 Table ht =
121 TEST_UTIL.createTable(TableName.valueOf(table), Bytes.toBytes(cf), Integer.MAX_VALUE);
122
123 String[] rows = new String[] { "\\x9C\\x00\\x044\\x00\\x00\\x00\\x00",
124 "\\x9C\\x00\\x044\\x01\\x00\\x00\\x00", "\\x9C\\x00\\x044\\x00\\x01\\x00\\x00",
125 "\\x9B\\x00\\x044e\\x9B\\x02\\xBB", "\\x9C\\x00\\x044\\x00\\x00\\x01\\x00",
126 "\\x9C\\x00\\x044\\x00\\x01\\x00\\x01", "\\x9B\\x00\\x044e\\xBB\\xB2\\xBB", };
127
128 for (int i = 0; i < rows.length; i++) {
129 Put p = new Put(Bytes.toBytesBinary(rows[i]));
130 p.addColumn(cf.getBytes(), cq.getBytes(), "value".getBytes());
131 ht.put(p);
132 }
133
134 TEST_UTIL.flush();
135
136 List<Pair<byte[], byte[]>> data = new ArrayList<Pair<byte[], byte[]>>();
137 byte[] fuzzyKey = Bytes.toBytesBinary("\\x9B\\x00\\x044e");
138 byte[] mask = new byte[] { 0, 0, 0, 0, 0 };
139
140
141 byte[] copyFuzzyKey = Arrays.copyOf(fuzzyKey, fuzzyKey.length);
142 byte[] copyMask = Arrays.copyOf(mask, mask.length);
143
144 data.add(new Pair<byte[], byte[]>(fuzzyKey, mask));
145 FuzzyRowFilter filter = new FuzzyRowFilter(data);
146
147 Scan scan = new Scan();
148 scan.setFilter(filter);
149
150 ResultScanner scanner = ht.getScanner(scan);
151 int total = 0;
152 while (scanner.next() != null) {
153 total++;
154 }
155 assertEquals(2, total);
156
157 assertEquals(true, Arrays.equals(copyFuzzyKey, fuzzyKey));
158 assertEquals(true, Arrays.equals(copyMask, mask));
159
160 TEST_UTIL.deleteTable(TableName.valueOf(table));
161 }
162
163 @Test
164 public void testHBASE14782() throws IOException
165 {
166 String cf = "f";
167 String cq = "q";
168 String table = "HBASE14872";
169
170 Table ht =
171 TEST_UTIL.createTable(TableName.valueOf(table), Bytes.toBytes(cf), Integer.MAX_VALUE);
172
173 String[] rows = new String[]{
174 "\\x9C\\x00\\x044\\x00\\x00\\x00\\x00",
175 "\\x9C\\x00\\x044\\x01\\x00\\x00\\x00",
176 "\\x9C\\x00\\x044\\x00\\x01\\x00\\x00",
177 "\\x9C\\x00\\x044\\x00\\x00\\x01\\x00",
178 "\\x9C\\x00\\x044\\x00\\x01\\x00\\x01",
179 "\\x9B\\x00\\x044e\\xBB\\xB2\\xBB",
180 };
181
182 String badRow = "\\x9C\\x00\\x03\\xE9e\\xBB{X\\x1Fwts\\x1F\\x15vRX";
183
184 for(int i=0; i < rows.length; i++){
185 Put p = new Put(Bytes.toBytesBinary(rows[i]));
186 p.addColumn(cf.getBytes(), cq.getBytes(), "value".getBytes());
187 ht.put(p);
188 }
189
190 Put p = new Put(Bytes.toBytesBinary(badRow));
191 p.addColumn(cf.getBytes(), cq.getBytes(), "value".getBytes());
192 ht.put(p);
193
194 TEST_UTIL.flush();
195
196 List<Pair<byte[], byte[]>> data = new ArrayList<Pair<byte[], byte[]>>();
197 byte[] fuzzyKey = Bytes.toBytesBinary("\\x00\\x00\\x044");
198 byte[] mask = new byte[] { 1,0,0,0};
199 data.add(new Pair<byte[], byte[]>(fuzzyKey, mask));
200 FuzzyRowFilter filter = new FuzzyRowFilter(data);
201
202 Scan scan = new Scan();
203 scan.setFilter(filter);
204
205 ResultScanner scanner = ht.getScanner(scan);
206 int total = 0;
207 while(scanner.next() != null){
208 total++;
209 }
210 assertEquals(rows.length, total);
211 TEST_UTIL.deleteTable(TableName.valueOf(table));
212 }
213
214 @Test
215 public void testEndToEnd() throws Exception {
216 String cf = "f";
217
218 HTable ht =
219 TEST_UTIL.createTable(TableName.valueOf(table), Bytes.toBytes(cf), Integer.MAX_VALUE);
220
221
222
223
224
225 for (int i0 = 0; i0 < firstPartCardinality; i0++) {
226
227 for (int i1 = 0; i1 < secondPartCardinality; i1++) {
228
229 for (int i2 = 0; i2 < thirdPartCardinality; i2++) {
230 byte[] rk = new byte[10];
231
232 ByteBuffer buf = ByteBuffer.wrap(rk);
233 buf.clear();
234 buf.putShort((short) i0);
235 buf.putInt(i1);
236 buf.putInt(i2);
237 for (int c = 0; c < colQualifiersTotal; c++) {
238 byte[] cq = new byte[4];
239 Bytes.putBytes(cq, 0, Bytes.toBytes(c), 0, 4);
240
241 Put p = new Put(rk);
242 p.setDurability(Durability.SKIP_WAL);
243 p.add(cf.getBytes(), cq, Bytes.toBytes(c));
244 ht.put(p);
245 }
246 }
247 }
248 }
249
250 TEST_UTIL.flush();
251
252
253 runTest1(ht);
254 runTest2(ht);
255
256 }
257
258 private void runTest1(Table hTable) throws IOException {
259
260
261 byte[] mask = new byte[] { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0 };
262
263 List<Pair<byte[], byte[]>> list = new ArrayList<Pair<byte[], byte[]>>();
264 for (int i = 0; i < totalFuzzyKeys; i++) {
265 byte[] fuzzyKey = new byte[10];
266 ByteBuffer buf = ByteBuffer.wrap(fuzzyKey);
267 buf.clear();
268 buf.putShort((short) 2);
269 for (int j = 0; j < 4; j++) {
270 buf.put(fuzzyValue);
271 }
272 buf.putInt(i);
273
274 Pair<byte[], byte[]> pair = new Pair<byte[], byte[]>(fuzzyKey, mask);
275 list.add(pair);
276 }
277
278 int expectedSize = secondPartCardinality * totalFuzzyKeys * colQualifiersTotal;
279 FuzzyRowFilter fuzzyRowFilter0 = new FuzzyRowFilter(list);
280
281 FuzzyRowFilter fuzzyRowFilter1 = new FuzzyRowFilter(list);
282
283
284 runScanner(hTable, expectedSize, fuzzyRowFilter0);
285
286 runScanner(hTable, expectedSize, fuzzyRowFilter1);
287
288 }
289
290 private void runTest2(Table hTable) throws IOException {
291
292
293 byte[] mask = new byte[] { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0 };
294
295 List<Pair<byte[], byte[]>> list = new ArrayList<Pair<byte[], byte[]>>();
296
297 for (int i = 0; i < totalFuzzyKeys; i++) {
298 byte[] fuzzyKey = new byte[10];
299 ByteBuffer buf = ByteBuffer.wrap(fuzzyKey);
300 buf.clear();
301 buf.putShort((short) (i * 2));
302 for (int j = 0; j < 4; j++) {
303 buf.put(fuzzyValue);
304 }
305 buf.putInt(i * 2);
306
307 Pair<byte[], byte[]> pair = new Pair<byte[], byte[]>(fuzzyKey, mask);
308 list.add(pair);
309 }
310
311 int expectedSize = totalFuzzyKeys * secondPartCardinality * colQualifiersTotal;
312
313 FuzzyRowFilter fuzzyRowFilter0 = new FuzzyRowFilter(list);
314
315 FuzzyRowFilter fuzzyRowFilter1 = new FuzzyRowFilter(list);
316
317
318 runScanner(hTable, expectedSize, fuzzyRowFilter0);
319
320 runScanner(hTable, expectedSize, fuzzyRowFilter1);
321
322 }
323
324 private void runScanner(Table hTable, int expectedSize, Filter filter) throws IOException {
325
326 String cf = "f";
327 Scan scan = new Scan();
328 scan.addFamily(cf.getBytes());
329 scan.setFilter(filter);
330 List<HRegion> regions = TEST_UTIL.getHBaseCluster().getRegions(table.getBytes());
331 HRegion first = regions.get(0);
332 first.getScanner(scan);
333 RegionScanner scanner = first.getScanner(scan);
334 List<Cell> results = new ArrayList<Cell>();
335
336 long timeBeforeScan = System.currentTimeMillis();
337 int found = 0;
338 while (scanner.next(results)) {
339 found += results.size();
340 results.clear();
341 }
342 found += results.size();
343 long scanTime = System.currentTimeMillis() - timeBeforeScan;
344 scanner.close();
345
346 LOG.info("\nscan time = " + scanTime + "ms");
347 LOG.info("found " + found + " results\n");
348
349 assertEquals(expectedSize, found);
350 }
351
352 @SuppressWarnings("deprecation")
353 @Test
354 public void testFilterList() throws Exception {
355 String cf = "f";
356 String table = "TestFuzzyRowFiltersInFilterList";
357 HTable ht =
358 TEST_UTIL.createTable(TableName.valueOf(table), Bytes.toBytes(cf), Integer.MAX_VALUE);
359
360
361
362
363
364 for (int i1 = 0; i1 < 5; i1++) {
365 for (int i2 = 0; i2 < 5; i2++) {
366 byte[] rk = new byte[10];
367
368 ByteBuffer buf = ByteBuffer.wrap(rk);
369 buf.clear();
370 buf.putShort((short) 2);
371 buf.putInt(i1);
372 buf.putInt(i2);
373
374
375 for (int c = 0; c < 5; c++) {
376 byte[] cq = new byte[4];
377 Bytes.putBytes(cq, 0, Bytes.toBytes(c), 0, 4);
378
379 Put p = new Put(rk);
380 p.setDurability(Durability.SKIP_WAL);
381 p.add(cf.getBytes(), cq, Bytes.toBytes(c));
382 ht.put(p);
383 LOG.info("Inserting: rk: " + Bytes.toStringBinary(rk) + " cq: "
384 + Bytes.toStringBinary(cq));
385 }
386 }
387 }
388
389 TEST_UTIL.flush();
390
391
392 runTest(ht, 5);
393
394 }
395
396 @SuppressWarnings("unchecked")
397 private void runTest(HTable hTable, int expectedSize) throws IOException {
398
399 byte[] fuzzyKey1 = new byte[10];
400 ByteBuffer buf = ByteBuffer.wrap(fuzzyKey1);
401 buf.clear();
402 buf.putShort((short) 2);
403 for (int i = 0; i < 4; i++)
404 buf.put(fuzzyValue);
405 buf.putInt((short) 1);
406 byte[] mask1 = new byte[] { 0, 0, 1, 1, 1, 1, 0, 0, 0, 0 };
407
408 byte[] fuzzyKey2 = new byte[10];
409 buf = ByteBuffer.wrap(fuzzyKey2);
410 buf.clear();
411 buf.putShort((short) 2);
412 buf.putInt((short) 2);
413 for (int i = 0; i < 4; i++)
414 buf.put(fuzzyValue);
415
416 byte[] mask2 = new byte[] { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 };
417
418 Pair<byte[], byte[]> pair1 = new Pair<byte[], byte[]>(fuzzyKey1, mask1);
419 Pair<byte[], byte[]> pair2 = new Pair<byte[], byte[]>(fuzzyKey2, mask2);
420
421 FuzzyRowFilter fuzzyRowFilter1 = new FuzzyRowFilter(Lists.newArrayList(pair1));
422 FuzzyRowFilter fuzzyRowFilter2 = new FuzzyRowFilter(Lists.newArrayList(pair2));
423
424 runScanner(hTable, expectedSize, fuzzyRowFilter1, fuzzyRowFilter2);
425 }
426
427 private void runScanner(Table hTable, int expectedSize, Filter filter1, Filter filter2)
428 throws IOException {
429 String cf = "f";
430 Scan scan = new Scan();
431 scan.addFamily(cf.getBytes());
432 FilterList filterList = new FilterList(Operator.MUST_PASS_ALL, filter1, filter2);
433 scan.setFilter(filterList);
434
435 ResultScanner scanner = hTable.getScanner(scan);
436 List<Cell> results = new ArrayList<Cell>();
437 Result result;
438 long timeBeforeScan = System.currentTimeMillis();
439 while ((result = scanner.next()) != null) {
440 for (Cell kv : result.listCells()) {
441 LOG.info("Got rk: " + Bytes.toStringBinary(CellUtil.cloneRow(kv)) + " cq: "
442 + Bytes.toStringBinary(CellUtil.cloneQualifier(kv)));
443 results.add(kv);
444 }
445 }
446 long scanTime = System.currentTimeMillis() - timeBeforeScan;
447 scanner.close();
448
449 LOG.info("scan time = " + scanTime + "ms");
450 LOG.info("found " + results.size() + " results");
451
452 assertEquals(expectedSize, results.size());
453 }
454 }