diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ClientScanner.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ClientScanner.java index d13f881..55e92d5 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ClientScanner.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ClientScanner.java @@ -336,39 +336,14 @@ public class ClientScanner extends AbstractClientScanner { callable.setCaching(this.caching); // This flag is set when we want to skip the result returned. We do // this when we reset scanner because it split under us. - boolean skipFirst = false; boolean retryAfterOutOfOrderException = true; do { try { - if (skipFirst) { - // Skip only the first row (which was the last row of the last - // already-processed batch). - callable.setCaching(1); - values = call(scan, callable, caller, scannerTimeout); - // When the replica switch happens, we need to do certain operations - // again. The scannercallable will openScanner with the right startkey - // but we need to pick up from there. Bypass the rest of the loop - // and let the catch-up happen in the beginning of the loop as it - // happens for the cases where we see exceptions. Since only openScanner - // would have happened, values would be null - if (values == null && callable.switchedToADifferentReplica()) { - if (this.lastResult != null) { //only skip if there was something read earlier - skipFirst = true; - } - this.currentRegion = callable.getHRegionInfo(); - continue; - } - callable.setCaching(this.caching); - skipFirst = false; - } // Server returns a null values if scanning is to stop. Else, // returns an empty array if scanning is to go on and we've just // exhausted current region. values = call(scan, callable, caller, scannerTimeout); - if (skipFirst && values != null && values.length == 1) { - skipFirst = false; // Already skipped, unset it before scanning again - values = call(scan, callable, caller, scannerTimeout); - } + // When the replica switch happens, we need to do certain operations // again. The callable will openScanner with the right startkey // but we need to pick up from there. Bypass the rest of the loop @@ -376,9 +351,6 @@ public class ClientScanner extends AbstractClientScanner { // happens for the cases where we see exceptions. Since only openScanner // would have happened, values would be null if (values == null && callable.switchedToADifferentReplica()) { - if (this.lastResult != null) { //only skip if there was something read earlier - skipFirst = true; - } this.currentRegion = callable.getHRegionInfo(); continue; } @@ -414,12 +386,6 @@ public class ClientScanner extends AbstractClientScanner { } } // Else, its signal from depths of ScannerCallable that we need to reset the scanner. - if (this.lastResult != null) { - this.scan.setStartRow(this.lastResult.getRow()); - // Skip first row returned. We already let it out on previous - // invocation. - skipFirst = true; - } if (e instanceof OutOfOrderScannerNextException) { if (retryAfterOutOfOrderException) { retryAfterOutOfOrderException = false; diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java index 975140c..1463125 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/client/TestFromClientSide.java @@ -6253,4 +6253,28 @@ public class TestFromClientSide { } } + @Test + public void testScansWithSplits() throws Exception { + byte[] TABLE = Bytes.toBytes("testScansWithSplits"); + HTable t = + TEST_UTIL.createTable(TABLE, new byte[][] { FAMILY }, 1, Bytes.toBytes("aaa"), + Bytes.toBytes("zzza"), 10); + TEST_UTIL.loadTable(t, FAMILY); + // scan/split a few time, make sure we always get exactly the same number of results. + for (int i=0; i<20; i++) { + if (i>0) Thread.sleep(1000); + Scan s = new Scan(Bytes.toBytes("fff"), Bytes.toBytes("qqq")); + s.setCaching(10); + ResultScanner rs = t.getScanner(s); + int c = 0; + while(rs.next() != null) c++; + assertEquals(7733, c); + TEST_UTIL.getHBaseAdmin().split(TABLE); + // Cannot check the number of region without risking updating the client cache, + // which is what we want to test (see MetaScanner/HTable, etc). + // So just wait a bit and run in a few loops, during which we should detect any + // kind of strange behavior. + } + t.close(); + } }