]> git.lizzy.rs Git - rust.git/blob - crates/ide_db/src/apply_change.rs
Merge #7353
[rust.git] / crates / ide_db / src / apply_change.rs
1 //! Applies changes to the IDE state transactionally.
2
3 use std::{fmt, sync::Arc};
4
5 use base_db::{
6     salsa::{Database, Durability, SweepStrategy},
7     Change, FileId, SourceRootId,
8 };
9 use profile::{memory_usage, Bytes};
10 use rustc_hash::FxHashSet;
11
12 use crate::{symbol_index::SymbolsDatabase, RootDatabase};
13
14 #[derive(Debug)]
15 struct AddFile {
16     file_id: FileId,
17     path: String,
18     text: Arc<String>,
19 }
20
21 #[derive(Debug)]
22 struct RemoveFile {
23     file_id: FileId,
24     path: String,
25 }
26
27 #[derive(Default)]
28 struct RootChange {
29     added: Vec<AddFile>,
30     removed: Vec<RemoveFile>,
31 }
32
33 impl fmt::Debug for RootChange {
34     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
35         fmt.debug_struct("AnalysisChange")
36             .field("added", &self.added.len())
37             .field("removed", &self.removed.len())
38             .finish()
39     }
40 }
41
42 impl RootDatabase {
43     pub fn request_cancellation(&mut self) {
44         let _p = profile::span("RootDatabase::request_cancellation");
45         self.salsa_runtime_mut().synthetic_write(Durability::LOW);
46     }
47
48     pub fn apply_change(&mut self, change: Change) {
49         let _p = profile::span("RootDatabase::apply_change");
50         self.request_cancellation();
51         log::info!("apply_change {:?}", change);
52         if let Some(roots) = &change.roots {
53             let mut local_roots = FxHashSet::default();
54             let mut library_roots = FxHashSet::default();
55             for (idx, root) in roots.iter().enumerate() {
56                 let root_id = SourceRootId(idx as u32);
57                 if root.is_library {
58                     library_roots.insert(root_id);
59                 } else {
60                     local_roots.insert(root_id);
61                 }
62             }
63             self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
64             self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
65         }
66         change.apply(self);
67     }
68
69     pub fn collect_garbage(&mut self) {
70         if cfg!(feature = "wasm") {
71             return;
72         }
73
74         let _p = profile::span("RootDatabase::collect_garbage");
75
76         let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
77
78         base_db::ParseQuery.in_db(self).sweep(sweep);
79         hir::db::ParseMacroExpansionQuery.in_db(self).sweep(sweep);
80
81         // Macros do take significant space, but less then the syntax trees
82         // self.query(hir::db::MacroDefQuery).sweep(sweep);
83         // self.query(hir::db::MacroArgTextQuery).sweep(sweep);
84         // self.query(hir::db::MacroExpandQuery).sweep(sweep);
85
86         hir::db::AstIdMapQuery.in_db(self).sweep(sweep);
87
88         hir::db::BodyWithSourceMapQuery.in_db(self).sweep(sweep);
89
90         hir::db::ExprScopesQuery.in_db(self).sweep(sweep);
91         hir::db::InferQueryQuery.in_db(self).sweep(sweep);
92         hir::db::BodyQuery.in_db(self).sweep(sweep);
93     }
94
95     // Feature: Memory Usage
96     //
97     // Clears rust-analyzer's internal database and prints memory usage statistics.
98     //
99     // |===
100     // | Editor  | Action Name
101     //
102     // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)**
103     // |===
104     pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
105         let mut acc: Vec<(String, Bytes)> = vec![];
106         let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
107         macro_rules! sweep_each_query {
108             ($($q:path)*) => {$(
109                 let before = memory_usage().allocated;
110                 $q.in_db(self).sweep(sweep);
111                 let after = memory_usage().allocated;
112                 let q: $q = Default::default();
113                 let name = format!("{:?}", q);
114                 acc.push((name, before - after));
115
116                 let before = memory_usage().allocated;
117                 $q.in_db(self).sweep(sweep.discard_everything());
118                 let after = memory_usage().allocated;
119                 let q: $q = Default::default();
120                 let name = format!("{:?} (deps)", q);
121                 acc.push((name, before - after));
122
123                 let before = memory_usage().allocated;
124                 $q.in_db(self).purge();
125                 let after = memory_usage().allocated;
126                 let q: $q = Default::default();
127                 let name = format!("{:?} (purge)", q);
128                 acc.push((name, before - after));
129             )*}
130         }
131         sweep_each_query![
132             // SourceDatabase
133             base_db::ParseQuery
134             base_db::CrateGraphQuery
135
136             // SourceDatabaseExt
137             base_db::FileTextQuery
138             base_db::FileSourceRootQuery
139             base_db::SourceRootQuery
140             base_db::SourceRootCratesQuery
141
142             // AstDatabase
143             hir::db::AstIdMapQuery
144             hir::db::MacroArgTextQuery
145             hir::db::MacroDefQuery
146             hir::db::ParseMacroExpansionQuery
147             hir::db::MacroExpandQuery
148             hir::db::HygieneFrameQuery
149
150             // DefDatabase
151             hir::db::ItemTreeQuery
152             hir::db::BlockDefMapQuery
153             hir::db::CrateDefMapQueryQuery
154             hir::db::StructDataQuery
155             hir::db::UnionDataQuery
156             hir::db::EnumDataQuery
157             hir::db::ImplDataQuery
158             hir::db::TraitDataQuery
159             hir::db::TypeAliasDataQuery
160             hir::db::FunctionDataQuery
161             hir::db::ConstDataQuery
162             hir::db::StaticDataQuery
163             hir::db::BodyWithSourceMapQuery
164             hir::db::BodyQuery
165             hir::db::ExprScopesQuery
166             hir::db::GenericParamsQuery
167             hir::db::AttrsQuery
168             hir::db::CrateLangItemsQuery
169             hir::db::LangItemQuery
170             hir::db::ImportMapQuery
171
172             // HirDatabase
173             hir::db::InferQueryQuery
174             hir::db::TyQuery
175             hir::db::ValueTyQuery
176             hir::db::ImplSelfTyQuery
177             hir::db::ImplTraitQuery
178             hir::db::FieldTypesQuery
179             hir::db::CallableItemSignatureQuery
180             hir::db::GenericPredicatesForParamQuery
181             hir::db::GenericPredicatesQuery
182             hir::db::GenericDefaultsQuery
183             hir::db::InherentImplsInCrateQuery
184             hir::db::TraitImplsInCrateQuery
185             hir::db::TraitImplsInDepsQuery
186             hir::db::AssociatedTyDataQuery
187             hir::db::AssociatedTyDataQuery
188             hir::db::TraitDatumQuery
189             hir::db::StructDatumQuery
190             hir::db::ImplDatumQuery
191             hir::db::FnDefDatumQuery
192             hir::db::ReturnTypeImplTraitsQuery
193             hir::db::InternCallableDefQuery
194             hir::db::InternTypeParamIdQuery
195             hir::db::InternImplTraitIdQuery
196             hir::db::InternClosureQuery
197             hir::db::AssociatedTyValueQuery
198             hir::db::TraitSolveQuery
199
200             // SymbolsDatabase
201             crate::symbol_index::FileSymbolsQuery
202             crate::symbol_index::LibrarySymbolsQuery
203             crate::symbol_index::LocalRootsQuery
204             crate::symbol_index::LibraryRootsQuery
205
206             // LineIndexDatabase
207             crate::LineIndexQuery
208         ];
209
210         // To collect interned data, we need to bump the revision counter by performing a synthetic
211         // write.
212         // We do this after collecting the non-interned queries to correctly attribute memory used
213         // by interned data.
214         self.salsa_runtime_mut().synthetic_write(Durability::HIGH);
215
216         sweep_each_query![
217             // AstDatabase
218             hir::db::InternMacroQuery
219             hir::db::InternEagerExpansionQuery
220
221             // InternDatabase
222             hir::db::InternFunctionQuery
223             hir::db::InternStructQuery
224             hir::db::InternUnionQuery
225             hir::db::InternEnumQuery
226             hir::db::InternConstQuery
227             hir::db::InternStaticQuery
228             hir::db::InternTraitQuery
229             hir::db::InternTypeAliasQuery
230             hir::db::InternImplQuery
231
232             // HirDatabase
233             hir::db::InternTypeParamIdQuery
234         ];
235
236         acc.sort_by_key(|it| std::cmp::Reverse(it.1));
237         acc
238     }
239 }