diff options
| author | Ben Kimock <kimockb@gmail.com> | 2024-07-28 16:54:14 -0400 |
|---|---|---|
| committer | Ben Kimock <kimockb@gmail.com> | 2025-02-24 19:46:48 -0500 |
| commit | cae7c76d509386ea29a90c4001bb8dbc59c79d22 (patch) | |
| tree | 809697abba06a0f819405dbbeb601ee5b7201f37 /compiler/rustc_fs_util/src | |
| parent | 9af8985e059071ea2e0566969a4f140eca73fca9 (diff) | |
| download | rust-cae7c76d509386ea29a90c4001bb8dbc59c79d22.tar.gz rust-cae7c76d509386ea29a90c4001bb8dbc59c79d22.zip | |
Avoid no-op unlink+link dances in incr comp
Diffstat (limited to 'compiler/rustc_fs_util/src')
| -rw-r--r-- | compiler/rustc_fs_util/src/lib.rs | 32 |
1 files changed, 19 insertions, 13 deletions
diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 4e9d21c900d..0df1b243d69 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -55,25 +55,31 @@ pub enum LinkOrCopy { Copy, } -/// Copies `p` into `q`, preferring to use hard-linking if possible. If -/// `q` already exists, it is removed first. +/// Copies `p` into `q`, preferring to use hard-linking if possible. /// The result indicates which of the two operations has been performed. pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<LinkOrCopy> { + // Creating a hard-link will fail if the destination path already exists. We could defensively + // call remove_file in this function, but that pessimizes callers who can avoid such calls. + // Incremental compilation calls this function a lot, and is able to avoid calls that + // would fail the first hard_link attempt. + let p = p.as_ref(); let q = q.as_ref(); - match fs::remove_file(q) { - Ok(()) => (), - Err(err) if err.kind() == io::ErrorKind::NotFound => (), - Err(err) => return Err(err), - } - match fs::hard_link(p, q) { - Ok(()) => Ok(LinkOrCopy::Link), - Err(_) => match fs::copy(p, q) { - Ok(_) => Ok(LinkOrCopy::Copy), - Err(e) => Err(e), - }, + let err = match fs::hard_link(p, q) { + Ok(()) => return Ok(LinkOrCopy::Link), + Err(err) => err, + }; + + if err.kind() == io::ErrorKind::AlreadyExists { + fs::remove_file(q)?; + if fs::hard_link(p, q).is_ok() { + return Ok(LinkOrCopy::Link); + } } + + // Hard linking failed, fall back to copying. + fs::copy(p, q).map(|_| LinkOrCopy::Copy) } #[cfg(any(unix, all(target_os = "wasi", target_env = "p1")))] |
