Skip to content

Commit 9aa8b9b

Browse files
jbewingApache9
authored andcommitted
HBASE-28012 Avoid CellUtil.cloneRow in BufferedEncodedSeeker (#5347)
Signed-off-by: Duo Zhang <zhangduo@apache.org> (cherry picked from commit 2fb2ae1)
1 parent b9696b8 commit 9aa8b9b

File tree

3 files changed

+223
-23
lines changed

3 files changed

+223
-23
lines changed

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

Lines changed: 134 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -88,21 +88,100 @@ public ByteBuffer decodeKeyValues(DataInputStream source,
8888
// Having this as static is fine but if META is having DBE then we should
8989
// change this.
9090
public static int compareCommonRowPrefix(Cell left, Cell right, int rowCommonPrefix) {
91-
return Bytes.compareTo(left.getRowArray(), left.getRowOffset() + rowCommonPrefix,
92-
left.getRowLength() - rowCommonPrefix, right.getRowArray(),
93-
right.getRowOffset() + rowCommonPrefix, right.getRowLength() - rowCommonPrefix);
91+
if (left instanceof ByteBufferExtendedCell) {
92+
ByteBufferExtendedCell bbLeft = (ByteBufferExtendedCell) left;
93+
if (right instanceof ByteBufferExtendedCell) {
94+
ByteBufferExtendedCell bbRight = (ByteBufferExtendedCell) right;
95+
return ByteBufferUtils.compareTo(bbLeft.getRowByteBuffer(),
96+
bbLeft.getRowPosition() + rowCommonPrefix, left.getRowLength() - rowCommonPrefix,
97+
bbRight.getRowByteBuffer(), bbRight.getRowPosition() + rowCommonPrefix,
98+
right.getRowLength() - rowCommonPrefix);
99+
} else {
100+
return ByteBufferUtils.compareTo(bbLeft.getRowByteBuffer(),
101+
bbLeft.getRowPosition() + rowCommonPrefix, left.getRowLength() - rowCommonPrefix,
102+
right.getRowArray(), right.getRowOffset() + rowCommonPrefix,
103+
right.getRowLength() - rowCommonPrefix);
104+
}
105+
} else {
106+
if (right instanceof ByteBufferExtendedCell) {
107+
ByteBufferExtendedCell bbRight = (ByteBufferExtendedCell) right;
108+
return ByteBufferUtils.compareTo(left.getRowArray(), left.getRowOffset() + rowCommonPrefix,
109+
left.getRowLength() - rowCommonPrefix, bbRight.getRowByteBuffer(),
110+
bbRight.getRowPosition() + rowCommonPrefix, right.getRowLength() - rowCommonPrefix);
111+
} else {
112+
return Bytes.compareTo(left.getRowArray(), left.getRowOffset() + rowCommonPrefix,
113+
left.getRowLength() - rowCommonPrefix, right.getRowArray(),
114+
right.getRowOffset() + rowCommonPrefix, right.getRowLength() - rowCommonPrefix);
115+
}
116+
}
94117
}
95118

96119
public static int compareCommonFamilyPrefix(Cell left, Cell right, int familyCommonPrefix) {
97-
return Bytes.compareTo(left.getFamilyArray(), left.getFamilyOffset() + familyCommonPrefix,
98-
left.getFamilyLength() - familyCommonPrefix, right.getFamilyArray(),
99-
right.getFamilyOffset() + familyCommonPrefix, right.getFamilyLength() - familyCommonPrefix);
120+
if (left instanceof ByteBufferExtendedCell) {
121+
ByteBufferExtendedCell bbLeft = (ByteBufferExtendedCell) left;
122+
if (right instanceof ByteBufferExtendedCell) {
123+
ByteBufferExtendedCell bbRight = (ByteBufferExtendedCell) right;
124+
return ByteBufferUtils.compareTo(bbLeft.getFamilyByteBuffer(),
125+
bbLeft.getFamilyPosition() + familyCommonPrefix,
126+
left.getFamilyLength() - familyCommonPrefix, bbRight.getFamilyByteBuffer(),
127+
bbRight.getFamilyPosition() + familyCommonPrefix,
128+
right.getFamilyLength() - familyCommonPrefix);
129+
} else {
130+
return ByteBufferUtils.compareTo(bbLeft.getFamilyByteBuffer(),
131+
bbLeft.getFamilyPosition() + familyCommonPrefix,
132+
left.getFamilyLength() - familyCommonPrefix, right.getFamilyArray(),
133+
right.getFamilyOffset() + familyCommonPrefix,
134+
right.getFamilyLength() - familyCommonPrefix);
135+
}
136+
} else {
137+
if (right instanceof ByteBufferExtendedCell) {
138+
ByteBufferExtendedCell bbRight = (ByteBufferExtendedCell) right;
139+
return ByteBufferUtils.compareTo(left.getFamilyArray(),
140+
left.getFamilyOffset() + familyCommonPrefix, left.getFamilyLength() - familyCommonPrefix,
141+
bbRight.getFamilyByteBuffer(), bbRight.getFamilyPosition() + familyCommonPrefix,
142+
right.getFamilyLength() - familyCommonPrefix);
143+
} else {
144+
return Bytes.compareTo(left.getFamilyArray(), left.getFamilyOffset() + familyCommonPrefix,
145+
left.getFamilyLength() - familyCommonPrefix, right.getFamilyArray(),
146+
right.getFamilyOffset() + familyCommonPrefix,
147+
right.getFamilyLength() - familyCommonPrefix);
148+
}
149+
}
100150
}
101151

102152
public static int compareCommonQualifierPrefix(Cell left, Cell right, int qualCommonPrefix) {
103-
return Bytes.compareTo(left.getQualifierArray(), left.getQualifierOffset() + qualCommonPrefix,
104-
left.getQualifierLength() - qualCommonPrefix, right.getQualifierArray(),
105-
right.getQualifierOffset() + qualCommonPrefix, right.getQualifierLength() - qualCommonPrefix);
153+
if (left instanceof ByteBufferExtendedCell) {
154+
ByteBufferExtendedCell bbLeft = (ByteBufferExtendedCell) left;
155+
if (right instanceof ByteBufferExtendedCell) {
156+
ByteBufferExtendedCell bbRight = (ByteBufferExtendedCell) right;
157+
return ByteBufferUtils.compareTo(bbLeft.getQualifierByteBuffer(),
158+
bbLeft.getQualifierPosition() + qualCommonPrefix,
159+
left.getQualifierLength() - qualCommonPrefix, bbRight.getQualifierByteBuffer(),
160+
bbRight.getQualifierPosition() + qualCommonPrefix,
161+
right.getQualifierLength() - qualCommonPrefix);
162+
} else {
163+
return ByteBufferUtils.compareTo(bbLeft.getQualifierByteBuffer(),
164+
bbLeft.getQualifierPosition() + qualCommonPrefix,
165+
left.getQualifierLength() - qualCommonPrefix, right.getQualifierArray(),
166+
right.getQualifierOffset() + qualCommonPrefix,
167+
right.getQualifierLength() - qualCommonPrefix);
168+
}
169+
} else {
170+
if (right instanceof ByteBufferExtendedCell) {
171+
ByteBufferExtendedCell bbRight = (ByteBufferExtendedCell) right;
172+
return ByteBufferUtils.compareTo(left.getQualifierArray(),
173+
left.getQualifierOffset() + qualCommonPrefix,
174+
left.getQualifierLength() - qualCommonPrefix, bbRight.getQualifierByteBuffer(),
175+
bbRight.getQualifierPosition() + qualCommonPrefix,
176+
right.getQualifierLength() - qualCommonPrefix);
177+
} else {
178+
return Bytes.compareTo(left.getQualifierArray(),
179+
left.getQualifierOffset() + qualCommonPrefix,
180+
left.getQualifierLength() - qualCommonPrefix, right.getQualifierArray(),
181+
right.getQualifierOffset() + qualCommonPrefix,
182+
right.getQualifierLength() - qualCommonPrefix);
183+
}
184+
}
106185
}
107186

108187
protected static class SeekerState {
@@ -951,25 +1030,57 @@ private int compareTypeBytes(Cell key, Cell right) {
9511030
return 0;
9521031
}
9531032

954-
private static int findCommonPrefixInRowPart(Cell left, Cell right, int rowCommonPrefix) {
955-
return Bytes.findCommonPrefix(left.getRowArray(), right.getRowArray(),
956-
left.getRowLength() - rowCommonPrefix, right.getRowLength() - rowCommonPrefix,
957-
left.getRowOffset() + rowCommonPrefix, right.getRowOffset() + rowCommonPrefix);
1033+
// These findCommonPrefix* methods rely on the fact that keyOnlyKv is the "right" cell argument
1034+
// and always on-heap
1035+
1036+
private static int findCommonPrefixInRowPart(Cell left, KeyValue.KeyOnlyKeyValue right,
1037+
int rowCommonPrefix) {
1038+
if (left instanceof ByteBufferExtendedCell) {
1039+
ByteBufferExtendedCell bbLeft = (ByteBufferExtendedCell) left;
1040+
return ByteBufferUtils.findCommonPrefix(bbLeft.getRowByteBuffer(),
1041+
bbLeft.getRowPosition() + rowCommonPrefix, left.getRowLength() - rowCommonPrefix,
1042+
right.getRowArray(), right.getRowOffset() + rowCommonPrefix,
1043+
right.getRowLength() - rowCommonPrefix);
1044+
} else {
1045+
return Bytes.findCommonPrefix(left.getRowArray(), right.getRowArray(),
1046+
left.getRowLength() - rowCommonPrefix, right.getRowLength() - rowCommonPrefix,
1047+
left.getRowOffset() + rowCommonPrefix, right.getRowOffset() + rowCommonPrefix);
1048+
}
9581049
}
9591050

960-
private static int findCommonPrefixInFamilyPart(Cell left, Cell right, int familyCommonPrefix) {
961-
return Bytes.findCommonPrefix(left.getFamilyArray(), right.getFamilyArray(),
962-
left.getFamilyLength() - familyCommonPrefix, right.getFamilyLength() - familyCommonPrefix,
963-
left.getFamilyOffset() + familyCommonPrefix, right.getFamilyOffset() + familyCommonPrefix);
1051+
private static int findCommonPrefixInFamilyPart(Cell left, KeyValue.KeyOnlyKeyValue right,
1052+
int familyCommonPrefix) {
1053+
if (left instanceof ByteBufferExtendedCell) {
1054+
ByteBufferExtendedCell bbLeft = (ByteBufferExtendedCell) left;
1055+
return ByteBufferUtils.findCommonPrefix(bbLeft.getFamilyByteBuffer(),
1056+
bbLeft.getFamilyPosition() + familyCommonPrefix,
1057+
left.getFamilyLength() - familyCommonPrefix, right.getFamilyArray(),
1058+
right.getFamilyOffset() + familyCommonPrefix,
1059+
right.getFamilyLength() - familyCommonPrefix);
1060+
} else {
1061+
return Bytes.findCommonPrefix(left.getFamilyArray(), right.getFamilyArray(),
1062+
left.getFamilyLength() - familyCommonPrefix, right.getFamilyLength() - familyCommonPrefix,
1063+
left.getFamilyOffset() + familyCommonPrefix,
1064+
right.getFamilyOffset() + familyCommonPrefix);
1065+
}
9641066
}
9651067

966-
private static int findCommonPrefixInQualifierPart(Cell left, Cell right,
1068+
private static int findCommonPrefixInQualifierPart(Cell left, KeyValue.KeyOnlyKeyValue right,
9671069
int qualifierCommonPrefix) {
968-
return Bytes.findCommonPrefix(left.getQualifierArray(), right.getQualifierArray(),
969-
left.getQualifierLength() - qualifierCommonPrefix,
970-
right.getQualifierLength() - qualifierCommonPrefix,
971-
left.getQualifierOffset() + qualifierCommonPrefix,
972-
right.getQualifierOffset() + qualifierCommonPrefix);
1070+
if (left instanceof ByteBufferExtendedCell) {
1071+
ByteBufferExtendedCell bbLeft = (ByteBufferExtendedCell) left;
1072+
return ByteBufferUtils.findCommonPrefix(bbLeft.getQualifierByteBuffer(),
1073+
bbLeft.getQualifierPosition() + qualifierCommonPrefix,
1074+
left.getQualifierLength() - qualifierCommonPrefix, right.getQualifierArray(),
1075+
right.getQualifierOffset() + qualifierCommonPrefix,
1076+
right.getQualifierLength() - qualifierCommonPrefix);
1077+
} else {
1078+
return Bytes.findCommonPrefix(left.getQualifierArray(), right.getQualifierArray(),
1079+
left.getQualifierLength() - qualifierCommonPrefix,
1080+
right.getQualifierLength() - qualifierCommonPrefix,
1081+
left.getQualifierOffset() + qualifierCommonPrefix,
1082+
right.getQualifierOffset() + qualifierCommonPrefix);
1083+
}
9731084
}
9741085

9751086
private void moveToPrevious() {

hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteBufferUtils.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,30 @@ public static int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLeng
796796
return result;
797797
}
798798

799+
/**
800+
* Find length of common prefix in two arrays.
801+
* @param left ByteBuffer to be compared.
802+
* @param leftOffset Offset in left ByteBuffer.
803+
* @param leftLength Length of left ByteBuffer.
804+
* @param right Array to be compared
805+
* @param rightOffset Offset in right Array.
806+
* @param rightLength Length of right Array.
807+
*/
808+
public static int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength, byte[] right,
809+
int rightOffset, int rightLength) {
810+
int length = Math.min(leftLength, rightLength);
811+
int result = 0;
812+
813+
while (
814+
result < length
815+
&& ByteBufferUtils.toByte(left, leftOffset + result) == right[rightOffset + result]
816+
) {
817+
result++;
818+
}
819+
820+
return result;
821+
}
822+
799823
/**
800824
* Check whether two parts in the same buffer are equal.
801825
* @param buffer In which buffer there are parts

hbase-server/src/test/java/org/apache/hadoop/hbase/io/encoding/TestDataBlockEncoders.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.Random;
3333
import java.util.concurrent.ThreadLocalRandom;
3434
import org.apache.hadoop.hbase.ArrayBackedTag;
35+
import org.apache.hadoop.hbase.ByteBufferKeyValue;
3536
import org.apache.hadoop.hbase.Cell;
3637
import org.apache.hadoop.hbase.CellComparatorImpl;
3738
import org.apache.hadoop.hbase.CellUtil;
@@ -227,6 +228,59 @@ public void testSeekingOnSample() throws IOException {
227228
LOG.info("Done");
228229
}
229230

231+
@Test
232+
public void testSeekingToOffHeapKeyValueInSample() throws IOException {
233+
List<KeyValue> sampleKv = generator.generateTestKeyValues(NUMBER_OF_KV, includesTags);
234+
235+
// create all seekers
236+
List<DataBlockEncoder.EncodedSeeker> encodedSeekers = new ArrayList<>();
237+
for (DataBlockEncoding encoding : DataBlockEncoding.values()) {
238+
LOG.info("Encoding: " + encoding);
239+
DataBlockEncoder encoder = encoding.getEncoder();
240+
if (encoder == null) {
241+
continue;
242+
}
243+
LOG.info("Encoder: " + encoder);
244+
ByteBuffer encodedBuffer = encodeKeyValues(encoding, sampleKv,
245+
getEncodingContext(Compression.Algorithm.NONE, encoding), this.useOffheapData);
246+
HFileContext meta =
247+
new HFileContextBuilder().withHBaseCheckSum(false).withIncludesMvcc(includesMemstoreTS)
248+
.withIncludesTags(includesTags).withCompression(Compression.Algorithm.NONE).build();
249+
DataBlockEncoder.EncodedSeeker seeker =
250+
encoder.createSeeker(encoder.newDataBlockDecodingContext(meta));
251+
seeker.setCurrentBuffer(new SingleByteBuff(encodedBuffer));
252+
encodedSeekers.add(seeker);
253+
}
254+
LOG.info("Testing it!");
255+
// test it!
256+
// try a few random seeks
257+
Random rand = ThreadLocalRandom.current();
258+
for (boolean seekBefore : new boolean[] { false, true }) {
259+
for (int i = 0; i < NUM_RANDOM_SEEKS; ++i) {
260+
int keyValueId;
261+
if (!seekBefore) {
262+
keyValueId = rand.nextInt(sampleKv.size());
263+
} else {
264+
keyValueId = rand.nextInt(sampleKv.size() - 1) + 1;
265+
}
266+
267+
KeyValue keyValue = sampleKv.get(keyValueId);
268+
checkSeekingConsistency(encodedSeekers, seekBefore, buildOffHeapKeyValue(keyValue));
269+
}
270+
}
271+
272+
// check edge cases
273+
LOG.info("Checking edge cases");
274+
checkSeekingConsistency(encodedSeekers, false, sampleKv.get(0));
275+
for (boolean seekBefore : new boolean[] { false, true }) {
276+
checkSeekingConsistency(encodedSeekers, seekBefore, sampleKv.get(sampleKv.size() - 1));
277+
KeyValue midKv = sampleKv.get(sampleKv.size() / 2);
278+
Cell lastMidKv = PrivateCellUtil.createLastOnRowCol(midKv);
279+
checkSeekingConsistency(encodedSeekers, seekBefore, lastMidKv);
280+
}
281+
LOG.info("Done");
282+
}
283+
230284
static ByteBuffer encodeKeyValues(DataBlockEncoding encoding, List<KeyValue> kvs,
231285
HFileBlockEncodingContext encodingContext, boolean useOffheapData) throws IOException {
232286
DataBlockEncoder encoder = encoding.getEncoder();
@@ -436,4 +490,15 @@ private void testAlgorithm(byte[] encodedData, ByteBuffer unencodedDataBuf,
436490
assertEquals("Encoding -> decoding gives different results for " + encoder,
437491
Bytes.toStringBinary(unencodedDataBuf), Bytes.toStringBinary(actualDataset));
438492
}
493+
494+
private static ByteBufferKeyValue buildOffHeapKeyValue(KeyValue keyValue) throws IOException {
495+
ByteArrayOutputStream out = new ByteArrayOutputStream();
496+
keyValue.write(out, false);
497+
byte[] bytes = out.toByteArray();
498+
ByteBuffer bb = ByteBuffer.allocateDirect(bytes.length);
499+
bb.put(bytes);
500+
bb.flip();
501+
502+
return new ByteBufferKeyValue(bb, 0, bytes.length);
503+
}
439504
}

0 commit comments

Comments
 (0)