use std::sync::Arc;
use wcompact::{CompactSession, CompactStore, CompactionStats, CompactionType, LogCompactor};
use wdev::Device;
use whlog::HybridLog;
use windex::HashIndex;
use crate::{
error::{Error, Result},
read_cache::is_read_cache_addr,
session::StoreSession,
store::WedbStore,
ttl::TTL_VALUE_LEN,
};
impl From<Error> for wcompact::Error {
fn from(e: Error) -> Self {
match e {
Error::Epoch(x) => Self::Epoch(x),
Error::HLog(x) => Self::Hlog(x),
Error::Record(x) => Self::Record(x),
other => Self::Host(Box::new(other)),
}
}
}
impl<D: Device> CompactSession<D> for StoreSession<D> {
type EpochGuard<'a>
= wepoch::EpochGuard<'a>
where
Self: 'a;
#[inline]
fn enter_epoch(&self) -> Self::EpochGuard<'_> {
self.participant.enter()
}
#[inline]
async fn append_record(
&self,
key: &[u8],
val: &[u8],
expected_main_addr: u64,
is_tombstone: bool,
) -> wcompact::Result<u64> {
self
.append_record_compacted(key, val, expected_main_addr, is_tombstone)
.await
.map_err(wcompact::Error::from)
}
#[inline]
async fn read_ttl_expiry(&self, ttl_key: &[u8]) -> wcompact::Result<Option<u64>> {
let mem_exp = {
let _guard = self.participant.enter();
let Some(first_addr) = self.store.index.find_tag(ttl_key) else {
return Ok(None);
};
self
.try_read_raw_in_memory_with_addr(ttl_key, Some(first_addr), |v| {
<[u8; TTL_VALUE_LEN]>::try_from(v)
.ok()
.map(u64::from_be_bytes)
})
.map_err(wcompact::Error::from)?
};
match mem_exp {
Some(Some(Some(exp))) => Ok(Some(exp)),
Some(None) | Some(Some(None)) => Ok(None),
None => {
if let Some(raw_ttl) = self
.read_raw(ttl_key)
.await
.map_err(wcompact::Error::from)?
&& let Ok(be) = <[u8; TTL_VALUE_LEN]>::try_from(raw_ttl.as_slice())
{
return Ok(Some(u64::from_be_bytes(be)));
}
Ok(None)
}
}
}
}
impl<D: Device> CompactStore for WedbStore<D> {
type Device = D;
type Session = StoreSession<D>;
#[inline]
fn new_session(self: &Arc<Self>) -> wcompact::Result<Self::Session> {
self.new_session().map_err(wcompact::Error::from)
}
#[inline]
fn hlog(&self) -> &HybridLog<D> {
&self.hlog
}
#[inline]
fn index(&self) -> &HashIndex {
&self.index
}
#[inline]
fn read_only_address(&self) -> u64 {
self.hlog.read_only_address()
}
#[inline]
fn begin_address(&self) -> u64 {
self.hlog.begin_address()
}
#[inline]
async fn shift_begin_address(&self, until: u64) -> wcompact::Result<()> {
self
.shift_begin_address(until)
.await
.map_err(wcompact::Error::from)
}
#[inline]
fn is_read_cache_addr(&self, addr: u64) -> bool {
is_read_cache_addr(addr)
}
#[inline]
fn skip_read_cache(&self, addr: u64) -> u64 {
if self.read_cache.is_enabled {
self.read_cache.skip_read_cache(addr)
} else {
0
}
}
#[inline]
fn enable_revivification(&self) -> bool {
self.config.enable_revivification
}
#[inline]
fn reviv_put(&self, addr: u64, size: u32, read_only_addr: u64) {
self.reviv_pool.put(addr, size, read_only_addr);
}
#[inline]
fn get_key_id_meta(&self, key_id: u64) -> Option<(u64, bool)> {
self.get_key_id_meta(key_id)
}
#[inline]
fn update_key_id_meta(&self, key_id: u64, version: u64, is_alive: bool) {
self.update_key_id_meta(key_id, version, is_alive);
}
#[inline]
fn remove_key_id_meta(&self, key_id: u64) {
self.remove_key_id_meta(key_id);
}
}
impl<D: Device> WedbStore<D> {
#[inline]
pub fn compactor(self: &Arc<Self>) -> LogCompactor<Self> {
LogCompactor::new(Arc::clone(self))
}
#[inline]
pub async fn compact(
self: &Arc<Self>,
until_address: u64,
comp_type: CompactionType,
) -> Result<CompactionStats> {
self
.compactor()
.compact(until_address, comp_type)
.await
.map_err(Error::from)
}
#[inline]
pub async fn compact_with_filter<F>(
self: &Arc<Self>,
until_address: u64,
comp_type: CompactionType,
is_deleted: F,
) -> Result<CompactionStats>
where
F: FnMut(&[u8], &[u8]) -> bool,
{
self
.compactor()
.compact_with_filter(until_address, comp_type, is_deleted)
.await
.map_err(Error::from)
}
#[inline]
pub async fn compact_lazy(self: &Arc<Self>, max_seek_bytes: u64) -> Result<CompactionStats> {
self
.compactor()
.compact_lazy(max_seek_bytes)
.await
.map_err(Error::from)
}
}