use log::debug;
use crate::config::PmbsConfigKeep;
mod ls;
mod safe_rm_subvol;
pub use ls::{Snapshot, get_re_t, get_re_year, ls_snapshot};
pub use safe_rm_subvol::{get_re_safe_check_path, safe_rm_subvol_list};
#[derive(Debug, Clone)]
struct KeepIter {
rule: Vec<PmbsConfigKeep>,
i: usize,
r: Option<PmbsConfigKeep>,
}
impl KeepIter {
pub fn new(rule: Vec<PmbsConfigKeep>) -> Self {
let r = if rule.len() > 0 {
Some(rule[0].clone())
} else {
None
};
Self { rule, i: 0, r }
}
fn check_load_next_rule(&mut self) {
match &mut self.r {
Some(r) => {
if r.n < 1 {
self.r = None;
self.check_load_next_rule();
}
}
None => {
if self.rule.len() > (self.i + 1) {
self.i += 1;
self.r = Some(self.rule[self.i].clone());
}
}
}
}
}
impl Iterator for KeepIter {
type Item = u64;
fn next(&mut self) -> Option<u64> {
self.check_load_next_rule();
match &mut self.r {
Some(r) => {
r.n -= 1;
Some(r.s)
}
None => None,
}
}
}
pub fn decide(
rule: Vec<PmbsConfigKeep>,
mut snapshot: Vec<Snapshot>,
) -> (Vec<Snapshot>, Vec<Snapshot>) {
fn debug_snapshot_list(list: &Vec<Snapshot>) -> String {
format!("{:?}", list.iter().map(|x| x.t).collect::<Vec<_>>())
}
debug!("rule {:?}", rule);
snapshot.sort_by(|a, b| b.t.cmp(&a.t));
debug!("snapshot {}", debug_snapshot_list(&snapshot));
let mut ki = KeepIter::new(rule);
let mut keep: Vec<Snapshot> = Vec::new();
let mut clean: Vec<Snapshot> = Vec::new();
const KEEP_LATEST: u64 = 300;
const KEEP_S: u64 = 10;
fn clear_tmp(tmp: &mut Vec<Snapshot>, keep: &mut Vec<Snapshot>, clean: &mut Vec<Snapshot>) {
if let Some(i) = tmp.pop() {
keep.push(i);
}
clear_tmp_all(tmp, clean);
}
fn clear_tmp_all(tmp: &mut Vec<Snapshot>, clean: &mut Vec<Snapshot>) {
loop {
match tmp.pop() {
Some(i) => {
clean.push(i);
}
None => {
break;
}
}
}
}
if snapshot.len() > 0 {
let mut rule = ki.next();
let t0 = snapshot[0].t - KEEP_LATEST;
let mut t = t0;
let mut tmp: Vec<Snapshot> = Vec::new();
for i in snapshot {
if (i.t + KEEP_S) > t0 {
keep.push(i.clone());
t = i.t;
continue;
}
match rule {
Some(s) => {
if i.t > (t - s + KEEP_S) {
tmp.push(i.clone());
} else {
clear_tmp(&mut tmp, &mut keep, &mut clean);
t = i.t;
tmp.push(i);
rule = ki.next();
}
}
None => {
clear_tmp_all(&mut tmp, &mut clean);
clean.push(i.clone());
}
}
}
clear_tmp(&mut tmp, &mut keep, &mut clean);
}
clean.sort_by(|a, b| a.t.cmp(&b.t));
debug!("keep {}", debug_snapshot_list(&keep));
debug!("clean {}", debug_snapshot_list(&clean));
(keep, clean)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn keep_iter() {
let mut ki = KeepIter::new(vec![
PmbsConfigKeep::new_sn(5, 3),
PmbsConfigKeep::new_sn(20, 2),
PmbsConfigKeep::new_sn(60, 1),
]);
assert_eq!(ki.next(), Some(5));
assert_eq!(ki.next(), Some(5));
assert_eq!(ki.next(), Some(5));
assert_eq!(ki.next(), Some(20));
assert_eq!(ki.next(), Some(20));
assert_eq!(ki.next(), Some(60));
assert_eq!(ki.next(), None);
assert_eq!(ki.next(), None);
}
}