]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_incremental/src/persist/load.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / compiler / rustc_incremental / src / persist / load.rs
CommitLineData
54a0048b
SL
1//! Code to save/load the dep-graph from files.
2
dfeec247 3use rustc_data_structures::fx::FxHashMap;
c295e0f8 4use rustc_data_structures::memmap::Mmap;
17df50a5 5use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
136023e0 6use rustc_middle::ty::OnDiskCache;
9e0c209e 7use rustc_serialize::opaque::Decoder;
cdc7bbd5 8use rustc_serialize::Decodable;
3c0e092e 9use rustc_session::config::IncrementalStateAssertion;
ba9703b0 10use rustc_session::Session;
ea8adc8c 11use std::path::Path;
54a0048b
SL
12
13use super::data::*;
9e0c209e 14use super::file_format;
dfeec247 15use super::fs::*;
32a655c1 16use super::work_product;
54a0048b 17
94b46f34
XL
18type WorkProductMap = FxHashMap<WorkProductId, WorkProduct>;
19
3c0e092e 20#[derive(Debug)]
a2a8927a 21/// Represents the result of an attempt to load incremental compilation data.
ff7c6d11 22pub enum LoadResult<T> {
a2a8927a
XL
23 /// Loading was successful.
24 Ok {
25 #[allow(missing_docs)]
26 data: T,
27 },
28 /// The file either didn't exist or was produced by an incompatible compiler version.
ff7c6d11 29 DataOutOfDate,
5e7ed085 30 /// An error occurred.
a2a8927a
XL
31 Error {
32 #[allow(missing_docs)]
33 message: String,
34 },
ff7c6d11
XL
35}
36
136023e0 37impl<T: Default> LoadResult<T> {
a2a8927a 38 /// Accesses the data returned in [`LoadResult::Ok`].
136023e0 39 pub fn open(self, sess: &Session) -> T {
3c0e092e
XL
40 // Check for errors when using `-Zassert-incremental-state`
41 match (sess.opts.assert_incr_state, &self) {
42 (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => {
43 sess.fatal(
44 "We asserted that the incremental cache should not be loaded, \
45 but it was loaded.",
46 );
47 }
48 (
49 Some(IncrementalStateAssertion::Loaded),
50 LoadResult::Error { .. } | LoadResult::DataOutOfDate,
51 ) => {
52 sess.fatal(
53 "We asserted that an existing incremental cache directory should \
54 be successfully loaded, but it was not.",
55 );
56 }
57 _ => {}
58 };
59
ff7c6d11
XL
60 match self {
61 LoadResult::Error { message } => {
0531ce1d 62 sess.warn(&message);
0bf4aa26 63 Default::default()
dfeec247 64 }
ff7c6d11
XL
65 LoadResult::DataOutOfDate => {
66 if let Err(err) = delete_all_session_dir_contents(sess) {
dfeec247
XL
67 sess.err(&format!(
68 "Failed to delete invalidated or incompatible \
3c0e092e 69 incremental compilation session directory contents `{}`: {}.",
dfeec247
XL
70 dep_graph_path(sess).display(),
71 err
72 ));
ff7c6d11 73 }
0bf4aa26 74 Default::default()
ff7c6d11 75 }
dfeec247 76 LoadResult::Ok { data } => data,
ff7c6d11
XL
77 }
78 }
79}
80
fc512014
XL
81fn load_data(
82 report_incremental_info: bool,
83 path: &Path,
84 nightly_build: bool,
c295e0f8 85) -> LoadResult<(Mmap, usize)> {
fc512014 86 match file_format::read_file(report_incremental_info, path, nightly_build) {
dfeec247 87 Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
9e0c209e
SL
88 Ok(None) => {
89 // The file either didn't exist or was produced by an incompatible
90 // compiler version. Neither is an error.
ff7c6d11 91 LoadResult::DataOutOfDate
5bcae85e 92 }
dfeec247
XL
93 Err(err) => LoadResult::Error {
94 message: format!("could not load dep-graph from `{}`: {}", path.display(), err),
95 },
54a0048b
SL
96 }
97}
98
dfeec247 99fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) {
5bcae85e 100 debug!("delete_dirty_work_product({:?})", swp);
94b46f34 101 work_product::delete_workproduct_files(sess, &swp.work_product);
54a0048b 102}
9e0c209e 103
ff7c6d11
XL
104/// Either a result that has already be computed or a
105/// handle that will let us wait until it is computed
106/// by a background thread.
107pub enum MaybeAsync<T> {
108 Sync(T),
dfeec247 109 Async(std::thread::JoinHandle<T>),
ff7c6d11 110}
136023e0
XL
111
112impl<T> MaybeAsync<LoadResult<T>> {
a2a8927a 113 /// Accesses the data returned in [`LoadResult::Ok`] in an asynchronous way if possible.
136023e0 114 pub fn open(self) -> LoadResult<T> {
ff7c6d11 115 match self {
136023e0
XL
116 MaybeAsync::Sync(result) => result,
117 MaybeAsync::Async(handle) => handle.join().unwrap_or_else(|e| LoadResult::Error {
118 message: format!("could not decode incremental cache: {:?}", e),
119 }),
9e0c209e
SL
120 }
121 }
9e0c209e
SL
122}
123
a2a8927a 124/// An asynchronous type for computing the dependency graph.
17df50a5 125pub type DepGraphFuture = MaybeAsync<LoadResult<(SerializedDepGraph, WorkProductMap)>>;
532ac7d7 126
ff7c6d11 127/// Launch a thread and load the dependency graph in the background.
532ac7d7 128pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
ff7c6d11
XL
129 // Since `sess` isn't `Sync`, we perform all accesses to `sess`
130 // before we fire the background thread.
ea8adc8c 131
e74abb32 132 let prof = sess.prof.clone();
0531ce1d 133
ea8adc8c 134 if sess.opts.incremental.is_none() {
ff7c6d11 135 // No incremental compilation.
dfeec247 136 return MaybeAsync::Sync(LoadResult::Ok { data: Default::default() });
8bb4bdeb
XL
137 }
138
dfeec247
XL
139 let _timer = sess.prof.generic_activity("incr_comp_prepare_load_dep_graph");
140
ff7c6d11
XL
141 // Calling `sess.incr_comp_session_dir()` will panic if `sess.opts.incremental.is_none()`.
142 // Fortunately, we just checked that this isn't the case.
3c0e092e 143 let path = dep_graph_path(&sess);
ff7c6d11 144 let report_incremental_info = sess.opts.debugging_opts.incremental_info;
cdc7bbd5 145 let expected_hash = sess.opts.dep_tracking_hash(false);
ff7c6d11 146
0bf4aa26 147 let mut prev_work_products = FxHashMap::default();
fc512014 148 let nightly_build = sess.is_nightly_build();
94b46f34
XL
149
150 // If we are only building with -Zquery-dep-graph but without an actual
151 // incr. comp. session directory, we skip this. Otherwise we'd fail
152 // when trying to load work products.
153 if sess.incr_comp_session_dir_opt().is_some() {
154 let work_products_path = work_products_path(sess);
fc512014 155 let load_result = load_data(report_incremental_info, &work_products_path, nightly_build);
94b46f34
XL
156
157 if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
158 // Decode the list of work_products
159 let mut work_product_decoder = Decoder::new(&work_products_data[..], start_pos);
160 let work_products: Vec<SerializedWorkProduct> =
5099ac24 161 Decodable::decode(&mut work_product_decoder);
94b46f34
XL
162
163 for swp in work_products {
164 let mut all_files_exist = true;
f9f354fc 165 if let Some(ref file_name) = swp.work_product.saved_file {
94b46f34
XL
166 let path = in_incr_comp_dir_sess(sess, file_name);
167 if !path.exists() {
168 all_files_exist = false;
169
170 if sess.opts.debugging_opts.incremental_info {
dfeec247
XL
171 eprintln!(
172 "incremental: could not find file for work \
173 product: {}",
174 path.display()
175 );
94b46f34
XL
176 }
177 }
178 }
179
180 if all_files_exist {
181 debug!("reconcile_work_products: all files for {:?} exist", swp);
182 prev_work_products.insert(swp.id, swp.work_product);
183 } else {
184 debug!("reconcile_work_products: some file for {:?} does not exist", swp);
185 delete_dirty_work_product(sess, swp);
186 }
187 }
188 }
189 }
190
ff7c6d11 191 MaybeAsync::Async(std::thread::spawn(move || {
dfeec247
XL
192 let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
193
fc512014 194 match load_data(report_incremental_info, &path, nightly_build) {
dfeec247
XL
195 LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
196 LoadResult::Error { message } => LoadResult::Error { message },
197 LoadResult::Ok { data: (bytes, start_pos) } => {
198 let mut decoder = Decoder::new(&bytes, start_pos);
5099ac24 199 let prev_commandline_args_hash = u64::decode(&mut decoder);
dfeec247
XL
200
201 if prev_commandline_args_hash != expected_hash {
202 if report_incremental_info {
6a06907d 203 eprintln!(
dfeec247
XL
204 "[incremental] completely ignoring cache because of \
205 differing commandline arguments"
206 );
ff7c6d11 207 }
dfeec247
XL
208 // We can't reuse the cache, purge it.
209 debug!("load_dep_graph_new: differing commandline arg hashes");
041b39d2 210
dfeec247
XL
211 // No need to do any further work
212 return LoadResult::DataOutOfDate;
ff7c6d11 213 }
dfeec247 214
5099ac24 215 let dep_graph = SerializedDepGraph::decode(&mut decoder);
dfeec247 216
17df50a5 217 LoadResult::Ok { data: (dep_graph, prev_work_products) }
ff7c6d11 218 }
dfeec247 219 }
ff7c6d11 220 }))
8bb4bdeb 221}
abe05a73 222
fc512014
XL
223/// Attempts to load the query result cache from disk
224///
225/// If we are not in incremental compilation mode, returns `None`.
226/// Otherwise, tries to load the query result cache from disk,
227/// creating an empty cache if it could not be loaded.
136023e0 228pub fn load_query_result_cache<'a, C: OnDiskCache<'a>>(sess: &'a Session) -> Option<C> {
ba9703b0 229 if sess.opts.incremental.is_none() {
fc512014 230 return None;
abe05a73
XL
231 }
232
e74abb32
XL
233 let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
234
fc512014
XL
235 match load_data(
236 sess.opts.debugging_opts.incremental_info,
237 &query_cache_path(sess),
238 sess.is_nightly_build(),
239 ) {
136023e0
XL
240 LoadResult::Ok { data: (bytes, start_pos) } => Some(C::new(sess, bytes, start_pos)),
241 _ => Some(C::new_empty(sess.source_map())),
abe05a73
XL
242 }
243}