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

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new 6263df2ca2 Fix AvgGroupsAccumulator::size() self-overcount (#25117)
6263df2ca2 is described below

commit 6263df2ca2a7dac79124814288880ff76499c5ad
Author: kosiew <[email protected]>
AuthorDate: Fri Sep 11 11:20:34 2026 +0000

    Fix AvgGroupsAccumulator::size() self-overcount (#25117)
    
    ## Which issue does this PR close?
    
    * Part of #23393
    
    ## Rationale for this change
    
    `GroupsAccumulator::size()` is expected to report retained state owned
    by the accumulator without counting the accumulator object itself.
    
    `AvgGroupsAccumulator::size()` was also charging for the inline `Vec`
    descriptors for `counts` and `sums`, even though those descriptors are
    part of the accumulator object rather than separately retained heap
    state. This caused AVG group accumulators to over-report their memory
    usage.
    
    ## What changes are included in this PR?
    
    This PR:
    
    * Removes the `size_of::<Vec<_>>()` charges for the inline `counts` and
    `sums` vector descriptors from `AvgGroupsAccumulator::size()`.
    * Keeps accounting for the heap capacities of `counts` and `sums`.
    * Keeps accounting for retained null-tracking state through
    `null_state.size()`.
    * Adds coverage verifying that the sum buffer is accounted for using the
    actual sum native type, including the `Decimal128` input / `Decimal256`
    sum case.
    
    ## Are these changes tested?
    
    Yes. This PR adds the following focused unit tests in
    `datafusion/functions-aggregate/src/average.rs`:
    
    * `avg_groups_size_excludes_accumulator_storage`
    * `avg_groups_size_uses_sum_native_type`
    
    The first verifies that an empty accumulator reports zero retained state
    and that, after group state is allocated, `size()` equals the capacities
    of `counts` and `sums` plus `null_state.size()`.
    
    The second verifies that memory accounting uses the sum accumulator's
    native type by checking a `Decimal128` AVG whose sum state uses
    `Decimal256`.
    
    No test execution results are shown in the patch.
    
    ## Are there any user-facing changes?
    
    No direct user-facing API or query-result changes are included.
    
    This changes the memory-size accounting reported by
    `AvgGroupsAccumulator` so that it follows the
    `GroupsAccumulator::size()` contract and no longer includes inline
    vector descriptors.
    
    ## LLM-generated code disclosure
    
    This PR includes LLM-generated code and comments. All LLM-generated
    content has been manually reviewed.
---
 datafusion/functions-aggregate/src/average.rs | 59 ++++++++++++++++++++++++---
 1 file changed, 53 insertions(+), 6 deletions(-)

diff --git a/datafusion/functions-aggregate/src/average.rs 
b/datafusion/functions-aggregate/src/average.rs
index 8ce893c17d..f59ac816a9 100644
--- a/datafusion/functions-aggregate/src/average.rs
+++ b/datafusion/functions-aggregate/src/average.rs
@@ -1246,12 +1246,9 @@ where
     fn size(&self) -> usize {
         // Heap buffers
         self.counts.capacity() * size_of::<u64>()
-        + self.sums.capacity() * size_of::<S::Native>()
-        // Vec struct overhead (ptr, len, cap) for each field
-        + size_of::<Vec<u64>>()
-        + size_of::<Vec<S::Native>>()
-        // Null tracking buffers
-        + self.null_state.size()
+            + self.sums.capacity() * size_of::<S::Native>()
+            // Null tracking buffers
+            + self.null_state.size()
     }
 }
 
@@ -1643,6 +1640,56 @@ mod tests {
         Ok(())
     }
 
+    #[test]
+    fn avg_groups_size_excludes_accumulator_storage() -> Result<()> {
+        let mut accumulator = AvgGroupsAccumulator::<Float64Type, _>::new(
+            &DataType::Float64,
+            &DataType::Float64,
+            |sum, count| Ok(sum / count as f64),
+        );
+
+        assert_eq!(accumulator.size(), 0);
+
+        let values = Arc::new(Float64Array::from(vec![Some(2.0), None, 
Some(4.0)]));
+        accumulator.update_batch(&[values], &[0, 1, 2], None, 3)?;
+
+        let expected_size = accumulator.counts.capacity() * size_of::<u64>()
+            + accumulator.sums.capacity() * size_of::<f64>()
+            + accumulator.null_state.size();
+        assert_eq!(accumulator.size(), expected_size);
+        assert!(accumulator.size() > 0);
+
+        Ok(())
+    }
+
+    #[test]
+    fn avg_groups_size_uses_sum_native_type() -> Result<()> {
+        let input_type = DataType::Decimal128(26, 0);
+        let sum_type = avg_sum_data_type(&input_type);
+        let return_type = 
Avg::new().return_type(std::slice::from_ref(&input_type))?;
+        assert_eq!(sum_type, DataType::Decimal256(76, 0));
+        assert_eq!(return_type, DataType::Decimal128(30, 4));
+        let mut accumulator = AvgGroupsAccumulator::<
+            Decimal128Type,
+            _,
+            Decimal256Type,
+            Decimal128Type,
+        >::new(&sum_type, &return_type, |_, _| Ok(0_i128));
+
+        let values = Arc::new(
+            Decimal128Array::from(vec![Some(2), None, Some(4)])
+                .with_precision_and_scale(26, 0)?,
+        );
+        accumulator.update_batch(&[values], &[0, 1, 2], None, 3)?;
+
+        let expected_size = accumulator.counts.capacity() * size_of::<u64>()
+            + accumulator.sums.capacity() * size_of::<i256>()
+            + accumulator.null_state.size();
+        assert_eq!(accumulator.size(), expected_size);
+
+        Ok(())
+    }
+
     #[test]
     fn average_groups_preserving_reads() -> Result<()> {
         let mut accumulator = AvgGroupsAccumulator::<Float64Type, _>::new(


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to