HBASE-14497 Reverse Scan threw StackOverflow caused by readPt checking (Yerui Sun)

This commit is contained in:
tedyu 2015-10-06 13:56:02 -07:00
parent aeb3a62459
commit 5e2db42d68
3 changed files with 124 additions and 53 deletions

View File

@ -969,7 +969,10 @@ public class DefaultMemStore implements MemStore {
* specified key, then seek to the first KeyValue of previous row
*/
@Override
public synchronized boolean seekToPreviousRow(Cell key) {
public synchronized boolean seekToPreviousRow(Cell originalKey) {
boolean keepSeeking = false;
Cell key = originalKey;
do {
Cell firstKeyOnRow = KeyValueUtil.createFirstOnRow(key.getRowArray(), key.getRowOffset(),
key.getRowLength());
SortedSet<Cell> cellHead = cellSetAtCreation.headSet(firstKeyOnRow);
@ -990,8 +993,13 @@ public class DefaultMemStore implements MemStore {
this.stopSkippingCellsIfNextRow = false;
if (peek() == null
|| comparator.compareRows(peek(), firstKeyOnPreviousRow) > 0) {
return seekToPreviousRow(lastCellBeforeRow);
keepSeeking = true;
key = firstKeyOnPreviousRow;
continue;
} else {
keepSeeking = false;
}
} while (keepSeeking);
return true;
}

View File

@ -437,9 +437,12 @@ public class StoreFileScanner implements KeyValueScanner {
@Override
@SuppressWarnings("deprecation")
public boolean seekToPreviousRow(Cell key) throws IOException {
public boolean seekToPreviousRow(Cell originalKey) throws IOException {
try {
try {
boolean keepSeeking = false;
Cell key = originalKey;
do {
KeyValue seekKey = KeyValueUtil.createFirstOnRow(key.getRowArray(), key.getRowOffset(),
key.getRowLength());
if (seekCount != null) seekCount.incrementAndGet();
@ -467,9 +470,13 @@ public class StoreFileScanner implements KeyValueScanner {
}
if (!resultOfSkipKVs
|| getComparator().compareRows(cur, firstKeyOfPreviousRow) > 0) {
return seekToPreviousRow(firstKeyOfPreviousRow);
keepSeeking = true;
key = firstKeyOfPreviousRow;
continue;
} else {
keepSeeking = false;
}
} while (keepSeeking);
return true;
} finally {
realSeekDone = true;
@ -478,7 +485,7 @@ public class StoreFileScanner implements KeyValueScanner {
throw e;
} catch (IOException ioe) {
throw new IOException("Could not seekToPreviousRow " + this + " to key "
+ key, ioe);
+ originalKey, ioe);
}
}

View File

@ -5748,6 +5748,62 @@ public class TestHRegion {
}
}
/**
* Test for HBASE-14497: Reverse Scan threw StackOverflow caused by readPt checking
*/
@Test (timeout = 60000)
public void testReverseScanner_StackOverflow() throws IOException {
byte[] cf1 = Bytes.toBytes("CF1");
byte[][] families = {cf1};
byte[] col = Bytes.toBytes("C");
String method = this.getName();
HBaseConfiguration conf = new HBaseConfiguration();
this.region = initHRegion(tableName, method, conf, families);
try {
// setup with one storefile and one memstore, to create scanner and get an earlier readPt
Put put = new Put(Bytes.toBytes("19998"));
put.add(cf1, col, Bytes.toBytes("val"));
region.put(put);
region.flushcache(true, true);
Put put2 = new Put(Bytes.toBytes("19997"));
put2.add(cf1, col, Bytes.toBytes("val"));
region.put(put2);
Scan scan = new Scan(Bytes.toBytes("19998"));
scan.setReversed(true);
InternalScanner scanner = region.getScanner(scan);
// create one storefile contains many rows will be skipped
// to check StoreFileScanner.seekToPreviousRow
for (int i = 10000; i < 20000; i++) {
Put p = new Put(Bytes.toBytes("" + i));
p.add(cf1, col, Bytes.toBytes("" + i));
region.put(p);
}
region.flushcache(true, true);
// create one memstore contains many rows will be skipped
// to check MemStoreScanner.seekToPreviousRow
for (int i = 10000; i < 20000; i++) {
Put p = new Put(Bytes.toBytes("" + i));
p.add(cf1, col, Bytes.toBytes("" + i));
region.put(p);
}
List<Cell> currRow = new ArrayList<>();
boolean hasNext;
do {
hasNext = scanner.next(currRow);
} while (hasNext);
assertEquals(2, currRow.size());
assertArrayEquals(Bytes.toBytes("19998"), currRow.get(0).getRow());
assertArrayEquals(Bytes.toBytes("19997"), currRow.get(1).getRow());
} finally {
HBaseTestingUtility.closeRegionAndWAL(this.region);
this.region = null;
}
}
@Test (timeout=60000)
public void testSplitRegionWithReverseScan() throws IOException {
byte [] tableName = Bytes.toBytes("testSplitRegionWithReverseScan");