-
Notifications
You must be signed in to change notification settings - Fork 2.5k
[DNM, stacked] fix(storage-format): fix multi-block previous-block offset and add byte-level HFile writer tests #19083
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
967995a
399874a
51b001f
03860b0
79aa0ab
0692a84
6b9f7e6
b3c9359
30141aa
f07170f
f4521b3
c799039
85266d8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |
| import org.apache.hudi.io.util.IOUtils; | ||
|
|
||
| import com.google.protobuf.ByteString; | ||
| import com.google.protobuf.CodedOutputStream; | ||
|
|
||
| import java.io.ByteArrayInputStream; | ||
| import java.io.ByteArrayOutputStream; | ||
|
|
@@ -103,11 +104,31 @@ public ByteBuffer getUncompressedBlockDataToWrite() throws IOException { | |
| outputStream.write(PB_MAGIC); | ||
| byte[] payload = builder.build().toByteArray(); | ||
| try { | ||
| outputStream.write(getVariableLengthEncodedBytes(payload.length)); | ||
| outputStream.write(getProtobufVarIntBytes(payload.length)); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This catch is unreachable (ByteArrayOutputStream never throws), drops the cause if it ever did, and the message misdescribes a write as a calculation. The enclosing method already declares |
||
| } catch (IOException e) { | ||
| throw new RuntimeException("Failed to calculate File Info variable length"); | ||
| } | ||
| outputStream.write(payload); | ||
| return ByteBuffer.wrap(outputStream.toByteArray()); | ||
| } | ||
|
|
||
| /** | ||
| * Encodes an integer as a Protobuf varint (base-128, little-endian with MSB continuation bits, | ||
| * via {@link CodedOutputStream#writeUInt32NoTag}): the length framing Protobuf's | ||
| * {@code writeDelimitedTo} produces. It is used for the file info and trailer length prefixes, | ||
| * which the reader decodes with {@code parseDelimitedFrom}. This is NOT interchangeable with the | ||
| * Hadoop {@code WritableUtils} VInt used by the block index | ||
| * ({@link HFileIndexBlock#getVarIntBytes(int)}): the two diverge for values >= 128. | ||
| * | ||
| * @param value the integer value to encode. | ||
| * @return the Protobuf varint encoding. | ||
| * @throws IOException upon error. | ||
| */ | ||
| static byte[] getProtobufVarIntBytes(int value) throws IOException { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This helper frames two unrelated sections -- file info AND the trailer ( |
||
| ByteArrayOutputStream varIntBuffer = new ByteArrayOutputStream(); | ||
| CodedOutputStream varIntOutput = CodedOutputStream.newInstance(varIntBuffer); | ||
| varIntOutput.writeUInt32NoTag(value); | ||
| varIntOutput.flush(); | ||
| return varIntBuffer.toByteArray(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,8 +31,8 @@ | |
| import java.util.Map; | ||
|
|
||
| import static org.apache.hudi.io.hfile.DataSize.SIZEOF_INT16; | ||
| import static org.apache.hudi.io.hfile.HFileBlock.getVariableLengthEncodedBytes; | ||
| import static org.apache.hudi.io.hfile.HFileBlockType.TRAILER; | ||
| import static org.apache.hudi.io.hfile.HFileFileInfoBlock.getProtobufVarIntBytes; | ||
| import static org.apache.hudi.io.hfile.HFileInfo.KEY_VALUE_VERSION_WITH_MVCC_TS; | ||
| import static org.apache.hudi.io.hfile.HFileInfo.LAST_KEY; | ||
| import static org.apache.hudi.io.hfile.HFileInfo.MAX_MVCC_TS_KEY; | ||
|
|
@@ -144,8 +144,8 @@ private void flushCurrentDataBlock() throws IOException { | |
| // 3. Create an index entry. | ||
| rootIndexBlock.add( | ||
| currentDataBlock.getFirstKey(), lastDataBlockOffset, blockBuffer.limit()); | ||
| // 4. Create a new data block. | ||
| currentDataBlock = HFileDataBlock.createDataBlockToWrite(context, currentOffset); | ||
| // 4. Create a new data block whose previous-block offset points at the block just flushed. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Worth a one-line note (here or in hfile_format.md) that only DATA blocks chain prev-offsets: root/meta index, file info, and meta blocks still write -1, while HBase's writer chains every block type. Benign today -- HBase's reader only consults prev-offset for data blocks in seekBefore -- but the intentional divergence is currently undocumented. |
||
| currentDataBlock = HFileDataBlock.createDataBlockToWrite(context, lastDataBlockOffset); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The fix is correct, but the offset is still threaded through a constructor arg at two call sites -- the exact shape that produced the bug. |
||
| } | ||
|
|
||
| // NOTE that: reader assumes that every meta info piece | ||
|
|
@@ -200,7 +200,7 @@ private void writeTrailer() throws IOException { | |
| ByteBuffer trailer = ByteBuffer.allocate(TRAILER_SIZE); | ||
| trailer.limit(TRAILER_SIZE); | ||
| trailer.put(TRAILER.getMagic()); | ||
| trailer.put(getVariableLengthEncodedBytes(trailerProto.getSerializedSize())); | ||
| trailer.put(getProtobufVarIntBytes(trailerProto.getSerializedSize())); | ||
| trailer.put(trailerProto.toByteArray()); | ||
| // Force trailer to have fixed length. | ||
| trailer.position(TRAILER_SIZE - 1); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the byte-identical-for-0..127 / diverge-at->=128 rule now appears four times (here, both encoder javadocs, the test javadoc). Suggest keeping this doc as the canonical statement and reducing the javadocs to one-line pointers so the copies can't drift.