use crate::physical_plan::aggregates::group_values::GroupValues;
use ahash::RandomState;
use arrow::row::{RowConverter, Rows, SortField};
use arrow_array::ArrayRef;
use arrow_schema::SchemaRef;
use datafusion_common::Result;
use datafusion_execution::memory_pool::proxy::{RawTableAllocExt, VecAllocExt};
use datafusion_physical_expr::hash_utils::create_hashes;
use datafusion_physical_expr::EmitTo;
use hashbrown::raw::RawTable;
pub struct GroupValuesRows {
row_converter: RowConverter,
map: RawTable<(u64, usize)>,
map_size: usize,
group_values: Rows,
hashes_buffer: Vec<u64>,
random_state: RandomState,
}
impl GroupValuesRows {
pub fn try_new(schema: SchemaRef) -> Result<Self> {
let row_converter = RowConverter::new(
schema
.fields()
.iter()
.map(|f| SortField::new(f.data_type().clone()))
.collect(),
)?;
let map = RawTable::with_capacity(0);
let group_values = row_converter.empty_rows(0, 0);
Ok(Self {
row_converter,
map,
map_size: 0,
group_values,
hashes_buffer: Default::default(),
random_state: Default::default(),
})
}
}
impl GroupValues for GroupValuesRows {
fn intern(&mut self, cols: &[ArrayRef], groups: &mut Vec<usize>) -> Result<()> {
let group_rows = self.row_converter.convert_columns(cols)?;
let n_rows = group_rows.num_rows();
groups.clear();
let batch_hashes = &mut self.hashes_buffer;
batch_hashes.clear();
batch_hashes.resize(n_rows, 0);
create_hashes(cols, &self.random_state, batch_hashes)?;
for (row, &hash) in batch_hashes.iter().enumerate() {
let entry = self.map.get_mut(hash, |(_hash, group_idx)| {
group_rows.row(row) == self.group_values.row(*group_idx)
});
let group_idx = match entry {
Some((_hash, group_idx)) => *group_idx,
None => {
let group_idx = self.group_values.num_rows();
self.group_values.push(group_rows.row(row));
self.map.insert_accounted(
(hash, group_idx),
|(hash, _group_index)| *hash,
&mut self.map_size,
);
group_idx
}
};
groups.push(group_idx);
}
Ok(())
}
fn size(&self) -> usize {
self.row_converter.size()
+ self.group_values.size()
+ self.map_size
+ self.hashes_buffer.allocated_size()
}
fn is_empty(&self) -> bool {
self.len() == 0
}
fn len(&self) -> usize {
self.group_values.num_rows()
}
fn emit(&mut self, emit_to: EmitTo) -> Result<Vec<ArrayRef>> {
Ok(match emit_to {
EmitTo::All => {
self.row_converter.convert_rows(&self.group_values)?
}
EmitTo::First(n) => {
let groups_rows = self.group_values.iter().take(n);
let output = self.row_converter.convert_rows(groups_rows)?;
let mut new_group_values = self.row_converter.empty_rows(0, 0);
for row in self.group_values.iter().skip(n) {
new_group_values.push(row);
}
std::mem::swap(&mut new_group_values, &mut self.group_values);
unsafe {
for bucket in self.map.iter() {
match bucket.as_ref().1.checked_sub(n) {
Some(sub) => bucket.as_mut().1 = sub,
None => self.map.erase(bucket),
}
}
}
output
}
})
}
}