Skip to content

Commit 48078ec

Browse files
committed
Encapsulate primitive group state
1 parent d1f96f1 commit 48078ec

1 file changed

Lines changed: 159 additions & 124 deletions

File tree

  • datafusion/functions-aggregate-common/src/aggregate/groups_accumulator

datafusion/functions-aggregate-common/src/aggregate/groups_accumulator/prim_op.rs

Lines changed: 159 additions & 124 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// under the License.
1717

1818
use std::fmt::Debug;
19+
use std::marker::PhantomData;
1920
use std::mem::size_of;
2021
use std::sync::Arc;
2122

@@ -28,10 +29,10 @@ use datafusion_common::{DataFusionError, Result, internal_datafusion_err};
2829
use datafusion_expr_common::groups_accumulator::{EmitTo, GroupsAccumulator};
2930

3031
use crate::aggregate::groups_accumulator::accumulate::{
31-
BlockedNullState, FlatNullState, NullState, SeenValueStore,
32+
BlockedNullState, BooleanBlock, FlatNullState, NullState, SeenValueStore,
3233
};
3334
use crate::aggregate::groups_accumulator::block_store::{
34-
BlockStore, FlatBlockStore, VecValues, VecValuesBlockStore,
35+
FlatBlockStore, VecValues, VecValuesBlockStore,
3536
};
3637
use crate::aggregate::groups_accumulator::blocks::Blocks;
3738
use crate::aggregate::groups_accumulator::group_index_operations::{
@@ -51,10 +52,11 @@ use crate::aggregate::groups_accumulator::group_index_operations::{
5152
pub struct PrimitiveGroupsAccumulator<T, F>
5253
where
5354
T: ArrowPrimitiveType + Send,
55+
T::Native: Debug + Send,
5456
F: Fn(&mut T::Native, T::Native) + Send + Sync + 'static,
5557
{
5658
/// Values and null state per group, stored according to the current group mode.
57-
state: PrimitiveGroupsState<T::Native>,
59+
state: PrimitiveGroupsStateAdapter<T::Native>,
5860

5961
/// The output type (needed for Decimal precision and scale)
6062
data_type: DataType,
@@ -66,29 +68,15 @@ where
6668
prim_fn: F,
6769
}
6870

69-
#[derive(Debug)]
70-
enum PrimitiveGroupsState<V: Clone + Debug> {
71-
Flat {
72-
values: FlatBlockStore<VecValues<V>>,
73-
null_state: FlatNullState,
74-
},
75-
Blocked {
76-
values: Blocks<VecValues<V>>,
77-
null_state: BlockedNullState,
78-
},
79-
}
80-
8171
impl<T, F> PrimitiveGroupsAccumulator<T, F>
8272
where
8373
T: ArrowPrimitiveType + Send,
74+
T::Native: Debug + Send,
8475
F: Fn(&mut T::Native, T::Native) + Send + Sync + 'static,
8576
{
8677
pub fn new(data_type: &DataType, prim_fn: F) -> Self {
8778
Self {
88-
state: PrimitiveGroupsState::Flat {
89-
values: FlatBlockStore::new(),
90-
null_state: FlatNullState::new(None),
91-
},
79+
state: PrimitiveGroupsStateAdapter::new_flat(),
9280
data_type: data_type.clone(),
9381
starting_value: T::default_value(),
9482
prim_fn,
@@ -110,59 +98,155 @@ struct UpdateBatchInput<'a, T: ArrowPrimitiveType> {
11098
total_num_groups: usize,
11199
}
112100

113-
fn update_batch_for<T, F, O, V, N>(
114-
values_store: &mut V,
115-
null_state: &mut NullState<O, N>,
116-
input: &UpdateBatchInput<'_, T>,
117-
starting_value: T::Native,
118-
prim_fn: &F,
119-
) where
120-
T: ArrowPrimitiveType + Send,
121-
T::Native: Debug,
122-
F: Fn(&mut T::Native, T::Native) + Send + Sync + 'static,
101+
#[derive(Debug)]
102+
struct PrimitiveGroupsState<V, VB, O, S>
103+
where
104+
V: Clone + Debug,
105+
VB: VecValuesBlockStore<V> + Send,
123106
O: GroupIndexOperations,
124-
V: BlockStore<VecValues<T::Native>> + Send,
125-
N: SeenValueStore + Send,
107+
S: SeenValueStore + Send,
126108
{
127-
// Expand to ensure values are large enough
128-
let new_block = |block_size: Option<usize>| {
129-
// In blocked mode, pre-allocate the full block capacity.
130-
// In flat mode (block_size=None), start with an empty Vec
131-
// and let `resize` grow it to exactly `total_num_groups`,
132-
// matching the standard Vec growth behavior.
133-
match block_size {
134-
Some(cap) => VecValues::with_capacity(cap),
135-
None => VecValues::default(),
109+
values: VB,
110+
null_state: NullState<O, S>,
111+
_phantom: PhantomData<V>,
112+
}
113+
114+
impl<V, VB, O, S> PrimitiveGroupsState<V, VB, O, S>
115+
where
116+
V: Clone + Debug,
117+
VB: VecValuesBlockStore<V> + Send,
118+
O: GroupIndexOperations,
119+
S: SeenValueStore + Send,
120+
{
121+
fn new(values: VB, null_state: NullState<O, S>) -> Self {
122+
Self {
123+
values,
124+
null_state,
125+
_phantom: PhantomData,
136126
}
137-
};
138-
values_store.resize(input.total_num_groups, new_block, starting_value);
139-
140-
null_state.accumulate(
141-
input.group_indices,
142-
input.values,
143-
input.opt_filter,
144-
input.total_num_groups,
145-
|block_id, block_offset, new_value| {
146-
// SAFETY: `block_id` and `block_offset` are guaranteed to be in bounds
147-
let value = unsafe {
148-
values_store[block_id as usize].get_unchecked_mut(block_offset as usize)
149-
};
150-
prim_fn(value, new_value);
151-
},
152-
);
127+
}
128+
129+
fn update_batch<T, F>(
130+
&mut self,
131+
input: &UpdateBatchInput<'_, T>,
132+
starting_value: V,
133+
prim_fn: &F,
134+
) where
135+
T: ArrowPrimitiveType<Native = V> + Send,
136+
F: Fn(&mut V, V) + Send + Sync + 'static,
137+
{
138+
// Expand to ensure values are large enough
139+
let new_block = |block_size: Option<usize>| {
140+
// In blocked mode, pre-allocate the full block capacity.
141+
// In flat mode (block_size=None), start with an empty Vec
142+
// and let `resize` grow it to exactly `total_num_groups`,
143+
// matching the standard Vec growth behavior.
144+
match block_size {
145+
Some(cap) => VecValues::with_capacity(cap),
146+
None => VecValues::default(),
147+
}
148+
};
149+
self.values
150+
.resize(input.total_num_groups, new_block, starting_value);
151+
152+
self.null_state.accumulate(
153+
input.group_indices,
154+
input.values,
155+
input.opt_filter,
156+
input.total_num_groups,
157+
|block_id, block_offset, new_value| {
158+
// SAFETY: `block_id` and `block_offset` are guaranteed to be in bounds
159+
let value = unsafe {
160+
self.values[block_id as usize]
161+
.get_unchecked_mut(block_offset as usize)
162+
};
163+
prim_fn(value, new_value);
164+
},
165+
);
166+
}
167+
168+
fn evaluate(&mut self, emit_to: EmitTo) -> Result<(Vec<V>, Option<NullBuffer>)> {
169+
Ok((self.values.emit(emit_to)?, self.null_state.build(emit_to)))
170+
}
171+
172+
fn size(&self) -> usize {
173+
if self.values.is_empty() {
174+
return 0;
175+
}
176+
self.values.num_blocks() * self.values[0].capacity() * size_of::<V>()
177+
+ self.null_state.size()
178+
}
153179
}
154180

155-
fn values_size<T: Clone + Debug, V: BlockStore<VecValues<T>>>(values: &V) -> usize {
156-
if values.is_empty() {
157-
return 0;
181+
type FlatPrimitiveGroupsState<V> = PrimitiveGroupsState<
182+
V,
183+
FlatBlockStore<VecValues<V>>,
184+
FlatGroupIndexOperations,
185+
FlatBlockStore<BooleanBlock>,
186+
>;
187+
188+
type BlockedPrimitiveGroupsState<V> = PrimitiveGroupsState<
189+
V,
190+
Blocks<VecValues<V>>,
191+
BlockedGroupIndexOperations,
192+
Blocks<BooleanBlock>,
193+
>;
194+
195+
#[derive(Debug)]
196+
enum PrimitiveGroupsStateAdapter<V: Clone + Debug + Send> {
197+
Flat(FlatPrimitiveGroupsState<V>),
198+
Blocked(BlockedPrimitiveGroupsState<V>),
199+
}
200+
201+
impl<V: Clone + Debug + Send> PrimitiveGroupsStateAdapter<V> {
202+
fn new_flat() -> Self {
203+
Self::Flat(PrimitiveGroupsState::new(
204+
FlatBlockStore::new(),
205+
FlatNullState::new(None),
206+
))
207+
}
208+
209+
fn new_blocked(block_size: usize) -> Self {
210+
Self::Blocked(PrimitiveGroupsState::new(
211+
Blocks::new(Some(block_size)),
212+
BlockedNullState::new(Some(block_size)),
213+
))
214+
}
215+
216+
fn update_batch<T, F>(
217+
&mut self,
218+
input: &UpdateBatchInput<'_, T>,
219+
starting_value: V,
220+
prim_fn: &F,
221+
) where
222+
T: ArrowPrimitiveType<Native = V> + Send,
223+
F: Fn(&mut V, V) + Send + Sync + 'static,
224+
{
225+
match self {
226+
Self::Flat(state) => state.update_batch(input, starting_value, prim_fn),
227+
Self::Blocked(state) => state.update_batch(input, starting_value, prim_fn),
228+
}
229+
}
230+
231+
fn evaluate(&mut self, emit_to: EmitTo) -> Result<(Vec<V>, Option<NullBuffer>)> {
232+
match self {
233+
Self::Flat(state) => state.evaluate(emit_to),
234+
Self::Blocked(state) => state.evaluate(emit_to),
235+
}
236+
}
237+
238+
fn size(&self) -> usize {
239+
match self {
240+
Self::Flat(state) => state.size(),
241+
Self::Blocked(state) => state.size(),
242+
}
158243
}
159-
values.num_blocks() * values[0].capacity() * size_of::<T>()
160244
}
161245

162246
impl<T, F> GroupsAccumulator for PrimitiveGroupsAccumulator<T, F>
163247
where
164248
T: ArrowPrimitiveType + Send,
165-
T::Native: Debug,
249+
T::Native: Debug + Send,
166250
F: Fn(&mut T::Native, T::Native) + Send + Sync + 'static,
167251
{
168252
fn update_batch(
@@ -174,52 +258,22 @@ where
174258
) -> Result<()> {
175259
assert_eq!(values.len(), 1, "single argument to update_batch");
176260
let input_values = values[0].as_primitive::<T>();
177-
178-
match &mut self.state {
179-
PrimitiveGroupsState::Flat { values, null_state } => {
180-
update_batch_for::<T, F, FlatGroupIndexOperations, _, _>(
181-
values,
182-
null_state,
183-
&UpdateBatchInput {
184-
values: input_values,
185-
group_indices,
186-
opt_filter,
187-
total_num_groups,
188-
},
189-
self.starting_value,
190-
&self.prim_fn,
191-
);
192-
}
193-
PrimitiveGroupsState::Blocked { values, null_state } => {
194-
update_batch_for::<T, F, BlockedGroupIndexOperations, _, _>(
195-
values,
196-
null_state,
197-
&UpdateBatchInput {
198-
values: input_values,
199-
group_indices,
200-
opt_filter,
201-
total_num_groups,
202-
},
203-
self.starting_value,
204-
&self.prim_fn,
205-
);
206-
}
207-
}
261+
self.state.update_batch(
262+
&UpdateBatchInput {
263+
values: input_values,
264+
group_indices,
265+
opt_filter,
266+
total_num_groups,
267+
},
268+
self.starting_value,
269+
&self.prim_fn,
270+
);
208271

209272
Ok(())
210273
}
211274

212275
fn evaluate(&mut self, emit_to: EmitTo) -> Result<ArrayRef> {
213-
let (values, nulls): (Vec<T::Native>, _) = match &mut self.state {
214-
PrimitiveGroupsState::Flat { values, null_state } => (
215-
VecValuesBlockStore::emit(values, emit_to)?,
216-
null_state.build(emit_to),
217-
),
218-
PrimitiveGroupsState::Blocked { values, null_state } => (
219-
VecValuesBlockStore::emit(values, emit_to)?,
220-
null_state.build(emit_to),
221-
),
222-
};
276+
let (values, nulls) = self.state.evaluate(emit_to)?;
223277
let values = PrimitiveArray::<T>::new(values.into(), nulls) // no copy
224278
.with_data_type(self.data_type.clone());
225279
Ok(Arc::new(values))
@@ -298,20 +352,7 @@ where
298352
}
299353

300354
fn size(&self) -> usize {
301-
match &self.state {
302-
PrimitiveGroupsState::Flat { values, null_state } => {
303-
if values.is_empty() {
304-
return 0;
305-
}
306-
values_size::<T::Native, _>(values) + null_state.size()
307-
}
308-
PrimitiveGroupsState::Blocked { values, null_state } => {
309-
if values.is_empty() {
310-
return 0;
311-
}
312-
values_size::<T::Native, _>(values) + null_state.size()
313-
}
314-
}
355+
self.state.size()
315356
}
316357

317358
fn supports_blocked_groups(&self) -> bool {
@@ -320,15 +361,9 @@ where
320361

321362
fn alter_block_size(&mut self, block_size: Option<usize>) -> Result<()> {
322363
self.state = if let Some(block_size) = block_size {
323-
PrimitiveGroupsState::Blocked {
324-
values: Blocks::new(Some(block_size)),
325-
null_state: BlockedNullState::new(Some(block_size)),
326-
}
364+
PrimitiveGroupsStateAdapter::new_blocked(block_size)
327365
} else {
328-
PrimitiveGroupsState::Flat {
329-
values: FlatBlockStore::new(),
330-
null_state: FlatNullState::new(None),
331-
}
366+
PrimitiveGroupsStateAdapter::new_flat()
332367
};
333368

334369
Ok(())

0 commit comments

Comments
 (0)