use serde::{Deserialize, Serialize};
use super::partition::PartitionInterval;
#[derive(Debug, thiserror::Error)]
#[error("config validation: {field} — {reason}")]
pub struct ConfigValidationError {
pub field: String,
pub reason: String,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub enum ArchiveCompression {
#[default]
Zstd,
Lz4,
Snappy,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TieredPartitionConfig {
pub memtable_flush_interval_ms: u64,
pub memtable_max_memory_bytes: u64,
pub partition_by: PartitionInterval,
pub merge_after_ms: u64,
pub merge_count: u32,
pub archive_after_ms: u64,
pub archive_compression: ArchiveCompression,
pub retention_period_ms: u64,
pub timestamp_column: String,
pub max_tag_cardinality: u32,
pub wal_enabled: bool,
pub cdc_enabled: bool,
pub sync_resolution_ms: u64,
pub sync_interval_ms: u64,
pub retain_until_synced: bool,
#[serde(default)]
pub battery_aware: bool,
#[serde(default)]
pub bulk_import_threshold_rows: u64,
#[serde(default)]
pub partition_size_target_bytes: u64,
#[serde(default)]
pub compaction_partition_threshold: u32,
}
impl TieredPartitionConfig {
pub fn origin_defaults() -> Self {
Self {
memtable_flush_interval_ms: 10_000,
memtable_max_memory_bytes: 64 * 1024 * 1024,
partition_by: PartitionInterval::Auto,
merge_after_ms: 30 * 86_400_000,
merge_count: 10,
archive_after_ms: 0,
retention_period_ms: 0,
archive_compression: ArchiveCompression::Zstd,
timestamp_column: String::new(),
max_tag_cardinality: 100_000,
wal_enabled: true,
cdc_enabled: false,
sync_resolution_ms: 0,
sync_interval_ms: 0,
retain_until_synced: false,
battery_aware: false,
bulk_import_threshold_rows: 0,
partition_size_target_bytes: 0,
compaction_partition_threshold: 0,
}
}
pub fn lite_defaults() -> Self {
Self {
memtable_flush_interval_ms: 30_000,
memtable_max_memory_bytes: 4 * 1024 * 1024,
partition_by: PartitionInterval::Auto,
merge_after_ms: 7 * 86_400_000,
merge_count: 4,
archive_after_ms: 0,
retention_period_ms: 7 * 86_400_000,
archive_compression: ArchiveCompression::Zstd,
timestamp_column: String::new(),
max_tag_cardinality: 10_000,
wal_enabled: true,
cdc_enabled: false,
sync_resolution_ms: 0,
sync_interval_ms: 30_000,
retain_until_synced: false,
battery_aware: false,
bulk_import_threshold_rows: 1_000_000,
partition_size_target_bytes: 1_024 * 1_024,
compaction_partition_threshold: 20,
}
}
pub fn validate(&self) -> Result<(), ConfigValidationError> {
if self.merge_count < 2 {
return Err(ConfigValidationError {
field: "merge_count".into(),
reason: "must be >= 2".into(),
});
}
if self.retention_period_ms > 0
&& self.archive_after_ms > 0
&& self.retention_period_ms < self.archive_after_ms
{
return Err(ConfigValidationError {
field: "retention_period".into(),
reason: "must be >= archive_after".into(),
});
}
Ok(())
}
}