use std::path::PathBuf;
use super::grace_repartition::FrameStreamReader;
use crate::data::executor::core_loop::CoreLoop;
#[derive(Clone)]
pub(super) enum RowSource {
LocalScan {
database_id: u64,
tenant_id: u64,
collection: String,
},
#[allow(dead_code)]
ShuffleStream { path: PathBuf },
}
impl RowSource {
pub(super) fn for_each<F>(&self, core: &CoreLoop, mut f: F) -> crate::Result<()>
where
F: FnMut(&str, &[u8]) -> crate::Result<()>,
{
match self {
RowSource::LocalScan {
database_id,
tenant_id,
collection,
} => core.scan_collection_for_each(*database_id, *tenant_id, collection, f),
RowSource::ShuffleStream { path } => {
let mut reader = FrameStreamReader::open(path)?;
while let Some(row) = reader.next_row()? {
f("", &row)?;
}
Ok(())
}
}
}
}
#[cfg(test)]
mod tests {
use std::io::Write as _;
fn write_staged_file(path: &std::path::Path, rows: &[Vec<u8>]) {
let mut f = std::fs::File::create(path).expect("create staged file");
for row in rows {
let len = u32::try_from(row.len()).expect("row fits u32");
f.write_all(&len.to_le_bytes()).expect("write len");
f.write_all(row).expect("write body");
}
f.flush().expect("flush");
}
#[test]
fn shuffle_stream_yields_rows_in_order_byte_identical() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("staged.frames");
let rows: Vec<Vec<u8>> = vec![
b"first-row-bytes".to_vec(),
Vec::new(),
vec![0u8, 1, 2, 3, 0xff, 0xfe],
b"another".to_vec(),
];
write_staged_file(&path, &rows);
let mut reader = super::FrameStreamReader::open(&path).expect("open reader");
let mut got: Vec<Vec<u8>> = Vec::new();
while let Some(row) = reader.next_row().expect("read frame") {
got.push(row);
}
assert_eq!(
got, rows,
"staged frames must read back in order, byte-identical"
);
}
#[test]
fn shuffle_stream_truncated_frame_is_hard_error() {
let dir = tempfile::tempdir().expect("tempdir");
let path = dir.path().join("truncated.frames");
let mut f = std::fs::File::create(&path).expect("create");
f.write_all(&10u32.to_le_bytes()).expect("write len");
f.write_all(b"abc").expect("write short body");
f.flush().expect("flush");
let mut reader = super::FrameStreamReader::open(&path).expect("open reader");
let err = reader.next_row();
assert!(
err.is_err(),
"a truncated frame body must surface as an error, not a silent EOF"
);
}
}