Skip to content

Commit e4edfab

Browse files
committed
HBASE-28482 Reverse scan with tags throws ArrayIndexOutOfBoundsException with DBE in setCurrentBlock flow
1 parent 90639d7 commit e4edfab

File tree

2 files changed

+28
-10
lines changed

2 files changed

+28
-10
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: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,32 +124,46 @@ public void testReverseScanWithDBE() throws IOException {
124124

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

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

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

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

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

0 commit comments

Comments
 (0)