]>
Commit | Line | Data |
---|---|---|
9ffffee4 | 1 | use crate::errors; |
476ff2be | 2 | use rustc_data_structures::fx::FxHashMap; |
94b46f34 | 3 | use rustc_data_structures::sync::join; |
17df50a5 | 4 | use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; |
ba9703b0 | 5 | use rustc_middle::ty::TyCtxt; |
5869c6ff | 6 | use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; |
dfeec247 | 7 | use rustc_serialize::Encodable as RustcEncodable; |
ba9703b0 | 8 | use rustc_session::Session; |
2c00a5a8 | 9 | use std::fs; |
54a0048b SL |
10 | |
11 | use super::data::*; | |
9e0c209e SL |
12 | use super::dirty_clean; |
13 | use super::file_format; | |
dfeec247 | 14 | use super::fs::*; |
32a655c1 | 15 | use 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 | 24 | pub 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 |
79 | pub 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 |
121 | fn 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 | 136 | fn 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 |
146 | pub 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 | } |