fix(puffin): implement LZ4 footer compression - #2921
Open
1fanwang wants to merge 2 commits into
Open
Conversation
The PuffinWriter exposed a `compress_footer: bool` flag that set the
FooterPayloadCompressed bit in the file footer and recorded LZ4 as the
codec, but `CompressionCodec::Lz4.compress` returned `FeatureUnsupported`,
so calling `PuffinWriter::new(_, _, true)` always failed at close time:
thread '...' panicked at crates/iceberg/src/puffin/writer.rs:350:
called `Result::unwrap()` on an `Err` value:
FeatureUnsupported => LZ4 compression is not supported currently
The reader side had the same hole: a Puffin file written by another
implementation with FooterPayloadCompressed=1 was unreadable.
Wire LZ4 through `CompressionCodec::{compress,decompress}` using
`lz4_flex`'s frame encoder/decoder, matching the Puffin spec requirement
of "LZ4 single compression frame with content size present" by setting
`FrameInfo::content_size(Some(len))` on the encoder. The reader path is
symmetric — `FrameDecoder::read_to_end` consumes the same frame.
Tests:
- `test_compress_empty_footer_lz4_succeeds` — direct reproducer from
the issue (close() with no blobs and compress_footer=true).
- `test_compress_footer_lz4_round_trips` — full encode/decode loop with
one blob and file properties.
- `test_write_lz4_compressed_metric_data` — was previously asserting the
error string; now asserts round-trip of two blobs.
- `test_lz4_compressed_footer_is_decoded` (metadata) — verifies the
reader honors the FooterPayloadCompressed flag.
- `test_compression_codec_lz4_roundtrip` — round-trip on empty + mixed
payloads, and asserts the frame begins with the LZ4 magic 0x184D2204.
Closes apache#2419.
Signed-off-by: 1fanwang <1fannnw@gmail.com>
- generalize the multi-codec compress test to cover empty and less-compressible payloads for every codec; split the LZ4 frame-magic-number assertion into its own test - rename the Snappy case to test_snappy_compression_is_unsupported - fix the Puffin footer test docs: pre-fix, close() failed with FeatureUnsupported rather than writing raw JSON, and these are feature tests, not regressions; drop issue-number references Signed-off-by: 1fanwang <1fannnw@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Which issue does this PR close?
Supersedes #2438, which the stale bot closed after it sat in the review queue. Same change, rebased onto current
main, with @xanderbailey's review feedback from that PR already folded in. GitHub refuses to reopen the old PR, hence the new one.What changes are included in this PR?
The Puffin spec allows a footer payload to be uncompressed or LZ4-compressed.
PuffinWriteralready exposes acompress_footerflag that records LZ4 as the footer codec, andvalidate_puffin_compressionalready acceptsLz4as a valid Puffin codec — but the codec itself was never implemented, soclose()withcompress_footer = truefailed:The reader had the symmetric gap: a Puffin file carrying an LZ4-compressed footer could not be read back.
This implements the codec with
lz4_flexin the frame format — a single frame with content size present, as the spec requires.lz4_flexwas already in the lock file as a transitiveparquetdependency, so no new crate enters the tree.Are these changes tested?
Yes. Unit tests cover the codec and the Puffin writer/reader:
close()withcompress_footer = true— now succeeds, and footer metadata plus blobs round-trip through an LZ4 footer.FooterPayloadCompressedflag and decodes an LZ4-compressed footer.The tests drive the real write/read path, not the codec in isolation: reverting the two
Lz4arms incompression.rsmakes all four fail atclose()with the error from the issue.Before the fix —
Lz4arms revertedAfter the fix —
cargo test -p iceberg --lib -- compression:: puffin::cargo clippy -p iceberg --all-targets --all-features -- -D warnings,cargo fmt --checkandcargo macheteare clean.