use crate::compaction::state::hidden_set::HiddenSet;
use crate::comparator::UserComparator;
use crate::range_tombstone::RangeTombstone;
use crate::version::{
RetentionEffect, Version,
run::{HoldsRangeTombstones, Ranged},
};
use crate::{HashMap, SeqNo, Table, TableId};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::ops::Bound;
pub fn covered_tables(
version: &Version,
gc_watermark: SeqNo,
hidden: &HiddenSet,
cmp: &dyn UserComparator,
) -> Option<(Vec<TableId>, RetentionEffect)> {
let mut covered: HashMap<TableId, SeqNo> = HashMap::default();
for holder in version
.iter_levels()
.flat_map(|level| level.iter())
.filter(|run| run.holds_range_tombstones())
.flat_map(|run| run.iter())
.filter(|t| t.holds_range_tombstones())
.filter(|t| t.global_seqno() == 0)
{
for rt in holder.visible_range_tombstones() {
if !rt.visible_at(gc_watermark) {
continue;
}
let span = (
Bound::Included(rt.start.as_ref()),
Bound::Excluded(rt.end.as_ref()),
);
for run in version.iter_levels().flat_map(|level| level.iter()) {
let Some(overlapping) = run
.range_overlap_indexes_cmp::<&[u8], _, _>(&span, cmp)
.and_then(|(lo, hi)| run.get(lo..=hi))
else {
continue;
};
for table in overlapping {
if table.id() == holder.id() || hidden.is_hidden(table.id()) {
continue;
}
let Some((_, newest)) = table.seqno_range() else {
continue;
};
if newest >= rt.seqno {
continue;
}
if !spans_whole(&rt, table, cmp) {
continue;
}
covered
.entry(table.id())
.and_modify(|oldest| *oldest = (*oldest).min(rt.seqno))
.or_insert(rt.seqno);
}
}
}
}
let floor = covered.values().copied().max()?;
let mut ids: Vec<TableId> = covered.into_keys().collect();
ids.sort_unstable();
Some((ids, RetentionEffect::GcBelow(floor + 1)))
}
fn spans_whole(rt: &RangeTombstone, table: &Table, cmp: &dyn UserComparator) -> bool {
use core::cmp::Ordering::Greater;
let range = table.key_range();
rt.fully_covers_with(range.min(), range.max(), cmp)
&& table.range_tombstones().iter().all(|own| {
cmp.compare(&rt.start, &own.start) != Greater
&& cmp.compare(&own.end, &rt.end) != Greater
})
}
#[cfg(test)]
mod tests;