pub mod report;
use crate::{id::SegmentId, Compressor, ValueLog};
#[allow(clippy::module_name_repetitions)]
pub trait GcStrategy<C: Compressor + Clone> {
fn pick(&self, value_log: &ValueLog<C>) -> Vec<SegmentId>;
}
pub struct StaleThresholdStrategy(f32);
impl StaleThresholdStrategy {
#[must_use]
pub fn new(ratio: f32) -> Self {
assert!(
ratio.is_finite() && ratio.is_sign_positive(),
"invalid stale ratio"
);
Self(ratio.min(1.0))
}
}
impl<C: Compressor + Clone> GcStrategy<C> for StaleThresholdStrategy {
fn pick(&self, value_log: &ValueLog<C>) -> Vec<SegmentId> {
value_log
.manifest
.segments
.read()
.expect("lock is poisoned")
.values()
.filter(|x| x.stale_ratio() > self.0)
.map(|x| x.id)
.collect::<Vec<_>>()
}
}
pub struct SpaceAmpStrategy(f32);
impl SpaceAmpStrategy {
#[must_use]
pub fn new(ratio: f32) -> Self {
assert!(ratio >= 1.0, "invalid space amp ratio");
Self(ratio)
}
}
impl<C: Compressor + Clone> GcStrategy<C> for SpaceAmpStrategy {
#[allow(clippy::cast_precision_loss, clippy::significant_drop_tightening)]
fn pick(&self, value_log: &ValueLog<C>) -> Vec<SegmentId> {
let space_amp_target = self.0;
let current_space_amp = value_log.space_amp();
if current_space_amp < space_amp_target {
log::trace!("Space amp is <= target {space_amp_target}, nothing to do");
vec![]
} else {
log::debug!("Selecting segments to GC, space_amp_target={space_amp_target}");
let lock = value_log
.manifest
.segments
.read()
.expect("lock is poisoned");
let mut segments = lock
.values()
.filter(|x| x.stale_ratio() > 0.0)
.collect::<Vec<_>>();
segments.sort_by(|a, b| {
b.stale_ratio()
.partial_cmp(&a.stale_ratio())
.unwrap_or(std::cmp::Ordering::Equal)
});
let mut selection = vec![];
let mut total_bytes = value_log.manifest.total_bytes();
let mut stale_bytes = value_log.manifest.stale_bytes();
for segment in segments {
let segment_stale_bytes = segment.gc_stats.stale_bytes();
stale_bytes -= segment_stale_bytes;
total_bytes -= segment_stale_bytes;
selection.push(segment.id);
let space_amp_after_gc =
total_bytes as f32 / (total_bytes as f32 - stale_bytes as f32);
log::debug!(
"Selected segment #{} for GC: will reduce space amp to {space_amp_after_gc}",
segment.id
);
if space_amp_after_gc <= space_amp_target {
break;
}
}
selection
}
}
}