Shuffle some locking around

This commit is contained in:
Lukas Wirth 2023-09-01 20:45:46 +02:00
parent 70e21dc30b
commit cc8b78601d
2 changed files with 29 additions and 12 deletions

View File

@ -12,12 +12,12 @@
use load_cargo::SourceRootConfig;
use lsp_types::{SemanticTokens, Url};
use nohash_hasher::IntMap;
use parking_lot::{Mutex, RwLock};
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard};
use proc_macro_api::ProcMacroServer;
use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
use rustc_hash::{FxHashMap, FxHashSet};
use triomphe::Arc;
use vfs::AnchoredPathBuf;
use vfs::{AnchoredPathBuf, Vfs};
use crate::{
config::{Config, ConfigError},
@ -216,12 +216,15 @@ pub(crate) fn process_changes(&mut self) -> bool {
let mut file_changes = FxHashMap::default();
let (change, changed_files, workspace_structure_change) = {
let mut change = Change::new();
let (vfs, line_endings_map) = &mut *self.vfs.write();
let changed_files = vfs.take_changes();
let mut guard = self.vfs.write();
let changed_files = guard.0.take_changes();
if changed_files.is_empty() {
return false;
}
// downgrade to read lock to allow more readers while we are normalizing text
let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
let vfs: &Vfs = &guard.0;
// We need to fix up the changed events a bit. If we have a create or modify for a file
// id that is followed by a delete we actually skip observing the file text from the
// earlier event, to avoid problems later on.
@ -272,6 +275,7 @@ pub(crate) fn process_changes(&mut self) -> bool {
let mut workspace_structure_change = None;
// A file was added or deleted
let mut has_structure_changes = false;
let mut bytes = vec![];
for file in &changed_files {
let vfs_path = &vfs.file_path(file.file_id);
if let Some(path) = vfs_path.as_path() {
@ -293,16 +297,28 @@ pub(crate) fn process_changes(&mut self) -> bool {
let text = if file.exists() {
let bytes = vfs.file_contents(file.file_id).to_vec();
String::from_utf8(bytes).ok().and_then(|text| {
// FIXME: Consider doing normalization in the `vfs` instead? That allows
// getting rid of some locking
let (text, line_endings) = LineEndings::normalize(text);
line_endings_map.insert(file.file_id, line_endings);
Some(Arc::from(text))
Some((Arc::from(text), line_endings))
})
} else {
None
};
change.change_file(file.file_id, text);
// delay `line_endings_map` changes until we are done normalizing the text
// this allows delaying the re-acquisition of the write lock
bytes.push((file.file_id, text));
}
let (vfs, line_endings_map) = &mut *RwLockUpgradableReadGuard::upgrade(guard);
bytes.into_iter().for_each(|(file_id, text)| match text {
None => change.change_file(file_id, None),
Some((text, line_endings)) => {
line_endings_map.insert(file_id, line_endings);
change.change_file(file_id, Some(text));
}
});
if has_structure_changes {
let roots = self.source_root_config.partition(vfs);
change.set_roots(roots);

View File

@ -84,15 +84,16 @@ pub(crate) fn handle_did_change_text_document(
}
};
let vfs = &mut state.vfs.write().0;
let file_id = vfs.file_id(&path).unwrap();
let text = apply_document_changes(
state.config.position_encoding(),
|| std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into(),
|| {
let vfs = &state.vfs.read().0;
let file_id = vfs.file_id(&path).unwrap();
std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into()
},
params.content_changes,
);
vfs.set_file_contents(path, Some(text.into_bytes()));
state.vfs.write().0.set_file_contents(path, Some(text.into_bytes()));
}
Ok(())
}