use std::path::Path;
use tracing::{info, warn};
use crate::control::cluster::snapshot_applier::DataPlaneSnapshotApplier;
use nodedb_cluster::SnapshotApplier;
pub async fn restore_persisted_snapshots(
data_dir: &Path,
applier: &DataPlaneSnapshotApplier,
) -> crate::Result<usize> {
let recv_dir = data_dir.join("recv_snapshots");
if !recv_dir.exists() {
return Ok(0);
}
let mut snaps: Vec<(u64, std::path::PathBuf)> = Vec::new();
for entry in std::fs::read_dir(&recv_dir)? {
let entry = entry?;
let path = entry.path();
if path.extension().and_then(|e| e.to_str()) != Some("snap") {
continue;
}
let group_id = match path
.file_stem()
.and_then(|s| s.to_str())
.and_then(|s| s.parse::<u64>().ok())
{
Some(id) => id,
None => {
warn!(
path = %path.display(),
"boot-restore: skipping snapshot with non-numeric group id stem"
);
continue;
}
};
snaps.push((group_id, path));
}
snaps.sort_by_key(|(group_id, _)| *group_id);
let mut applied = 0usize;
for (group_id, path) in snaps {
let bytes = std::fs::read(&path)?;
if bytes.is_empty() {
warn!(
group_id,
path = %path.display(),
"boot-restore: skipping empty persisted snapshot"
);
continue;
}
applier
.apply_snapshot(group_id, &bytes)
.await
.map_err(|e| crate::Error::Internal {
detail: format!("boot-restore: apply group {group_id} snapshot: {e}"),
})?;
info!(
group_id,
bytes = bytes.len(),
"boot-restore: re-installed persisted group snapshot"
);
applied += 1;
}
Ok(applied)
}