use crate::tracked_file_summary::TrackedFileSummary;
use hashbrown::HashMap;
#[derive(Debug)]
pub struct UtilizationTracker {
tracked_files: HashMap<u32, TrackedFileSummary>,
tracked_bytes: i64,
track_detail: bool,
}
impl UtilizationTracker {
pub fn new(track_detail: bool) -> Self {
Self { tracked_files: HashMap::new(), tracked_bytes: 0, track_detail }
}
pub fn track_obsolete(
&mut self,
file_number: u32,
offset: u32,
size: i32,
count_as_ln: bool,
) {
let tracked =
self.tracked_files.entry(file_number).or_insert_with(|| {
TrackedFileSummary::new(file_number, self.track_detail)
});
tracked.add_obsolete_offset(offset);
let summary = tracked.get_summary_mut();
if count_as_ln {
summary.obsolete_ln_count += 1;
summary.obsolete_ln_size += size;
summary.obsolete_ln_size_counted += 1;
} else {
summary.obsolete_in_count += 1;
}
self.update_tracked_bytes();
}
pub fn count_new_log_entry(
&mut self,
file_number: u32,
size: i32,
is_ln: bool,
is_in: bool,
) {
let tracked =
self.tracked_files.entry(file_number).or_insert_with(|| {
TrackedFileSummary::new(file_number, self.track_detail)
});
let summary = tracked.get_summary_mut();
summary.total_count += 1;
summary.total_size += size;
if is_ln {
summary.total_ln_count += 1;
summary.total_ln_size += size;
if size > summary.max_ln_size {
summary.max_ln_size = size;
}
}
if is_in {
summary.total_in_count += 1;
summary.total_in_size += size;
}
self.update_tracked_bytes();
}
pub fn get_tracked_summary(
&self,
file_number: u32,
) -> Option<&TrackedFileSummary> {
self.tracked_files.get(&file_number)
}
pub fn get_tracked_summary_mut(
&mut self,
file_number: u32,
) -> Option<&mut TrackedFileSummary> {
self.tracked_files.get_mut(&file_number)
}
pub fn get_tracked_files(&self) -> &HashMap<u32, TrackedFileSummary> {
&self.tracked_files
}
pub fn get_tracked_files_mut(
&mut self,
) -> &mut HashMap<u32, TrackedFileSummary> {
&mut self.tracked_files
}
pub fn remove_all_tracked_files(
&mut self,
) -> HashMap<u32, TrackedFileSummary> {
self.tracked_bytes = 0;
std::mem::take(&mut self.tracked_files)
}
pub fn get_bytes_tracked(&self) -> i64 {
self.tracked_bytes
}
pub fn get_tracked_file_count(&self) -> usize {
self.tracked_files.len()
}
pub fn clear(&mut self) {
self.tracked_files.clear();
self.tracked_bytes = 0;
}
fn update_tracked_bytes(&mut self) {
self.tracked_bytes =
self.tracked_files.values().map(|t| t.memory_size() as i64).sum();
}
}
impl Default for UtilizationTracker {
fn default() -> Self {
Self::new(true)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new() {
let tracker = UtilizationTracker::new(true);
assert_eq!(tracker.get_tracked_file_count(), 0);
assert_eq!(tracker.get_bytes_tracked(), 0);
}
#[test]
fn test_track_obsolete_ln() {
let mut tracker = UtilizationTracker::new(true);
tracker.track_obsolete(1, 100, 50, true);
let tracked = tracker.get_tracked_summary(1).unwrap();
assert_eq!(tracked.get_summary().obsolete_ln_count, 1);
assert_eq!(tracked.get_summary().obsolete_ln_size, 50);
assert_eq!(tracked.get_summary().obsolete_ln_size_counted, 1);
assert_eq!(tracked.obsolete_offset_count(), 1);
}
#[test]
fn test_track_obsolete_in() {
let mut tracker = UtilizationTracker::new(true);
tracker.track_obsolete(1, 100, 50, false);
let tracked = tracker.get_tracked_summary(1).unwrap();
assert_eq!(tracked.get_summary().obsolete_in_count, 1);
assert_eq!(tracked.get_summary().obsolete_ln_count, 0);
}
#[test]
fn test_count_new_ln_entry() {
let mut tracker = UtilizationTracker::new(true);
tracker.count_new_log_entry(1, 100, true, false);
let tracked = tracker.get_tracked_summary(1).unwrap();
assert_eq!(tracked.get_summary().total_count, 1);
assert_eq!(tracked.get_summary().total_size, 100);
assert_eq!(tracked.get_summary().total_ln_count, 1);
assert_eq!(tracked.get_summary().total_ln_size, 100);
assert_eq!(tracked.get_summary().max_ln_size, 100);
}
#[test]
fn test_count_new_in_entry() {
let mut tracker = UtilizationTracker::new(true);
tracker.count_new_log_entry(1, 200, false, true);
let tracked = tracker.get_tracked_summary(1).unwrap();
assert_eq!(tracked.get_summary().total_count, 1);
assert_eq!(tracked.get_summary().total_size, 200);
assert_eq!(tracked.get_summary().total_in_count, 1);
assert_eq!(tracked.get_summary().total_in_size, 200);
}
#[test]
fn test_max_ln_size_tracking() {
let mut tracker = UtilizationTracker::new(true);
tracker.count_new_log_entry(1, 50, true, false);
tracker.count_new_log_entry(1, 100, true, false);
tracker.count_new_log_entry(1, 75, true, false);
let tracked = tracker.get_tracked_summary(1).unwrap();
assert_eq!(tracked.get_summary().max_ln_size, 100);
}
#[test]
fn test_multiple_files() {
let mut tracker = UtilizationTracker::new(true);
tracker.count_new_log_entry(1, 100, true, false);
tracker.count_new_log_entry(2, 200, true, false);
tracker.count_new_log_entry(3, 300, true, false);
assert_eq!(tracker.get_tracked_file_count(), 3);
assert!(tracker.get_tracked_summary(1).is_some());
assert!(tracker.get_tracked_summary(2).is_some());
assert!(tracker.get_tracked_summary(3).is_some());
}
#[test]
fn test_track_detail_disabled() {
let mut tracker = UtilizationTracker::new(false);
tracker.track_obsolete(1, 100, 50, true);
let tracked = tracker.get_tracked_summary(1).unwrap();
assert_eq!(tracked.get_summary().obsolete_ln_count, 1);
assert_eq!(tracked.obsolete_offset_count(), 0);
}
#[test]
fn test_remove_all_tracked_files() {
let mut tracker = UtilizationTracker::new(true);
tracker.count_new_log_entry(1, 100, true, false);
tracker.count_new_log_entry(2, 200, true, false);
let tracked_files = tracker.remove_all_tracked_files();
assert_eq!(tracked_files.len(), 2);
assert_eq!(tracker.get_tracked_file_count(), 0);
assert_eq!(tracker.get_bytes_tracked(), 0);
}
#[test]
fn test_clear() {
let mut tracker = UtilizationTracker::new(true);
tracker.count_new_log_entry(1, 100, true, false);
tracker.track_obsolete(1, 100, 50, true);
tracker.clear();
assert_eq!(tracker.get_tracked_file_count(), 0);
assert_eq!(tracker.get_bytes_tracked(), 0);
}
#[test]
fn test_get_tracked_files_mut() {
let mut tracker = UtilizationTracker::new(true);
tracker.count_new_log_entry(1, 100, true, false);
{
let files = tracker.get_tracked_files_mut();
if let Some(tracked) = files.get_mut(&1) {
tracked.get_summary_mut().total_count += 10;
}
}
let tracked = tracker.get_tracked_summary(1).unwrap();
assert_eq!(tracked.get_summary().total_count, 11);
}
#[test]
fn test_bytes_tracked_increases() {
let mut tracker = UtilizationTracker::new(true);
let initial_bytes = tracker.get_bytes_tracked();
tracker.count_new_log_entry(1, 100, true, false);
let after_entry = tracker.get_bytes_tracked();
assert!(after_entry > initial_bytes);
tracker.track_obsolete(1, 100, 50, true);
let after_obsolete = tracker.get_bytes_tracked();
assert!(after_obsolete >= after_entry);
}
#[test]
fn test_accumulate_entries_same_file() {
let mut tracker = UtilizationTracker::new(true);
for i in 0..10 {
tracker.count_new_log_entry(1, 100, true, false);
tracker.track_obsolete(1, i * 100, 50, true);
}
let tracked = tracker.get_tracked_summary(1).unwrap();
assert_eq!(tracked.get_summary().total_count, 10);
assert_eq!(tracked.get_summary().obsolete_ln_count, 10);
assert_eq!(tracked.obsolete_offset_count(), 10);
}
#[test]
fn test_default() {
let tracker = UtilizationTracker::default();
assert_eq!(tracker.get_tracked_file_count(), 0);
}
}