Improved memory and disk usage, best practices. Review done by GPT 5.2, code written by Claude Opus 4.5

This commit is contained in:
2026-01-22 10:09:52 +01:00
parent 169409738f
commit 7e03af23de
4 changed files with 445 additions and 193 deletions

View File

@@ -1,10 +1,41 @@
use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use chrono::NaiveDate;
use flate2::read::GzDecoder;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::io::{BufRead, BufReader, Read};
use std::path::PathBuf;
/// Enum-based reader to avoid Box<dyn BufRead> heap allocation and dynamic dispatch
pub enum LogReader {
Plain(BufReader<File>),
Gzip(BufReader<GzDecoder<File>>),
}
impl Read for LogReader {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
match self {
LogReader::Plain(r) => r.read(buf),
LogReader::Gzip(r) => r.read(buf),
}
}
}
impl BufRead for LogReader {
fn fill_buf(&mut self) -> std::io::Result<&[u8]> {
match self {
LogReader::Plain(r) => r.fill_buf(),
LogReader::Gzip(r) => r.fill_buf(),
}
}
fn consume(&mut self, amt: usize) {
match self {
LogReader::Plain(r) => r.consume(amt),
LogReader::Gzip(r) => r.consume(amt),
}
}
}
/// Discovers log files for a given date range
pub struct LogFileDiscovery {
base_dir: PathBuf,
@@ -25,9 +56,7 @@ impl LogFileDiscovery {
if let Some(log_file) = self.find_log_for_date(current)? {
files.push(log_file);
}
current = current
.succ_opt()
.ok_or_else(|| anyhow!("Date overflow"))?;
current = current.succ_opt().ok_or_else(|| anyhow!("Date overflow"))?;
}
Ok(files)
@@ -72,26 +101,26 @@ pub struct LogFile {
impl LogFile {
/// Returns a buffered reader for this log file, handling compression transparently
pub fn reader(&self) -> Result<Box<dyn BufRead>> {
pub fn reader(&self) -> Result<LogReader> {
let file = File::open(&self.path)?;
if self.compressed {
let decoder = GzDecoder::new(file);
Ok(Box::new(BufReader::new(decoder)))
Ok(LogReader::Gzip(BufReader::new(decoder)))
} else {
Ok(Box::new(BufReader::new(file)))
Ok(LogReader::Plain(BufReader::new(file)))
}
}
}
/// For reading a single file directly (e.g., for testing)
pub fn read_log_file(path: &str) -> Result<Box<dyn BufRead>> {
pub fn read_log_file(path: &str) -> Result<LogReader> {
let file = File::open(path)?;
if path.ends_with(".gz") {
let decoder = GzDecoder::new(file);
Ok(Box::new(BufReader::new(decoder)))
Ok(LogReader::Gzip(BufReader::new(decoder)))
} else {
Ok(Box::new(BufReader::new(file)))
Ok(LogReader::Plain(BufReader::new(file)))
}
}