This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-3461-bdee10e629f3d2b68336b2dc9a5a7a6fd2ae7e3b in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git
commit 582b9e103513f21094f61cd1f09fdbf39dccf13e Author: Giladi <[email protected]> AuthorDate: Thu Oct 15 05:44:23 2026 +0000 feat(delete-vector): make the delete_vector module public (#3461) An engine that uses the crate for metadata but reads Parquet with a reader of its own cannot go through ArrowReader, and so far had to reimplement the deletion-vector-v1 decoding to apply deletion vectors. Expose the module, the way puffin already is, with the docs deny(missing_docs) then requires, an is_empty next to len, and the public API snapshot regenerated. Co-authored-by: Claude <[email protected]> --- crates/iceberg/public-api.txt | 22 ++++++++++++++++++++++ crates/iceberg/src/delete_vector.rs | 20 +++++++++++++++++++- crates/iceberg/src/lib.rs | 2 +- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/crates/iceberg/public-api.txt b/crates/iceberg/public-api.txt index 466614757..ff417ddb5 100644 --- a/crates/iceberg/public-api.txt +++ b/crates/iceberg/public-api.txt @@ -229,6 +229,28 @@ impl core::marker::Copy for iceberg::cow_rewrite::CowRewriteStats impl core::marker::StructuralPartialEq for iceberg::cow_rewrite::CowRewriteStats pub trait iceberg::cow_rewrite::CowBatchRewriter: core::marker::Send + core::marker::Sync pub fn iceberg::cow_rewrite::CowBatchRewriter::rewrite_batch(&self, batch: arrow_array::record_batch::RecordBatch) -> iceberg::Result<iceberg::cow_rewrite::CowBatchRewrite> +pub mod iceberg::delete_vector +pub struct iceberg::delete_vector::DeleteVector +impl iceberg::delete_vector::DeleteVector +pub fn iceberg::delete_vector::DeleteVector::deserialize(blob: &[u8]) -> iceberg::Result<Self> +pub fn iceberg::delete_vector::DeleteVector::insert(&mut self, pos: u64) -> bool +pub fn iceberg::delete_vector::DeleteVector::insert_positions(&mut self, positions: &[u64]) -> iceberg::Result<usize> +pub fn iceberg::delete_vector::DeleteVector::is_empty(&self) -> bool +pub fn iceberg::delete_vector::DeleteVector::iter(&self) -> iceberg::delete_vector::DeleteVectorIterator<'_> +pub fn iceberg::delete_vector::DeleteVector::len(&self) -> u64 +pub fn iceberg::delete_vector::DeleteVector::new(roaring_treemap: roaring::treemap::RoaringTreemap) -> iceberg::delete_vector::DeleteVector +impl core::default::Default for iceberg::delete_vector::DeleteVector +pub fn iceberg::delete_vector::DeleteVector::default() -> iceberg::delete_vector::DeleteVector +impl core::fmt::Debug for iceberg::delete_vector::DeleteVector +pub fn iceberg::delete_vector::DeleteVector::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result +impl core::ops::bit::BitOrAssign for iceberg::delete_vector::DeleteVector +pub fn iceberg::delete_vector::DeleteVector::bitor_assign(&mut self, other: Self) +pub struct iceberg::delete_vector::DeleteVectorIterator<'a> +impl iceberg::delete_vector::DeleteVectorIterator<'_> +pub fn iceberg::delete_vector::DeleteVectorIterator<'_>::advance_to(&mut self, pos: u64) +impl core::iter::traits::iterator::Iterator for iceberg::delete_vector::DeleteVectorIterator<'_> +pub type iceberg::delete_vector::DeleteVectorIterator<'_>::Item = u64 +pub fn iceberg::delete_vector::DeleteVectorIterator<'_>::next(&mut self) -> core::option::Option<Self::Item> pub mod iceberg::encryption pub mod iceberg::encryption::kms pub struct iceberg::encryption::kms::GeneratedKey diff --git a/crates/iceberg/src/delete_vector.rs b/crates/iceberg/src/delete_vector.rs index 9b2d48d91..dc76eeadb 100644 --- a/crates/iceberg/src/delete_vector.rs +++ b/crates/iceberg/src/delete_vector.rs @@ -15,6 +15,11 @@ // specific language governing permissions and limitations // under the License. +//! Deletion vectors: the deleted row positions of one data file, as a Puffin +//! `deletion-vector-v1` blob decodes to. Public so an engine that reads +//! Parquet with a reader of its own can still decode the vectors Iceberg +//! writes. + use std::ops::BitOrAssign; use bytes::Buf; @@ -33,24 +38,28 @@ const DV_MAGIC_BYTES: usize = 4; const DV_CRC_BYTES: usize = 4; const DV_MIN_BLOB_BYTES: usize = DV_LENGTH_PREFIX_BYTES + DV_MAGIC_BYTES + DV_CRC_BYTES; +/// The deleted row positions of one data file: a set of 64-bit positions, +/// kept as a [`RoaringTreemap`]. #[derive(Debug, Default)] pub struct DeleteVector { inner: RoaringTreemap, } impl DeleteVector { - #[allow(unused)] + /// Wraps `roaring_treemap`, whose members are the deleted positions. pub fn new(roaring_treemap: RoaringTreemap) -> DeleteVector { DeleteVector { inner: roaring_treemap, } } + /// Iterates the deleted positions in ascending order. pub fn iter(&self) -> DeleteVectorIterator<'_> { let outer = self.inner.bitmaps(); DeleteVectorIterator { outer, inner: None } } + /// Marks `pos` as deleted, returning whether it was not already. pub fn insert(&mut self, pos: u64) -> bool { self.inner.insert(pos) } @@ -73,10 +82,16 @@ impl DeleteVector { Ok(positions.len()) } + /// How many positions are deleted. pub fn len(&self) -> u64 { self.inner.len() } + /// Whether no position is deleted. + pub fn is_empty(&self) -> bool { + self.inner.is_empty() + } + /// Parses a `deletion-vector-v1` Puffin blob into a `DeleteVector`. /// /// The layout, defined by the Iceberg Puffin spec and matching Iceberg-Java's @@ -216,6 +231,7 @@ fn decode_roaring_directory(mut reader: &[u8]) -> Result<RoaringTreemap> { // There is a PR open on roaring to add this (https://github.com/RoaringBitmap/roaring-rs/pull/314) // and if that gets merged then we can simplify `DeleteVectorIterator` here, refactoring `advance_to` // to just a wrapper around the underlying iterator's method. +/// Iterates the deleted positions of a [`DeleteVector`] in ascending order. pub struct DeleteVectorIterator<'a> { // NB: `BitMapIter` was only exposed publicly in https://github.com/RoaringBitmap/roaring-rs/pull/316 // which is not yet released. As a consequence our Cargo.toml temporarily uses a git reference for @@ -253,6 +269,8 @@ impl Iterator for DeleteVectorIterator<'_> { } impl DeleteVectorIterator<'_> { + /// Skips the positions below `pos`, so the next one yielded is the first + /// at or after it. Does nothing before the first position is yielded. pub fn advance_to(&mut self, pos: u64) { let hi = (pos >> 32) as u32; let lo = pos as u32; diff --git a/crates/iceberg/src/lib.rs b/crates/iceberg/src/lib.rs index 9733fac32..72c2acd3e 100644 --- a/crates/iceberg/src/lib.rs +++ b/crates/iceberg/src/lib.rs @@ -104,7 +104,7 @@ pub mod encryption; mod test_utils; pub mod writer; -mod delete_vector; +pub mod delete_vector; pub mod metadata_columns; pub mod partitioning; pub mod puffin;
