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