]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_incremental/src/persist/file_format.rs
New upstream version 1.57.0+dfsg1
[rustc.git] / compiler / rustc_incremental / src / persist / file_format.rs
index b821ed6cff9f83f2706f378f8ef953e823a323f9..572a4fc69717380aa6a8867a175425fd270da670 100644 (file)
 use std::env;
 use std::fs;
 use std::io::{self, Read};
-use std::path::Path;
+use std::path::{Path, PathBuf};
 
+use rustc_data_structures::memmap::Mmap;
 use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
 use rustc_serialize::Encoder;
+use rustc_session::Session;
 
 /// The first few bytes of files generated by incremental compilation.
 const FILE_MAGIC: &[u8] = b"RSIC";
@@ -28,7 +30,7 @@ const HEADER_FORMAT_VERSION: u16 = 0;
 /// the Git commit hash.
 const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
 
-pub fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult {
+pub(crate) fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileEncodeResult {
     stream.emit_raw_bytes(FILE_MAGIC)?;
     stream.emit_raw_bytes(&[
         (HEADER_FORMAT_VERSION >> 0) as u8,
@@ -41,6 +43,61 @@ pub fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) -> FileE
     stream.emit_raw_bytes(rustc_version.as_bytes())
 }
 
+pub(crate) fn save_in<F>(sess: &Session, path_buf: PathBuf, name: &str, encode: F)
+where
+    F: FnOnce(&mut FileEncoder) -> FileEncodeResult,
+{
+    debug!("save: storing data in {}", path_buf.display());
+
+    // Delete the old file, if any.
+    // Note: It's important that we actually delete the old file and not just
+    // truncate and overwrite it, since it might be a shared hard-link, the
+    // underlying data of which we don't want to modify.
+    //
+    // We have to ensure we have dropped the memory maps to this file
+    // before performing this removal.
+    match fs::remove_file(&path_buf) {
+        Ok(()) => {
+            debug!("save: remove old file");
+        }
+        Err(err) if err.kind() == io::ErrorKind::NotFound => (),
+        Err(err) => {
+            sess.err(&format!(
+                "unable to delete old {} at `{}`: {}",
+                name,
+                path_buf.display(),
+                err
+            ));
+            return;
+        }
+    }
+
+    let mut encoder = match FileEncoder::new(&path_buf) {
+        Ok(encoder) => encoder,
+        Err(err) => {
+            sess.err(&format!("failed to create {} at `{}`: {}", name, path_buf.display(), err));
+            return;
+        }
+    };
+
+    if let Err(err) = write_file_header(&mut encoder, sess.is_nightly_build()) {
+        sess.err(&format!("failed to write {} header to `{}`: {}", name, path_buf.display(), err));
+        return;
+    }
+
+    if let Err(err) = encode(&mut encoder) {
+        sess.err(&format!("failed to write {} to `{}`: {}", name, path_buf.display(), err));
+        return;
+    }
+
+    if let Err(err) = encoder.flush() {
+        sess.err(&format!("failed to flush {} to `{}`: {}", name, path_buf.display(), err));
+        return;
+    }
+
+    debug!("save: data written to disk successfully");
+}
+
 /// Reads the contents of a file with a file header as defined in this module.
 ///
 /// - Returns `Ok(Some(data, pos))` if the file existed and was generated by a
@@ -54,14 +111,21 @@ pub fn read_file(
     report_incremental_info: bool,
     path: &Path,
     nightly_build: bool,
-) -> io::Result<Option<(Vec<u8>, usize)>> {
-    let data = match fs::read(path) {
-        Ok(data) => data,
+) -> io::Result<Option<(Mmap, usize)>> {
+    let file = match fs::File::open(path) {
+        Ok(file) => file,
         Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None),
         Err(err) => return Err(err),
     };
+    // SAFETY: This process must not modify nor remove the backing file while the memory map lives.
+    // For the dep-graph and the work product index, it is as soon as the decoding is done.
+    // For the query result cache, the memory map is dropped in save_dep_graph before calling
+    // save_in and trying to remove the backing file.
+    //
+    // There is no way to prevent another process from modifying this file.
+    let mmap = unsafe { Mmap::map(file) }?;
 
-    let mut file = io::Cursor::new(data);
+    let mut file = io::Cursor::new(&*mmap);
 
     // Check FILE_MAGIC
     {
@@ -103,7 +167,7 @@ pub fn read_file(
     }
 
     let post_header_start_pos = file.position() as usize;
-    Ok(Some((file.into_inner(), post_header_start_pos)))
+    Ok(Some((mmap, post_header_start_pos)))
 }
 
 fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &str) {