use crate::config::error::LoadError;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::path::Path;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct CompactionConfig {
pub intermediate: IntermediateCompaction,
}
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
pub struct IntermediateCompaction {
pub trigger: CompactionTrigger,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub n: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub keep_recent: Option<u32>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum CompactionTrigger {
EveryNCommits,
EveryTSeconds,
OnFlush,
}
pub(super) fn validate_compaction(path: &Path, c: &CompactionConfig) -> Result<(), LoadError> {
let needs_n = matches!(
c.intermediate.trigger,
CompactionTrigger::EveryNCommits | CompactionTrigger::EveryTSeconds
);
let has_n = c.intermediate.n.is_some_and(|n| n > 0);
if needs_n && !has_n {
return Err(LoadError::Invalid {
path: path.to_path_buf(),
key: "compaction.intermediate.n".into(),
message: "must be a positive integer for the chosen trigger".into(),
});
}
let keep = c.intermediate.keep_recent.unwrap_or(0);
if matches!(c.intermediate.trigger, CompactionTrigger::EveryNCommits)
&& c.intermediate.n.is_some_and(|n| keep >= n)
{
return Err(LoadError::Invalid {
path: path.to_path_buf(),
key: "compaction.intermediate.keep_recent".into(),
message: "must be smaller than n: a retained tail at or over the commit \
trigger would re-arm the clock at every landing"
.into(),
});
}
Ok(())
}