From 6b35308cf0f523e175bb6e036502dd6102410f10 Mon Sep 17 00:00:00 2001 From: zjushch Date: Sun, 28 Apr 2013 08:11:25 +0000 Subject: [PATCH] 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 --- .../codec/prefixtree/PrefixTreeSeeker.java | 14 +++-- .../io/encoding/TestPrefixTreeEncoding.java | 59 ++++++++++++++++++- 2 files changed, 67 insertions(+), 6 deletions(-) diff --git a/hbase-prefix-tree/src/main/java/org/apache/hadoop/hbase/codec/prefixtree/PrefixTreeSeeker.java b/hbase-prefix-tree/src/main/java/org/apache/hadoop/hbase/codec/prefixtree/PrefixTreeSeeker.java index a46a34a52bf..b2609fd9341 100644 --- a/hbase-prefix-tree/src/main/java/org/apache/hadoop/hbase/codec/prefixtree/PrefixTreeSeeker.java +++ b/hbase-prefix-tree/src/main/java/org/apache/hadoop/hbase/codec/prefixtree/PrefixTreeSeeker.java @@ -91,6 +91,9 @@ public class PrefixTreeSeeker implements EncodedSeeker { */ @Override public KeyValue getKeyValue() { + if (ptSearcher.current() == null) { + return null; + } return KeyValueUtil.copyToNewKeyValue(ptSearcher.current()); } @@ -163,14 +166,14 @@ public class PrefixTreeSeeker implements EncodedSeeker { */ 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 KeyValue kv = KeyValue.createKeyValueFromKey(keyOnlyBytes, offset, length); CellScannerPosition position = ptSearcher.seekForwardToOrBefore(kv); if(CellScannerPosition.AT == position){ - if (forceBeforeOnExactMatch) { + if (seekBefore) { ptSearcher.previous(); return 1; } @@ -182,7 +185,7 @@ public class PrefixTreeSeeker implements EncodedSeeker { 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 KeyValue kv = KeyValue.createKeyValueFromKey(keyOnlyBytes, offset, length); @@ -190,7 +193,7 @@ public class PrefixTreeSeeker implements EncodedSeeker { CellScannerPosition position = ptSearcher.seekForwardToOrAfter(kv); if(CellScannerPosition.AT == position){ - if (forceBeforeOnExactMatch) { + if (seekBefore) { ptSearcher.previous(); return 1; } @@ -206,6 +209,9 @@ public class PrefixTreeSeeker implements EncodedSeeker { } if(position == CellScannerPosition.AFTER_LAST){ + if (seekBefore) { + ptSearcher.previous(); + } return 1; } diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/io/encoding/TestPrefixTreeEncoding.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/io/encoding/TestPrefixTreeEncoding.java index 2ea0db5377a..40b365f5b8e 100644 --- a/hbase-server/src/test/java/org/apache/hadoop/hbase/io/encoding/TestPrefixTreeEncoding.java +++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/io/encoding/TestPrefixTreeEncoding.java @@ -18,6 +18,9 @@ */ 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 java.io.ByteArrayOutputStream; @@ -57,9 +60,54 @@ public class TestPrefixTreeEncoding { private ConcurrentSkipListSet kvset = new ConcurrentSkipListSet( KeyValue.COMPARATOR); + private static boolean formatRowNum = false; + @Before public void setUp() throws Exception { 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 @@ -157,10 +205,16 @@ public class TestPrefixTreeEncoding { private static ByteBuffer generateFixedTestData( ConcurrentSkipListSet kvset, int batchId) throws Exception { + return generateFixedTestData(kvset, batchId, true); + } + + private static ByteBuffer generateFixedTestData( + ConcurrentSkipListSet kvset, int batchId, boolean partial) + throws Exception { ByteArrayOutputStream baosInMemory = new ByteArrayOutputStream(); DataOutputStream userDataStream = new DataOutputStream(baosInMemory); 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) { KeyValue kv = new KeyValue(getRowKey(batchId, i), CF_BYTES, getQualifier(j), getValue(batchId, i, j)); @@ -204,7 +258,8 @@ public class TestPrefixTreeEncoding { } 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) {