Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 5d9ba49

Browse files
committed
move encode_and_write_metadata to rustc_metadata::fs
1 parent 709a782 commit 5d9ba49

File tree

5 files changed

+95
-73
lines changed

5 files changed

+95
-73
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3982,7 +3982,6 @@ dependencies = [
39823982
"rustc_ty_utils",
39833983
"rustc_typeck",
39843984
"smallvec",
3985-
"tempfile",
39863985
"tracing",
39873986
"winapi",
39883987
]
@@ -4092,6 +4091,7 @@ dependencies = [
40924091
"rustc_type_ir",
40934092
"smallvec",
40944093
"snap",
4094+
"tempfile",
40954095
"tracing",
40964096
]
40974097

compiler/rustc_interface/Cargo.toml

Lines changed: 0 additions & 1 deletion
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

Lines changed: 4 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ use rustc_borrowck as mir_borrowck;
88
use rustc_codegen_ssa::traits::CodegenBackend;
99
use rustc_data_structures::parallel;
1010
use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
11-
use rustc_data_structures::temp_dir::MaybeTempDir;
1211
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan, PResult};
1312
use rustc_expand::base::{ExtCtxt, LintStoreExpand, ResolverExpand};
14-
use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
13+
use rustc_hir::def_id::StableCrateId;
1514
use rustc_hir::definitions::Definitions;
1615
use rustc_hir::Crate;
1716
use rustc_lint::{EarlyCheckNode, LintStore};
1817
use rustc_metadata::creader::CStore;
19-
use rustc_metadata::fs::emit_metadata;
20-
use rustc_metadata::{encode_metadata, EncodedMetadata};
2118
use rustc_middle::arena::Arena;
2219
use rustc_middle::dep_graph::DepGraph;
2320
use rustc_middle::ty::query::{ExternProviders, Providers};
@@ -30,14 +27,13 @@ use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
3027
use rustc_resolve::{Resolver, ResolverArenas};
3128
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
3229
use rustc_session::cstore::{CrateStoreDyn, MetadataLoader, MetadataLoaderDyn};
33-
use rustc_session::output::{filename_for_input, filename_for_metadata};
30+
use rustc_session::output::filename_for_input;
3431
use rustc_session::search_paths::PathKind;
3532
use rustc_session::{Limit, Session};
3633
use rustc_span::symbol::{sym, Symbol};
3734
use rustc_span::FileName;
3835
use rustc_trait_selection::traits;
3936
use rustc_typeck as typeck;
40-
use tempfile::Builder as TempFileBuilder;
4137
use tracing::{info, warn};
4238

4339
use std::any::Any;
@@ -1030,69 +1026,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
10301026
Ok(())
10311027
}
10321028

1033-
fn encode_and_write_metadata(
1034-
tcx: TyCtxt<'_>,
1035-
outputs: &OutputFilenames,
1036-
) -> (EncodedMetadata, bool) {
1037-
#[derive(PartialEq, Eq, PartialOrd, Ord)]
1038-
enum MetadataKind {
1039-
None,
1040-
Uncompressed,
1041-
Compressed,
1042-
}
1043-
1044-
let metadata_kind = tcx
1045-
.sess
1046-
.crate_types()
1047-
.iter()
1048-
.map(|ty| match *ty {
1049-
CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None,
1050-
1051-
CrateType::Rlib => MetadataKind::Uncompressed,
1052-
1053-
CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
1054-
})
1055-
.max()
1056-
.unwrap_or(MetadataKind::None);
1057-
1058-
let metadata = match metadata_kind {
1059-
MetadataKind::None => EncodedMetadata::new(),
1060-
MetadataKind::Uncompressed | MetadataKind::Compressed => encode_metadata(tcx),
1061-
};
1062-
1063-
let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata");
1064-
1065-
let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
1066-
if need_metadata_file {
1067-
let crate_name = tcx.crate_name(LOCAL_CRATE);
1068-
let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs);
1069-
// To avoid races with another rustc process scanning the output directory,
1070-
// we need to write the file somewhere else and atomically move it to its
1071-
// final destination, with an `fs::rename` call. In order for the rename to
1072-
// always succeed, the temporary file needs to be on the same filesystem,
1073-
// which is why we create it inside the output directory specifically.
1074-
let metadata_tmpdir = TempFileBuilder::new()
1075-
.prefix("rmeta")
1076-
.tempdir_in(out_filename.parent().unwrap())
1077-
.unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
1078-
let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
1079-
let metadata_filename = emit_metadata(tcx.sess, metadata.raw_data(), &metadata_tmpdir);
1080-
if let Err(e) = util::non_durable_rename(&metadata_filename, &out_filename) {
1081-
tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
1082-
}
1083-
if tcx.sess.opts.json_artifact_notifications {
1084-
tcx.sess
1085-
.parse_sess
1086-
.span_diagnostic
1087-
.emit_artifact_notification(&out_filename, "metadata");
1088-
}
1089-
}
1090-
1091-
let need_metadata_module = metadata_kind == MetadataKind::Compressed;
1092-
1093-
(metadata, need_metadata_module)
1094-
}
1095-
10961029
/// Runs the codegen backend, after which the AST and analysis can
10971030
/// be discarded.
10981031
pub fn start_codegen<'tcx>(
@@ -1102,7 +1035,8 @@ pub fn start_codegen<'tcx>(
11021035
) -> Box<dyn Any> {
11031036
info!("Pre-codegen\n{:?}", tcx.debug_stats());
11041037

1105-
let (metadata, need_metadata_module) = encode_and_write_metadata(tcx, outputs);
1038+
let (metadata, need_metadata_module) =
1039+
rustc_metadata::fs::encode_and_write_metadata(tcx, outputs);
11061040

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

compiler/rustc_metadata/Cargo.toml

Lines changed: 1 addition & 0 deletions
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" }

compiler/rustc_metadata/src/fs.rs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1+
use crate::{encode_metadata, EncodedMetadata};
2+
13
use rustc_data_structures::temp_dir::MaybeTempDir;
4+
use rustc_hir::def_id::LOCAL_CRATE;
5+
use rustc_middle::ty::TyCtxt;
6+
use rustc_session::config::{CrateType, OutputFilenames, OutputType};
7+
use rustc_session::output::filename_for_metadata;
28
use rustc_session::Session;
9+
use tempfile::Builder as TempFileBuilder;
310

411
use std::fs;
5-
use std::path::PathBuf;
12+
use std::path::{Path, PathBuf};
613

714
// FIXME(eddyb) maybe include the crate name in this?
815
pub const METADATA_FILENAME: &str = "lib.rmeta";
@@ -22,3 +29,84 @@ pub fn emit_metadata(sess: &Session, metadata: &[u8], tmpdir: &MaybeTempDir) ->
2229

2330
out_filename
2431
}
32+
33+
pub fn encode_and_write_metadata(
34+
tcx: TyCtxt<'_>,
35+
outputs: &OutputFilenames,
36+
) -> (EncodedMetadata, bool) {
37+
#[derive(PartialEq, Eq, PartialOrd, Ord)]
38+
enum MetadataKind {
39+
None,
40+
Uncompressed,
41+
Compressed,
42+
}
43+
44+
let metadata_kind = tcx
45+
.sess
46+
.crate_types()
47+
.iter()
48+
.map(|ty| match *ty {
49+
CrateType::Executable | CrateType::Staticlib | CrateType::Cdylib => MetadataKind::None,
50+
51+
CrateType::Rlib => MetadataKind::Uncompressed,
52+
53+
CrateType::Dylib | CrateType::ProcMacro => MetadataKind::Compressed,
54+
})
55+
.max()
56+
.unwrap_or(MetadataKind::None);
57+
58+
let metadata = match metadata_kind {
59+
MetadataKind::None => EncodedMetadata::new(),
60+
MetadataKind::Uncompressed | MetadataKind::Compressed => encode_metadata(tcx),
61+
};
62+
63+
let _prof_timer = tcx.sess.prof.generic_activity("write_crate_metadata");
64+
65+
let need_metadata_file = tcx.sess.opts.output_types.contains_key(&OutputType::Metadata);
66+
if need_metadata_file {
67+
let crate_name = tcx.crate_name(LOCAL_CRATE);
68+
let out_filename = filename_for_metadata(tcx.sess, crate_name.as_str(), outputs);
69+
// To avoid races with another rustc process scanning the output directory,
70+
// we need to write the file somewhere else and atomically move it to its
71+
// final destination, with an `fs::rename` call. In order for the rename to
72+
// always succeed, the temporary file needs to be on the same filesystem,
73+
// which is why we create it inside the output directory specifically.
74+
let metadata_tmpdir = TempFileBuilder::new()
75+
.prefix("rmeta")
76+
.tempdir_in(out_filename.parent().unwrap())
77+
.unwrap_or_else(|err| tcx.sess.fatal(&format!("couldn't create a temp dir: {}", err)));
78+
let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
79+
let metadata_filename = emit_metadata(tcx.sess, metadata.raw_data(), &metadata_tmpdir);
80+
if let Err(e) = non_durable_rename(&metadata_filename, &out_filename) {
81+
tcx.sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e));
82+
}
83+
if tcx.sess.opts.json_artifact_notifications {
84+
tcx.sess
85+
.parse_sess
86+
.span_diagnostic
87+
.emit_artifact_notification(&out_filename, "metadata");
88+
}
89+
}
90+
91+
let need_metadata_module = metadata_kind == MetadataKind::Compressed;
92+
93+
(metadata, need_metadata_module)
94+
}
95+
96+
#[cfg(not(target_os = "linux"))]
97+
pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
98+
std::fs::rename(src, dst)
99+
}
100+
101+
/// This function attempts to bypass the auto_da_alloc heuristic implemented by some filesystems
102+
/// such as btrfs and ext4. When renaming over a file that already exists then they will "helpfully"
103+
/// write back the source file before committing the rename in case a developer forgot some of
104+
/// the fsyncs in the open/write/fsync(file)/rename/fsync(dir) dance for atomic file updates.
105+
///
106+
/// To avoid triggering this heuristic we delete the destination first, if it exists.
107+
/// The cost of an extra syscall is much lower than getting descheduled for the sync IO.
108+
#[cfg(target_os = "linux")]
109+
pub fn non_durable_rename(src: &Path, dst: &Path) -> std::io::Result<()> {
110+
let _ = std::fs::remove_file(dst);
111+
std::fs::rename(src, dst)
112+
}

0 commit comments

Comments
 (0)