rustc_incremental/persist/
load.rs
1use std::path::{Path, PathBuf};
4use std::sync::Arc;
5
6use rustc_data_structures::memmap::Mmap;
7use rustc_data_structures::unord::UnordMap;
8use rustc_middle::dep_graph::{DepGraph, DepsType, SerializedDepGraph, WorkProductMap};
9use rustc_middle::query::on_disk_cache::OnDiskCache;
10use rustc_serialize::Decodable;
11use rustc_serialize::opaque::MemDecoder;
12use rustc_session::Session;
13use rustc_session::config::IncrementalStateAssertion;
14use tracing::{debug, warn};
15
16use super::data::*;
17use super::fs::*;
18use super::save::build_dep_graph;
19use super::{file_format, work_product};
20use crate::errors;
21
22#[derive(Debug)]
23pub enum LoadResult<T> {
25 Ok {
27 #[allow(missing_docs)]
28 data: T,
29 },
30 DataOutOfDate,
32 LoadDepGraph(PathBuf, std::io::Error),
34}
35
36impl<T: Default> LoadResult<T> {
37 pub fn open(self, sess: &Session) -> T {
39 match (sess.opts.assert_incr_state, &self) {
41 (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => {
42 sess.dcx().emit_fatal(errors::AssertNotLoaded);
43 }
44 (
45 Some(IncrementalStateAssertion::Loaded),
46 LoadResult::LoadDepGraph(..) | LoadResult::DataOutOfDate,
47 ) => {
48 sess.dcx().emit_fatal(errors::AssertLoaded);
49 }
50 _ => {}
51 };
52
53 match self {
54 LoadResult::LoadDepGraph(path, err) => {
55 sess.dcx().emit_warn(errors::LoadDepGraph { path, err });
56 Default::default()
57 }
58 LoadResult::DataOutOfDate => {
59 if let Err(err) = delete_all_session_dir_contents(sess) {
60 sess.dcx()
61 .emit_err(errors::DeleteIncompatible { path: dep_graph_path(sess), err });
62 }
63 Default::default()
64 }
65 LoadResult::Ok { data } => data,
66 }
67 }
68}
69
70fn load_data(path: &Path, sess: &Session) -> LoadResult<(Mmap, usize)> {
71 match file_format::read_file(
72 path,
73 sess.opts.unstable_opts.incremental_info,
74 sess.is_nightly_build(),
75 sess.cfg_version,
76 ) {
77 Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
78 Ok(None) => {
79 LoadResult::DataOutOfDate
82 }
83 Err(err) => LoadResult::LoadDepGraph(path.to_path_buf(), err),
84 }
85}
86
87fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) {
88 debug!("delete_dirty_work_product({:?})", swp);
89 work_product::delete_workproduct_files(sess, &swp.work_product);
90}
91
92fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkProductMap)> {
93 let prof = sess.prof.clone();
94
95 if sess.opts.incremental.is_none() {
96 return LoadResult::Ok { data: Default::default() };
98 }
99
100 let _timer = sess.prof.generic_activity("incr_comp_prepare_load_dep_graph");
101
102 let path = dep_graph_path(sess);
105 let expected_hash = sess.opts.dep_tracking_hash(false);
106
107 let mut prev_work_products = UnordMap::default();
108
109 if sess.incr_comp_session_dir_opt().is_some() {
113 let work_products_path = work_products_path(sess);
114 let load_result = load_data(&work_products_path, sess);
115
116 if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
117 let Ok(mut work_product_decoder) = MemDecoder::new(&work_products_data[..], start_pos)
119 else {
120 sess.dcx().emit_warn(errors::CorruptFile { path: &work_products_path });
121 return LoadResult::DataOutOfDate;
122 };
123 let work_products: Vec<SerializedWorkProduct> =
124 Decodable::decode(&mut work_product_decoder);
125
126 for swp in work_products {
127 let all_files_exist = swp.work_product.saved_files.items().all(|(_, path)| {
128 let exists = in_incr_comp_dir_sess(sess, path).exists();
129 if !exists && sess.opts.unstable_opts.incremental_info {
130 eprintln!("incremental: could not find file for work product: {path}",);
131 }
132 exists
133 });
134
135 if all_files_exist {
136 debug!("reconcile_work_products: all files for {:?} exist", swp);
137 prev_work_products.insert(swp.id, swp.work_product);
138 } else {
139 debug!("reconcile_work_products: some file for {:?} does not exist", swp);
140 delete_dirty_work_product(sess, swp);
141 }
142 }
143 }
144 }
145
146 let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
147
148 match load_data(&path, sess) {
149 LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
150 LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err),
151 LoadResult::Ok { data: (bytes, start_pos) } => {
152 let Ok(mut decoder) = MemDecoder::new(&bytes, start_pos) else {
153 sess.dcx().emit_warn(errors::CorruptFile { path: &path });
154 return LoadResult::DataOutOfDate;
155 };
156 let prev_commandline_args_hash = u64::decode(&mut decoder);
157
158 if prev_commandline_args_hash != expected_hash {
159 if sess.opts.unstable_opts.incremental_info {
160 eprintln!(
161 "[incremental] completely ignoring cache because of \
162 differing commandline arguments"
163 );
164 }
165 debug!("load_dep_graph_new: differing commandline arg hashes");
167
168 return LoadResult::DataOutOfDate;
170 }
171
172 let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
173
174 LoadResult::Ok { data: (dep_graph, prev_work_products) }
175 }
176 }
177}
178
179pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache> {
185 if sess.opts.incremental.is_none() {
186 return None;
187 }
188
189 let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
190
191 let path = query_cache_path(sess);
192 match load_data(&path, sess) {
193 LoadResult::Ok { data: (bytes, start_pos) } => {
194 let cache = OnDiskCache::new(sess, bytes, start_pos).unwrap_or_else(|()| {
195 sess.dcx().emit_warn(errors::CorruptFile { path: &path });
196 OnDiskCache::new_empty()
197 });
198 Some(cache)
199 }
200 _ => Some(OnDiskCache::new_empty()),
201 }
202}
203
204pub fn setup_dep_graph(sess: &Session) -> DepGraph {
207 prepare_session_directory(sess);
209
210 let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess));
211
212 if sess.opts.incremental.is_some() {
213 sess.time("incr_comp_garbage_collect_session_directories", || {
214 if let Err(e) = garbage_collect_session_directories(sess) {
215 warn!(
216 "Error while trying to garbage collect incremental \
217 compilation cache directory: {}",
218 e
219 );
220 }
221 });
222 }
223
224 res.and_then(|result| {
225 let (prev_graph, prev_work_products) = result.open(sess);
226 build_dep_graph(sess, prev_graph, prev_work_products)
227 })
228 .unwrap_or_else(DepGraph::new_disabled)
229}