use crate::active_tombstone_set::ActiveTombstoneSet;
use crate::range_tombstone::RangeTombstone;
use crate::{InternalValue, SeqNo, comparator::SharedComparator};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
pub(super) struct BottommostSeqnoZeroer<I> {
inner: I,
enabled: bool,
comparator: SharedComparator,
gc_watermark: SeqNo,
tombstones: Vec<RangeTombstone>,
idx: usize,
active: ActiveTombstoneSet,
tombstones_sorted: bool,
gc_balance: alloc::sync::Arc<portable_atomic::AtomicU64>,
zeroed_any: bool,
}
impl<I> BottommostSeqnoZeroer<I> {
pub(super) fn new(
inner: I,
enabled: bool,
tombstones: Vec<RangeTombstone>,
gc_watermark: SeqNo,
comparator: SharedComparator,
gc_balance: alloc::sync::Arc<portable_atomic::AtomicU64>,
) -> Self {
Self {
inner,
enabled,
comparator: comparator.clone(),
gc_watermark,
tombstones,
idx: 0,
active: ActiveTombstoneSet::new_with_comparator(comparator),
tombstones_sorted: false,
gc_balance,
zeroed_any: false,
}
}
fn covered(&mut self, key: &[u8]) -> bool {
if self.idx == self.tombstones.len() && self.active.is_empty() {
return false;
}
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) == core::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<'a, I, F> BottommostSeqnoZeroer<super::stream::CompactionStream<'a, I, F>>
where
I: Iterator<Item = crate::Result<InternalValue>>,
F: super::stream::StreamFilter + 'a,
{
pub(super) fn next_starts_key(&self) -> bool {
self.inner.next_starts_key()
}
}
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_watermark
&& !self.covered(kv.key.user_key.as_ref())
{
kv.key.seqno = 0;
if !self.zeroed_any {
self.zeroed_any = true;
self.gc_balance
.fetch_add(1, core::sync::atomic::Ordering::Relaxed);
}
}
Some(Ok(kv))
}
other => Some(other),
}
}
}