From 619f94f113f9952995c61c851b379aec72bf52bb Mon Sep 17 00:00:00 2001 From: xieliang Date: Tue, 30 Dec 2014 11:52:33 +0800 Subject: [PATCH] HBASE-12767 Fix a StoreFileScanner NPE in reverse scan flow --- .../hadoop/hbase/io/HalfStoreFileReader.java | 12 ++- .../hbase/regionserver/TestHRegion.java | 102 ++++++++++++++++++ 2 files changed, 112 insertions(+), 2 deletions(-) diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/HalfStoreFileReader.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/HalfStoreFileReader.java index bc7d6586f3c..05c996f5052 100644 --- a/hbase-server/src/main/java/org/apache/hadoop/hbase/io/HalfStoreFileReader.java +++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/io/HalfStoreFileReader.java @@ -304,10 +304,18 @@ public class HalfStoreFileReader extends StoreFile.Reader { // The equals sign isn't strictly necessary just here to be consistent // with seekTo if (getComparator().compareOnlyKeyPortion(key, splitCell) >= 0) { - return this.delegate.seekBefore(splitCell); + boolean ret = this.delegate.seekBefore(splitCell); + if (ret) { + atEnd = false; + } + return ret; } } - return this.delegate.seekBefore(key); + boolean ret = this.delegate.seekBefore(key); + if (ret) { + atEnd = false; + } + return ret; } }; } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegion.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegion.java index 5a7e002b2e1..b238cd534ea 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegion.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestHRegion.java @@ -5008,6 +5008,7 @@ public class TestHRegion { Bytes.toString(CellUtil.cloneValue(kv))); } + @Test (timeout=60000) public void testReverseScanner_FromMemStore_SingleCF_Normal() throws IOException { byte[] rowC = Bytes.toBytes("rowC"); @@ -5063,6 +5064,7 @@ public class TestHRegion { } } + @Test (timeout=60000) public void testReverseScanner_FromMemStore_SingleCF_LargerKey() throws IOException { byte[] rowC = Bytes.toBytes("rowC"); @@ -5119,6 +5121,7 @@ public class TestHRegion { } } + @Test (timeout=60000) public void testReverseScanner_FromMemStore_SingleCF_FullScan() throws IOException { byte[] rowC = Bytes.toBytes("rowC"); @@ -5172,6 +5175,7 @@ public class TestHRegion { } } + @Test (timeout=60000) public void testReverseScanner_moreRowsMayExistAfter() throws IOException { // case for "INCLUDE_AND_SEEK_NEXT_ROW & SEEK_NEXT_ROW" endless loop byte[] rowA = Bytes.toBytes("rowA"); @@ -5249,6 +5253,7 @@ public class TestHRegion { } } + @Test (timeout=60000) public void testReverseScanner_smaller_blocksize() throws IOException { // case to ensure no conflict with HFile index optimization byte[] rowA = Bytes.toBytes("rowA"); @@ -5328,6 +5333,7 @@ public class TestHRegion { } } + @Test (timeout=60000) public void testReverseScanner_FromMemStoreAndHFiles_MultiCFs1() throws IOException { byte[] row0 = Bytes.toBytes("row0"); // 1 kv @@ -5488,6 +5494,7 @@ public class TestHRegion { } } + @Test (timeout=60000) public void testReverseScanner_FromMemStoreAndHFiles_MultiCFs2() throws IOException { byte[] row1 = Bytes.toBytes("row1"); @@ -5561,6 +5568,101 @@ public class TestHRegion { } } + @Test (timeout=60000) + public void testSplitRegionWithReverseScan() throws IOException { + byte [] tableName = Bytes.toBytes("testSplitRegionWithReverseScan"); + byte [] qualifier = Bytes.toBytes("qualifier"); + Configuration hc = initSplit(); + int numRows = 3; + byte [][] families = {fam1}; + + //Setting up region + String method = this.getName(); + this.region = initHRegion(tableName, method, hc, families); + + //Put data in region + int startRow = 100; + putData(startRow, numRows, qualifier, families); + int splitRow = startRow + numRows; + putData(splitRow, numRows, qualifier, families); + int endRow = splitRow + numRows; + region.flushcache(); + + HRegion [] regions = null; + try { + regions = splitRegion(region, Bytes.toBytes("" + splitRow)); + //Opening the regions returned. + for (int i = 0; i < regions.length; i++) { + regions[i] = HRegion.openHRegion(regions[i], null); + } + //Verifying that the region has been split + assertEquals(2, regions.length); + + //Verifying that all data is still there and that data is in the right + //place + verifyData(regions[0], startRow, numRows, qualifier, families); + verifyData(regions[1], splitRow, numRows, qualifier, families); + + //fire the reverse scan1: top range, and larger than the last row + Scan scan = new Scan(Bytes.toBytes(String.valueOf(startRow + 10 * numRows))); + scan.setReversed(true); + InternalScanner scanner = regions[1].getScanner(scan); + List currRow = new ArrayList(); + boolean more = false; + int verify = startRow + 2 * numRows - 1; + do { + more = scanner.next(currRow); + assertEquals(Bytes.toString(currRow.get(0).getRow()), verify + ""); + verify--; + currRow.clear(); + } while(more); + assertEquals(verify, startRow + numRows - 1); + scanner.close(); + //fire the reverse scan2: top range, and equals to the last row + scan = new Scan(Bytes.toBytes(String.valueOf(startRow + 2 * numRows - 1))); + scan.setReversed(true); + scanner = regions[1].getScanner(scan); + verify = startRow + 2 * numRows - 1; + do { + more = scanner.next(currRow); + assertEquals(Bytes.toString(currRow.get(0).getRow()), verify + ""); + verify--; + currRow.clear(); + } while(more); + assertEquals(verify, startRow + numRows - 1); + scanner.close(); + //fire the reverse scan3: bottom range, and larger than the last row + scan = new Scan(Bytes.toBytes(String.valueOf(startRow + numRows))); + scan.setReversed(true); + scanner = regions[0].getScanner(scan); + verify = startRow + numRows - 1; + do { + more = scanner.next(currRow); + assertEquals(Bytes.toString(currRow.get(0).getRow()), verify + ""); + verify--; + currRow.clear(); + } while(more); + assertEquals(verify, 99); + scanner.close(); + //fire the reverse scan4: bottom range, and equals to the last row + scan = new Scan(Bytes.toBytes(String.valueOf(startRow + numRows - 1))); + scan.setReversed(true); + scanner = regions[0].getScanner(scan); + verify = startRow + numRows - 1; + do { + more = scanner.next(currRow); + assertEquals(Bytes.toString(currRow.get(0).getRow()), verify + ""); + verify--; + currRow.clear(); + } while(more); + assertEquals(verify, startRow - 1); + scanner.close(); + } finally { + HRegion.closeHRegion(this.region); + this.region = null; + } + } + @Test public void testWriteRequestsCounter() throws IOException { byte[] fam = Bytes.toBytes("info");