use crate::utilization_tracker::UtilizationTracker;
use noxu_util::{Lsn, NULL_LSN};
use std::collections::HashSet;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct CheckLsnsResult {
pub obsolete_contains_live: Vec<Lsn>,
}
impl CheckLsnsResult {
pub fn is_ok(&self) -> bool {
self.obsolete_contains_live.is_empty()
}
}
pub fn obsolete_lsn_set(tracker: &UtilizationTracker) -> HashSet<Lsn> {
let mut obsolete = HashSet::new();
for (&file_num, tracked) in tracker.get_tracked_files() {
for &offset in tracked.get_obsolete_offsets() {
obsolete.insert(Lsn::new(file_num, offset));
}
}
obsolete
}
pub fn check_lsns<I>(
live_lsns: I,
tracker: &UtilizationTracker,
) -> CheckLsnsResult
where
I: IntoIterator<Item = Lsn>,
{
let obsolete = obsolete_lsn_set(tracker);
let mut result = CheckLsnsResult::default();
for lsn in live_lsns {
if lsn == NULL_LSN {
continue;
}
if obsolete.contains(&lsn) {
result.obsolete_contains_live.push(lsn);
}
}
result
}
#[cfg(test)]
mod tests {
use super::*;
use crate::utilization_tracker::UtilizationTracker;
#[test]
fn test_check_lsns_healthy_passes() {
let mut tracker = UtilizationTracker::new(true);
tracker.count_obsolete_node(1, 100, 50, true, None);
tracker.count_obsolete_node(1, 200, 50, true, None);
let live = vec![Lsn::new(1, 300), Lsn::new(1, 400), Lsn::new(2, 10)];
let result = check_lsns(live, &tracker);
assert!(result.is_ok(), "healthy env must pass: {result:?}");
}
#[test]
fn test_check_lsns_detects_live_in_obsolete() {
let mut tracker = UtilizationTracker::new(true);
tracker.count_obsolete_node(1, 300, 50, true, None);
let live = vec![Lsn::new(1, 300), Lsn::new(1, 400)];
let result = check_lsns(live, &tracker);
assert!(!result.is_ok(), "violation must be detected");
assert_eq!(result.obsolete_contains_live, vec![Lsn::new(1, 300)]);
}
#[test]
fn test_check_lsns_ignores_null_lsn() {
let tracker = UtilizationTracker::new(true);
let live = vec![NULL_LSN, Lsn::new(1, 10)];
let result = check_lsns(live, &tracker);
assert!(result.is_ok());
}
}