Skip to content

Commit a28e664

Browse files
rkhouryBurntSushi
authored andcommitted
ignore: check ignore rules before issuing stat calls
This seems like an obvious optimization but becomes critical when filesystem operations even as simple as stat can result in significant overheads; an example of this was a bespoke filesystem layer in Windows that hosted files remotely and would download them on-demand when particular filesystem operations occurred. Users of this system who ensured correct file-type fileters were being used could still get unnecessary file access resulting in large downloads. Fixes #1657, Closes #1660
1 parent 0ca96e0 commit a28e664

File tree

2 files changed

+23
-7
lines changed

2 files changed

+23
-7
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ Security fixes:
2727
This is the public facing issue tracking CVE-2021-3013. ripgrep's README
2828
now contains a section describing how to report a vulnerability.
2929

30+
Performance improvements:
31+
32+
* [PERF #1657](https://github.com/BurntSushi/ripgrep/discussions/1657):
33+
Check if a file should be ignored first before issuing stat calls.
34+
3035
Feature enhancements:
3136

3237
* Added or improved file type filtering for ASP, Bazel, dvc, FlatBuffers,

crates/ignore/src/walk.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -934,15 +934,23 @@ impl Walk {
934934
if ent.depth() == 0 {
935935
return Ok(false);
936936
}
937-
937+
// We ensure that trivial skipping is done before any other potentially
938+
// expensive operations (stat, filesystem other) are done. This seems
939+
// like an obvious optimization but becomes critical when filesystem
940+
// operations even as simple as stat can result in significant
941+
// overheads; an example of this was a bespoke filesystem layer in
942+
// Windows that hosted files remotely and would download them on-demand
943+
// when particular filesystem operations occurred. Users of this system
944+
// who ensured correct file-type fileters were being used could still
945+
// get unnecessary file access resulting in large downloads.
946+
if should_skip_entry(&self.ig, ent) {
947+
return Ok(true);
948+
}
938949
if let Some(ref stdout) = self.skip {
939950
if path_equals(ent, stdout)? {
940951
return Ok(true);
941952
}
942953
}
943-
if should_skip_entry(&self.ig, ent) {
944-
return Ok(true);
945-
}
946954
if self.max_filesize.is_some() && !ent.is_dir() {
947955
return Ok(skip_filesize(
948956
self.max_filesize.unwrap(),
@@ -1549,6 +1557,11 @@ impl<'s> Worker<'s> {
15491557
}
15501558
}
15511559
}
1560+
// N.B. See analogous call in the single-threaded implementation about
1561+
// why it's important for this to come before the checks below.
1562+
if should_skip_entry(ig, &dent) {
1563+
return WalkState::Continue;
1564+
}
15521565
if let Some(ref stdout) = self.skip {
15531566
let is_stdout = match path_equals(&dent, stdout) {
15541567
Ok(is_stdout) => is_stdout,
@@ -1558,7 +1571,6 @@ impl<'s> Worker<'s> {
15581571
return WalkState::Continue;
15591572
}
15601573
}
1561-
let should_skip_path = should_skip_entry(ig, &dent);
15621574
let should_skip_filesize =
15631575
if self.max_filesize.is_some() && !dent.is_dir() {
15641576
skip_filesize(
@@ -1575,8 +1587,7 @@ impl<'s> Worker<'s> {
15751587
} else {
15761588
false
15771589
};
1578-
if !should_skip_path && !should_skip_filesize && !should_skip_filtered
1579-
{
1590+
if !should_skip_filesize && !should_skip_filtered {
15801591
self.send(Work { dent, ignore: ig.clone(), root_device });
15811592
}
15821593
WalkState::Continue

0 commit comments

Comments
 (0)