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:
51
src/files.rs
51
src/files.rs
@@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user