From 40e01512cf308c6e10f7cadde7093d6a1d5ebc92 Mon Sep 17 00:00:00 2001 From: chenheng Date: Thu, 19 Nov 2015 10:56:18 +0800 Subject: [PATCH] HBASE-14782 FuzzyRowFilter skips valid rows (Vladimir Rodionov) --- .../hadoop/hbase/filter/FuzzyRowFilter.java | 27 +++++++++- .../hbase/filter/TestFuzzyRowFilter.java | 8 +-- .../filter/TestFuzzyRowFilterEndToEnd.java | 51 +++++++++++++++++++ 3 files changed, 81 insertions(+), 5 deletions(-) diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java index 1f125e52cf8..3bc5b7440c2 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java @@ -151,6 +151,7 @@ public class FuzzyRowFilter extends FilterBase { } // NOT FOUND -> seek next using hint lastFoundIndex = -1; + return ReturnCode.SEEK_NEXT_USING_HINT; } @@ -584,7 +585,31 @@ public class FuzzyRowFilter extends FilterBase { } } - return result; + return reverse? result: trimTrailingZeroes(result, fuzzyKeyMeta, toInc); + } + + /** + * For forward scanner, next cell hint should not contain any trailing zeroes + * unless they are part of fuzzyKeyMeta + * hint = '\x01\x01\x01\x00\x00' + * will skip valid row '\x01\x01\x01' + * + * @param result + * @param fuzzyKeyMeta + * @param toInc - position of incremented byte + * @return trimmed version of result + */ + + private static byte[] trimTrailingZeroes(byte[] result, byte[] fuzzyKeyMeta, int toInc) { + int off = fuzzyKeyMeta.length >= result.length? result.length -1: + fuzzyKeyMeta.length -1; + for( ; off >= 0; off--){ + if(fuzzyKeyMeta[off] != 0) break; + } + if (off < toInc) off = toInc; + byte[] retValue = new byte[off+1]; + System.arraycopy(result, 0, retValue, 0, retValue.length); + return retValue; } /** diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilter.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilter.java index 4e44d2c548b..c2599796a27 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilter.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilter.java @@ -230,7 +230,7 @@ public class TestFuzzyRowFilter { new byte[]{0, 1, 2}, // fuzzy row new byte[]{0, -1, -1}, // mask new byte[]{1, 2, 1, 0, 1}, // current - new byte[]{2, 1, 2, 0, 0}); // expected next + new byte[]{2, 1, 2}); // expected next assertNext(false, new byte[]{0, 1, 2}, // fuzzy row @@ -242,13 +242,13 @@ public class TestFuzzyRowFilter { new byte[]{0, 1, 0, 2, 0}, // fuzzy row new byte[]{0, -1, 0, -1, 0}, // mask new byte[]{1, 0, 2, 0, 1}, // current - new byte[]{1, 1, 0, 2, 0}); // expected next + new byte[]{1, 1, 0, 2}); // expected next assertNext(false, new byte[]{1, 0, 1}, new byte[]{-1, 0, -1}, new byte[]{1, (byte) 128, 2, 0, 1}, - new byte[]{1, (byte) 129, 1, 0, 0}); + new byte[]{1, (byte) 129, 1}); assertNext(false, new byte[]{0, 1, 0, 1}, @@ -314,7 +314,7 @@ public class TestFuzzyRowFilter { new byte[]{1, 1, 0, 0}, new byte[]{-1, -1, 0, 0}, new byte[]{0, 1, 3, 2}, - new byte[]{1, 1, 0, 0}); + new byte[]{1, 1}); // No next for this one Assert.assertNull(FuzzyRowFilter.getNextForFuzzyRule( diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilterEndToEnd.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilterEndToEnd.java index cc2f7b80f11..91795495371 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilterEndToEnd.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/filter/TestFuzzyRowFilterEndToEnd.java @@ -110,6 +110,57 @@ public class TestFuzzyRowFilterEndToEnd { // Nothing to do. } + @Test + public void testHBASE14782() throws IOException + { + String cf = "f"; + String cq = "q"; + String table = "HBASE14872"; + + Table ht = + TEST_UTIL.createTable(TableName.valueOf(table), Bytes.toBytes(cf), Integer.MAX_VALUE); + // Load data + String[] rows = new String[]{ + "\\x9C\\x00\\x044\\x00\\x00\\x00\\x00", + "\\x9C\\x00\\x044\\x01\\x00\\x00\\x00", + "\\x9C\\x00\\x044\\x00\\x01\\x00\\x00", + "\\x9C\\x00\\x044\\x00\\x00\\x01\\x00", + "\\x9C\\x00\\x044\\x00\\x01\\x00\\x01", + "\\x9B\\x00\\x044e\\xBB\\xB2\\xBB", + }; + + String badRow = "\\x9C\\x00\\x03\\xE9e\\xBB{X\\x1Fwts\\x1F\\x15vRX"; + + for(int i=0; i < rows.length; i++){ + Put p = new Put(Bytes.toBytesBinary(rows[i])); + p.addColumn(cf.getBytes(), cq.getBytes(), "value".getBytes()); + ht.put(p); + } + + Put p = new Put(Bytes.toBytesBinary(badRow)); + p.addColumn(cf.getBytes(), cq.getBytes(), "value".getBytes()); + ht.put(p); + + TEST_UTIL.flush(); + + List> data = new ArrayList>(); + byte[] fuzzyKey = Bytes.toBytesBinary("\\x00\\x00\\x044"); + byte[] mask = new byte[] { 1,0,0,0}; + data.add(new Pair(fuzzyKey, mask)); + FuzzyRowFilter filter = new FuzzyRowFilter(data); + + Scan scan = new Scan(); + scan.setFilter(filter); + + ResultScanner scanner = ht.getScanner(scan); + int total = 0; + while(scanner.next() != null){ + total++; + } + assertEquals(rows.length, total); + TEST_UTIL.deleteTable(TableName.valueOf(table)); + } + @Test public void testEndToEnd() throws Exception { String cf = "f";