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 java.util.Arrays;
21  
22  import org.apache.hadoop.hbase.KeyValue;
23  import org.apache.hadoop.hbase.KeyValueUtil;
24  import org.apache.hadoop.hbase.testclassification.SmallTests;
25  import org.apache.hadoop.hbase.util.Bytes;
26  import org.junit.Assert;
27  import org.junit.Test;
28  import org.junit.experimental.categories.Category;
29  import org.junit.internal.ArrayComparisonFailure;
30  
31  @Category(SmallTests.class)
32  public class TestFuzzyRowFilter {
33  
34    @Test
35    public void testIdempotentMaskShift() {
36      byte[] test = new byte[] {
37        -1,
38        FuzzyRowFilter.V1_PROCESSED_WILDCARD_MASK,
39        FuzzyRowFilter.V2_PROCESSED_WILDCARD_MASK
40      };
41  
42      byte[] original = Arrays.copyOf(test, test.length);
43      byte[] expected = new byte[] { -1, 0, 0};
44  
45      Assert.assertArrayEquals(test, original);
46      assertArrayNotEquals(expected, test);
47  
48      // shifting once should equal expected
49      FuzzyRowFilter.idempotentMaskShift(test);
50      Assert.assertArrayEquals(expected, test);
51      assertArrayNotEquals(original, test);
52  
53      // shifting again should still equal expected, because it's idempotent
54      FuzzyRowFilter.idempotentMaskShift(test);
55      Assert.assertArrayEquals(expected, test);
56      assertArrayNotEquals(original, test);
57    }
58  
59    private void assertArrayNotEquals(byte[] expected, byte[] testcase) {
60      try {
61        Assert.assertArrayEquals(expected, testcase);
62        Assert.fail("expected arrays to fail equality test");
63      } catch (ArrayComparisonFailure e) {
64        // success
65      }
66    }
67  
68    @Test
69    public void testSatisfiesNoUnsafeForward() {
70  
71      Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
72              FuzzyRowFilter.satisfiesNoUnsafe(false,
73                                       new byte[]{1, (byte) -128, 1, 0, 1},
74                                       0, 5,
75                                       new byte[]{1, 0, 1},
76                                       new byte[]{0, 1, 0}));
77  
78      Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
79              FuzzyRowFilter.satisfiesNoUnsafe(false,
80                                       new byte[]{1, (byte) -128, 2, 0, 1},
81                                       0, 5,
82                                       new byte[]{1, 0, 1},
83                                       new byte[]{0, 1, 0}));
84  
85  
86      Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
87              FuzzyRowFilter.satisfiesNoUnsafe(false,
88                                       new byte[]{1, 2, 1, 3, 3},
89                                       0, 5,
90                                       new byte[]{1, 2, 0, 3},
91                                       new byte[]{0, 0, 1, 0}));
92  
93      Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
94              FuzzyRowFilter.satisfiesNoUnsafe(false,
95                                       new byte[]{1, 1, 1, 3, 0}, // row to check
96                                       0, 5,
97                                       new byte[]{1, 2, 0, 3}, // fuzzy row
98                                       new byte[]{0, 0, 1, 0})); // mask
99  
100     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
101             FuzzyRowFilter.satisfiesNoUnsafe(false,
102                                      new byte[]{1, 1, 1, 3, 0},
103                                      0, 5,
104                                      new byte[]{1, (byte) 245, 0, 3},
105                                      new byte[]{0, 0, 1, 0}));
106 
107     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
108             FuzzyRowFilter.satisfiesNoUnsafe(false,
109                                      new byte[]{1, 2, 1, 0, 1},
110                                      0, 5,
111                                      new byte[]{0, 1, 2},
112                                      new byte[]{1, 0, 0}));
113   }
114 
115   @Test
116   public void testSatisfiesForward() {
117 
118     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
119             FuzzyRowFilter.satisfies(false,
120                                      new byte[]{1, (byte) -128, 1, 0, 1},
121                                      new byte[]{1, 0, 1},
122                                      new byte[]{-1, 0, -1}));
123 
124     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
125             FuzzyRowFilter.satisfies(false,
126                                      new byte[]{1, (byte) -128, 2, 0, 1},
127                                      new byte[]{1, 0, 1},
128                                      new byte[]{-1, 0, -1}));
129 
130 
131     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
132             FuzzyRowFilter.satisfies(false,
133                                      new byte[]{1, 2, 1, 3, 3},
134                                      new byte[]{1, 2, 0, 3},
135                                      new byte[]{-1, -1, 0, -1}));
136 
137     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
138             FuzzyRowFilter.satisfies(false,
139                                      new byte[]{1, 1, 1, 3, 0}, // row to check
140                                      new byte[]{1, 2, 0, 3}, // fuzzy row
141                                      new byte[]{-1, -1, 0, -1})); // mask
142 
143     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
144             FuzzyRowFilter.satisfies(false,
145                                      new byte[]{1, 1, 1, 3, 0},
146                                      new byte[]{1, (byte) 245, 0, 3},
147                                      new byte[]{-1, -1, 0, -1}));
148 
149     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
150             FuzzyRowFilter.satisfies(false,
151                                      new byte[]{1, 2, 1, 0, 1},
152                                      new byte[]{0, 1, 2},
153                                      new byte[]{0, -1, -1}));
154   }
155 
156   @Test
157   public void testSatisfiesReverse() {
158     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
159       FuzzyRowFilter.satisfies(true,
160         new byte[]{1, (byte) -128, 1, 0, 1},
161         new byte[]{1, 0, 1},
162         new byte[]{-1, 0, -1}));
163 
164     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
165       FuzzyRowFilter.satisfies(true,
166         new byte[]{1, (byte) -128, 2, 0, 1},
167         new byte[]{1, 0, 1},
168         new byte[]{-1, 0, -1}));
169 
170     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
171       FuzzyRowFilter.satisfies(true,
172         new byte[]{2, 3, 1, 1, 1},
173         new byte[]{1, 0, 1},
174         new byte[]{-1, 0, -1}));
175 
176     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
177       FuzzyRowFilter.satisfies(true,
178         new byte[]{1, 2, 1, 3, 3},
179         new byte[]{1, 2, 0, 3},
180         new byte[]{-1, -1, 0, -1}));
181 
182     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
183       FuzzyRowFilter.satisfies(true,
184         new byte[]{1, (byte) 245, 1, 3, 0},
185         new byte[]{1, 1, 0, 3},
186         new byte[]{-1, -1, 0, -1}));
187 
188     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
189       FuzzyRowFilter.satisfies(true,
190         new byte[]{1, 3, 1, 3, 0},
191         new byte[]{1, 2, 0, 3},
192         new byte[]{-1, -1, 0, -1}));
193 
194     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
195       FuzzyRowFilter.satisfies(true,
196         new byte[]{2, 1, 1, 1, 0},
197         new byte[]{1, 2, 0, 3},
198         new byte[]{-1, -1, 0, -1}));
199 
200     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
201       FuzzyRowFilter.satisfies(true,
202         new byte[]{1, 2, 1, 0, 1},
203         new byte[]{0, 1, 2},
204         new byte[]{0, -1, -1}));
205   }
206 
207   @Test
208   public void testSatisfiesNoUnsafeReverse() {
209     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
210       FuzzyRowFilter.satisfiesNoUnsafe(true,
211         new byte[]{1, (byte) -128, 1, 0, 1},
212         0, 5,
213         new byte[]{1, 0, 1},
214         new byte[]{0, 1, 0}));
215 
216     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
217       FuzzyRowFilter.satisfiesNoUnsafe(true,
218         new byte[]{1, (byte) -128, 2, 0, 1},
219         0, 5,
220         new byte[]{1, 0, 1},
221         new byte[]{0, 1, 0}));
222 
223     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
224       FuzzyRowFilter.satisfiesNoUnsafe(true,
225         new byte[]{2, 3, 1, 1, 1},
226         0, 5,
227         new byte[]{1, 0, 1},
228         new byte[]{0, 1, 0}));
229 
230     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.YES,
231       FuzzyRowFilter.satisfiesNoUnsafe(true,
232         new byte[]{1, 2, 1, 3, 3},
233         0, 5,
234         new byte[]{1, 2, 0, 3},
235         new byte[]{0, 0, 1, 0}));
236 
237     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
238       FuzzyRowFilter.satisfiesNoUnsafe(true,
239         new byte[]{1, (byte) 245, 1, 3, 0},
240         0, 5,
241         new byte[]{1, 1, 0, 3},
242         new byte[]{0, 0, 1, 0}));
243 
244     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
245       FuzzyRowFilter.satisfiesNoUnsafe(true,
246         new byte[]{1, 3, 1, 3, 0},
247         0, 5,
248         new byte[]{1, 2, 0, 3},
249         new byte[]{0, 0, 1, 0}));
250 
251     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
252       FuzzyRowFilter.satisfiesNoUnsafe(true,
253         new byte[]{2, 1, 1, 1, 0},
254         0, 5,
255         new byte[]{1, 2, 0, 3},
256         new byte[]{0, 0, 1, 0}));
257 
258     Assert.assertEquals(FuzzyRowFilter.SatisfiesCode.NEXT_EXISTS,
259       FuzzyRowFilter.satisfiesNoUnsafe(true,
260         new byte[]{1, 2, 1, 0, 1},
261         0, 5,
262         new byte[]{0, 1, 2},
263         new byte[]{1, 0, 0}));
264   }  
265   @Test
266   public void testGetNextForFuzzyRuleForward() {
267     assertNext(false,
268             new byte[]{0, 1, 2}, // fuzzy row
269             new byte[]{0, -1, -1}, // mask
270             new byte[]{1, 2, 1, 0, 1}, // current
271             new byte[]{2, 1, 2}); // expected next
272 
273     assertNext(false,
274             new byte[]{0, 1, 2}, // fuzzy row
275             new byte[]{0, -1, -1}, // mask
276             new byte[]{1, 1, 2, 0, 1}, // current
277             new byte[]{1, 1, 2, 0, 2}); // expected next
278 
279     assertNext(false,
280             new byte[]{0, 1, 0, 2, 0}, // fuzzy row
281             new byte[]{0, -1, 0, -1, 0}, // mask
282             new byte[]{1, 0, 2, 0, 1}, // current
283             new byte[]{1, 1, 0, 2}); // expected next
284 
285     assertNext(false,
286             new byte[]{1, 0, 1},
287             new byte[]{-1, 0, -1},
288             new byte[]{1, (byte) 128, 2, 0, 1},
289             new byte[]{1, (byte) 129, 1});
290 
291     assertNext(false,
292             new byte[]{0, 1, 0, 1},
293             new byte[]{0, -1, 0, -1},
294             new byte[]{5, 1, 0, 1},
295             new byte[]{5, 1, 1, 1});
296 
297     assertNext(false,
298             new byte[]{0, 1, 0, 1},
299             new byte[]{0, -1, 0, -1},
300             new byte[]{5, 1, 0, 1, 1},
301             new byte[]{5, 1, 0, 1, 2});
302 
303     assertNext(false,
304             new byte[]{0, 1, 0, 0}, // fuzzy row
305             new byte[]{0, -1, 0, 0}, // mask
306             new byte[]{5, 1, (byte) 255, 1}, // current
307             new byte[]{5, 1, (byte) 255, 2}); // expected next
308 
309     assertNext(false,
310             new byte[]{0, 1, 0, 1}, // fuzzy row
311             new byte[]{0, -1, 0, -1}, // mask
312             new byte[]{5, 1, (byte) 255, 1}, // current
313             new byte[]{6, 1, 0, 1}); // expected next
314 
315     assertNext(false,
316             new byte[]{0, 1, 0, 1}, // fuzzy row
317             new byte[]{0, -1, 0, -1}, // mask
318             new byte[]{5, 1, (byte) 255, 0}, // current
319             new byte[]{5, 1, (byte) 255, 1}); // expected next
320 
321     assertNext(false,
322             new byte[]{5, 1, 1, 0},
323             new byte[]{-1, -1, 0, 0},
324             new byte[]{5, 1, (byte) 255, 1},
325             new byte[]{5, 1, (byte) 255, 2});
326 
327     assertNext(false,
328             new byte[]{1, 1, 1, 1},
329             new byte[]{-1, -1, 0, 0},
330             new byte[]{1, 1, 2, 2},
331             new byte[]{1, 1, 2, 3});
332 
333     assertNext(false,
334             new byte[]{1, 1, 1, 1},
335             new byte[]{-1, -1, 0, 0},
336             new byte[]{1, 1, 3, 2},
337             new byte[]{1, 1, 3, 3});
338 
339     assertNext(false,
340             new byte[]{1, 1, 1, 1},
341             new byte[]{0, 0, 0, 0},
342             new byte[]{1, 1, 2, 3},
343             new byte[]{1, 1, 2, 4});
344 
345     assertNext(false,
346             new byte[]{1, 1, 1, 1},
347             new byte[]{0, 0, 0, 0},
348             new byte[]{1, 1, 3, 2},
349             new byte[]{1, 1, 3, 3});
350 
351     assertNext(false,
352             new byte[]{1, 1, 0, 0},
353             new byte[]{-1, -1, 0, 0},
354             new byte[]{0, 1, 3, 2},
355             new byte[]{1, 1});
356 
357     // No next for this one
358     Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
359             new byte[]{2, 3, 1, 1, 1}, // row to check
360             new byte[]{1, 0, 1}, // fuzzy row
361             new byte[]{-1, 0, -1})); // mask
362     Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
363             new byte[]{1, (byte) 245, 1, 3, 0},
364             new byte[]{1, 1, 0, 3},
365             new byte[]{-1, -1, 0, -1}));
366     Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
367             new byte[]{1, 3, 1, 3, 0},
368             new byte[]{1, 2, 0, 3},
369             new byte[]{-1, -1, 0, -1}));
370     Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(
371             new byte[]{2, 1, 1, 1, 0},
372             new byte[]{1, 2, 0, 3},
373             new byte[]{-1, -1, 0, -1}));
374   }
375 
376   @Test
377   public void testGetNextForFuzzyRuleReverse() {
378     assertNext(true,
379       new byte[]{0, 1, 2}, // fuzzy row
380       new byte[]{0, -1, -1}, // mask
381       new byte[]{1, 2, 1, 0, 1}, // current
382       // TODO: should be {1, 1, 3} ?
383       new byte[]{1, 1, 2, (byte) 0xFF, (byte) 0xFF}); // expected next
384 
385     assertNext(true,
386       new byte[]{0, 1, 0, 2, 0}, // fuzzy row
387       new byte[]{0, -1, 0, -1, 0}, // mask
388       new byte[]{1, 2, 1, 3, 1}, // current
389       // TODO: should be {1, 1, 1, 3} ?
390       new byte[]{1, 1, 0, 2, 0}); // expected next
391 
392     assertNext(true,
393       new byte[]{1, 0, 1},
394       new byte[]{-1, 0, -1},
395       new byte[]{1, (byte) 128, 2, 0, 1},
396       // TODO: should be {1, (byte) 128, 2} ?
397       new byte[]{1, (byte) 128, 1, (byte) 0xFF, (byte) 0xFF});
398 
399     assertNext(true,
400       new byte[]{0, 1, 0, 1},
401       new byte[]{0, -1, 0, -1},
402       new byte[]{5, 1, 0, 2, 1},
403       // TODO: should be {5, 1, 0, 2} ?
404       new byte[]{5, 1, 0, 1, (byte) 0xFF});
405 
406     assertNext(true,
407       new byte[]{0, 1, 0, 0}, // fuzzy row
408       new byte[]{0, -1, 0, 0}, // mask
409       new byte[]{5, 1, (byte) 255, 1}, // current
410       new byte[]{5, 1, (byte) 255, 0}); // expected next
411 
412     assertNext(true,
413       new byte[]{0, 1, 0, 1}, // fuzzy row
414       new byte[]{0, -1, 0, -1}, // mask
415       new byte[]{5, 1, 0, 1}, // current
416       new byte[]{4, 1, (byte) 255, 1}); // expected next
417 
418     assertNext(true,
419       new byte[]{0, 1, 0, 1}, // fuzzy row
420       new byte[]{0, -1, 0, -1}, // mask
421       new byte[]{5, 1, (byte) 255, 0}, // current
422       new byte[]{5, 1, (byte) 254, 1}); // expected next
423 
424     assertNext(true,
425       new byte[]{1, 1, 0, 0},
426       new byte[]{-1, -1, 0, 0},
427       new byte[]{2, 1, 3, 2},
428       // TODO: should be {1, 0} ?
429       new byte[]{1, 1, 0, 0});
430 
431     assertNext(true,
432       new byte[]{1, 0, 1}, // fuzzy row
433       new byte[]{-1, 0, -1}, // mask
434       new byte[]{2, 3, 1, 1, 1}, // row to check
435       // TODO: should be {1, (byte) 0xFF, 2} ?
436       new byte[]{1, 0, 1, (byte) 0xFF, (byte) 0xFF});
437 
438     assertNext(true,
439       new byte[]{1, 1, 0, 3},
440       new byte[]{-1, -1, 0, -1},
441       new byte[]{1, (byte) 245, 1, 3, 0},
442       // TODO: should be {1, 1, (byte) 255, 4} ?
443       new byte[]{1, 1, 0, 3, (byte) 0xFF});
444 
445     assertNext(true,
446       new byte[]{1, 2, 0, 3},
447       new byte[]{-1, -1, 0, -1},
448       new byte[]{1, 3, 1, 3, 0},
449       // TODO: should be 1, 2, (byte) 255, 4 ?
450       new byte[]{1, 2, 0, 3, (byte) 0xFF});
451 
452     assertNext(true,
453       new byte[]{1, 2, 0, 3},
454       new byte[]{-1, -1, 0, -1},
455       new byte[]{2, 1, 1, 1, 0},
456       // TODO: should be {1, 2, (byte) 255, 4} ?
457       new byte[]{1, 2, 0, 3, (byte) 0xFF});
458 
459     assertNext(true,
460       // TODO: should be null?
461       new byte[]{1, 0, 1},
462       new byte[]{-1, 0, -1},
463       new byte[]{1, (byte) 128, 2},
464       new byte[]{1, (byte) 128, 1});
465 
466     assertNext(true,
467       // TODO: should be null?
468       new byte[]{0, 1, 0, 1},
469       new byte[]{0, -1, 0, -1},
470       new byte[]{5, 1, 0, 2},
471       new byte[]{5, 1, 0, 1});
472 
473     assertNext(true,
474       // TODO: should be null?
475       new byte[]{5, 1, 1, 0},
476       new byte[]{-1, -1, 0, 0},
477       new byte[]{5, 1, (byte) 0xFF, 1},
478       new byte[]{5, 1, (byte) 0xFF, 0});
479 
480     assertNext(true,
481       // TODO: should be null?
482       new byte[]{1, 1, 1, 1},
483       new byte[]{-1, -1, 0, 0},
484       new byte[]{1, 1, 2, 2},
485       new byte[]{1, 1, 2, 1});
486 
487     assertNext(true,
488       // TODO: should be null?
489       new byte[]{1, 1, 1, 1},
490       new byte[]{0, 0, 0, 0},
491       new byte[]{1, 1, 2, 3},
492       new byte[]{1, 1, 2, 2});
493 
494     Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule(true,
495       new byte[]{1, 1, 1, 3, 0},
496       new byte[]{1, 2, 0, 3},
497       new byte[]{-1, -1, 0, -1}));
498   }
499 
500   private static void assertNext(boolean reverse, byte[] fuzzyRow, byte[] mask, byte[] current,
501       byte[] expected) {
502     KeyValue kv = KeyValueUtil.createFirstOnRow(current);
503     byte[] nextForFuzzyRule = FuzzyRowFilter.getNextForFuzzyRule(reverse, kv.getRowArray(),
504         kv.getRowOffset(), kv.getRowLength(), fuzzyRow, mask);
505     Assert.assertEquals(Bytes.toStringBinary(expected), Bytes.toStringBinary(nextForFuzzyRule));
506   }
507 }