use super::{RowSelection, RowSelector};
use crate::file::page_index::offset_index::PageLocation;
use std::ops::Range;
#[inline]
pub(super) fn scan_ranges_from_selectors<I>(
selectors: I,
page_locations: &[PageLocation],
) -> Vec<Range<u64>>
where
I: IntoIterator<Item = RowSelector>,
{
let mut ranges: Vec<Range<u64>> = vec![];
let mut row_offset = 0;
let mut pages = page_locations.iter().peekable();
let mut selectors = selectors.into_iter();
let mut current_selector = selectors.next();
let mut current_page = pages.next();
let mut current_page_included = false;
while let Some((selector, page)) = current_selector.as_mut().zip(current_page) {
if !(selector.skip || current_page_included) {
let start = page.offset as u64;
let end = start + page.compressed_page_size as u64;
ranges.push(start..end);
current_page_included = true;
}
if let Some(next_page) = pages.peek() {
if row_offset + selector.row_count > next_page.first_row_index as usize {
let remaining_in_page = next_page.first_row_index as usize - row_offset;
selector.row_count -= remaining_in_page;
row_offset += remaining_in_page;
current_page = pages.next();
current_page_included = false;
continue;
} else {
if row_offset + selector.row_count == next_page.first_row_index as usize {
current_page = pages.next();
current_page_included = false;
}
row_offset += selector.row_count;
current_selector = selectors.next();
}
} else {
if !(selector.skip || current_page_included) {
let start = page.offset as u64;
let end = start + page.compressed_page_size as u64;
ranges.push(start..end);
}
current_selector = selectors.next()
}
}
ranges
}
#[inline]
pub(super) fn expand_to_batch_boundaries_from_selectors<I>(
selectors: I,
batch_size: usize,
total_rows: usize,
) -> RowSelection
where
I: IntoIterator<Item = RowSelector>,
{
let mut expanded_ranges = Vec::new();
let mut row_offset = 0;
for selector in selectors {
if selector.skip {
row_offset += selector.row_count;
} else {
let start = row_offset;
let end = row_offset + selector.row_count;
let expanded_start = (start / batch_size) * batch_size;
let expanded_end = end.div_ceil(batch_size) * batch_size;
let expanded_end = expanded_end.min(total_rows);
expanded_ranges.push(expanded_start..expanded_end);
row_offset += selector.row_count;
}
}
expanded_ranges.sort_by_key(|range| range.start);
let mut merged_ranges: Vec<Range<usize>> = Vec::new();
for range in expanded_ranges {
if let Some(last) = merged_ranges.last_mut() {
if range.start <= last.end {
last.end = last.end.max(range.end);
} else {
merged_ranges.push(range);
}
} else {
merged_ranges.push(range);
}
}
RowSelection::from_consecutive_ranges(merged_ranges.into_iter(), total_rows)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scan_ranges() {
let index = vec![
PageLocation {
offset: 0,
compressed_page_size: 10,
first_row_index: 0,
},
PageLocation {
offset: 10,
compressed_page_size: 10,
first_row_index: 10,
},
PageLocation {
offset: 20,
compressed_page_size: 10,
first_row_index: 20,
},
PageLocation {
offset: 30,
compressed_page_size: 10,
first_row_index: 30,
},
PageLocation {
offset: 40,
compressed_page_size: 10,
first_row_index: 40,
},
PageLocation {
offset: 50,
compressed_page_size: 10,
first_row_index: 50,
},
PageLocation {
offset: 60,
compressed_page_size: 10,
first_row_index: 60,
},
];
let selection = RowSelection::from(vec![
RowSelector::skip(10),
RowSelector::select(3),
RowSelector::skip(3),
RowSelector::select(4),
RowSelector::skip(5),
RowSelector::select(5),
RowSelector::skip(12),
RowSelector::select(12),
RowSelector::skip(12),
]);
let ranges = selection.scan_ranges(&index);
assert_eq!(ranges, vec![10..20, 20..30, 40..50, 50..60]);
assert_eq!(
selection.row_ranges_for_selected_pages(&index, 70),
vec![10..20, 20..30, 40..50, 50..60]
);
let selection = RowSelection::from(vec![
RowSelector::skip(10),
RowSelector::select(3),
RowSelector::skip(3),
RowSelector::select(4),
RowSelector::skip(5),
RowSelector::select(5),
RowSelector::skip(12),
RowSelector::select(12),
RowSelector::skip(1),
RowSelector::select(8),
]);
let ranges = selection.scan_ranges(&index);
assert_eq!(ranges, vec![10..20, 20..30, 40..50, 50..60, 60..70]);
let selection = RowSelection::from(vec![
RowSelector::skip(10),
RowSelector::select(3),
RowSelector::skip(3),
RowSelector::select(4),
RowSelector::skip(5),
RowSelector::select(5),
RowSelector::skip(12),
RowSelector::select(12),
RowSelector::skip(1),
RowSelector::skip(8),
RowSelector::select(4),
]);
let ranges = selection.scan_ranges(&index);
assert_eq!(ranges, vec![10..20, 20..30, 40..50, 50..60, 60..70]);
let selection = RowSelection::from(vec![
RowSelector::skip(10),
RowSelector::select(3),
RowSelector::skip(3),
RowSelector::select(4),
RowSelector::skip(5),
RowSelector::select(6),
RowSelector::skip(50),
]);
let ranges = selection.scan_ranges(&index);
assert_eq!(ranges, vec![10..20, 20..30, 30..40]);
}
}