perf: cache SECRET_PATTERNS's RegexSet (#2570)

Improves the performance of `History::should_save` by constructing the
`SECRET_PATTERNS` `RegexSet` only once with a `LazyLock`.

This speeds up `atuin history prune` by ~100x (~7s to ~70ms on my
machine) (lol).
This commit is contained in:
DaniPopes
2025-02-19 06:07:30 +01:00
committed by GitHub
parent 7be6694b85
commit 17223da048
2 changed files with 13 additions and 7 deletions

View File

@@ -8,10 +8,10 @@ use atuin_common::record::DecryptedData;
use atuin_common::utils::uuid_v7; use atuin_common::utils::uuid_v7;
use eyre::{bail, eyre, Result}; use eyre::{bail, eyre, Result};
use regex::RegexSet;
use crate::secrets::SECRET_PATTERNS_RE;
use crate::settings::Settings;
use crate::utils::get_host_user; use crate::utils::get_host_user;
use crate::{secrets::SECRET_PATTERNS, settings::Settings};
use time::OffsetDateTime; use time::OffsetDateTime;
mod builder; mod builder;
@@ -374,13 +374,10 @@ impl History {
} }
pub fn should_save(&self, settings: &Settings) -> bool { pub fn should_save(&self, settings: &Settings) -> bool {
let secret_regex = SECRET_PATTERNS.iter().map(|f| f.1);
let secret_regex = RegexSet::new(secret_regex).expect("Failed to build secrets regex");
!(self.command.starts_with(' ') !(self.command.starts_with(' ')
|| settings.history_filter.is_match(&self.command) || settings.history_filter.is_match(&self.command)
|| settings.cwd_filter.is_match(&self.cwd) || settings.cwd_filter.is_match(&self.cwd)
|| (secret_regex.is_match(&self.command)) && settings.secrets_filter) || (settings.secrets_filter && SECRET_PATTERNS_RE.is_match(&self.command)))
} }
} }

View File

@@ -1,11 +1,14 @@
// This file will probably trigger a lot of scanners. Sorry. // This file will probably trigger a lot of scanners. Sorry.
use regex::RegexSet;
use std::sync::LazyLock;
pub enum TestValue<'a> { pub enum TestValue<'a> {
Single(&'a str), Single(&'a str),
Multiple(&'a [&'a str]), Multiple(&'a [&'a str]),
} }
// A list of (name, regex, test), where test should match against regex /// A list of `(name, regex, test)`, where `test` should match against `regex`.
pub static SECRET_PATTERNS: &[(&str, &str, TestValue)] = &[ pub static SECRET_PATTERNS: &[(&str, &str, TestValue)] = &[
( (
"AWS Access Key ID", "AWS Access Key ID",
@@ -114,6 +117,12 @@ pub static SECRET_PATTERNS: &[(&str, &str, TestValue)] = &[
), ),
]; ];
/// The `regex` expressions from [`SECRET_PATTERNS`] compiled into a `RegexSet`.
pub static SECRET_PATTERNS_RE: LazyLock<RegexSet> = LazyLock::new(|| {
let exprs = SECRET_PATTERNS.iter().map(|f| f.1);
RegexSet::new(exprs).expect("Failed to build secrets regex")
});
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use regex::Regex; use regex::Regex;