1 use rustc_data_structures
::fx
::FxHashMap
;
2 use rustc_data_structures
::sync
::join
;
3 use rustc_middle
::dep_graph
::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId}
;
4 use rustc_middle
::ty
::TyCtxt
;
5 use rustc_serialize
::opaque
::{FileEncodeResult, FileEncoder}
;
6 use rustc_serialize
::Encodable
as RustcEncodable
;
7 use rustc_session
::Session
;
11 use super::dirty_clean
;
12 use super::file_format
;
14 use super::work_product
;
16 /// Saves and writes the [`DepGraph`] to the file system.
18 /// This function saves both the dep-graph and the query result cache,
19 /// and drops the result cache.
21 /// This function should only run after all queries have completed.
22 /// Trying to execute a query afterwards would attempt to read the result cache we just dropped.
23 pub fn save_dep_graph(tcx
: TyCtxt
<'_
>) {
24 debug
!("save_dep_graph()");
25 tcx
.dep_graph
.with_ignore(|| {
27 if sess
.opts
.incremental
.is_none() {
30 // This is going to be deleted in finalize_session_directory, so let's not create it
31 if sess
.has_errors_or_delayed_span_bugs() {
35 let query_cache_path
= query_cache_path(sess
);
36 let dep_graph_path
= dep_graph_path(sess
);
37 let staging_dep_graph_path
= staging_dep_graph_path(sess
);
39 sess
.time("assert_dep_graph", || crate::assert_dep_graph(tcx
));
40 sess
.time("check_dirty_clean", || dirty_clean
::check_dirty_clean_annotations(tcx
));
42 if sess
.opts
.debugging_opts
.incremental_info
{
43 tcx
.dep_graph
.print_incremental_info()
48 sess
.time("incr_comp_persist_result_cache", || {
49 // Drop the memory map so that we can remove the file and write to it.
50 if let Some(odc
) = &tcx
.on_disk_cache
{
51 odc
.drop_serialized_data(tcx
);
54 file_format
::save_in(sess
, query_cache_path
, "query cache", |e
| {
55 encode_query_cache(tcx
, e
)
60 sess
.time("incr_comp_persist_dep_graph", || {
61 if let Err(err
) = tcx
.dep_graph
.encode(&tcx
.sess
.prof
) {
63 "failed to write dependency graph to `{}`: {}",
64 staging_dep_graph_path
.display(),
68 if let Err(err
) = fs
::rename(&staging_dep_graph_path
, &dep_graph_path
) {
70 "failed to move dependency graph from `{}` to `{}`: {}",
71 staging_dep_graph_path
.display(),
72 dep_graph_path
.display(),
82 /// Saves the work product index.
83 pub fn save_work_product_index(
86 new_work_products
: FxHashMap
<WorkProductId
, WorkProduct
>,
88 if sess
.opts
.incremental
.is_none() {
91 // This is going to be deleted in finalize_session_directory, so let's not create it
92 if sess
.has_errors_or_delayed_span_bugs() {
96 debug
!("save_work_product_index()");
97 dep_graph
.assert_ignored();
98 let path
= work_products_path(sess
);
99 file_format
::save_in(sess
, path
, "work product index", |e
| {
100 encode_work_product_index(&new_work_products
, e
)
103 // We also need to clean out old work-products, as not all of them are
104 // deleted during invalidation. Some object files don't change their
105 // content, they are just not needed anymore.
106 let previous_work_products
= dep_graph
.previous_work_products();
107 for (id
, wp
) in previous_work_products
.iter() {
108 if !new_work_products
.contains_key(id
) {
109 work_product
::delete_workproduct_files(sess
, wp
);
111 wp
.saved_file
.as_ref().map_or(true, |file_name
| {
112 !in_incr_comp_dir_sess(sess
, &file_name
).exists()
118 // Check that we did not delete one of the current work-products:
122 .flat_map(|(_
, wp
)| wp
.saved_file
.iter())
123 .map(|name
| in_incr_comp_dir_sess(sess
, name
))
124 .all(|path
| path
.exists())
128 fn encode_work_product_index(
129 work_products
: &FxHashMap
<WorkProductId
, WorkProduct
>,
130 encoder
: &mut FileEncoder
,
131 ) -> FileEncodeResult
{
132 let serialized_products
: Vec
<_
> = work_products
134 .map(|(id
, work_product
)| SerializedWorkProduct
{
136 work_product
: work_product
.clone(),
140 serialized_products
.encode(encoder
)
143 fn encode_query_cache(tcx
: TyCtxt
<'_
>, encoder
: &mut FileEncoder
) -> FileEncodeResult
{
144 tcx
.sess
.time("incr_comp_serialize_result_cache", || tcx
.serialize_query_result_cache(encoder
))
147 /// Builds the dependency graph.
149 /// This function creates the *staging dep-graph*. When the dep-graph is modified by a query
150 /// execution, the new dependency information is not kept in memory but directly
151 /// output to this file. `save_dep_graph` then finalizes the staging dep-graph
152 /// and moves it to the permanent dep-graph path
153 pub fn build_dep_graph(
155 prev_graph
: SerializedDepGraph
,
156 prev_work_products
: FxHashMap
<WorkProductId
, WorkProduct
>,
157 ) -> Option
<DepGraph
> {
158 if sess
.opts
.incremental
.is_none() {
159 // No incremental compilation.
163 // Stream the dep-graph to an alternate file, to avoid overwriting anything in case of errors.
164 let path_buf
= staging_dep_graph_path(sess
);
166 let mut encoder
= match FileEncoder
::new(&path_buf
) {
167 Ok(encoder
) => encoder
,
170 "failed to create dependency graph at `{}`: {}",
178 if let Err(err
) = file_format
::write_file_header(&mut encoder
, sess
.is_nightly_build()) {
180 "failed to write dependency graph header to `{}`: {}",
187 // First encode the commandline arguments hash
188 if let Err(err
) = sess
.opts
.dep_tracking_hash(false).encode(&mut encoder
) {
190 "failed to write dependency graph hash `{}`: {}",
202 sess
.opts
.debugging_opts
.query_dep_graph
,
203 sess
.opts
.debugging_opts
.incremental_info
,