This is an automated email from the ASF dual-hosted git repository.

Jefffrey pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 4a1c655c75 fix(arrow-data): account for view payload buffers in slice 
memory size (#10519)
4a1c655c75 is described below

commit 4a1c655c75d86ea5c9064e01985d2cf075150e9e
Author: wterrr <[email protected]>
AuthorDate: Tue Aug 4 06:38:58 2026 +0700

    fix(arrow-data): account for view payload buffers in slice memory size 
(#10519)
    
    Closes #8230.
    
    ## Rationale
    
    `ArrayData::get_slice_memory_size` accounts for the fixed-width view
    buffer of `Utf8View` and `BinaryView` arrays, but previously omitted
    their variadic payload buffers.
    
    Slicing these arrays retains all payload buffers unchanged, so this
    could substantially underestimate the memory retained by the slice.
    
    ## Changes
    
    - Include the capacity of all trailing variadic payload buffers in
    `get_slice_memory_size`
    - Document the retained-buffer accounting behavior for variadic layouts
    - Add regression coverage for both `Utf8View` and `BinaryView`
    - Cover inline-only values, multiple payload buffers, and payload
    capacity greater than logical length
    
    ## Testing
    
    - `cargo test -p arrow-data --lib test_slice_memory_size`
    - `cargo test -p arrow-data --all-features`
    - `cargo clippy -p arrow-data --all-targets --all-features -- -D
    warnings`
    - `cargo fmt --all -- --check`
    
    All affected crate tests, doc tests, formatting, and focused Clippy
    checks pass.
    
    ## AI assistance
    
    Claude was used to help investigate the issue, draft the implementation
    and regression tests, and review the change. I reviewed the final change
    and take responsibility for the submitted code.
---
 arrow-data/src/data.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 61 insertions(+), 1 deletion(-)

diff --git a/arrow-data/src/data.rs b/arrow-data/src/data.rs
index 2c9dfe6ddb..465c96352b 100644
--- a/arrow-data/src/data.rs
+++ b/arrow-data/src/data.rs
@@ -516,7 +516,9 @@ impl ArrayData {
     ///
     /// This is approximately the number of bytes if a new
     /// [`ArrayData`] was formed by creating new [`Buffer`]s with
-    /// exactly the data needed.
+    /// exactly the data needed. For variadic layouts, this includes the full
+    /// capacity of every variadic buffer retained by a zero-copy slice, 
without
+    /// inspecting which buffers or ranges are referenced by the slice.
     ///
     /// For example, a [`DataType::Int64`] with `100` elements,
     /// [`Self::get_slice_memory_size`] would return `100 * 8 = 800`. If
@@ -578,6 +580,13 @@ impl ArrayData {
             }
         }
 
+        if layout.variadic {
+            // Slicing view arrays retains all variadic data buffers unchanged.
+            for buffer in self.buffers.iter().skip(layout.buffers.len()) {
+                result += buffer.capacity();
+            }
+        }
+
         if self.nulls().is_some() {
             result += bit_util::ceil(self.len, 8);
         }
@@ -2344,6 +2353,7 @@ pub(crate) fn get_fixed_size_binary_width(data_type: 
&DataType) -> usize {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use crate::ByteView;
     use arrow_buffer::{OffsetBuffer, ScalarBuffer};
     use arrow_schema::{Field, Fields};
 
@@ -2628,6 +2638,56 @@ mod tests {
         assert!(!string_data_slice.ptr_eq(&string_data))
     }
 
+    #[test]
+    fn test_slice_memory_size_view_payload_buffers() {
+        for data_type in [DataType::Utf8View, DataType::BinaryView] {
+            let inline_only = ArrayData::builder(data_type.clone())
+                .len(2)
+                .add_buffer(Buffer::from_vec(vec![0_u128; 2]))
+                .build()
+                .unwrap();
+            assert_eq!(
+                inline_only.get_slice_memory_size().unwrap(),
+                2 * mem::size_of::<u128>()
+            );
+
+            let mut first_payload = Vec::with_capacity(32);
+            first_payload.extend_from_slice(b"first payload");
+            let first_view =
+                ByteView::new(first_payload.len().try_into().unwrap(), 
&first_payload[..4])
+                    .as_u128();
+            let first_payload = Buffer::from_vec(first_payload);
+            assert!(first_payload.capacity() > first_payload.len());
+            let first_payload_capacity = first_payload.capacity();
+
+            let mut second_payload = Vec::with_capacity(64);
+            second_payload.extend_from_slice(b"second payload");
+            let second_view = ByteView::new(
+                second_payload.len().try_into().unwrap(),
+                &second_payload[..4],
+            )
+            .with_buffer_index(1)
+            .as_u128();
+            let second_payload = Buffer::from_vec(second_payload);
+            assert!(second_payload.capacity() > second_payload.len());
+            let second_payload_capacity = second_payload.capacity();
+
+            let data = ArrayData::builder(data_type)
+                .len(3)
+                .add_buffer(Buffer::from_vec(vec![first_view, 0_u128, 
second_view]))
+                .add_buffer(first_payload)
+                .add_buffer(second_payload)
+                .build()
+                .unwrap();
+            let sliced = data.slice(1, 1);
+
+            assert_eq!(
+                sliced.get_slice_memory_size().unwrap(),
+                mem::size_of::<u128>() + first_payload_capacity + 
second_payload_capacity
+            );
+        }
+    }
+
     #[test]
     fn test_slice_memory_size_utf8_offset_buffer_len_plus_one() {
         // 2-element array ["hello", "world"]: array len = 2, 10 bytes

Reply via email to