@@ -7,11 +7,12 @@ mod topologic_sort;
77use std:: time:: Duration ;
88
99use hir:: db:: DefDatabase ;
10+ use itertools:: Itertools ;
1011
1112use crate :: {
1213 base_db:: {
1314 ra_salsa:: { Database , ParallelDatabase , Snapshot } ,
14- Cancelled , CrateId , SourceDatabase , SourceRootDatabase ,
15+ Cancelled , CrateId , SourceDatabase ,
1516 } ,
1617 symbol_index:: SymbolsDatabase ,
1718 FxIndexMap , RootDatabase ,
@@ -26,6 +27,7 @@ pub struct ParallelPrimeCachesProgress {
2627 pub crates_total : usize ,
2728 /// the total number of crates that have finished priming
2829 pub crates_done : usize ,
30+ pub work_type : & ' static str ,
2931}
3032
3133pub fn parallel_prime_caches (
@@ -51,37 +53,28 @@ pub fn parallel_prime_caches(
5153 EndCrate { crate_id : CrateId } ,
5254 }
5355
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+
5466 let ( work_sender, progress_receiver) = {
5567 let ( progress_sender, progress_receiver) = crossbeam_channel:: unbounded ( ) ;
5668 let ( work_sender, work_receiver) = crossbeam_channel:: unbounded ( ) ;
57- let graph = graph. clone ( ) ;
58- let local_roots = db. local_roots ( ) ;
5969 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 ( ) {
6171 progress_sender
6272 . send ( ParallelPrimeCacheWorkerProgress :: BeginCrate { crate_id, crate_name } ) ?;
6373
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 ( ) ) ,
8578 }
8679
8780 progress_sender. send ( ParallelPrimeCacheWorkerProgress :: EndCrate { crate_id } ) ?;
@@ -112,16 +105,30 @@ pub fn parallel_prime_caches(
112105 let mut crates_currently_indexing =
113106 FxIndexMap :: with_capacity_and_hasher ( num_worker_threads, Default :: default ( ) ) ;
114107
108+ let mut additional_phases = vec ! [ ] ;
109+
115110 while crates_done < crates_total {
116111 db. unwind_if_cancelled ( ) ;
117112
118113 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 ( ) ;
125132 }
126133
127134 // 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(
153160 crates_currently_indexing : crates_currently_indexing. values ( ) . cloned ( ) . collect ( ) ,
154161 crates_done,
155162 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" ,
156208 } ;
157209
158210 cb ( progress) ;
0 commit comments