Skip to content

Commit e62ea6c

Browse files
vineet4008bbeaudreault
authored andcommitted
HBASE-28482 Reverse scan with tags throws ArrayIndexOutOfBoundsException with DBE in setCurrentBlock flow (#5792)
Signed-off-by: Pankaj Kumar <[email protected]> Signed-off-by: Bryan Beaudreault <[email protected]>
1 parent 53809ab commit e62ea6c

File tree

2 files changed

+32
-14
lines changed

2 files changed

+32
-14
lines changed

hbase-common/src/main/java/org/apache/hadoop/hbase/io/encoding/BufferedDataBlockEncoder.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,13 @@ public int compareKey(CellComparator comparator, Cell key) {
834834
public void setCurrentBuffer(ByteBuff buffer) {
835835
if (this.tagCompressionContext != null) {
836836
this.tagCompressionContext.clear();
837+
838+
// Prior seekToKeyInBlock may have reset this to false if we fell back to previous
839+
// seeker state. This is an optimization so we don't have to uncompress tags again when
840+
// reading last state.
841+
// In seekBefore flow, if block change happens then rewind is not called and
842+
// setCurrentBuffer is called, so need to uncompress any tags we see.
843+
current.uncompressTags = true;
837844
}
838845
currentBuffer = buffer;
839846
current.currentBuffer = currentBuffer;
@@ -876,9 +883,6 @@ public void rewind() {
876883
// reading last state.
877884
// In case of rewind, we are starting from the beginning of the buffer, so we need
878885
// to uncompress any tags we see.
879-
// It may make sense to reset this in setCurrentBuffer as well, but we seem to only call
880-
// setCurrentBuffer after StoreFileScanner.seekAtOrAfter which calls next to consume the
881-
// seeker state. Rewind is called by seekBefore, which doesn't and leaves us in this state.
882886
current.uncompressTags = true;
883887
}
884888
decodeFirst();

hbase-server/src/test/java/org/apache/hadoop/hbase/regionserver/TestTags.java

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,32 +125,46 @@ public void testReverseScanWithDBE() throws IOException {
125125

126126
try (Connection connection = ConnectionFactory.createConnection(conf)) {
127127
for (DataBlockEncoding encoding : DataBlockEncoding.values()) {
128-
testReverseScanWithDBE(connection, encoding, family);
128+
testReverseScanWithDBE(connection, encoding, family, HConstants.DEFAULT_BLOCKSIZE, 10);
129129
}
130130
}
131131
}
132132

133-
private void testReverseScanWithDBE(Connection conn, DataBlockEncoding encoding, byte[] family)
134-
throws IOException {
133+
/**
134+
* Test that we can do reverse scans when writing tags and using DataBlockEncoding. Fails with an
135+
* exception for PREFIX, DIFF, and FAST_DIFF
136+
*/
137+
@Test
138+
public void testReverseScanWithDBEWhenCurrentBlockUpdates() throws IOException {
139+
byte[] family = Bytes.toBytes("0");
140+
141+
Configuration conf = new Configuration(TEST_UTIL.getConfiguration());
142+
conf.setInt(HConstants.HBASE_CLIENT_RETRIES_NUMBER, 1);
143+
144+
try (Connection connection = ConnectionFactory.createConnection(conf)) {
145+
for (DataBlockEncoding encoding : DataBlockEncoding.values()) {
146+
testReverseScanWithDBE(connection, encoding, family, 1024, 30000);
147+
}
148+
}
149+
}
150+
151+
private void testReverseScanWithDBE(Connection conn, DataBlockEncoding encoding, byte[] family,
152+
int blockSize, int maxRows) throws IOException {
135153
LOG.info("Running test with DBE={}", encoding);
136154
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName() + "-" + encoding);
137-
TEST_UTIL.createTable(TableDescriptorBuilder.newBuilder(tableName)
138-
.setColumnFamily(
139-
ColumnFamilyDescriptorBuilder.newBuilder(family).setDataBlockEncoding(encoding).build())
140-
.build(), null);
155+
TEST_UTIL.createTable(
156+
TableDescriptorBuilder.newBuilder(tableName).setColumnFamily(ColumnFamilyDescriptorBuilder
157+
.newBuilder(family).setDataBlockEncoding(encoding).setBlocksize(blockSize).build()).build(),
158+
null);
141159

142160
Table table = conn.getTable(tableName);
143161

144-
int maxRows = 10;
145162
byte[] val1 = new byte[10];
146163
byte[] val2 = new byte[10];
147164
Bytes.random(val1);
148165
Bytes.random(val2);
149166

150167
for (int i = 0; i < maxRows; i++) {
151-
if (i == maxRows / 2) {
152-
TEST_UTIL.flush(tableName);
153-
}
154168
table.put(new Put(Bytes.toBytes(i)).addColumn(family, Bytes.toBytes(1), val1)
155169
.addColumn(family, Bytes.toBytes(2), val2).setTTL(600_000));
156170
}

0 commit comments

Comments
 (0)