diff --git a/Cargo.lock b/Cargo.lock index 2b3381ce..0bccda26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -311,6 +311,7 @@ dependencies = [ "portable-atomic", "rayon", "regex", + "rustc-hash", "serde", "serde_json", "stfu8", @@ -707,6 +708,12 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "323c417e1d9665a65b263ec744ba09030cfb277e9daa0b018a4ab62e57bc8189" +[[package]] +name = "rustc-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" + [[package]] name = "rustix" version = "1.1.4" diff --git a/Cargo.toml b/Cargo.toml index 8bb0cf50..cdd55995 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ serde_json = "1.0" sysinfo = "0.39" ctrlc = "3" chrono = "0.4" +rustc-hash = "2" [target.'cfg(not(target_has_atomic = "64"))'.dependencies] portable-atomic = "1.4" diff --git a/src/dir_walker.rs b/src/dir_walker.rs index 11d331b2..c245d6ad 100644 --- a/src/dir_walker.rs +++ b/src/dir_walker.rs @@ -20,6 +20,8 @@ use std::path::PathBuf; use std::collections::HashSet; +use rustc_hash::FxHashSet; + use crate::node::build_node; use std::fs::DirEntry; @@ -68,7 +70,10 @@ struct PendingDir { } pub fn walk_it(dirs: HashSet, walk_data: &WalkData) -> Vec { - let mut inodes = HashSet::new(); + // FxHash is substantially faster than std's default SipHash on small + // primitive keys. DoS resistance is irrelevant here; the keys are + // (inode, device) pairs from the filesystem, not user input. + let mut inodes: FxHashSet<(u64, u64)> = FxHashSet::default(); let mut top_level_nodes: Vec = Vec::new(); for d in dirs { @@ -126,7 +131,7 @@ pub fn walk_it(dirs: HashSet, walk_data: &WalkData) -> Vec { } // Remove files which have the same inode, we don't want to double count them. -fn clean_inodes(x: Node, inodes: &mut HashSet<(u64, u64)>, walk_data: &WalkData) -> Option { +fn clean_inodes(x: Node, inodes: &mut FxHashSet<(u64, u64)>, walk_data: &WalkData) -> Option { if !walk_data.use_apparent_size && let Some(id) = x.inode_device && !inodes.insert(id) @@ -522,7 +527,7 @@ mod tests { #[test] #[allow(clippy::redundant_clone)] fn test_should_ignore_file() { - let mut inodes = HashSet::new(); + let mut inodes = FxHashSet::default(); let n = create_node(); let walkdata = create_walker(false); @@ -539,7 +544,7 @@ mod tests { #[test] #[allow(clippy::redundant_clone)] fn test_should_not_ignore_files_if_using_apparent_size() { - let mut inodes = HashSet::new(); + let mut inodes = FxHashSet::default(); let n = create_node(); let walkdata = create_walker(true);