]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_incremental/src/persist/save.rs
New upstream version 1.69.0+dfsg1
[rustc.git] / compiler / rustc_incremental / src / persist / save.rs
CommitLineData
9ffffee4 1use crate::errors;
476ff2be 2use rustc_data_structures::fx::FxHashMap;
94b46f34 3use rustc_data_structures::sync::join;
17df50a5 4use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId};
ba9703b0 5use rustc_middle::ty::TyCtxt;
5869c6ff 6use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
dfeec247 7use rustc_serialize::Encodable as RustcEncodable;
ba9703b0 8use rustc_session::Session;
2c00a5a8 9use std::fs;
54a0048b
SL
10
11use super::data::*;
9e0c209e
SL
12use super::dirty_clean;
13use super::file_format;
dfeec247 14use super::fs::*;
32a655c1 15use super::work_product;
54a0048b 16
a2a8927a 17/// Saves and writes the [`DepGraph`] to the file system.
cdc7bbd5 18///
a2a8927a
XL
19/// This function saves both the dep-graph and the query result cache,
20/// and drops the result cache.
21///
22/// This function should only run after all queries have completed.
23/// Trying to execute a query afterwards would attempt to read the result cache we just dropped.
416331ca 24pub fn save_dep_graph(tcx: TyCtxt<'_>) {
5bcae85e 25 debug!("save_dep_graph()");
2c00a5a8
XL
26 tcx.dep_graph.with_ignore(|| {
27 let sess = tcx.sess;
28 if sess.opts.incremental.is_none() {
29 return;
30 }
e74abb32 31 // This is going to be deleted in finalize_session_directory, so let's not create it
487cf647 32 if let Some(_) = sess.has_errors_or_delayed_span_bugs() {
e74abb32
XL
33 return;
34 }
9e0c209e 35
94b46f34
XL
36 let query_cache_path = query_cache_path(sess);
37 let dep_graph_path = dep_graph_path(sess);
cdc7bbd5
XL
38 let staging_dep_graph_path = staging_dep_graph_path(sess);
39
40 sess.time("assert_dep_graph", || crate::assert_dep_graph(tcx));
41 sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx));
42
064997fb 43 if sess.opts.unstable_opts.incremental_info {
cdc7bbd5
XL
44 tcx.dep_graph.print_incremental_info()
45 }
abe05a73 46
dfeec247
XL
47 join(
48 move || {
ba9703b0 49 sess.time("incr_comp_persist_result_cache", || {
c295e0f8
XL
50 // Drop the memory map so that we can remove the file and write to it.
51 if let Some(odc) = &tcx.on_disk_cache {
52 odc.drop_serialized_data(tcx);
53 }
54
55 file_format::save_in(sess, query_cache_path, "query cache", |e| {
56 encode_query_cache(tcx, e)
57 });
ba9703b0 58 });
dfeec247 59 },
cdc7bbd5 60 move || {
dfeec247 61 sess.time("incr_comp_persist_dep_graph", || {
cdc7bbd5 62 if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) {
9ffffee4 63 sess.emit_err(errors::WriteDepGraph { path: &staging_dep_graph_path, err });
cdc7bbd5
XL
64 }
65 if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) {
9ffffee4
FG
66 sess.emit_err(errors::MoveDepGraph {
67 from: &staging_dep_graph_path,
68 to: &dep_graph_path,
69 err,
70 });
cdc7bbd5 71 }
94b46f34 72 });
dfeec247
XL
73 },
74 );
2c00a5a8 75 })
a7813a04 76}
54a0048b 77
a2a8927a 78/// Saves the work product index.
dfeec247
XL
79pub fn save_work_product_index(
80 sess: &Session,
81 dep_graph: &DepGraph,
82 new_work_products: FxHashMap<WorkProductId, WorkProduct>,
83) {
9e0c209e
SL
84 if sess.opts.incremental.is_none() {
85 return;
86 }
e74abb32 87 // This is going to be deleted in finalize_session_directory, so let's not create it
487cf647 88 if let Some(_) = sess.has_errors_or_delayed_span_bugs() {
dfeec247 89 return;
e74abb32 90 }
9e0c209e 91
94b46f34 92 debug!("save_work_product_index()");
2c00a5a8 93 dep_graph.assert_ignored();
9e0c209e 94 let path = work_products_path(sess);
923072b8
FG
95 file_format::save_in(sess, path, "work product index", |mut e| {
96 encode_work_product_index(&new_work_products, &mut e);
97 e.finish()
c295e0f8 98 });
32a655c1
SL
99
100 // We also need to clean out old work-products, as not all of them are
101 // deleted during invalidation. Some object files don't change their
102 // content, they are just not needed anymore.
ea8adc8c 103 let previous_work_products = dep_graph.previous_work_products();
32a655c1
SL
104 for (id, wp) in previous_work_products.iter() {
105 if !new_work_products.contains_key(id) {
106 work_product::delete_workproduct_files(sess, wp);
064997fb
FG
107 debug_assert!(
108 !wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
109 );
32a655c1
SL
110 }
111 }
112
113 // Check that we did not delete one of the current work-products:
114 debug_assert!({
064997fb
FG
115 new_work_products.iter().all(|(_, wp)| {
116 wp.saved_files.iter().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
117 })
32a655c1 118 });
5bcae85e 119}
a7813a04 120
dfeec247
XL
121fn encode_work_product_index(
122 work_products: &FxHashMap<WorkProductId, WorkProduct>,
5869c6ff 123 encoder: &mut FileEncoder,
923072b8 124) {
94b46f34 125 let serialized_products: Vec<_> = work_products
5bcae85e 126 .iter()
dfeec247
XL
127 .map(|(id, work_product)| SerializedWorkProduct {
128 id: *id,
129 work_product: work_product.clone(),
5bcae85e
SL
130 })
131 .collect();
132
5869c6ff 133 serialized_products.encode(encoder)
5bcae85e 134}
abe05a73 135
923072b8 136fn encode_query_cache(tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult {
5869c6ff 137 tcx.sess.time("incr_comp_serialize_result_cache", || tcx.serialize_query_result_cache(encoder))
abe05a73 138}
cdc7bbd5 139
a2a8927a
XL
140/// Builds the dependency graph.
141///
5e7ed085 142/// This function creates the *staging dep-graph*. When the dep-graph is modified by a query
a2a8927a
XL
143/// execution, the new dependency information is not kept in memory but directly
144/// output to this file. `save_dep_graph` then finalizes the staging dep-graph
145/// and moves it to the permanent dep-graph path
cdc7bbd5
XL
146pub fn build_dep_graph(
147 sess: &Session,
17df50a5 148 prev_graph: SerializedDepGraph,
cdc7bbd5
XL
149 prev_work_products: FxHashMap<WorkProductId, WorkProduct>,
150) -> Option<DepGraph> {
151 if sess.opts.incremental.is_none() {
152 // No incremental compilation.
153 return None;
154 }
155
156 // Stream the dep-graph to an alternate file, to avoid overwriting anything in case of errors.
157 let path_buf = staging_dep_graph_path(sess);
158
159 let mut encoder = match FileEncoder::new(&path_buf) {
160 Ok(encoder) => encoder,
161 Err(err) => {
9ffffee4 162 sess.emit_err(errors::CreateDepGraph { path: &path_buf, err });
cdc7bbd5
XL
163 return None;
164 }
165 };
166
923072b8 167 file_format::write_file_header(&mut encoder, sess.is_nightly_build());
cdc7bbd5
XL
168
169 // First encode the commandline arguments hash
923072b8 170 sess.opts.dep_tracking_hash(false).encode(&mut encoder);
cdc7bbd5
XL
171
172 Some(DepGraph::new(
17df50a5 173 &sess.prof,
cdc7bbd5
XL
174 prev_graph,
175 prev_work_products,
176 encoder,
064997fb
FG
177 sess.opts.unstable_opts.query_dep_graph,
178 sess.opts.unstable_opts.incremental_info,
cdc7bbd5
XL
179 ))
180}