use std::collections::HashMap;
use std::path::{Path, PathBuf};
use rkyv::{Archive, Deserialize, Serialize};
use crate::error::{HoldError, Result};
#[cfg(test)]
mod tests;
pub const METADATA_VERSION: u32 = 4;
#[derive(Archive, Deserialize, Serialize, Debug, Clone, PartialEq)]
pub struct FileState {
#[rkyv(with = rkyv::with::AsString)]
pub path: PathBuf,
pub size: u64,
pub hash: String,
pub mtime_nanos: u128,
}
#[derive(Archive, Deserialize, Serialize, Debug, Clone)]
pub struct StateMetadata {
pub version: u32,
pub files: HashMap<String, FileState>,
pub last_gc_mtime_nanos: Option<u128>,
pub gc_metrics: GcMetrics,
}
impl StateMetadata {
pub fn new() -> Self {
Self {
version: METADATA_VERSION,
files: HashMap::new(),
last_gc_mtime_nanos: None,
gc_metrics: GcMetrics::default(),
}
}
pub fn max_mtime_nanos(&self) -> Option<u128> {
self.files.values().map(|state| state.mtime_nanos).max()
}
pub fn upsert(&mut self, state: FileState) -> Result<()> {
let key = state
.path
.to_str()
.ok_or_else(|| HoldError::InvalidUtf8Path(state.path.clone()))?
.to_string();
self.files.insert(key, state);
Ok(())
}
pub fn remove(&mut self, path: &Path) -> Result<Option<FileState>> {
let key = path
.to_str()
.ok_or_else(|| HoldError::InvalidUtf8Path(path.to_path_buf()))?;
Ok(self.files.remove(key))
}
pub fn get(&self, path: &Path) -> Result<Option<&FileState>> {
let key = path
.to_str()
.ok_or_else(|| HoldError::InvalidUtf8Path(path.to_path_buf()))?;
Ok(self.files.get(key))
}
pub fn contains(&self, path: &Path) -> Result<bool> {
let key = path
.to_str()
.ok_or_else(|| HoldError::InvalidUtf8Path(path.to_path_buf()))?;
Ok(self.files.contains_key(key))
}
pub fn len(&self) -> usize {
self.files.len()
}
pub fn is_empty(&self) -> bool {
self.files.is_empty()
}
}
impl Default for StateMetadata {
fn default() -> Self {
Self::new()
}
}
#[derive(Archive, Deserialize, Serialize, Debug, Clone, PartialEq, Default)]
pub struct GcMetrics {
pub runs: u32,
pub seed_initial_size: Option<u64>,
pub recent_initial_sizes: Vec<u64>,
pub recent_bytes_freed: Vec<u64>,
pub last_suggested_cap: Option<u64>,
pub recent_final_sizes: Vec<u64>,
pub last_cap_trace: Option<CapTrace>,
}
#[derive(Archive, Deserialize, Serialize, Debug, Clone, PartialEq, Default)]
pub struct CapTrace {
pub baseline: u64,
pub growth_budget: u64,
pub observed_growth_pct: u64,
pub clamp_reason: String,
}