diff options
-rw-r--r-- | crates/libanalysis/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/libanalysis/src/lib.rs | 36 |
2 files changed, 35 insertions, 2 deletions
diff --git a/crates/libanalysis/Cargo.toml b/crates/libanalysis/Cargo.toml index 88b1099f2..42a5aca14 100644 --- a/crates/libanalysis/Cargo.toml +++ b/crates/libanalysis/Cargo.toml | |||
@@ -8,6 +8,7 @@ log = "0.4.2" | |||
8 | failure = "0.1.2" | 8 | failure = "0.1.2" |
9 | parking_lot = "0.6.3" | 9 | parking_lot = "0.6.3" |
10 | once_cell = "0.1.4" | 10 | once_cell = "0.1.4" |
11 | rayon = "1.0.2" | ||
11 | fst = { git = "https://github.com/matklad/fst", branch = "subsequence"} | 12 | fst = { git = "https://github.com/matklad/fst", branch = "subsequence"} |
12 | libsyntax2 = { path = "../libsyntax2" } | 13 | libsyntax2 = { path = "../libsyntax2" } |
13 | libeditor = { path = "../libeditor" } | 14 | libeditor = { path = "../libeditor" } |
diff --git a/crates/libanalysis/src/lib.rs b/crates/libanalysis/src/lib.rs index 562fab290..ffd81bef8 100644 --- a/crates/libanalysis/src/lib.rs +++ b/crates/libanalysis/src/lib.rs | |||
@@ -7,15 +7,21 @@ extern crate once_cell; | |||
7 | extern crate libsyntax2; | 7 | extern crate libsyntax2; |
8 | extern crate libeditor; | 8 | extern crate libeditor; |
9 | extern crate fst; | 9 | extern crate fst; |
10 | extern crate rayon; | ||
10 | 11 | ||
11 | mod symbol_index; | 12 | mod symbol_index; |
12 | 13 | ||
13 | use once_cell::sync::OnceCell; | 14 | use once_cell::sync::OnceCell; |
15 | use rayon::prelude::*; | ||
14 | 16 | ||
15 | use std::{ | 17 | use std::{ |
16 | sync::Arc, | 18 | sync::{ |
19 | Arc, | ||
20 | atomic::{AtomicUsize, Ordering::SeqCst}, | ||
21 | }, | ||
17 | collections::hash_map::HashMap, | 22 | collections::hash_map::HashMap, |
18 | path::{PathBuf, Path}, | 23 | path::{PathBuf, Path}, |
24 | time::Instant, | ||
19 | }; | 25 | }; |
20 | 26 | ||
21 | use libsyntax2::{ | 27 | use libsyntax2::{ |
@@ -29,6 +35,7 @@ use self::symbol_index::FileSymbols; | |||
29 | pub use self::symbol_index::Query; | 35 | pub use self::symbol_index::Query; |
30 | 36 | ||
31 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 37 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
38 | const INDEXING_THRESHOLD: usize = 128; | ||
32 | 39 | ||
33 | pub struct WorldState { | 40 | pub struct WorldState { |
34 | data: Arc<WorldData> | 41 | data: Arc<WorldData> |
@@ -56,7 +63,9 @@ impl WorldState { | |||
56 | 63 | ||
57 | pub fn change_files(&mut self, changes: impl Iterator<Item=(PathBuf, Option<String>)>) { | 64 | pub fn change_files(&mut self, changes: impl Iterator<Item=(PathBuf, Option<String>)>) { |
58 | let data = self.data_mut(); | 65 | let data = self.data_mut(); |
66 | let mut cnt = 0; | ||
59 | for (path, text) in changes { | 67 | for (path, text) in changes { |
68 | cnt += 1; | ||
60 | data.file_map.remove(&path); | 69 | data.file_map.remove(&path); |
61 | if let Some(text) = text { | 70 | if let Some(text) = text { |
62 | let file_data = FileData::new(text); | 71 | let file_data = FileData::new(text); |
@@ -65,11 +74,15 @@ impl WorldState { | |||
65 | data.file_map.remove(&path); | 74 | data.file_map.remove(&path); |
66 | } | 75 | } |
67 | } | 76 | } |
77 | *data.unindexed.get_mut() += cnt; | ||
68 | } | 78 | } |
69 | 79 | ||
70 | fn data_mut(&mut self) -> &mut WorldData { | 80 | fn data_mut(&mut self) -> &mut WorldData { |
71 | if Arc::get_mut(&mut self.data).is_none() { | 81 | if Arc::get_mut(&mut self.data).is_none() { |
72 | self.data = Arc::new(WorldData { | 82 | self.data = Arc::new(WorldData { |
83 | unindexed: AtomicUsize::new( | ||
84 | self.data.unindexed.load(SeqCst) | ||
85 | ), | ||
73 | file_map: self.data.file_map.clone(), | 86 | file_map: self.data.file_map.clone(), |
74 | }); | 87 | }); |
75 | } | 88 | } |
@@ -95,10 +108,11 @@ impl World { | |||
95 | } | 108 | } |
96 | 109 | ||
97 | pub fn world_symbols<'a>(&'a self, mut query: Query) -> impl Iterator<Item=(&'a Path, &'a FileSymbol)> + 'a { | 110 | pub fn world_symbols<'a>(&'a self, mut query: Query) -> impl Iterator<Item=(&'a Path, &'a FileSymbol)> + 'a { |
111 | self.reindex(); | ||
98 | self.data.file_map.iter() | 112 | self.data.file_map.iter() |
99 | .flat_map(move |(path, data)| { | 113 | .flat_map(move |(path, data)| { |
100 | let path: &'a Path = path.as_path(); | ||
101 | let symbols = data.symbols(); | 114 | let symbols = data.symbols(); |
115 | let path: &'a Path = path.as_path(); | ||
102 | query.process(symbols).into_iter().map(move |s| (path, s)) | 116 | query.process(symbols).into_iter().map(move |s| (path, s)) |
103 | }) | 117 | }) |
104 | } | 118 | } |
@@ -129,6 +143,23 @@ impl World { | |||
129 | Ok(self.world_symbols(query).collect()) | 143 | Ok(self.world_symbols(query).collect()) |
130 | } | 144 | } |
131 | 145 | ||
146 | fn reindex(&self) { | ||
147 | let data = &*self.data; | ||
148 | let unindexed = data.unindexed.load(SeqCst); | ||
149 | if unindexed < INDEXING_THRESHOLD { | ||
150 | return; | ||
151 | } | ||
152 | if unindexed == data.unindexed.compare_and_swap(unindexed, 0, SeqCst) { | ||
153 | let now = Instant::now(); | ||
154 | data.file_map | ||
155 | .par_iter() | ||
156 | .for_each(|(_, data)| { | ||
157 | data.symbols(); | ||
158 | }); | ||
159 | info!("parallel indexing took {:?}", now.elapsed()); | ||
160 | } | ||
161 | } | ||
162 | |||
132 | fn file_data(&self, path: &Path) -> Result<Arc<FileData>> { | 163 | fn file_data(&self, path: &Path) -> Result<Arc<FileData>> { |
133 | match self.data.file_map.get(path) { | 164 | match self.data.file_map.get(path) { |
134 | Some(data) => Ok(data.clone()), | 165 | Some(data) => Ok(data.clone()), |
@@ -150,6 +181,7 @@ pub const BREAK: SearchResult = Err(Break); | |||
150 | 181 | ||
151 | #[derive(Default, Debug)] | 182 | #[derive(Default, Debug)] |
152 | struct WorldData { | 183 | struct WorldData { |
184 | unindexed: AtomicUsize, | ||
153 | file_map: HashMap<PathBuf, Arc<FileData>>, | 185 | file_map: HashMap<PathBuf, Arc<FileData>>, |
154 | } | 186 | } |
155 | 187 | ||