aboutsummaryrefslogtreecommitdiff
path: root/crates/libanalysis/src/roots.rs
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2018-09-15 22:11:25 +0100
committerbors[bot] <bors[bot]@users.noreply.github.com>2018-09-15 22:11:25 +0100
commit3993bb4de95af407e5edc1fe551bec0f001a3f0f (patch)
tree31893552cd739187080048df24a629d416174305 /crates/libanalysis/src/roots.rs
parent2a56b5c4f096736d6795eecb835cc2dc14b00107 (diff)
parentfcdf3a52b4b61a39474950486ea0edf5ebf33bea (diff)
Merge #67
67: Salsa r=matklad a=matklad The aim of this PR is to transition from rather ad-hock FileData and ModuleMap caching strategy to something resembling a general-purpose red-green engine. Ideally, we shouldn't recompute ModuleMap at all, unless the set of mod decls or files changes. Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/libanalysis/src/roots.rs')
-rw-r--r--crates/libanalysis/src/roots.rs166
1 files changed, 77 insertions, 89 deletions
diff --git a/crates/libanalysis/src/roots.rs b/crates/libanalysis/src/roots.rs
index 629a697c5..191d0d821 100644
--- a/crates/libanalysis/src/roots.rs
+++ b/crates/libanalysis/src/roots.rs
@@ -1,6 +1,5 @@
1use std::{ 1use std::{
2 collections::HashMap, 2 collections::HashMap,
3 time::Instant,
4 sync::Arc, 3 sync::Arc,
5 panic, 4 panic,
6}; 5};
@@ -13,94 +12,82 @@ use libsyntax2::File;
13use { 12use {
14 FileId, 13 FileId,
15 imp::FileResolverImp, 14 imp::FileResolverImp,
16 module_map::{ModuleMap, ChangeKind},
17 symbol_index::SymbolIndex, 15 symbol_index::SymbolIndex,
16 descriptors::{ModuleDescriptor, ModuleTreeDescriptor},
17 db::Db,
18}; 18};
19 19
20pub(crate) trait SourceRoot { 20pub(crate) trait SourceRoot {
21 fn contains(&self, file_id: FileId) -> bool; 21 fn contains(&self, file_id: FileId) -> bool;
22 fn module_map(&self) -> &ModuleMap; 22 fn module_tree(&self) -> Arc<ModuleTreeDescriptor>;
23 fn lines(&self, file_id: FileId) -> &LineIndex; 23 fn lines(&self, file_id: FileId) -> Arc<LineIndex>;
24 fn syntax(&self, file_id: FileId) -> &File; 24 fn syntax(&self, file_id: FileId) -> File;
25 fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>); 25 fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>);
26} 26}
27 27
28#[derive(Clone, Default, Debug)] 28#[derive(Default, Debug)]
29pub(crate) struct WritableSourceRoot { 29pub(crate) struct WritableSourceRoot {
30 file_map: HashMap<FileId, Arc<(FileData, OnceCell<SymbolIndex>)>>, 30 db: Db,
31 module_map: ModuleMap,
32} 31}
33 32
34impl WritableSourceRoot { 33impl WritableSourceRoot {
35 pub fn update(&mut self, file_id: FileId, text: Option<String>) { 34 pub fn apply_changes(
36 let change_kind = if self.file_map.remove(&file_id).is_some() { 35 &self,
37 if text.is_some() { 36 changes: &mut dyn Iterator<Item=(FileId, Option<String>)>,
38 ChangeKind::Update 37 file_resolver: Option<FileResolverImp>,
39 } else { 38 ) -> WritableSourceRoot {
40 ChangeKind::Delete 39 let resolver_changed = file_resolver.is_some();
40 let mut changed_files = Vec::new();
41 let mut new_state = self.db.state().clone();
42
43 for (file_id, text) in changes {
44 changed_files.push(file_id);
45 match text {
46 Some(text) => {
47 new_state.file_map.insert(file_id, Arc::new(text));
48 },
49 None => {
50 new_state.file_map.remove(&file_id);
51 }
41 } 52 }
42 } else {
43 ChangeKind::Insert
44 };
45 self.module_map.update_file(file_id, change_kind);
46 self.file_map.remove(&file_id);
47 if let Some(text) = text {
48 let file_data = FileData::new(text);
49 self.file_map.insert(file_id, Arc::new((file_data, Default::default())));
50 } 53 }
51 } 54 if let Some(file_resolver) = file_resolver {
52 pub fn set_file_resolver(&mut self, file_resolver: FileResolverImp) { 55 new_state.file_resolver = file_resolver
53 self.module_map.set_file_resolver(file_resolver) 56 }
54 } 57 WritableSourceRoot {
55 pub fn reindex(&self) { 58 db: self.db.with_changes(new_state, &changed_files, resolver_changed)
56 let now = Instant::now();
57 self.file_map
58 .par_iter()
59 .for_each(|(&file_id, data)| {
60 symbols(file_id, data);
61 });
62 info!("parallel indexing took {:?}", now.elapsed());
63
64 }
65 fn data(&self, file_id: FileId) -> &FileData {
66 match self.file_map.get(&file_id) {
67 Some(data) => &data.0,
68 None => panic!("unknown file: {:?}", file_id),
69 } 59 }
70 } 60 }
71} 61}
72 62
73impl SourceRoot for WritableSourceRoot { 63impl SourceRoot for WritableSourceRoot {
74 fn contains(&self, file_id: FileId) -> bool { 64 fn module_tree(&self) -> Arc<ModuleTreeDescriptor> {
75 self.file_map.contains_key(&file_id) 65 self.db.make_query(::module_map::module_tree)
76 } 66 }
77 fn module_map(&self) -> &ModuleMap { 67
78 &self.module_map 68 fn contains(&self, file_id: FileId) -> bool {
69 self.db.state().file_map.contains_key(&file_id)
79 } 70 }
80 fn lines(&self, file_id: FileId) -> &LineIndex { 71 fn lines(&self, file_id: FileId) -> Arc<LineIndex> {
81 self.data(file_id).lines() 72 self.db.make_query(|ctx| ::queries::file_lines(ctx, file_id))
82 } 73 }
83 fn syntax(&self, file_id: FileId) -> &File { 74 fn syntax(&self, file_id: FileId) -> File {
84 self.data(file_id).syntax() 75 self.db.make_query(|ctx| ::queries::file_syntax(ctx, file_id))
85 } 76 }
86 fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { 77 fn symbols<'a>(&'a self, acc: &mut Vec<Arc<SymbolIndex>>) {
87 acc.extend( 78 self.db.make_query(|ctx| {
88 self.file_map 79 let file_set = ::queries::file_set(ctx);
89 .iter() 80 let syms = file_set.0.iter()
90 .map(|(&file_id, data)| symbols(file_id, data)) 81 .map(|file_id| ::queries::file_symbols(ctx, *file_id));
91 ) 82 acc.extend(syms);
83 });
92 } 84 }
93} 85}
94 86
95fn symbols(file_id: FileId, (data, symbols): &(FileData, OnceCell<SymbolIndex>)) -> &SymbolIndex {
96 let syntax = data.syntax_transient();
97 symbols.get_or_init(|| SymbolIndex::for_file(file_id, syntax))
98}
99
100#[derive(Debug)] 87#[derive(Debug)]
101struct FileData { 88struct FileData {
102 text: String, 89 text: String,
103 lines: OnceCell<LineIndex>, 90 lines: OnceCell<Arc<LineIndex>>,
104 syntax: OnceCell<File>, 91 syntax: OnceCell<File>,
105} 92}
106 93
@@ -112,8 +99,8 @@ impl FileData {
112 lines: OnceCell::new(), 99 lines: OnceCell::new(),
113 } 100 }
114 } 101 }
115 fn lines(&self) -> &LineIndex { 102 fn lines(&self) -> &Arc<LineIndex> {
116 self.lines.get_or_init(|| LineIndex::new(&self.text)) 103 self.lines.get_or_init(|| Arc::new(LineIndex::new(&self.text)))
117 } 104 }
118 fn syntax(&self) -> &File { 105 fn syntax(&self) -> &File {
119 let text = &self.text; 106 let text = &self.text;
@@ -126,40 +113,41 @@ impl FileData {
126 } 113 }
127 } 114 }
128 } 115 }
129 fn syntax_transient(&self) -> File {
130 self.syntax.get().map(|s| s.clone())
131 .unwrap_or_else(|| File::parse(&self.text))
132 }
133} 116}
134 117
135#[derive(Debug)] 118#[derive(Debug)]
136pub(crate) struct ReadonlySourceRoot { 119pub(crate) struct ReadonlySourceRoot {
137 symbol_index: SymbolIndex, 120 symbol_index: Arc<SymbolIndex>,
138 file_map: HashMap<FileId, FileData>, 121 file_map: HashMap<FileId, FileData>,
139 module_map: ModuleMap, 122 module_tree: Arc<ModuleTreeDescriptor>,
140} 123}
141 124
142impl ReadonlySourceRoot { 125impl ReadonlySourceRoot {
143 pub(crate) fn new(files: Vec<(FileId, String)>, file_resolver: FileResolverImp) -> ReadonlySourceRoot { 126 pub(crate) fn new(files: Vec<(FileId, String)>, file_resolver: FileResolverImp) -> ReadonlySourceRoot {
144 let mut module_map = ModuleMap::new(); 127 let modules = files.par_iter()
145 module_map.set_file_resolver(file_resolver); 128 .map(|(file_id, text)| {
146 let symbol_index = SymbolIndex::for_files( 129 let syntax = File::parse(text);
147 files.par_iter().map(|(file_id, text)| { 130 let mod_descr = ModuleDescriptor::new(syntax.ast());
148 (*file_id, File::parse(text)) 131 (*file_id, syntax, mod_descr)
149 }) 132 })
133 .collect::<Vec<_>>();
134 let module_tree = ModuleTreeDescriptor::new(
135 modules.iter().map(|it| (it.0, &it.2)),
136 &file_resolver,
137 );
138
139 let symbol_index = SymbolIndex::for_files(
140 modules.par_iter().map(|it| (it.0, it.1.clone()))
150 ); 141 );
151 let file_map: HashMap<FileId, FileData> = files 142 let file_map: HashMap<FileId, FileData> = files
152 .into_iter() 143 .into_iter()
153 .map(|(id, text)| { 144 .map(|(id, text)| (id, FileData::new(text)))
154 module_map.update_file(id, ChangeKind::Insert);
155 (id, FileData::new(text))
156 })
157 .collect(); 145 .collect();
158 146
159 ReadonlySourceRoot { 147 ReadonlySourceRoot {
160 symbol_index, 148 symbol_index: Arc::new(symbol_index),
161 file_map, 149 file_map,
162 module_map, 150 module_tree: Arc::new(module_tree),
163 } 151 }
164 } 152 }
165 153
@@ -172,19 +160,19 @@ impl ReadonlySourceRoot {
172} 160}
173 161
174impl SourceRoot for ReadonlySourceRoot { 162impl SourceRoot for ReadonlySourceRoot {
163 fn module_tree(&self) -> Arc<ModuleTreeDescriptor> {
164 Arc::clone(&self.module_tree)
165 }
175 fn contains(&self, file_id: FileId) -> bool { 166 fn contains(&self, file_id: FileId) -> bool {
176 self.file_map.contains_key(&file_id) 167 self.file_map.contains_key(&file_id)
177 } 168 }
178 fn module_map(&self) -> &ModuleMap { 169 fn lines(&self, file_id: FileId) -> Arc<LineIndex> {
179 &self.module_map 170 Arc::clone(self.data(file_id).lines())
180 }
181 fn lines(&self, file_id: FileId) -> &LineIndex {
182 self.data(file_id).lines()
183 } 171 }
184 fn syntax(&self, file_id: FileId) -> &File { 172 fn syntax(&self, file_id: FileId) -> File {
185 self.data(file_id).syntax() 173 self.data(file_id).syntax().clone()
186 } 174 }
187 fn symbols<'a>(&'a self, acc: &mut Vec<&'a SymbolIndex>) { 175 fn symbols(&self, acc: &mut Vec<Arc<SymbolIndex>>) {
188 acc.push(&self.symbol_index) 176 acc.push(Arc::clone(&self.symbol_index))
189 } 177 }
190} 178}