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