Skip to content

feat(scan): [3/N] read and apply V3 deletion vectors - #3035

Open
mbutrovich wants to merge 18 commits into
apache:mainfrom
mbutrovich:dv-apply
Open

feat(scan): [3/N] read and apply V3 deletion vectors#3035
mbutrovich wants to merge 18 commits into
apache:mainfrom
mbutrovich:dv-apply

Conversation

@mbutrovich

@mbutrovich mbutrovich commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

Which issue does this PR close?

What changes are included in this PR?

Task 3 of the deletion-vector read epic: reading and applying V3 deletion vectors during a scan. Follows #2868, now merged, so this is based on main.

  • CachingDeleteFileLoader reads a deletion vector's deletion-vector-v1 blob directly from its Puffin file by byte range (content_offset / content_size_in_bytes), decrypting first via EncryptedInputFile when the entry carries key metadata.
  • After decoding, the blob's cardinality is checked against the manifest entry's record_count, matching the check Iceberg-Java does in BitmapPositionDeleteIndex.deserializeBitmap. A mismatch is a DataInvalid error, not a silent wrong result.
  • DeleteFileIndex indexes deletion vectors by referenced_data_file and applies them ahead of position delete files, since a DV supersedes any position deletes for the same data file per spec.
  • FileScanTaskDeleteFile gains a file_format field, populated from the manifest entry. Both the index and the loader now identify a deletion vector as a PositionDeletes entry stored as Puffin, rather than by the presence of content_offset, per @CTTY's review feedback on feat(scan): [2/N] carry deletion-vector coordinates on FileScanTaskDeleteFile #2868.
  • Spec invariants that were previously mishandled silently are now errors:
    • a deletion vector missing referenced_data_file, content_offset, content_size_in_bytes, or record_count, all of which the spec requires
    • two deletion vectors referencing the same data file, where the spec allows at most one per data file per snapshot
    • a deletion vector whose partition or sequence number disagrees with the data file it references
  • DeleteVector::deserialize (from feat(delete-vector): [1/N] decode deletion-vector-v1 puffin blobs #2866) is wired in, and its #[allow(dead_code)] removed.

The data file read path is unchanged outside of deletion vectors, as is existing position delete and equality delete handling.

Are these changes tested?

Yes.

  • Unit tests in delete_file_index.rs: DV supersedes partition-scoped and path-scoped position deletes, DV coexists with equality deletes, and rejection of a DV that is missing referenced_data_file or its Puffin coordinates, duplicated for one data file, or carrying a mismatched partition or stale sequence number.
  • Unit tests in caching_delete_file_loader.rs: reading and applying a DV, reading an encrypted DV, rejecting a cardinality mismatch, and the coordinate and cardinality validation helpers against each missing or negative field.
  • End-to-end tests in positional_deletes.rs reading a Parquet data file with a DV applied through ArrowReader, including the cardinality mismatch failure path through the full read.

AI Disclosure

Developed with the help of Claude Code, but I understand and support these changes.

@mbutrovich
mbutrovich marked this pull request as ready for review August 27, 2026 15:01
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.

[EPIC] Deletion vector read support (deletion-vector-v1 Puffin blobs)

1 participant