use tessarikv_types::SequenceNumber;
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct RangeTombstone {
pub(crate) start: Vec<u8>,
pub(crate) end: Vec<u8>,
pub(crate) sequence: SequenceNumber,
}
#[derive(Debug, Default)]
pub(crate) struct Fragments {
pieces: Vec<(Vec<u8>, Vec<u8>, SequenceNumber)>,
}
impl Fragments {
pub(crate) fn new(tombstones: &[RangeTombstone], snapshot: SequenceNumber) -> Self {
let visible: Vec<&RangeTombstone> = tombstones
.iter()
.filter(|tombstone| tombstone.sequence <= snapshot && tombstone.start < tombstone.end)
.collect();
if visible.is_empty() {
return Self::default();
}
let mut boundaries: Vec<&[u8]> = visible
.iter()
.flat_map(|tombstone| [tombstone.start.as_slice(), tombstone.end.as_slice()])
.collect();
boundaries.sort_unstable();
boundaries.dedup();
let mut pieces: Vec<(Vec<u8>, Vec<u8>, SequenceNumber)> = Vec::new();
for pair in boundaries.windows(2) {
let [from, to] = pair else { continue };
let covering = visible
.iter()
.filter(|tombstone| {
tombstone.start.as_slice() <= *from && *to <= tombstone.end.as_slice()
})
.map(|tombstone| tombstone.sequence)
.max();
let Some(sequence) = covering else { continue };
match pieces.last_mut() {
Some(last) if last.1.as_slice() == *from && last.2 == sequence => {
last.1 = to.to_vec();
}
_ => pieces.push((from.to_vec(), to.to_vec(), sequence)),
}
}
Self { pieces }
}
pub(crate) fn is_empty(&self) -> bool {
self.pieces.is_empty()
}
pub(crate) fn deletes(&self, key: &[u8], sequence: SequenceNumber) -> bool {
let after = self
.pieces
.partition_point(|(start, _, _)| start.as_slice() <= key);
after
.checked_sub(1)
.and_then(|index| self.pieces.get(index))
.is_some_and(|(_, end, covering)| key < end.as_slice() && sequence < *covering)
}
}
#[cfg(test)]
mod tests;