rustc_incremental/persist/
load.rs1use std::path::PathBuf;
4use std::sync::Arc;
5
6use rustc_data_structures::unord::UnordMap;
7use rustc_hashes::Hash64;
8use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProductMap};
9use rustc_middle::query::on_disk_cache::OnDiskCache;
10use rustc_serialize::Decodable;
11use rustc_serialize::opaque::MemDecoder;
12use rustc_session::config::IncrementalStateAssertion;
13use rustc_session::{Session, StableCrateId};
14use rustc_span::Symbol;
15use tracing::{debug, warn};
16
17use super::data::*;
18use super::fs::*;
19use super::save::build_dep_graph;
20use super::{file_format, work_product};
21use crate::errors;
22use crate::persist::file_format::{OpenFile, OpenFileError};
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 maybe_assert_incr_state(sess, &self);
43
44 match self {
45 LoadResult::LoadDepGraph(path, err) => {
46 sess.dcx().emit_warn(errors::LoadDepGraph { path, err });
47 Default::default()
48 }
49 LoadResult::DataOutOfDate => {
50 if let Err(err) = delete_all_session_dir_contents(sess) {
51 sess.dcx()
52 .emit_err(errors::DeleteIncompatible { path: dep_graph_path(sess), err });
53 }
54 Default::default()
55 }
56 LoadResult::Ok { data } => data,
57 }
58 }
59}
60
61fn delete_dirty_work_product(sess: &Session, swp: SerializedWorkProduct) {
62 {
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:62",
"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(62u32),
::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);
63 work_product::delete_workproduct_files(sess, &swp.work_product);
64}
65
66fn load_dep_graph(sess: &Session) -> LoadResult<(Arc<SerializedDepGraph>, WorkProductMap)> {
67 let prof = sess.prof.clone();
68
69 if sess.opts.incremental.is_none() {
70 return LoadResult::Ok { data: Default::default() };
72 }
73
74 let _timer = sess.prof.generic_activity("incr_comp_prepare_load_dep_graph");
75
76 let path = dep_graph_path(sess);
79 let expected_hash = sess.opts.dep_tracking_hash(false);
80
81 let mut prev_work_products = UnordMap::default();
82
83 if sess.incr_comp_session_dir_opt().is_some() {
87 let work_products_path = work_products_path(sess);
88
89 if let Ok(OpenFile { mmap, start_pos }) =
90 file_format::open_incremental_file(sess, &work_products_path)
91 {
92 let Ok(mut work_product_decoder) = MemDecoder::new(&mmap[..], start_pos) else {
94 sess.dcx().emit_warn(errors::CorruptFile { path: &work_products_path });
95 return LoadResult::DataOutOfDate;
96 };
97 let work_products: Vec<SerializedWorkProduct> =
98 Decodable::decode(&mut work_product_decoder);
99
100 for swp in work_products {
101 let all_files_exist = swp.work_product.saved_files.items().all(|(_, path)| {
102 let exists = in_incr_comp_dir_sess(sess, path).exists();
103 if !exists && sess.opts.unstable_opts.incremental_info {
104 {
::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}",);
105 }
106 exists
107 });
108
109 if all_files_exist {
110 {
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:110",
"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(110u32),
::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);
111 prev_work_products.insert(swp.id, swp.work_product);
112 } else {
113 {
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:113",
"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(113u32),
::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);
114 delete_dirty_work_product(sess, swp);
115 }
116 }
117 }
118 }
119
120 let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
121
122 match file_format::open_incremental_file(sess, &path) {
123 Err(OpenFileError::NotFoundOrHeaderMismatch) => LoadResult::DataOutOfDate,
124 Err(OpenFileError::IoError { err }) => LoadResult::LoadDepGraph(path.to_owned(), err),
125 Ok(OpenFile { mmap, start_pos }) => {
126 let Ok(mut decoder) = MemDecoder::new(&mmap, start_pos) else {
127 sess.dcx().emit_warn(errors::CorruptFile { path: &path });
128 return LoadResult::DataOutOfDate;
129 };
130 let prev_commandline_args_hash = Hash64::decode(&mut decoder);
131
132 if prev_commandline_args_hash != expected_hash {
133 if sess.opts.unstable_opts.incremental_info {
134 {
::std::io::_eprint(format_args!("[incremental] completely ignoring cache because of differing commandline arguments\n"));
};eprintln!(
135 "[incremental] completely ignoring cache because of \
136 differing commandline arguments"
137 );
138 }
139 {
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:140",
"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(140u32),
::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");
141
142 return LoadResult::DataOutOfDate;
144 }
145
146 let dep_graph = SerializedDepGraph::decode(&mut decoder);
147
148 LoadResult::Ok { data: (dep_graph, prev_work_products) }
149 }
150 }
151}
152
153pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache> {
159 if sess.opts.incremental.is_none() {
160 return None;
161 }
162
163 let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
164
165 let path = query_cache_path(sess);
166 match file_format::open_incremental_file(sess, &path) {
167 Ok(OpenFile { mmap, start_pos }) => {
168 let cache = OnDiskCache::new(sess, mmap, start_pos).unwrap_or_else(|()| {
169 sess.dcx().emit_warn(errors::CorruptFile { path: &path });
170 OnDiskCache::new_empty()
171 });
172 Some(cache)
173 }
174 Err(OpenFileError::NotFoundOrHeaderMismatch | OpenFileError::IoError { .. }) => {
175 Some(OnDiskCache::new_empty())
176 }
177 }
178}
179
180fn maybe_assert_incr_state(sess: &Session, load_result: &LoadResult<impl Sized>) {
183 let Some(assertion) = sess.opts.unstable_opts.assert_incr_state else { return };
185
186 let loaded = match load_result {
188 LoadResult::Ok { .. } => true,
189 LoadResult::DataOutOfDate | LoadResult::LoadDepGraph(..) => false,
190 };
191
192 match assertion {
193 IncrementalStateAssertion::Loaded => {
194 if !loaded {
195 sess.dcx().emit_fatal(errors::AssertLoaded);
196 }
197 }
198 IncrementalStateAssertion::NotLoaded => {
199 if loaded {
200 sess.dcx().emit_fatal(errors::AssertNotLoaded)
201 }
202 }
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}