Skip to content

Commit 1ba1fec

Browse files
committed
Auto merge of #96544 - m-ysk:feature/issue-96358, r=cjgillot
Stop keeping metadata in memory before writing it to disk Fixes #96358 I created this PR according with the instruction given in the issue except for the following points: - While the issue says "Write metadata into the temporary file in `encode_and_write_metadata` even if `!need_metadata_file`", I could not do that. That is because though I tried to do that and run `x.py test`, I got a lot of test failures as follows. <details> <summary>List of failed tests</summary> <pre> <code> failures: [ui] src/test/ui/json-multiple.rs [ui] src/test/ui/json-options.rs [ui] src/test/ui/rmeta/rmeta-rpass.rs [ui] src/test/ui/save-analysis/emit-notifications.rs [ui] src/test/ui/svh/changing-crates.rs [ui] src/test/ui/svh/svh-change-lit.rs [ui] src/test/ui/svh/svh-change-significant-cfg.rs [ui] src/test/ui/svh/svh-change-trait-bound.rs [ui] src/test/ui/svh/svh-change-type-arg.rs [ui] src/test/ui/svh/svh-change-type-ret.rs [ui] src/test/ui/svh/svh-change-type-static.rs [ui] src/test/ui/svh/svh-use-trait.rs test result: FAILED. 12915 passed; 12 failed; 100 ignored; 0 measured; 0 filtered out; finished in 71.41s Some tests failed in compiletest suite=ui mode=ui host=x86_64-unknown-linux-gnu target=x86_64-unknown-linux-gnu Build completed unsuccessfully in 0:01:58 </code> </pre> </details> - I could not resolve the extra tasks about `create_rmeta_file` and `create_compressed_metadata_file` for my lack of ability.
2 parents c2f428d + 1147d50 commit 1ba1fec

File tree

16 files changed

+300
-147
lines changed

16 files changed

+300
-147
lines changed

Cargo.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -3969,7 +3969,6 @@ dependencies = [
39693969
"rustc_ty_utils",
39703970
"rustc_typeck",
39713971
"smallvec",
3972-
"tempfile",
39733972
"tracing",
39743973
"winapi",
39753974
]
@@ -4080,6 +4079,7 @@ dependencies = [
40804079
"rustc_type_ir",
40814080
"smallvec",
40824081
"snap",
4082+
"tempfile",
40834083
"tracing",
40844084
]
40854085

compiler/rustc_codegen_ssa/src/back/link.rs

+2-20
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir;
66
use rustc_errors::{ErrorGuaranteed, Handler};
77
use rustc_fs_util::fix_windows_verbatim_for_gcc;
88
use rustc_hir::def_id::CrateNum;
9+
use rustc_metadata::fs::{emit_metadata, METADATA_FILENAME};
910
use rustc_middle::middle::dependency_format::Linkage;
1011
use rustc_middle::middle::exported_symbols::SymbolExportKind;
1112
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
@@ -28,10 +29,7 @@ use super::command::Command;
2829
use super::linker::{self, Linker};
2930
use super::metadata::{create_rmeta_file, MetadataPosition};
3031
use super::rpath::{self, RPathConfig};
31-
use crate::{
32-
looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib,
33-
METADATA_FILENAME,
34-
};
32+
use crate::{looks_like_rust_object_file, CodegenResults, CompiledModule, CrateInfo, NativeLib};
3533

3634
use cc::windows_registry;
3735
use regex::Regex;
@@ -241,22 +239,6 @@ pub fn each_linked_rlib(
241239
Ok(())
242240
}
243241

244-
/// We use a temp directory here to avoid races between concurrent rustc processes,
245-
/// such as builds in the same directory using the same filename for metadata while
246-
/// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a
247-
/// directory being searched for `extern crate` (observing an incomplete file).
248-
/// The returned path is the temporary file containing the complete metadata.
249-
pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) -> PathBuf {
250-
let out_filename = tmpdir.as_ref().join(METADATA_FILENAME);
251-
let result = fs::write(&out_filename, metadata);
252-
253-
if let Err(e) = result {
254-
sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
255-
}
256-
257-
out_filename
258-
}
259-
260242
/// Create an 'rlib'.
261243
///
262244
/// An rlib in its current incarnation is essentially a renamed .a file. The rlib primarily contains

compiler/rustc_codegen_ssa/src/back/metadata.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@ use rustc_data_structures::memmap::Mmap;
1616
use rustc_data_structures::owning_ref::OwningRef;
1717
use rustc_data_structures::rustc_erase_owner;
1818
use rustc_data_structures::sync::MetadataRef;
19+
use rustc_metadata::fs::METADATA_FILENAME;
1920
use rustc_metadata::EncodedMetadata;
2021
use rustc_session::cstore::MetadataLoader;
2122
use rustc_session::Session;
2223
use rustc_target::abi::Endian;
2324
use rustc_target::spec::{RelocModel, Target};
2425

25-
use crate::METADATA_FILENAME;
26-
2726
/// The default metadata loader. This is used by cg_llvm and cg_clif.
2827
///
2928
/// # Metadata location

compiler/rustc_codegen_ssa/src/lib.rs

-3
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@ pub struct ModuleCodegen<M> {
6464
pub kind: ModuleKind,
6565
}
6666

67-
// FIXME(eddyb) maybe include the crate name in this?
68-
pub const METADATA_FILENAME: &str = "lib.rmeta";
69-
7067
impl<M> ModuleCodegen<M> {
7168
pub fn into_compiled_module(
7269
self,

compiler/rustc_data_structures/src/memmap.rs

+62-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::fs::File;
22
use std::io;
3-
use std::ops::Deref;
3+
use std::ops::{Deref, DerefMut};
44

55
use crate::owning_ref::StableAddress;
66

@@ -45,3 +45,64 @@ impl Deref for Mmap {
4545
// export any function that can cause the `Vec` to be re-allocated. As such the address of the
4646
// bytes inside this `Vec` is stable.
4747
unsafe impl StableAddress for Mmap {}
48+
49+
#[cfg(not(target_arch = "wasm32"))]
50+
pub struct MmapMut(memmap2::MmapMut);
51+
52+
#[cfg(target_arch = "wasm32")]
53+
pub struct MmapMut(Vec<u8>);
54+
55+
#[cfg(not(target_arch = "wasm32"))]
56+
impl MmapMut {
57+
#[inline]
58+
pub fn map_anon(len: usize) -> io::Result<Self> {
59+
let mmap = memmap2::MmapMut::map_anon(len)?;
60+
Ok(MmapMut(mmap))
61+
}
62+
63+
#[inline]
64+
pub fn flush(&mut self) -> io::Result<()> {
65+
self.0.flush()
66+
}
67+
68+
#[inline]
69+
pub fn make_read_only(self) -> std::io::Result<Mmap> {
70+
let mmap = self.0.make_read_only()?;
71+
Ok(Mmap(mmap))
72+
}
73+
}
74+
75+
#[cfg(target_arch = "wasm32")]
76+
impl MmapMut {
77+
#[inline]
78+
pub fn map_anon(len: usize) -> io::Result<Self> {
79+
let data = Vec::with_capacity(len);
80+
Ok(MmapMut(data))
81+
}
82+
83+
#[inline]
84+
pub fn flush(&mut self) -> io::Result<()> {
85+
Ok(())
86+
}
87+
88+
#[inline]
89+
pub fn make_read_only(self) -> std::io::Result<Mmap> {
90+
Ok(Mmap(self.0))
91+
}
92+
}
93+
94+
impl Deref for MmapMut {
95+
type Target = [u8];
96+
97+
#[inline]
98+
fn deref(&self) -> &[u8] {
99+
&*self.0
100+
}
101+
}
102+
103+
impl DerefMut for MmapMut {
104+
#[inline]
105+
fn deref_mut(&mut self) -> &mut [u8] {
106+
&mut *self.0
107+
}
108+
}

compiler/rustc_interface/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ rustc_query_impl = { path = "../rustc_query_impl" }
4646
rustc_resolve = { path = "../rustc_resolve" }
4747
rustc_trait_selection = { path = "../rustc_trait_selection" }
4848
rustc_ty_utils = { path = "../rustc_ty_utils" }
49-
tempfile = "3.2"
5049

5150
[target.'cfg(unix)'.dependencies]
5251
libc = "0.2"

compiler/rustc_interface/src/passes.rs

+4-70
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,15 @@ use crate::util;
55
use ast::CRATE_NODE_ID;
66
use rustc_ast::{self as ast, visit};
77
use rustc_borrowck as mir_borrowck;
8-
use rustc_codegen_ssa::back::link::emit_metadata;
98
use rustc_codegen_ssa::traits::CodegenBackend;
109
use rustc_data_structures::parallel;
1110
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
12-
use rustc_data_structures::temp_dir::MaybeTempDir;
1311
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult};
1412
use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
15-
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
13+
use rustc_hir::def_id::StableCrateId;
1614
use rustc_hir::definitions::Definitions;
1715
use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore};
1816
use rustc_metadata::creader::CStore;
19-
use rustc_metadata::{encode_metadata, EncodedMetadata};
2017
use rustc_middle::arena::Arena;
2118
use rustc_middle::dep_graph::DepGraph;
2219
use rustc_middle::ty::query::{ExternProviders, Providers};
@@ -29,14 +26,13 @@ use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
2926
use rustc_resolve::{Resolver, ResolverArenas};
3027
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
3128
use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn};
32-
use rustc_session::output::{filename_for_input, filename_for_metadata};
29+
use rustc_session::output::filename_for_input;
3330
use rustc_session::search_paths::PathKind;
3431
use rustc_session::{Limit, Session};
3532
use rustc_span::symbol::{sym, Symbol};
3633
use rustc_span::FileName;
3734
use rustc_trait_selection::traits;
3835
use rustc_typeck as typeck;
39-
use tempfile::Builder as TempFileBuilder;
4036
use tracing::{info, warn};
4137

4238
use std::any::Any;
@@ -993,69 +989,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
993989
Ok(())
994990
}
995991

996-
fn encode_and_write_metadata(
997-
tcx: TyCtxt<'_>,
998-
outputs: &OutputFilenames,
999-
) -> (EncodedMetadata, bool) {
1000-
#[derive(PartialEq, Eq, PartialOrd, Ord)]
1001-
enum MetadataKind {
1002-
None,
1003-
Uncompressed,
1004-
Compressed,
1005-
}
1006-
1007-
let metadata_kind = tcx
1008-
.sess
1009-
.crate_types()
1010-
.iter()
1011-
.map(|ty| match *ty {
1012-
CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None,
1013-
1014-
CrateType::Rlib => MetadataKind::Uncompressed,
1015-
1016-
CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
1017-
})
1018-
.max()
1019-
.unwrap_or(MetadataKind::None);
1020-
1021-
let metadata = match metadata_kind {
1022-
MetadataKind::None => EncodedMetadata::new(),
1023-
MetadataKind::Uncompressed | MetadataKind::Compressed => encode_metadata(tcx),
1024-
};
1025-
1026-
let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata");
1027-
1028-
let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
1029-
if need_metadata_file {
1030-
let crate_name = tcx.crate_name(LOCAL_CRATE);
1031-
let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs);
1032-
// To avoid races with another rustc process scanning the output directory,
1033-
// we need to write the file somewhere else and atomically move it to its
1034-
// final destination, with an `fs::rename` call. In order for the rename to
1035-
// always succeed, the temporary file needs to be on the same filesystem,
1036-
// which is why we create it inside the output directory specifically.
1037-
let metadata_tmpdir = TempFileBuilder::new()
1038-
.prefix("rmeta")
1039-
.tempdir_in(out_filename.parent().unwrap())
1040-
.unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
1041-
let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
1042-
let metadata_filename = emit_metadata(tcx.sess, metadata.raw_data(), &metadata_tmpdir);
1043-
if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) {
1044-
tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
1045-
}
1046-
if tcx.sess.opts.json_artifact_notifications {
1047-
tcx.sess
1048-
.parse_sess
1049-
.span_diagnostic
1050-
.emit_artifact_notification(&out_filename, "metadata");
1051-
}
1052-
}
1053-
1054-
let need_metadata_module = metadata_kind == MetadataKind::Compressed;
1055-
1056-
(metadata, need_metadata_module)
1057-
}
1058-
1059992
/// Runs the codegen backend, after which the AST and analysis can
1060993
/// be discarded.
1061994
pub fn start_codegen<'tcx>(
@@ -1065,7 +998,8 @@ pub fn start_codegen<'tcx>(
1065998
) -> Box<dyn Any> {
1066999
info!("Pre-codegen\n{:?}", tcx.debug_stats());
10671000

1068-
let (metadata, need_metadata_module) = encode_and_write_metadata(tcx, outputs);
1001+
let (metadata, need_metadata_module) =
1002+
rustc_metadata::fs::encode_and_write_metadata(tcx, outputs);
10691003

10701004
let codegen = tcx.sess.time("codegen_crate", move || {
10711005
codegen_backend.codegen_crate(tcx, metadata, need_metadata_module)

compiler/rustc_interface/src/util.rs

-18
Original file line numberDiff line numberDiff line change
@@ -650,24 +650,6 @@ pub fn build_output_filenames(
650650
}
651651
}
652652

653-
#[cfg(not(target_os = "linux"))]
654-
pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
655-
std::fs::rename(src, dst)
656-
}
657-
658-
/// This function attempts to bypass the auto_da_alloc heuristic implemented by some filesystems
659-
/// such as btrfs and ext4. When renaming over a file that already exists then they will "helpfully"
660-
/// write back the source file before committing the rename in case a developer forgot some of
661-
/// the fsyncs in the open/write/fsync(file)/rename/fsync(dir) dance for atomic file updates.
662-
///
663-
/// To avoid triggering this heuristic we delete the destination first, if it exists.
664-
/// The cost of an extra syscall is much lower than getting descheduled for the sync IO.
665-
#[cfg(target_os = "linux")]
666-
pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
667-
let _ = std::fs::remove_file(dst);
668-
std::fs::rename(src, dst)
669-
}
670-
671653
/// Returns a version string such as "1.46.0 (04488afe3 2020-08-24)"
672654
pub fn version_str() -> Option<&'static str> {
673655
option_env!("CFG_VERSION")

compiler/rustc_metadata/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ odht = { version = "0.3.1", features = ["nightly"] }
1212
snap = "1"
1313
tracing = "0.1"
1414
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
15+
tempfile = "3.2"
1516
rustc_middle = { path = "../rustc_middle" }
1617
rustc_attr = { path = "../rustc_attr" }
1718
rustc_data_structures = { path = "../rustc_data_structures" }

0 commit comments

Comments
 (0)