Skip to content

Commit cc8b786

Browse files
committed
Shuffle some locking around
1 parent 70e21dc commit cc8b786

File tree

2 files changed

+29
-12
lines changed

2 files changed

+29
-12
lines changed

crates/rust-analyzer/src/global_state.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ use ide_db::base_db::{CrateId, FileLoader, ProcMacroPaths, SourceDatabase};
1212
use load_cargo::SourceRootConfig;
1313
use lsp_types::{SemanticTokens, Url};
1414
use nohash_hasher::IntMap;
15-
use parking_lot::{Mutex, RwLock};
15+
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard};
1616
use proc_macro_api::ProcMacroServer;
1717
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
1818
use rustc_hash::{FxHashMap, FxHashSet};
1919
use triomphe::Arc;
20-
use vfs::AnchoredPathBuf;
20+
use vfs::{AnchoredPathBuf, Vfs};
2121

2222
use 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);

crates/rust-analyzer/src/handlers/notification.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,15 +84,16 @@ pub(crate) fn handle_did_change_text_document(
8484
}
8585
};
8686

87-
let vfs = &mut state.vfs.write().0;
88-
let file_id = vfs.file_id(&path).unwrap();
8987
let text = apply_document_changes(
9088
state.config.position_encoding(),
91-
|| std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into(),
89+
|| {
90+
let vfs = &state.vfs.read().0;
91+
let file_id = vfs.file_id(&path).unwrap();
92+
std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into()
93+
},
9294
params.content_changes,
9395
);
94-
95-
vfs.set_file_contents(path, Some(text.into_bytes()));
96+
state.vfs.write().0.set_file_contents(path, Some(text.into_bytes()));
9697
}
9798
Ok(())
9899
}

0 commit comments

Comments
 (0)