Don't panic when failing to initialize incremental directory.

This commit is contained in:
Eric Huss 2021-05-25 11:48:59 -07:00
parent cdbe288897
commit 074d667cf5
7 changed files with 49 additions and 27 deletions

View file

@ -3876,6 +3876,7 @@ dependencies = [
"rand 0.7.3",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_fs_util",
"rustc_graphviz",
"rustc_hir",

View file

@ -34,7 +34,7 @@ tempfile = "3.2"
version = "0.11"
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["fileapi", "psapi"] }
winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] }
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
memmap2 = "0.2.1"

View file

@ -54,6 +54,10 @@ pub fn new(p: &Path,
Ok(Lock { _file: file })
}
}
pub fn error_unsupported(err: &io::Error) -> bool {
matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
}
}
// Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by
@ -103,6 +107,10 @@ pub fn new(p: &Path,
Ok(Lock { file })
}
}
pub fn error_unsupported(err: &io::Error) -> bool {
matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS))
}
}
impl Drop for Lock {
@ -122,6 +130,7 @@ fn drop(&mut self) {
use std::mem;
use std::os::windows::prelude::*;
use winapi::shared::winerror::ERROR_INVALID_FUNCTION;
use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK};
use winapi::um::fileapi::LockFileEx;
use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE};
@ -194,6 +203,10 @@ pub fn new(p: &Path,
Ok(Lock { _file: file })
}
}
pub fn error_unsupported(err: &io::Error) -> bool {
err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32)
}
}
// Note that we don't need a Drop impl on the Windows: The file is unlocked

View file

@ -20,3 +20,4 @@ rustc_macros = { path = "../rustc_macros" }
rustc_span = { path = "../rustc_span" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_session = { path = "../rustc_session" }
rustc_errors = { path = "../rustc_errors" }

View file

@ -106,6 +106,7 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::svh::Svh;
use rustc_data_structures::{base_n, flock};
use rustc_errors::ErrorReported;
use rustc_fs_util::{link_or_copy, LinkOrCopy};
use rustc_session::{CrateDisambiguator, Session};
@ -189,9 +190,9 @@ pub fn prepare_session_directory(
sess: &Session,
crate_name: &str,
crate_disambiguator: CrateDisambiguator,
) {
) -> Result<(), ErrorReported> {
if sess.opts.incremental.is_none() {
return;
return Ok(());
}
let _timer = sess.timer("incr_comp_prepare_session_directory");
@ -201,9 +202,7 @@ pub fn prepare_session_directory(
// {incr-comp-dir}/{crate-name-and-disambiguator}
let crate_dir = crate_path(sess, crate_name, crate_disambiguator);
debug!("crate-dir: {}", crate_dir.display());
if create_dir(sess, &crate_dir, "crate").is_err() {
return;
}
create_dir(sess, &crate_dir, "crate")?;
// Hack: canonicalize the path *after creating the directory*
// because, on windows, long paths can cause problems;
@ -217,7 +216,7 @@ pub fn prepare_session_directory(
crate_dir.display(),
err
));
return;
return Err(ErrorReported);
}
};
@ -232,16 +231,11 @@ pub fn prepare_session_directory(
// Lock the new session directory. If this fails, return an
// error without retrying
let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) {
Ok(e) => e,
Err(_) => return,
};
let (directory_lock, lock_file_path) = lock_directory(sess, &session_dir)?;
// Now that we have the lock, we can actually create the session
// directory
if create_dir(sess, &session_dir, "session").is_err() {
return;
}
create_dir(sess, &session_dir, "session")?;
// Find a suitable source directory to copy from. Ignore those that we
// have already tried before.
@ -257,7 +251,7 @@ pub fn prepare_session_directory(
);
sess.init_incr_comp_session(session_dir, directory_lock, false);
return;
return Ok(());
};
debug!("attempting to copy data from source: {}", source_directory.display());
@ -278,7 +272,7 @@ pub fn prepare_session_directory(
}
sess.init_incr_comp_session(session_dir, directory_lock, true);
return;
return Ok(());
} else {
debug!("copying failed - trying next directory");
@ -478,7 +472,7 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
directory_path
}
fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> {
fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorReported> {
match std_fs::create_dir_all(path) {
Ok(()) => {
debug!("{} directory created successfully", dir_tag);
@ -492,13 +486,16 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> {
path.display(),
err
));
Err(())
Err(ErrorReported)
}
}
}
/// Allocate the lock-file and lock it.
fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, PathBuf), ()> {
fn lock_directory(
sess: &Session,
session_dir: &Path,
) -> Result<(flock::Lock, PathBuf), ErrorReported> {
let lock_file_path = lock_file_path(session_dir);
debug!("lock_directory() - lock_file: {}", lock_file_path.display());
@ -510,13 +507,23 @@ fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, Pa
) {
// the lock should be exclusive
Ok(lock) => Ok((lock, lock_file_path)),
Err(err) => {
sess.err(&format!(
Err(lock_err) => {
let mut err = sess.struct_err(&format!(
"incremental compilation: could not create \
session directory lock file: {}",
err
session directory lock file: {}",
lock_err
));
Err(())
if flock::Lock::error_unsupported(&lock_err) {
err.note(&format!(
"the filesystem for the incremental path at {} \
does not appear to support locking, consider changing the \
incremental path to a filesystem that supports locking \
or disable incremental compilation",
session_dir.display()
));
}
err.emit();
Err(ErrorReported)
}
}
}

View file

@ -172,7 +172,7 @@ pub fn register_plugins<'a>(
let disambiguator = util::compute_crate_disambiguator(sess);
sess.crate_disambiguator.set(disambiguator).expect("not yet initialized");
rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator);
rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator)?;
if sess.opts.incremental.is_some() {
sess.time("incr_comp_garbage_collect_session_directories", || {

View file

@ -148,7 +148,7 @@ pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
krate,
&crate_name,
);
)?;
// Compute the dependency graph (in the background). We want to do
// this as early as possible, to give the DepGraph maximum time to
@ -157,7 +157,7 @@ pub fn register_plugins(&self) -> Result<&Query<(ast::Crate, Lrc<LintStore>)>> {
// called, which happens within passes::register_plugins().
self.dep_graph_future().ok();
result
Ok(result)
})
}