summaryrefslogtreecommitdiffstats
path: root/ignore
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2018-02-20 19:32:58 -0500
committerAndrew Gallant <jamslam@gmail.com>2018-02-20 19:50:52 -0500
commitd65966efbca5cfe2afdc6930e868d02e53591a43 (patch)
tree09a109f4a2e3c504ac61eee6d94b8fa4df3b0ef7 /ignore
parent597bf04a56d43aa9c0eb0f8fbb90c9d51c53656c (diff)
ignore: fix performance regression on Windows
This commit fixes a performance regression in Windows that resulted from fallout from fixing #705. In particular, we introduced an additional stat call for every single directory entry, which can be quite disastrous for performance. There is a corresponding companion PR that fixes the same bug in walkdir: https://github.com/BurntSushi/walkdir/pull/96 Fixes #820
Diffstat (limited to 'ignore')
-rw-r--r--ignore/src/walk.rs47
1 files changed, 39 insertions, 8 deletions
diff --git a/ignore/src/walk.rs b/ignore/src/walk.rs
index 6a260f85..c185a288 100644
--- a/ignore/src/walk.rs
+++ b/ignore/src/walk.rs
@@ -249,6 +249,14 @@ struct DirEntryRaw {
/// The underlying inode number (Unix only).
#[cfg(unix)]
ino: u64,
+ /// The underlying metadata (Windows only). We store this on Windows
+ /// because this comes for free while reading a directory.
+ ///
+ /// We use this to determine whether an entry is a directory or not, which
+ /// works around a bug in Rust's standard library:
+ /// https://github.com/rust-lang/rust/issues/46484
+ #[cfg(windows)]
+ metadata: fs::Metadata,
}
impl fmt::Debug for DirEntryRaw {
@@ -274,6 +282,20 @@ impl DirEntryRaw {
}
fn metadata(&self) -> Result<Metadata, Error> {
+ self.metadata_internal()
+ }
+
+ #[cfg(windows)]
+ fn metadata_internal(&self) -> Result<fs::Metadata, Error> {
+ if self.follow_link {
+ fs::metadata(&self.path)
+ } else {
+ Ok(self.metadata.clone())
+ }.map_err(|err| Error::Io(io::Error::from(err)).with_path(&self.path))
+ }
+
+ #[cfg(not(windows))]
+ fn metadata_internal(&self) -> Result<fs::Metadata, Error> {
if self.follow_link {
fs::metadata(&self.path)
} else {
@@ -309,21 +331,29 @@ impl DirEntryRaw {
err: Box::new(err),
}
})?;
- Ok(DirEntryRaw::from_entry_os(depth, ent, ty))
+ DirEntryRaw::from_entry_os(depth, ent, ty)
}
- #[cfg(not(unix))]
+ #[cfg(windows)]
fn from_entry_os(
depth: usize,
ent: &fs::DirEntry,
ty: fs::FileType,
- ) -> DirEntryRaw {
- DirEntryRaw {
+ ) -> Result<DirEntryRaw, Error> {
+ let md = ent.metadata().map_err(|err| {
+ let err = Error::Io(io::Error::from(err)).with_path(ent.path());
+ Error::WithDepth {
+ depth: depth,
+ err: Box::new(err),
+ }
+ })?;
+ Ok(DirEntryRaw {
path: ent.path(),
ty: ty,
follow_link: false,
depth: depth,
- }
+ metadata: md,
+ })
}
#[cfg(unix)]
@@ -331,16 +361,16 @@ impl DirEntryRaw {
depth: usize,
ent: &fs::DirEntry,
ty: fs::FileType,
- ) -> DirEntryRaw {
+ ) -> Result<DirEntryRaw, Error> {
use std::os::unix::fs::DirEntryExt;
- DirEntryRaw {
+ Ok(DirEntryRaw {
path: ent.path(),
ty: ty,
follow_link: false,
depth: depth,
ino: ent.ino(),
- }
+ })
}
#[cfg(not(unix))]
@@ -353,6 +383,7 @@ impl DirEntryRaw {
ty: md.file_type(),
follow_link: true,
depth: depth,
+ metadata: md,
})
}