use crate::discarded_prune_limits::Limits;
use crate::discarded_prune_stamps::{DAY_MILLISECONDS, STAMP_RESOLUTION_MILLISECONDS, Stamped, YOUNG_FLOOR_MILLISECONDS};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Reason {
Age,
Size,
}
impl Reason {
pub fn word(self) -> &'static str {
return match self {
Reason::Age => "age",
Reason::Size => "size",
};
}
}
fn age_of(entry: &Stamped, now_millis: i64) -> i128 {
return i128::from(now_millis) - (i128::from(entry.millis) + i128::from(STAMP_RESOLUTION_MILLISECONDS));
}
fn is_reachable(entry: &Stamped, now_millis: i64, keep: Option<&str>) -> bool {
return age_of(entry, now_millis) >= i128::from(YOUNG_FLOOR_MILLISECONDS) && keep != Some(entry.name.as_str());
}
fn is_doomed(doomed: &[(usize, Reason)], index: usize) -> bool {
for (gone, _reason) in doomed {
if *gone == index {
return true;
}
}
return false;
}
pub fn plan(entries: &[Stamped], now_millis: i64, limits: Limits, keep: Option<&str>) -> Vec<(usize, Reason)> {
let age_limit: i128 = i128::from(limits.max_age_days) * i128::from(DAY_MILLISECONDS);
let mut doomed: Vec<(usize, Reason)> = Vec::new();
for (index, entry) in entries.iter().enumerate() {
if is_reachable(entry, now_millis, keep) && age_of(entry, now_millis) > age_limit {
doomed.push((index, Reason::Age));
}
}
let mut total: u128 = 0;
for (index, entry) in entries.iter().enumerate() {
if !is_doomed(&doomed, index) {
total += entry.bytes;
}
}
let mut candidates: Vec<(i64, &String, usize)> = Vec::new();
for (index, entry) in entries.iter().enumerate() {
if is_reachable(entry, now_millis, keep) && !is_doomed(&doomed, index) {
candidates.push((entry.millis, &entry.name, index));
}
}
candidates.sort();
for (_millis, _name, index) in candidates {
if total <= u128::from(limits.max_bytes) {
break;
}
total = total.saturating_sub(entries[index].bytes);
doomed.push((index, Reason::Size));
}
return doomed;
}