HBASE-8436 SeekBefore returns wrong result with PREFIX_TREE Encoding
git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1476730 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
e12e470d5f
commit
6b35308cf0
|
@ -91,6 +91,9 @@ public class PrefixTreeSeeker implements EncodedSeeker {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public KeyValue getKeyValue() {
|
public KeyValue getKeyValue() {
|
||||||
|
if (ptSearcher.current() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return KeyValueUtil.copyToNewKeyValue(ptSearcher.current());
|
return KeyValueUtil.copyToNewKeyValue(ptSearcher.current());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,14 +166,14 @@ public class PrefixTreeSeeker implements EncodedSeeker {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
protected int seekToOrBeforeUsingPositionAtOrBefore(byte[] keyOnlyBytes, int offset, int length,
|
protected int seekToOrBeforeUsingPositionAtOrBefore(byte[] keyOnlyBytes, int offset, int length,
|
||||||
boolean forceBeforeOnExactMatch){
|
boolean seekBefore){
|
||||||
// this does a deep copy of the key byte[] because the CellSearcher interface wants a Cell
|
// this does a deep copy of the key byte[] because the CellSearcher interface wants a Cell
|
||||||
KeyValue kv = KeyValue.createKeyValueFromKey(keyOnlyBytes, offset, length);
|
KeyValue kv = KeyValue.createKeyValueFromKey(keyOnlyBytes, offset, length);
|
||||||
|
|
||||||
CellScannerPosition position = ptSearcher.seekForwardToOrBefore(kv);
|
CellScannerPosition position = ptSearcher.seekForwardToOrBefore(kv);
|
||||||
|
|
||||||
if(CellScannerPosition.AT == position){
|
if(CellScannerPosition.AT == position){
|
||||||
if (forceBeforeOnExactMatch) {
|
if (seekBefore) {
|
||||||
ptSearcher.previous();
|
ptSearcher.previous();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -182,7 +185,7 @@ public class PrefixTreeSeeker implements EncodedSeeker {
|
||||||
|
|
||||||
|
|
||||||
protected int seekToOrBeforeUsingPositionAtOrAfter(byte[] keyOnlyBytes, int offset, int length,
|
protected int seekToOrBeforeUsingPositionAtOrAfter(byte[] keyOnlyBytes, int offset, int length,
|
||||||
boolean forceBeforeOnExactMatch){
|
boolean seekBefore){
|
||||||
// this does a deep copy of the key byte[] because the CellSearcher interface wants a Cell
|
// this does a deep copy of the key byte[] because the CellSearcher interface wants a Cell
|
||||||
KeyValue kv = KeyValue.createKeyValueFromKey(keyOnlyBytes, offset, length);
|
KeyValue kv = KeyValue.createKeyValueFromKey(keyOnlyBytes, offset, length);
|
||||||
|
|
||||||
|
@ -190,7 +193,7 @@ public class PrefixTreeSeeker implements EncodedSeeker {
|
||||||
CellScannerPosition position = ptSearcher.seekForwardToOrAfter(kv);
|
CellScannerPosition position = ptSearcher.seekForwardToOrAfter(kv);
|
||||||
|
|
||||||
if(CellScannerPosition.AT == position){
|
if(CellScannerPosition.AT == position){
|
||||||
if (forceBeforeOnExactMatch) {
|
if (seekBefore) {
|
||||||
ptSearcher.previous();
|
ptSearcher.previous();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -206,6 +209,9 @@ public class PrefixTreeSeeker implements EncodedSeeker {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(position == CellScannerPosition.AFTER_LAST){
|
if(position == CellScannerPosition.AFTER_LAST){
|
||||||
|
if (seekBefore) {
|
||||||
|
ptSearcher.previous();
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hbase.io.encoding;
|
package org.apache.hadoop.hbase.io.encoding;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
@ -57,9 +60,54 @@ public class TestPrefixTreeEncoding {
|
||||||
private ConcurrentSkipListSet<KeyValue> kvset = new ConcurrentSkipListSet<KeyValue>(
|
private ConcurrentSkipListSet<KeyValue> kvset = new ConcurrentSkipListSet<KeyValue>(
|
||||||
KeyValue.COMPARATOR);
|
KeyValue.COMPARATOR);
|
||||||
|
|
||||||
|
private static boolean formatRowNum = false;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
kvset.clear();
|
kvset.clear();
|
||||||
|
formatRowNum = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSeekBeforeWithFixedData() throws Exception {
|
||||||
|
formatRowNum = true;
|
||||||
|
PrefixTreeCodec encoder = new PrefixTreeCodec();
|
||||||
|
int batchId = numBatchesWritten++;
|
||||||
|
ByteBuffer dataBuffer = generateFixedTestData(kvset, batchId, false);
|
||||||
|
HFileBlockEncodingContext blkEncodingCtx = new HFileBlockDefaultEncodingContext(
|
||||||
|
Algorithm.NONE, DataBlockEncoding.PREFIX_TREE, new byte[0]);
|
||||||
|
encoder.encodeKeyValues(dataBuffer, false, blkEncodingCtx);
|
||||||
|
EncodedSeeker seeker = encoder.createSeeker(KeyValue.KEY_COMPARATOR, false);
|
||||||
|
byte[] onDiskBytes = blkEncodingCtx.getOnDiskBytesWithHeader();
|
||||||
|
ByteBuffer readBuffer = ByteBuffer.wrap(onDiskBytes,
|
||||||
|
DataBlockEncoding.ID_SIZE, onDiskBytes.length
|
||||||
|
- DataBlockEncoding.ID_SIZE);
|
||||||
|
seeker.setCurrentBuffer(readBuffer);
|
||||||
|
|
||||||
|
// Seek before the first keyvalue;
|
||||||
|
KeyValue seekKey = KeyValue.createFirstDeleteFamilyOnRow(
|
||||||
|
getRowKey(batchId, 0), CF_BYTES);
|
||||||
|
seeker.seekToKeyInBlock(seekKey.getBuffer(), seekKey.getKeyOffset(),
|
||||||
|
seekKey.getKeyLength(), true);
|
||||||
|
assertEquals(null, seeker.getKeyValue());
|
||||||
|
|
||||||
|
// Seek before the middle keyvalue;
|
||||||
|
seekKey = KeyValue.createFirstDeleteFamilyOnRow(
|
||||||
|
getRowKey(batchId, NUM_ROWS_PER_BATCH / 3), CF_BYTES);
|
||||||
|
seeker.seekToKeyInBlock(seekKey.getBuffer(), seekKey.getKeyOffset(),
|
||||||
|
seekKey.getKeyLength(), true);
|
||||||
|
assertNotNull(seeker.getKeyValue());
|
||||||
|
assertArrayEquals(getRowKey(batchId, NUM_ROWS_PER_BATCH / 3 - 1), seeker
|
||||||
|
.getKeyValue().getRow());
|
||||||
|
|
||||||
|
// Seek before the last keyvalue;
|
||||||
|
seekKey = KeyValue.createFirstDeleteFamilyOnRow(Bytes.toBytes("zzzz"),
|
||||||
|
CF_BYTES);
|
||||||
|
seeker.seekToKeyInBlock(seekKey.getBuffer(), seekKey.getKeyOffset(),
|
||||||
|
seekKey.getKeyLength(), true);
|
||||||
|
assertNotNull(seeker.getKeyValue());
|
||||||
|
assertArrayEquals(getRowKey(batchId, NUM_ROWS_PER_BATCH - 1), seeker
|
||||||
|
.getKeyValue().getRow());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -157,10 +205,16 @@ public class TestPrefixTreeEncoding {
|
||||||
|
|
||||||
private static ByteBuffer generateFixedTestData(
|
private static ByteBuffer generateFixedTestData(
|
||||||
ConcurrentSkipListSet<KeyValue> kvset, int batchId) throws Exception {
|
ConcurrentSkipListSet<KeyValue> kvset, int batchId) throws Exception {
|
||||||
|
return generateFixedTestData(kvset, batchId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ByteBuffer generateFixedTestData(
|
||||||
|
ConcurrentSkipListSet<KeyValue> kvset, int batchId, boolean partial)
|
||||||
|
throws Exception {
|
||||||
ByteArrayOutputStream baosInMemory = new ByteArrayOutputStream();
|
ByteArrayOutputStream baosInMemory = new ByteArrayOutputStream();
|
||||||
DataOutputStream userDataStream = new DataOutputStream(baosInMemory);
|
DataOutputStream userDataStream = new DataOutputStream(baosInMemory);
|
||||||
for (int i = 0; i < NUM_ROWS_PER_BATCH; ++i) {
|
for (int i = 0; i < NUM_ROWS_PER_BATCH; ++i) {
|
||||||
if (i / 10 % 2 == 1) continue;
|
if (partial && i / 10 % 2 == 1) continue;
|
||||||
for (int j = 0; j < NUM_COLS_PER_ROW; ++j) {
|
for (int j = 0; j < NUM_COLS_PER_ROW; ++j) {
|
||||||
KeyValue kv = new KeyValue(getRowKey(batchId, i), CF_BYTES,
|
KeyValue kv = new KeyValue(getRowKey(batchId, i), CF_BYTES,
|
||||||
getQualifier(j), getValue(batchId, i, j));
|
getQualifier(j), getValue(batchId, i, j));
|
||||||
|
@ -204,7 +258,8 @@ public class TestPrefixTreeEncoding {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] getRowKey(int batchId, int i) {
|
private static byte[] getRowKey(int batchId, int i) {
|
||||||
return Bytes.toBytes("batch" + batchId + "_row" + i);
|
return Bytes.toBytes("batch" + batchId + "_row"
|
||||||
|
+ (formatRowNum ? String.format("%04d", i) : i));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] getQualifier(int j) {
|
private static byte[] getQualifier(int j) {
|
||||||
|
|
Loading…
Reference in New Issue