use crate::errors;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::join;
use rustc_middle::dep_graph::{
DepGraph, SerializedDepGraph, WorkProduct, WorkProductId, WorkProductMap,
};
use rustc_middle::ty::TyCtxt;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_serialize::Encodable as RustcEncodable;
use rustc_session::Session;
use std::fs;
use super::data::*;
use super::dirty_clean;
use super::file_format;
use super::fs::*;
use super::work_product;
pub fn save_dep_graph(tcx: TyCtxt<'_>) {
debug!("save_dep_graph()");
tcx.dep_graph.with_ignore(|| {
let sess = tcx.sess;
if sess.opts.incremental.is_none() {
return;
}
if let Some(_) = sess.has_errors_or_delayed_span_bugs() {
return;
}
let query_cache_path = query_cache_path(sess);
let dep_graph_path = dep_graph_path(sess);
let staging_dep_graph_path = staging_dep_graph_path(sess);
sess.time("assert_dep_graph", || crate::assert_dep_graph(tcx));
sess.time("check_dirty_clean", || dirty_clean::check_dirty_clean_annotations(tcx));
if sess.opts.unstable_opts.incremental_info {
tcx.dep_graph.print_incremental_info()
}
join(
move || {
sess.time("incr_comp_persist_dep_graph", || {
if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) {
sess.emit_err(errors::WriteDepGraph { path: &staging_dep_graph_path, err });
}
if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) {
sess.emit_err(errors::MoveDepGraph {
from: &staging_dep_graph_path,
to: &dep_graph_path,
err,
});
}
});
},
move || {
sess.time("incr_comp_persist_result_cache", || {
if let Some(odc) = &tcx.query_system.on_disk_cache {
odc.drop_serialized_data(tcx);
}
file_format::save_in(sess, query_cache_path, "query cache", |e| {
encode_query_cache(tcx, e)
});
});
},
);
})
}
pub fn save_work_product_index(
sess: &Session,
dep_graph: &DepGraph,
new_work_products: FxIndexMap<WorkProductId, WorkProduct>,
) {
if sess.opts.incremental.is_none() {
return;
}
if let Some(_) = sess.has_errors_or_delayed_span_bugs() {
return;
}
debug!("save_work_product_index()");
dep_graph.assert_ignored();
let path = work_products_path(sess);
file_format::save_in(sess, path, "work product index", |mut e| {
encode_work_product_index(&new_work_products, &mut e);
e.finish()
});
let previous_work_products = dep_graph.previous_work_products();
for (id, wp) in previous_work_products.to_sorted_stable_ord().iter() {
if !new_work_products.contains_key(id) {
work_product::delete_workproduct_files(sess, wp);
debug_assert!(
!wp.saved_files.items().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
);
}
}
debug_assert!({
new_work_products.iter().all(|(_, wp)| {
wp.saved_files.items().all(|(_, path)| in_incr_comp_dir_sess(sess, path).exists())
})
});
}
fn encode_work_product_index(
work_products: &FxIndexMap<WorkProductId, WorkProduct>,
encoder: &mut FileEncoder,
) {
let serialized_products: Vec<_> = work_products
.iter()
.map(|(id, work_product)| SerializedWorkProduct {
id: *id,
work_product: work_product.clone(),
})
.collect();
serialized_products.encode(encoder)
}
fn encode_query_cache(tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult {
tcx.sess.time("incr_comp_serialize_result_cache", || tcx.serialize_query_result_cache(encoder))
}
pub(crate) fn build_dep_graph(
sess: &Session,
prev_graph: SerializedDepGraph,
prev_work_products: WorkProductMap,
) -> Option<DepGraph> {
if sess.opts.incremental.is_none() {
return None;
}
let path_buf = staging_dep_graph_path(sess);
let mut encoder = match FileEncoder::new(&path_buf) {
Ok(encoder) => encoder,
Err(err) => {
sess.emit_err(errors::CreateDepGraph { path: &path_buf, err });
return None;
}
};
file_format::write_file_header(&mut encoder, sess);
sess.opts.dep_tracking_hash(false).encode(&mut encoder);
Some(DepGraph::new(
&sess.prof,
prev_graph,
prev_work_products,
encoder,
sess.opts.unstable_opts.query_dep_graph,
sess.opts.unstable_opts.incremental_info,
))
}