@@ -12,12 +12,12 @@ use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase};
12
12
use load_cargo:: SourceRootConfig ;
13
13
use lsp_types:: { SemanticTokens , Url } ;
14
14
use nohash_hasher:: IntMap ;
15
- use parking_lot:: { Mutex , RwLock } ;
15
+ use parking_lot:: { Mutex , RwLock , RwLockUpgradableReadGuard , RwLockWriteGuard } ;
16
16
use proc_macro_api:: ProcMacroServer ;
17
17
use project_model:: { CargoWorkspace , ProjectWorkspace , Target , WorkspaceBuildScripts } ;
18
18
use rustc_hash:: { FxHashMap , FxHashSet } ;
19
19
use triomphe:: Arc ;
20
- use vfs:: AnchoredPathBuf ;
20
+ use vfs:: { AnchoredPathBuf , Vfs } ;
21
21
22
22
use crate :: {
23
23
config:: { Config , ConfigError } ,
@@ -216,12 +216,15 @@ impl GlobalState {
216
216
let mut file_changes = FxHashMap :: default ( ) ;
217
217
let ( change, changed_files, workspace_structure_change) = {
218
218
let mut change = Change :: new ( ) ;
219
- let ( vfs , line_endings_map ) = & mut * self . vfs . write ( ) ;
220
- let changed_files = vfs . take_changes ( ) ;
219
+ let mut guard = self . vfs . write ( ) ;
220
+ let changed_files = guard . 0 . take_changes ( ) ;
221
221
if changed_files. is_empty ( ) {
222
222
return false ;
223
223
}
224
224
225
+ // downgrade to read lock to allow more readers while we are normalizing text
226
+ let guard = RwLockWriteGuard :: downgrade_to_upgradable ( guard) ;
227
+ let vfs: & Vfs = & guard. 0 ;
225
228
// We need to fix up the changed events a bit. If we have a create or modify for a file
226
229
// id that is followed by a delete we actually skip observing the file text from the
227
230
// earlier event, to avoid problems later on.
@@ -272,6 +275,7 @@ impl GlobalState {
272
275
let mut workspace_structure_change = None ;
273
276
// A file was added or deleted
274
277
let mut has_structure_changes = false ;
278
+ let mut bytes = vec ! [ ] ;
275
279
for file in & changed_files {
276
280
let vfs_path = & vfs. file_path ( file. file_id ) ;
277
281
if let Some ( path) = vfs_path. as_path ( ) {
@@ -293,16 +297,28 @@ impl GlobalState {
293
297
294
298
let text = if file. exists ( ) {
295
299
let bytes = vfs. file_contents ( file. file_id ) . to_vec ( ) ;
300
+
296
301
String :: from_utf8 ( bytes) . ok ( ) . and_then ( |text| {
302
+ // FIXME: Consider doing normalization in the `vfs` instead? That allows
303
+ // getting rid of some locking
297
304
let ( text, line_endings) = LineEndings :: normalize ( text) ;
298
- line_endings_map. insert ( file. file_id , line_endings) ;
299
- Some ( Arc :: from ( text) )
305
+ Some ( ( Arc :: from ( text) , line_endings) )
300
306
} )
301
307
} else {
302
308
None
303
309
} ;
304
- change. change_file ( file. file_id , text) ;
310
+ // delay `line_endings_map` changes until we are done normalizing the text
311
+ // this allows delaying the re-acquisition of the write lock
312
+ bytes. push ( ( file. file_id , text) ) ;
305
313
}
314
+ let ( vfs, line_endings_map) = & mut * RwLockUpgradableReadGuard :: upgrade ( guard) ;
315
+ bytes. into_iter ( ) . for_each ( |( file_id, text) | match text {
316
+ None => change. change_file ( file_id, None ) ,
317
+ Some ( ( text, line_endings) ) => {
318
+ line_endings_map. insert ( file_id, line_endings) ;
319
+ change. change_file ( file_id, Some ( text) ) ;
320
+ }
321
+ } ) ;
306
322
if has_structure_changes {
307
323
let roots = self . source_root_config . partition ( vfs) ;
308
324
change. set_roots ( roots) ;
0 commit comments