@@ -12,12 +12,12 @@ use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase};
1212use load_cargo:: SourceRootConfig ;
1313use lsp_types:: { SemanticTokens , Url } ;
1414use nohash_hasher:: IntMap ;
15- use parking_lot:: { Mutex , RwLock } ;
15+ use parking_lot:: { Mutex , RwLock , RwLockUpgradableReadGuard , RwLockWriteGuard } ;
1616use proc_macro_api:: ProcMacroServer ;
1717use project_model:: { CargoWorkspace , ProjectWorkspace , Target , WorkspaceBuildScripts } ;
1818use rustc_hash:: { FxHashMap , FxHashSet } ;
1919use triomphe:: Arc ;
20- use vfs:: AnchoredPathBuf ;
20+ use vfs:: { AnchoredPathBuf , Vfs } ;
2121
2222use crate :: {
2323 config:: { Config , ConfigError } ,
@@ -216,12 +216,15 @@ impl GlobalState {
216216 let mut file_changes = FxHashMap :: default ( ) ;
217217 let ( change, changed_files, workspace_structure_change) = {
218218 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 ( ) ;
221221 if changed_files. is_empty ( ) {
222222 return false ;
223223 }
224224
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 ;
225228 // We need to fix up the changed events a bit. If we have a create or modify for a file
226229 // id that is followed by a delete we actually skip observing the file text from the
227230 // earlier event, to avoid problems later on.
@@ -272,6 +275,7 @@ impl GlobalState {
272275 let mut workspace_structure_change = None ;
273276 // A file was added or deleted
274277 let mut has_structure_changes = false ;
278+ let mut bytes = vec ! [ ] ;
275279 for file in & changed_files {
276280 let vfs_path = & vfs. file_path ( file. file_id ) ;
277281 if let Some ( path) = vfs_path. as_path ( ) {
@@ -293,16 +297,28 @@ impl GlobalState {
293297
294298 let text = if file. exists ( ) {
295299 let bytes = vfs. file_contents ( file. file_id ) . to_vec ( ) ;
300+
296301 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
297304 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) )
300306 } )
301307 } else {
302308 None
303309 } ;
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) ) ;
305313 }
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+ } ) ;
306322 if has_structure_changes {
307323 let roots = self . source_root_config . partition ( vfs) ;
308324 change. set_roots ( roots) ;
0 commit comments