Repository navigation
Conversation
2fc0bff to
86dfdfb
Compare
There was a problem hiding this comment.
Pull request overview
Implements end-to-end LZ4 support needed for Puffin footer compression/decompression so PuffinWriter can successfully close when compress_footer=true, and FileMetadata reading can open Puffin files with an LZ4-compressed footer per the Puffin spec.
Changes:
- Implement LZ4 frame compression/decompression via
lz4_flexinCompressionCodec. - Update Puffin writer/reader tests to validate LZ4-compressed blobs and LZ4-compressed footers round-trip.
- Add
lz4_flexas a direct workspace dependency (and in theicebergcrate) to make the codec implementation explicit.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| crates/iceberg/src/puffin/writer.rs | Updates tests to expect LZ4 compression to work and adds coverage for compressed footers. |
| crates/iceberg/src/puffin/metadata.rs | Updates footer-metadata test to ensure LZ4-compressed footer payloads decode successfully. |
| crates/iceberg/src/compression.rs | Implements LZ4 frame compress/decompress and expands codec tests (including frame magic assertion). |
| crates/iceberg/Cargo.toml | Adds lz4_flex as a direct dependency for the iceberg crate. |
| Cargo.toml | Adds lz4_flex to workspace dependencies to share the version across crates. |
| Cargo.lock | Records lz4_flex as a direct dependency of iceberg. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
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>
Signed-off-by: 1fanwang <1fannnw@gmail.com>
Generated-by: GitHub Copilot CLI (GPT-5.6 Sol) Signed-off-by: 1fanwang <1fannnw@gmail.com>
The updated base also resolves lz4_flex 0.14.0. Qualify Iceberg's direct dependency so Cargo accepts the merged lockfile without rewriting it. Generated-by: GitHub Copilot CLI (GPT-5.6 Sol) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Stefan Wang <1fannnw@gmail.com>
56dd67c to
cff5734
Compare
JeonDaehong
left a comment
There was a problem hiding this comment.
Checked the frames against the reference liblz4 (1.9.4, via python-lz4) both ways: frames from liblz4 (incl. multi-block and block-checksum variants) decode here, and frames written here decode with liblz4 with the content size set. LGTM. A few small things:
- Parquet uses lz4_flex 0.14.0, so
lz4_flex = "0.14"would share its copy (0.13 comes from another dep). It builds and the tests pass with 0.14 unchanged. log = "0.4.28"in the workspace Cargo.toml isn't used anywhere.- Java can't read LZ4 footers yet (
PuffinFormatcompress/decompress are still TODO), so it may be worth a note oncompress_footerthat such files aren't readable by iceberg-java today.
Signed-off-by: 1fanwang <1fannnw@gmail.com>
@JeonDaehong done in 927c8aa. All three suggestions are addressed. |
|
Thanks @1fanwang, all three look good: |
Which issue does this PR close?
Fixes #2419
Supersedes #2438.
What changes are included in this PR?
Writing a Puffin file with footer compression enabled fails when the writer closes:
Writers can now finish these files, and readers can open them. The encoding follows the Puffin spec.
Footer compression stays opt-in because the Java reader cannot decode these footers yet.
Are these changes tested?
Testing Done
Rust 1.97.0-nightly on macOS, using the local filesystem and cached dependencies.
The same standalone program writes real Puffin files, closes them, and reads back their metadata and blobs through the public API. It starts with an empty file with footer compression enabled.
Save the manifests and shared program below at their labelled paths, then run from the checkout root. The unchanged source for the first run is 000e791.
mkdir -p ../iceberg-main-snapshot git archive 000e791d5229d9d136cda2b41fa0d7563fa58e1e | tar -x -C ../iceberg-main-snapshotWithout the fix:
With the fix:
The passing cases cover empty files and uncompressed, LZ4, and Zstd blobs, each with footer compression enabled and disabled. Metadata and blob contents are compared after read-back.
Reproducer source: evidence/puffin-footer-repro/Cargo.toml
Reproducer source: evidence/puffin-footer-repro-main/Cargo.toml
Reproducer source: evidence/puffin-footer-repro/src/main.rs
AI Disclosure
AI disclosure: GitHub Copilot CLI wrote the implementation and tests; GitHub Copilot CLI (GPT-6.1 Sol) handled this update. No Java runtime interoperability run was performed.