1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
//! Applies changes to the IDE state transactionally.

use base_db::{
    ra_salsa::{
        debug::{DebugQueryTable, TableEntry},
        Database, Durability, Query, QueryTable,
    },
    SourceRootId,
};
use profile::{memory_usage, Bytes};
use rustc_hash::FxHashSet;
use triomphe::Arc;

use crate::{symbol_index::SymbolsDatabase, ChangeWithProcMacros, RootDatabase};

impl RootDatabase {
    pub fn request_cancellation(&mut self) {
        let _p = tracing::info_span!("RootDatabase::request_cancellation").entered();
        self.synthetic_write(Durability::LOW);
    }

    pub fn apply_change(&mut self, change: ChangeWithProcMacros) {
        let _p = tracing::info_span!("RootDatabase::apply_change").entered();
        self.request_cancellation();
        tracing::trace!("apply_change {:?}", change);
        if let Some(roots) = &change.source_change.roots {
            let mut local_roots = FxHashSet::default();
            let mut library_roots = FxHashSet::default();
            for (idx, root) in roots.iter().enumerate() {
                let root_id = SourceRootId(idx as u32);
                if root.is_library {
                    library_roots.insert(root_id);
                } else {
                    local_roots.insert(root_id);
                }
            }
            self.set_local_roots_with_durability(Arc::new(local_roots), Durability::HIGH);
            self.set_library_roots_with_durability(Arc::new(library_roots), Durability::HIGH);
        }
        change.apply(self);
    }

    // Feature: Memory Usage
    //
    // Clears rust-analyzer's internal database and prints memory usage statistics.
    //
    // |===
    // | Editor  | Action Name
    //
    // | VS Code | **rust-analyzer: Memory Usage (Clears Database)**
    // |===
    // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[]
    pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes, usize)> {
        let mut acc: Vec<(String, Bytes, usize)> = vec![];

        fn collect_query_count<'q, Q>(table: &QueryTable<'q, Q>) -> usize
        where
            QueryTable<'q, Q>: DebugQueryTable,
            Q: Query,
            <Q as Query>::Storage: 'q,
        {
            struct EntryCounter(usize);
            impl<K, V> FromIterator<TableEntry<K, V>> for EntryCounter {
                fn from_iter<T>(iter: T) -> EntryCounter
                where
                    T: IntoIterator<Item = TableEntry<K, V>>,
                {
                    EntryCounter(iter.into_iter().count())
                }
            }
            table.entries::<EntryCounter>().0
        }

        macro_rules! purge_each_query {
            ($($q:path)*) => {$(
                let before = memory_usage().allocated;
                let table = $q.in_db(self);
                let count = collect_query_count(&table);
                table.purge();
                let after = memory_usage().allocated;
                let q: $q = Default::default();
                let name = format!("{:?}", q);
                acc.push((name, before - after, count));
            )*}
        }
        purge_each_query![
            // SymbolsDatabase
            crate::symbol_index::ModuleSymbolsQuery
            crate::symbol_index::LibrarySymbolsQuery
            crate::symbol_index::LocalRootsQuery
            crate::symbol_index::LibraryRootsQuery
            // HirDatabase
            hir::db::AdtDatumQuery
            hir::db::AdtVarianceQuery
            hir::db::AssociatedTyDataQuery
            hir::db::AssociatedTyValueQuery
            hir::db::BorrowckQuery
            hir::db::CallableItemSignatureQuery
            hir::db::ConstEvalDiscriminantQuery
            hir::db::ConstEvalQuery
            hir::db::ConstEvalStaticQuery
            hir::db::ConstParamTyQuery
            hir::db::DynCompatibilityOfTraitQuery
            hir::db::FieldTypesQuery
            hir::db::FnDefDatumQuery
            hir::db::FnDefVarianceQuery
            hir::db::GenericDefaultsQuery
            hir::db::GenericPredicatesForParamQuery
            hir::db::GenericPredicatesQuery
            hir::db::GenericPredicatesWithoutParentQuery
            hir::db::ImplDatumQuery
            hir::db::ImplSelfTyQuery
            hir::db::ImplTraitQuery
            hir::db::IncoherentInherentImplCratesQuery
            hir::db::InferQuery
            hir::db::InherentImplsInBlockQuery
            hir::db::InherentImplsInCrateQuery
            hir::db::InternCallableDefQuery
            hir::db::InternClosureQuery
            hir::db::InternCoroutineQuery
            hir::db::InternImplTraitIdQuery
            hir::db::InternLifetimeParamIdQuery
            hir::db::InternTypeOrConstParamIdQuery
            hir::db::LayoutOfAdtQuery
            hir::db::LayoutOfTyQuery
            hir::db::LookupImplMethodQuery
            hir::db::MirBodyForClosureQuery
            hir::db::MirBodyQuery
            hir::db::MonomorphizedMirBodyForClosureQuery
            hir::db::MonomorphizedMirBodyQuery
            hir::db::ProgramClausesForChalkEnvQuery
            hir::db::ReturnTypeImplTraitsQuery
            hir::db::TargetDataLayoutQuery
            hir::db::TraitDatumQuery
            hir::db::TraitEnvironmentQuery
            hir::db::TraitImplsInBlockQuery
            hir::db::TraitImplsInCrateQuery
            hir::db::TraitImplsInDepsQuery
            hir::db::TraitSolveQuery
            hir::db::TyQuery
            hir::db::TypeAliasImplTraitsQuery
            hir::db::ValueTyQuery

            // DefDatabase
            hir::db::AttrsQuery
            hir::db::BlockDefMapQuery
            hir::db::BlockItemTreeQuery
            hir::db::BlockItemTreeWithSourceMapQuery
            hir::db::BodyQuery
            hir::db::BodyWithSourceMapQuery
            hir::db::ConstDataQuery
            hir::db::ConstVisibilityQuery
            hir::db::CrateDefMapQuery
            hir::db::CrateLangItemsQuery
            hir::db::CrateNotableTraitsQuery
            hir::db::CrateSupportsNoStdQuery
            hir::db::EnumDataQuery
            hir::db::EnumVariantDataWithDiagnosticsQuery
            hir::db::ExpandProcAttrMacrosQuery
            hir::db::ExprScopesQuery
            hir::db::ExternCrateDeclDataQuery
            hir::db::FieldVisibilitiesQuery
            hir::db::FieldsAttrsQuery
            hir::db::FieldsAttrsSourceMapQuery
            hir::db::FileItemTreeQuery
            hir::db::FileItemTreeWithSourceMapQuery
            hir::db::FunctionDataQuery
            hir::db::FunctionVisibilityQuery
            hir::db::GenericParamsQuery
            hir::db::GenericParamsWithSourceMapQuery
            hir::db::ImplDataWithDiagnosticsQuery
            hir::db::ImportMapQuery
            hir::db::IncludeMacroInvocQuery
            hir::db::InternAnonymousConstQuery
            hir::db::InternBlockQuery
            hir::db::InternConstQuery
            hir::db::InternEnumQuery
            hir::db::InternExternBlockQuery
            hir::db::InternExternCrateQuery
            hir::db::InternFunctionQuery
            hir::db::InternImplQuery
            hir::db::InternInTypeConstQuery
            hir::db::InternMacro2Query
            hir::db::InternMacroRulesQuery
            hir::db::InternProcMacroQuery
            hir::db::InternStaticQuery
            hir::db::InternStructQuery
            hir::db::InternTraitAliasQuery
            hir::db::InternTraitQuery
            hir::db::InternTypeAliasQuery
            hir::db::InternUnionQuery
            hir::db::InternUseQuery
            hir::db::LangItemQuery
            hir::db::Macro2DataQuery
            hir::db::MacroDefQuery
            hir::db::MacroRulesDataQuery
            hir::db::NotableTraitsInDepsQuery
            hir::db::ProcMacroDataQuery
            hir::db::StaticDataQuery
            hir::db::StructDataWithDiagnosticsQuery
            hir::db::TraitAliasDataQuery
            hir::db::TraitDataWithDiagnosticsQuery
            hir::db::TypeAliasDataQuery
            hir::db::UnionDataWithDiagnosticsQuery

            // InternDatabase
            hir::db::InternFunctionQuery
            hir::db::InternStructQuery
            hir::db::InternUnionQuery
            hir::db::InternEnumQuery
            hir::db::InternConstQuery
            hir::db::InternStaticQuery
            hir::db::InternTraitQuery
            hir::db::InternTraitAliasQuery
            hir::db::InternTypeAliasQuery
            hir::db::InternImplQuery
            hir::db::InternExternBlockQuery
            hir::db::InternBlockQuery
            hir::db::InternMacro2Query
            hir::db::InternProcMacroQuery
            hir::db::InternMacroRulesQuery

            // ExpandDatabase
            hir::db::AstIdMapQuery
            hir::db::DeclMacroExpanderQuery
            hir::db::ExpandProcMacroQuery
            hir::db::InternMacroCallQuery
            hir::db::InternSyntaxContextQuery
            hir::db::MacroArgQuery
            hir::db::ParseMacroExpansionErrorQuery
            hir::db::ParseMacroExpansionQuery
            hir::db::ProcMacroSpanQuery
            hir::db::ProcMacrosQuery
            hir::db::RealSpanMapQuery

            // LineIndexDatabase
            crate::LineIndexQuery

            // SourceDatabase
            base_db::ParseQuery
            base_db::ParseErrorsQuery
            base_db::CrateGraphQuery
            base_db::CrateWorkspaceDataQuery

            // SourceDatabaseExt
            base_db::FileTextQuery
            base_db::CompressedFileTextQuery
            base_db::FileSourceRootQuery
            base_db::SourceRootQuery
            base_db::SourceRootCratesQuery
        ];

        acc.sort_by_key(|it| std::cmp::Reverse(it.1));
        acc
    }
}