Skip to content

fix(puffin): implement LZ4 footer compression - #2921

Open
1fanwang wants to merge 4 commits into
apache:mainfrom
1fanwang:fix/puffin-footer-lz4-compression
Open

fix(puffin): implement LZ4 footer compression#2921
1fanwang wants to merge 4 commits into
apache:mainfrom
1fanwang:fix/puffin-footer-lz4-compression

Conversation

@1fanwang

@1fanwang 1fanwang commented Jul 29, 2026

Copy link
Copy Markdown

Which issue does this PR close?

Fixes #2419

Supersedes #2438, which was closed as stale before review finished.

What changes are included in this PR?

PuffinWriter exposes footer compression, but closing a writer with it enabled fails with:

FeatureUnsupported => LZ4 compression is not supported currently

The reader also cannot open a Puffin file with an LZ4-compressed footer. LZ4 now uses a single frame with content size in its header, as required by the Puffin spec. Writers close successfully, and readers open the compressed footer. The crate was already present transitively through Parquet.

Are these changes tested?

The tests drive the real Puffin writer and reader for empty and populated compressed footers.

Raw before/after output
$ git checkout upstream/main -- crates/iceberg/src/compression.rs
$ cargo test -p iceberg --lib -- compression:: puffin::
test result: FAILED. 42 passed; 6 failed; 0 ignored; 0 measured
FeatureUnsupported => LZ4 compression is not supported currently

$ git checkout HEAD -- crates/iceberg/src/compression.rs
$ cargo test -p iceberg --lib -- compression:: puffin::
test result: ok. 48 passed; 0 failed; 0 ignored; 0 measured; 1529 filtered out

Hygiene: cargo fmt --check, Clippy with all targets and features, and cargo machete pass.

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>
@1fanwang
1fanwang force-pushed the fix/puffin-footer-lz4-compression branch from 2fc0bff to 86dfdfb Compare August 24, 2026 06:25
Copilot AI lite review requested due to automatic review settings August 24, 2026 06:25

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_flex in CompressionCodec.
  • Update Puffin writer/reader tests to validate LZ4-compressed blobs and LZ4-compressed footers round-trip.
  • Add lz4_flex as a direct workspace dependency (and in the iceberg crate) 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.

Comment on lines +327 to +331
let input_file = output_file.to_input_file();
let metadata = read_file_metadata(&input_file).await.unwrap();
assert_eq!(metadata.properties, file_properties());
assert_eq!(metadata.blobs.len(), 1);
assert_eq!(read_all_blobs_from_puffin_file(input_file).await, vec![
Generated-by: GitHub Copilot CLI (GPT-5.6 Sol)
Signed-off-by: 1fanwang <1fannnw@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG: failed to write compressed puffin footer

2 participants