use crate::active_tombstone_set::ActiveTombstoneSet;
use crate::range_tombstone::RangeTombstone;
use crate::{InternalValue, SeqNo, comparator::SharedComparator};
pub(super) struct BottommostSeqnoZeroer<I> {
inner: I,
enabled: bool,
comparator: SharedComparator,
gc_seqno_threshold: SeqNo,
tombstones: Vec<RangeTombstone>,
idx: usize,
active: ActiveTombstoneSet,
tombstones_sorted: bool,
}
impl<I> BottommostSeqnoZeroer<I> {
pub(super) fn new(
inner: I,
enabled: bool,
tombstones: Vec<RangeTombstone>,
gc_seqno_threshold: SeqNo,
comparator: SharedComparator,
) -> Self {
Self {
inner,
enabled,
comparator: comparator.clone(),
gc_seqno_threshold,
tombstones,
idx: 0,
active: ActiveTombstoneSet::new_with_comparator(comparator),
tombstones_sorted: false,
}
}
fn covered(&mut self, key: &[u8]) -> bool {
if !self.tombstones_sorted {
let comparator = self.comparator.as_ref();
self.tombstones
.sort_by(|a, b| a.cmp_with_comparator(b, comparator));
self.tombstones_sorted = true;
}
while let Some(rt) = self.tombstones.get(self.idx) {
if self.comparator.compare(&rt.start, key) == std::cmp::Ordering::Greater {
break;
}
self.active.activate(rt, SeqNo::MAX);
self.idx += 1;
}
self.active.expire_until(key);
self.active.max_active_seqno().is_some()
}
}
impl<I: Iterator<Item = crate::Result<InternalValue>>> Iterator for BottommostSeqnoZeroer<I> {
type Item = crate::Result<InternalValue>;
fn next(&mut self) -> Option<Self::Item> {
if !self.enabled {
return self.inner.next();
}
match self.inner.next()? {
Ok(mut kv) => {
if kv.key.seqno > 0
&& kv.key.seqno < self.gc_seqno_threshold
&& !self.covered(kv.key.user_key.as_ref())
{
kv.key.seqno = 0;
}
Some(Ok(kv))
}
other => Some(other),
}
}
}