diff --git a/src/compression_engine/program.rs b/src/compression_engine/program.rs index 8d906ae..d36db87 100644 --- a/src/compression_engine/program.rs +++ b/src/compression_engine/program.rs @@ -7,6 +7,9 @@ use std::io::{Read, Write}; use std::os::unix::fs::PermissionsExt; use std::path::PathBuf; use std::process::{Child, Command, Stdio}; +use std::collections::HashMap; +use std::sync::Mutex; +use once_cell::sync::Lazy; use crate::compression_engine::CompressionEngine; @@ -78,22 +81,52 @@ impl CompressionEngineProgram { } } +// Cache for program lookup results to avoid redundant filesystem operations +static PROGRAM_CACHE: Lazy>>> = + Lazy::new(|| Mutex::new(HashMap::new())); + fn get_program_path(program: &str) -> Result { + // Check cache first + { + let cache = PROGRAM_CACHE.lock().unwrap(); + if let Some(result) = cache.get(program) { + return match result { + Some(path) => Ok(path.clone()), + None => Err(anyhow!("Unable to find binary {} in PATH", program)), + }; + } + } + debug!("COMPRESSION: Looking for executable: {}", program); - if let Ok(path) = env::var("PATH") { + let result = if let Ok(path) = env::var("PATH") { + let mut found_path = None; for p in path.split(':') { let p_str = format!("{}/{}", p, program); - let stat = fs::metadata(p_str.clone()); - if let Ok(stat) = stat { - let md = stat; - let permissions = md.permissions(); - if md.is_file() && permissions.mode() & 0o111 != 0 { - return Ok(p_str); + if let Ok(stat) = fs::metadata(&p_str) { + let permissions = stat.permissions(); + if stat.is_file() && permissions.mode() & 0o111 != 0 { + found_path = Some(p_str); + break; } } } + found_path + } else { + None + }; + + // Store result in cache + let mut cache = PROGRAM_CACHE.lock().unwrap(); + match &result { + Some(path) => { + cache.insert(program.to_string(), Some(path.clone())); + Ok(path.clone()) + } + None => { + cache.insert(program.to_string(), None); + Err(anyhow!("Unable to find binary {} in PATH", program)) + } } - Err(anyhow!("Unable to find binary {} in PATH", program)) } impl CompressionEngine for CompressionEngineProgram { diff --git a/src/meta_plugin/program.rs b/src/meta_plugin/program.rs index 19c1cc1..be38488 100644 --- a/src/meta_plugin/program.rs +++ b/src/meta_plugin/program.rs @@ -7,6 +7,9 @@ use std::io; use std::io::Write; use std::os::unix::fs::PermissionsExt; use std::process::{Command, Stdio}; +use std::collections::HashMap; +use std::sync::Mutex; +use once_cell::sync::Lazy; use crate::meta_plugin::MetaPlugin; @@ -132,20 +135,50 @@ impl MetaPlugin for MetaPluginProgram { } +// Cache for program lookup results to avoid redundant filesystem operations +static PROGRAM_CACHE: Lazy>>> = + Lazy::new(|| Mutex::new(HashMap::new())); + fn get_program_path(program: &str) -> Result { + // Check cache first + { + let cache = PROGRAM_CACHE.lock().unwrap(); + if let Some(result) = cache.get(program) { + return match result { + Some(path) => Ok(path.clone()), + None => Err(anyhow!("Unable to find binary {} in PATH", program)), + }; + } + } + debug!("META: Looking for executable: {}", program); - if let Ok(path) = env::var("PATH") { + let result = if let Ok(path) = env::var("PATH") { + let mut found_path = None; for p in path.split(':') { let p_str = format!("{}/{}", p, program); - let stat = fs::metadata(p_str.clone()); - if let Ok(stat) = stat { - let md = stat; - let permissions = md.permissions(); - if md.is_file() && permissions.mode() & 0o111 != 0 { - return Ok(p_str); + if let Ok(stat) = fs::metadata(&p_str) { + let permissions = stat.permissions(); + if stat.is_file() && permissions.mode() & 0o111 != 0 { + found_path = Some(p_str); + break; } } } + found_path + } else { + None + }; + + // Store result in cache + let mut cache = PROGRAM_CACHE.lock().unwrap(); + match &result { + Some(path) => { + cache.insert(program.to_string(), Some(path.clone())); + Ok(path.clone()) + } + None => { + cache.insert(program.to_string(), None); + Err(anyhow!("Unable to find binary {} in PATH", program)) + } } - Err(anyhow!("Unable to find binary {} in PATH", program)) }