use egglog_concurrency::ThreadPool;
use rand::{Rng, SeedableRng, rngs::StdRng};
use crate::{
common::Value,
free_join::Database,
numeric_id::NumericId,
offsets::RowId,
table::SortedWritesTable,
table_spec::{ColumnId, Table, WrappedTable},
};
use super::{ColumnIndex, IndexBase, merge_sorted_blocks_dedup, radix_sort_slice_by_value};
pub fn gen_blocks(
n_rows: usize,
n_cols: usize,
distinct: u32,
seed: u64,
) -> (Vec<(Value, RowId)>, Vec<usize>) {
let mut rng = StdRng::seed_from_u64(seed);
let mut pairs = Vec::with_capacity(n_rows * n_cols);
let mut bounds = vec![0usize];
for _ in 0..n_cols {
for r in 0..n_rows {
pairs.push((
Value::new(rng.random_range(0..distinct)),
RowId::from_usize(r),
));
}
bounds.push(pairs.len());
}
(pairs, bounds)
}
pub fn sort_merge_custom(mut pairs: Vec<(Value, RowId)>, bounds: &[usize]) -> Vec<(Value, RowId)> {
let widest = bounds.windows(2).map(|w| w[1] - w[0]).max().unwrap_or(0);
let mut scratch = vec![(Value::new_const(0), RowId::new_const(0)); widest];
for b in 0..bounds.len() - 1 {
radix_sort_slice_by_value(&mut pairs[bounds[b]..bounds[b + 1]], &mut scratch);
}
if bounds.len() <= 2 {
pairs
} else {
merge_sorted_blocks_dedup(pairs, bounds)
}
}
pub fn sort_merge_std(mut pairs: Vec<(Value, RowId)>, dedup: bool) -> Vec<(Value, RowId)> {
pairs.sort_unstable();
if dedup {
pairs.dedup();
}
pairs
}
pub fn with_threads<R>(n: usize, f: impl FnOnce() -> R) -> R {
ThreadPool::new(n.max(1)).install(f)
}
pub struct IndexInput {
table: WrappedTable,
cols: Vec<ColumnId>,
}
impl IndexInput {
pub fn random(n_rows: usize, n_val_cols: usize, distinct: u32, seed: u64) -> Self {
let mut rng = StdRng::seed_from_u64(seed);
let n_cols = n_val_cols + 1;
let mut table = SortedWritesTable::new(
1,
n_cols,
None,
vec![],
Box::new(|_, _old, new, out: &mut Vec<Value>| {
out.extend_from_slice(new);
false
}),
);
{
let mut buf = table.new_buffer();
let mut row = vec![Value::new(0); n_cols];
for i in 0..n_rows {
row[0] = Value::from_usize(i);
for cell in row.iter_mut().skip(1) {
*cell = Value::new(rng.random_range(0..distinct));
}
buf.stage_insert(&row);
}
}
let db = Database::default();
db.with_execution_state(None, |es| {
table.merge(es);
});
IndexInput {
table: WrappedTable::new(table),
cols: (1..n_cols).map(ColumnId::from_usize).collect(),
}
}
pub fn build_serial(&self) {
let mut ci = ColumnIndex::new();
ci.rebuild_full(&self.cols, self.table.as_ref(), self.table.all().as_ref());
std::hint::black_box(&ci);
}
pub fn build_parallel(&self) {
let mut ci = ColumnIndex::new();
ci.merge_parallel(&self.cols, self.table.as_ref(), self.table.all().as_ref());
std::hint::black_box(&ci);
}
}