use wval::{KeyTag, NamespaceDbCodec, TtlCodec};
use super::LogCompactor;
use crate::host::{CompactSession, CompactStore};
impl<S: CompactStore> LogCompactor<S> {
#[inline]
pub(super) fn is_stale_subkey(&self, key: &[u8]) -> bool {
if let Some((_tag, key_id, sub_version)) = NamespaceDbCodec::decode_subkey_id_version(key) {
match self.store.get_key_id_meta(key_id) {
None => false,
Some((current_version, is_alive)) => !is_alive || current_version > sub_version,
}
} else {
false
}
}
pub(super) async fn judge_dead<F>(
&self,
session: &S::Session,
is_tombstone: bool,
key: &[u8],
val: &[u8],
now: u64,
is_deleted: &mut F,
) -> bool
where
F: FnMut(&[u8], &[u8]) -> bool,
{
is_tombstone
|| is_deleted(key, val)
|| self.is_stale_subkey(key)
|| self
.is_expired_or_orphan_record(session, key, val, now)
.await
}
async fn is_expired_or_orphan_record(
&self,
session: &S::Session,
key: &[u8],
val: &[u8],
now: u64,
) -> bool {
let Ok((_ns, _db, tag, user_key)) = NamespaceDbCodec::decode_tagged_key(key) else {
return false;
};
let Some(tag_offset) = key.len().checked_sub(user_key.len() + 1) else {
return false;
};
match tag {
KeyTag::Ttl => {
if let Some(exp) = TtlCodec::decode(val)
&& exp <= now
{
return true;
}
let _guard = session.enter_epoch();
let str_k = NamespaceDbCodec::replace_tag_at(key, tag_offset, KeyTag::String);
if self.store.index().find_tag(&str_k).is_some() {
return false;
}
let meta_k = NamespaceDbCodec::replace_tag_at(key, tag_offset, KeyTag::Meta);
self.store.index().find_tag(&meta_k).is_none()
}
KeyTag::String | KeyTag::Meta => {
let ttl_k = NamespaceDbCodec::replace_tag_at(key, tag_offset, KeyTag::Ttl);
if let Ok(Some(exp)) = session.read_ttl_expiry(&ttl_k).await {
exp <= now
} else {
false
}
}
_ => false,
}
}
}