@@ -7,11 +7,12 @@ mod topologic_sort;
7
7
use std:: time:: Duration ;
8
8
9
9
use hir:: db:: DefDatabase ;
10
+ use itertools:: Itertools ;
10
11
11
12
use crate :: {
12
13
base_db:: {
13
14
ra_salsa:: { Database , ParallelDatabase , Snapshot } ,
14
- Cancelled , CrateId , SourceDatabase , SourceRootDatabase ,
15
+ Cancelled , CrateId , SourceDatabase ,
15
16
} ,
16
17
symbol_index:: SymbolsDatabase ,
17
18
FxIndexMap , RootDatabase ,
@@ -26,6 +27,7 @@ pub struct ParallelPrimeCachesProgress {
26
27
pub crates_total : usize ,
27
28
/// the total number of crates that have finished priming
28
29
pub crates_done : usize ,
30
+ pub work_type : & ' static str ,
29
31
}
30
32
31
33
pub fn parallel_prime_caches (
@@ -51,37 +53,28 @@ pub fn parallel_prime_caches(
51
53
EndCrate { crate_id : CrateId } ,
52
54
}
53
55
56
+ // We split off def map computation from other work,
57
+ // as the def map is the relevant one. Once the defmaps are computed
58
+ // the project is ready to go, the other indices are just nice to have for some IDE features.
59
+ #[ derive( PartialOrd , Ord , PartialEq , Eq , Copy , Clone ) ]
60
+ enum PrimingPhase {
61
+ DefMap ,
62
+ ImportMap ,
63
+ CrateSymbols ,
64
+ }
65
+
54
66
let ( work_sender, progress_receiver) = {
55
67
let ( progress_sender, progress_receiver) = crossbeam_channel:: unbounded ( ) ;
56
68
let ( work_sender, work_receiver) = crossbeam_channel:: unbounded ( ) ;
57
- let graph = graph. clone ( ) ;
58
- let local_roots = db. local_roots ( ) ;
59
69
let prime_caches_worker = move |db : Snapshot < RootDatabase > | {
60
- while let Ok ( ( crate_id, crate_name) ) = work_receiver. recv ( ) {
70
+ while let Ok ( ( crate_id, crate_name, kind ) ) = work_receiver. recv ( ) {
61
71
progress_sender
62
72
. send ( ParallelPrimeCacheWorkerProgress :: BeginCrate { crate_id, crate_name } ) ?;
63
73
64
- // Compute the DefMap and possibly ImportMap
65
- let file_id = graph[ crate_id] . root_file_id ;
66
- let root_id = db. file_source_root ( file_id) ;
67
- if db. source_root ( root_id) . is_library {
68
- db. crate_def_map ( crate_id) ;
69
- } else {
70
- // This also computes the DefMap
71
- db. import_map ( crate_id) ;
72
- }
73
-
74
- // Compute the symbol search index.
75
- // This primes the cache for `ide_db::symbol_index::world_symbols()`.
76
- //
77
- // We do this for workspace crates only (members of local_roots), because doing it
78
- // for all dependencies could be *very* unnecessarily slow in a large project.
79
- //
80
- // FIXME: We should do it unconditionally if the configuration is set to default to
81
- // searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
82
- // would need to pipe that configuration information down here.
83
- if local_roots. contains ( & root_id) {
84
- db. crate_symbols ( crate_id. into ( ) ) ;
74
+ match kind {
75
+ PrimingPhase :: DefMap => _ = db. crate_def_map ( crate_id) ,
76
+ PrimingPhase :: ImportMap => _ = db. import_map ( crate_id) ,
77
+ PrimingPhase :: CrateSymbols => _ = db. crate_symbols ( crate_id. into ( ) ) ,
85
78
}
86
79
87
80
progress_sender. send ( ParallelPrimeCacheWorkerProgress :: EndCrate { crate_id } ) ?;
@@ -112,16 +105,30 @@ pub fn parallel_prime_caches(
112
105
let mut crates_currently_indexing =
113
106
FxIndexMap :: with_capacity_and_hasher ( num_worker_threads, Default :: default ( ) ) ;
114
107
108
+ let mut additional_phases = vec ! [ ] ;
109
+
115
110
while crates_done < crates_total {
116
111
db. unwind_if_cancelled ( ) ;
117
112
118
113
for crate_id in & mut crates_to_prime {
119
- work_sender
120
- . send ( (
121
- crate_id,
122
- graph[ crate_id] . display_name . as_deref ( ) . unwrap_or_default ( ) . to_owned ( ) ,
123
- ) )
124
- . ok ( ) ;
114
+ let krate = & graph[ crate_id] ;
115
+ let name = krate. display_name . as_deref ( ) . unwrap_or_default ( ) . to_owned ( ) ;
116
+ if krate. origin . is_lang ( ) {
117
+ additional_phases. push ( ( crate_id, name. clone ( ) , PrimingPhase :: ImportMap ) ) ;
118
+ } else if krate. origin . is_local ( ) {
119
+ // Compute the symbol search index.
120
+ // This primes the cache for `ide_db::symbol_index::world_symbols()`.
121
+ //
122
+ // We do this for workspace crates only (members of local_roots), because doing it
123
+ // for all dependencies could be *very* unnecessarily slow in a large project.
124
+ //
125
+ // FIXME: We should do it unconditionally if the configuration is set to default to
126
+ // searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
127
+ // would need to pipe that configuration information down here.
128
+ additional_phases. push ( ( crate_id, name. clone ( ) , PrimingPhase :: CrateSymbols ) ) ;
129
+ }
130
+
131
+ work_sender. send ( ( crate_id, name, PrimingPhase :: DefMap ) ) . ok ( ) ;
125
132
}
126
133
127
134
// recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
@@ -153,6 +160,51 @@ pub fn parallel_prime_caches(
153
160
crates_currently_indexing : crates_currently_indexing. values ( ) . cloned ( ) . collect ( ) ,
154
161
crates_done,
155
162
crates_total,
163
+ work_type : "Indexing" ,
164
+ } ;
165
+
166
+ cb ( progress) ;
167
+ }
168
+
169
+ let mut crates_done = 0 ;
170
+ let crates_total = additional_phases. len ( ) ;
171
+ for w in additional_phases. into_iter ( ) . sorted_by_key ( |& ( _, _, phase) | phase) {
172
+ work_sender. send ( w) . ok ( ) ;
173
+ }
174
+
175
+ while crates_done < crates_total {
176
+ db. unwind_if_cancelled ( ) ;
177
+
178
+ // recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
179
+ // is cancelled on a regular basis. workers will only exit if they are processing a task that is cancelled, or
180
+ // if this thread exits, and closes the work channel.
181
+ let worker_progress = match progress_receiver. recv_timeout ( Duration :: from_millis ( 10 ) ) {
182
+ Ok ( p) => p,
183
+ Err ( crossbeam_channel:: RecvTimeoutError :: Timeout ) => {
184
+ continue ;
185
+ }
186
+ Err ( crossbeam_channel:: RecvTimeoutError :: Disconnected ) => {
187
+ // our workers may have died from a cancelled task, so we'll check and re-raise here.
188
+ db. unwind_if_cancelled ( ) ;
189
+ break ;
190
+ }
191
+ } ;
192
+ match worker_progress {
193
+ ParallelPrimeCacheWorkerProgress :: BeginCrate { crate_id, crate_name } => {
194
+ crates_currently_indexing. insert ( crate_id, crate_name) ;
195
+ }
196
+ ParallelPrimeCacheWorkerProgress :: EndCrate { crate_id } => {
197
+ crates_currently_indexing. swap_remove ( & crate_id) ;
198
+ crates_to_prime. mark_done ( crate_id) ;
199
+ crates_done += 1 ;
200
+ }
201
+ } ;
202
+
203
+ let progress = ParallelPrimeCachesProgress {
204
+ crates_currently_indexing : crates_currently_indexing. values ( ) . cloned ( ) . collect ( ) ,
205
+ crates_done,
206
+ crates_total,
207
+ work_type : "Populating symbols" ,
156
208
} ;
157
209
158
210
cb ( progress) ;
0 commit comments