rustc_incremental/persist/
load.rs1use std::path::{Path, PathBuf};
4use std::sync::Arc;
5
6use rustc_data_structures::memmap::Mmap;
7use rustc_data_structures::unord::UnordMap;
8use rustc_hashes::Hash64;
9use rustc_middle::dep_graph::{DepGraph, DepsType, SerializedDepGraph, WorkProductMap};
10use rustc_middle::query::on_disk_cache::OnDiskCache;
11use rustc_serialize::Decodable;
12use rustc_serialize::opaque::MemDecoder;
13use rustc_session::config::IncrementalStateAssertion;
14use rustc_session::{Session, StableCrateId};
15use rustc_span::Symbol;
16use tracing::{debug, warn};
17
18use super::data::*;
19use super::fs::*;
20use super::save::build_dep_graph;
21use super::{file_format, work_product};
22use crate::errors;
23
24#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug> ::core::fmt::Debug for LoadResult<T> {
#[inline]
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
match self {
LoadResult::Ok { data: __self_0 } =>
::core::fmt::Formatter::debug_struct_field1_finish(f, "Ok",
"data", &__self_0),
LoadResult::DataOutOfDate =>
::core::fmt::Formatter::write_str(f, "DataOutOfDate"),
LoadResult::LoadDepGraph(__self_0, __self_1) =>
::core::fmt::Formatter::debug_tuple_field2_finish(f,
"LoadDepGraph", __self_0, &__self_1),
}
}
}Debug)]
25pub enum LoadResult<T> {
27 Ok {
29 #[allow(missing_docs)]
30 data: T,
31 },
32 DataOutOfDate,
34 LoadDepGraph(PathBuf, std::io::Error),
36}
37
38impl<T: Default> LoadResult<T> {
39 pub fn open(self, sess: &Session) -> T {
41 match (sess.opts.assert_incr_state, &self) {
43 (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => {
44 sess.dcx().emit_fatal(errors::AssertNotLoaded);
45 }
46 (
47 Some(IncrementalStateAssertion::Loaded),
48 LoadResult::LoadDepGraph(..) | LoadResult::DataOutOfDate,
49 ) => {
50 sess.dcx().emit_fatal(errors::AssertLoaded);
51 }
52 _ => {}
53 };
54
55 match self {
56 LoadResult::LoadDepGraph(path, err) => {
57 sess.dcx().emit_warn(errors::LoadDepGraph { path, err });
58 Default::default()
59 }
60 LoadResult::DataOutOfDate => {
61 if let Err(err) = delete_all_session_dir_contents(sess) {
62 sess.dcx()
63 .emit_err(errors::DeleteIncompatible { path: dep_graph_path(sess), err });
64 }
65 Default::default()
66 }
67 LoadResult::Ok { data } => data,
68 }
69 }
70}
71
72fn load_data(path: &Path, sess: &Session) -> LoadResult<(Mmap, usize)> {
73 match file_format::read_file(
74 path,
75 sess.opts.unstable_opts.incremental_info,
76 sess.is_nightly_build(),
77 sess.cfg_version,
78 ) {
79 Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
80 Ok(None) => {
81 LoadResult::DataOutOfDate
84 }
85 Err(err) => LoadResult::LoadDepGraph(path.to_path_buf(), err),
86 }
87}
88
89fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) {
90 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_incremental/src/persist/load.rs:90",
"rustc_incremental::persist::load", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_incremental/src/persist/load.rs"),
::tracing_core::__macro_support::Option::Some(90u32),
::tracing_core::__macro_support::Option::Some("rustc_incremental::persist::load"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("delete_dirty_work_product({0:?})",
swp) as &dyn Value))])
});
} else { ; }
};debug!("delete_dirty_work_product({:?})", swp);
91 work_product::delete_workproduct_files(sess, &swp.work_product);
92}
93
94fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkProductMap)> {
95 let prof = sess.prof.clone();
96
97 if sess.opts.incremental.is_none() {
98 return LoadResult::Ok { data: Default::default() };
100 }
101
102 let _timer = sess.prof.generic_activity("incr_comp_prepare_load_dep_graph");
103
104 let path = dep_graph_path(sess);
107 let expected_hash = sess.opts.dep_tracking_hash(false);
108
109 let mut prev_work_products = UnordMap::default();
110
111 if sess.incr_comp_session_dir_opt().is_some() {
115 let work_products_path = work_products_path(sess);
116 let load_result = load_data(&work_products_path, sess);
117
118 if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
119 let Ok(mut work_product_decoder) = MemDecoder::new(&work_products_data[..], start_pos)
121 else {
122 sess.dcx().emit_warn(errors::CorruptFile { path: &work_products_path });
123 return LoadResult::DataOutOfDate;
124 };
125 let work_products: Vec<SerializedWorkProduct> =
126 Decodable::decode(&mut work_product_decoder);
127
128 for swp in work_products {
129 let all_files_exist = swp.work_product.saved_files.items().all(|(_, path)| {
130 let exists = in_incr_comp_dir_sess(sess, path).exists();
131 if !exists && sess.opts.unstable_opts.incremental_info {
132 {
::std::io::_eprint(format_args!("incremental: could not find file for work product: {0}\n",
path));
};eprintln!("incremental: could not find file for work product: {path}",);
133 }
134 exists
135 });
136
137 if all_files_exist {
138 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_incremental/src/persist/load.rs:138",
"rustc_incremental::persist::load", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_incremental/src/persist/load.rs"),
::tracing_core::__macro_support::Option::Some(138u32),
::tracing_core::__macro_support::Option::Some("rustc_incremental::persist::load"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("reconcile_work_products: all files for {0:?} exist",
swp) as &dyn Value))])
});
} else { ; }
};debug!("reconcile_work_products: all files for {:?} exist", swp);
139 prev_work_products.insert(swp.id, swp.work_product);
140 } else {
141 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_incremental/src/persist/load.rs:141",
"rustc_incremental::persist::load", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_incremental/src/persist/load.rs"),
::tracing_core::__macro_support::Option::Some(141u32),
::tracing_core::__macro_support::Option::Some("rustc_incremental::persist::load"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("reconcile_work_products: some file for {0:?} does not exist",
swp) as &dyn Value))])
});
} else { ; }
};debug!("reconcile_work_products: some file for {:?} does not exist", swp);
142 delete_dirty_work_product(sess, swp);
143 }
144 }
145 }
146 }
147
148 let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
149
150 match load_data(&path, sess) {
151 LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
152 LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err),
153 LoadResult::Ok { data: (bytes, start_pos) } => {
154 let Ok(mut decoder) = MemDecoder::new(&bytes, start_pos) else {
155 sess.dcx().emit_warn(errors::CorruptFile { path: &path });
156 return LoadResult::DataOutOfDate;
157 };
158 let prev_commandline_args_hash = Hash64::decode(&mut decoder);
159
160 if prev_commandline_args_hash != expected_hash {
161 if sess.opts.unstable_opts.incremental_info {
162 {
::std::io::_eprint(format_args!("[incremental] completely ignoring cache because of differing commandline arguments\n"));
};eprintln!(
163 "[incremental] completely ignoring cache because of \
164 differing commandline arguments"
165 );
166 }
167 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_incremental/src/persist/load.rs:168",
"rustc_incremental::persist::load", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_incremental/src/persist/load.rs"),
::tracing_core::__macro_support::Option::Some(168u32),
::tracing_core::__macro_support::Option::Some("rustc_incremental::persist::load"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("load_dep_graph_new: differing commandline arg hashes")
as &dyn Value))])
});
} else { ; }
};debug!("load_dep_graph_new: differing commandline arg hashes");
169
170 return LoadResult::DataOutOfDate;
172 }
173
174 let dep_graph = SerializedDepGraph::decode::<DepsType>(&mut decoder);
175
176 LoadResult::Ok { data: (dep_graph, prev_work_products) }
177 }
178 }
179}
180
181pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache> {
187 if sess.opts.incremental.is_none() {
188 return None;
189 }
190
191 let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
192
193 let path = query_cache_path(sess);
194 match load_data(&path, sess) {
195 LoadResult::Ok { data: (bytes, start_pos) } => {
196 let cache = OnDiskCache::new(sess, bytes, start_pos).unwrap_or_else(|()| {
197 sess.dcx().emit_warn(errors::CorruptFile { path: &path });
198 OnDiskCache::new_empty()
199 });
200 Some(cache)
201 }
202 _ => Some(OnDiskCache::new_empty()),
203 }
204}
205
206pub fn setup_dep_graph(
209 sess: &Session,
210 crate_name: Symbol,
211 stable_crate_id: StableCrateId,
212) -> DepGraph {
213 prepare_session_directory(sess, crate_name, stable_crate_id);
215
216 let res = sess.opts.build_dep_graph().then(|| load_dep_graph(sess));
217
218 if sess.opts.incremental.is_some() {
219 sess.time("incr_comp_garbage_collect_session_directories", || {
220 if let Err(e) = garbage_collect_session_directories(sess) {
221 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_incremental/src/persist/load.rs:221",
"rustc_incremental::persist::load", ::tracing::Level::WARN,
::tracing_core::__macro_support::Option::Some("compiler/rustc_incremental/src/persist/load.rs"),
::tracing_core::__macro_support::Option::Some(221u32),
::tracing_core::__macro_support::Option::Some("rustc_incremental::persist::load"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::WARN <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::WARN <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&format_args!("Error while trying to garbage collect incremental compilation cache directory: {0}",
e) as &dyn Value))])
});
} else { ; }
};warn!(
222 "Error while trying to garbage collect incremental \
223 compilation cache directory: {}",
224 e
225 );
226 }
227 });
228 }
229
230 res.and_then(|result| {
231 let (prev_graph, prev_work_products) = result.open(sess);
232 build_dep_graph(sess, prev_graph, prev_work_products)
233 })
234 .unwrap_or_else(DepGraph::new_disabled)
235}