Remove RWLock from check watcher.

@matklad mentioned this might be a good idea.

So the general idea is that we don't really need the lock, as we can
just clone the check watcher state when creating a snapshot. We can then
use `Arc::get_mut` to get mutable access to the state from `WorldState`
when needed.

Running with this it seems to improve responsiveness a bit while cargo
is running, but I have no hard numbers to prove it. In any case, a
serialization point less is always better when we're trying to be
responsive.
This commit is contained in:
Emil Lauridsen 2020-01-23 09:26:08 +01:00
parent 2fb8a46122
commit 05aa5b854b
5 changed files with 16 additions and 18 deletions

View file

@ -117,7 +117,7 @@ fn is_deprecated(rd: &RustDiagnostic) -> bool {
}
}
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct SuggestedFix {
pub title: String,
pub location: Location,

View file

@ -7,7 +7,6 @@ use lsp_types::{
Diagnostic, Url, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressEnd,
WorkDoneProgressReport,
};
use parking_lot::RwLock;
use std::{
collections::HashMap,
path::PathBuf,
@ -38,7 +37,7 @@ pub struct CheckOptions {
#[derive(Debug)]
pub struct CheckWatcher {
pub task_recv: Receiver<CheckTask>,
pub state: Arc<RwLock<CheckState>>,
pub state: Arc<CheckState>,
cmd_send: Option<Sender<CheckCommand>>,
handle: Option<JoinHandle<()>>,
}
@ -46,7 +45,7 @@ pub struct CheckWatcher {
impl CheckWatcher {
pub fn new(options: &CheckOptions, workspace_root: PathBuf) -> CheckWatcher {
let options = options.clone();
let state = Arc::new(RwLock::new(CheckState::new()));
let state = Arc::new(CheckState::new());
let (task_send, task_recv) = unbounded::<CheckTask>();
let (cmd_send, cmd_recv) = unbounded::<CheckCommand>();
@ -59,7 +58,7 @@ impl CheckWatcher {
/// Returns a CheckWatcher that doesn't actually do anything
pub fn dummy() -> CheckWatcher {
let state = Arc::new(RwLock::new(CheckState::new()));
let state = Arc::new(CheckState::new());
CheckWatcher { task_recv: never(), cmd_send: None, handle: None, state }
}
@ -87,7 +86,7 @@ impl std::ops::Drop for CheckWatcher {
}
}
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct CheckState {
diagnostic_collection: HashMap<Url, Vec<Diagnostic>>,
suggested_fix_collection: HashMap<Url, Vec<SuggestedFix>>,

View file

@ -586,12 +586,14 @@ fn on_notification(
fn on_check_task(
task: CheckTask,
world_state: &WorldState,
world_state: &mut WorldState,
task_sender: &Sender<Task>,
) -> Result<()> {
match task {
CheckTask::ClearDiagnostics => {
let cleared_files = world_state.check_watcher.state.write().clear();
let state = Arc::get_mut(&mut world_state.check_watcher.state)
.expect("couldn't get check watcher state as mutable");
let cleared_files = state.clear();
// Send updated diagnostics for each cleared file
for url in cleared_files {
@ -600,11 +602,9 @@ fn on_check_task(
}
CheckTask::AddDiagnostic(url, diagnostic) => {
world_state
.check_watcher
.state
.write()
.add_diagnostic_with_fixes(url.clone(), diagnostic);
let state = Arc::get_mut(&mut world_state.check_watcher.state)
.expect("couldn't get check watcher state as mutable");
state.add_diagnostic_with_fixes(url.clone(), diagnostic);
// We manually send a diagnostic update when the watcher asks
// us to, to avoid the issue of having to change the file to

View file

@ -674,8 +674,7 @@ pub fn handle_code_action(
res.push(action.into());
}
for fix in world.check_watcher.read().fixes_for(&params.text_document.uri).into_iter().flatten()
{
for fix in world.check_watcher.fixes_for(&params.text_document.uri).into_iter().flatten() {
let fix_range = fix.location.range.conv_with(&line_index);
if fix_range.intersection(&range).is_none() {
continue;
@ -895,7 +894,7 @@ pub fn publish_diagnostics(
tags: None,
})
.collect();
if let Some(check_diags) = world.check_watcher.read().diagnostics_for(&uri) {
if let Some(check_diags) = world.check_watcher.diagnostics_for(&uri) {
diagnostics.extend(check_diags.iter().cloned());
}
Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None })

View file

@ -63,7 +63,7 @@ pub struct WorldSnapshot {
pub workspaces: Arc<Vec<ProjectWorkspace>>,
pub analysis: Analysis,
pub latest_requests: Arc<RwLock<LatestRequests>>,
pub check_watcher: Arc<RwLock<CheckState>>,
pub check_watcher: CheckState,
vfs: Arc<RwLock<Vfs>>,
}
@ -220,7 +220,7 @@ impl WorldState {
analysis: self.analysis_host.analysis(),
vfs: Arc::clone(&self.vfs),
latest_requests: Arc::clone(&self.latest_requests),
check_watcher: self.check_watcher.state.clone(),
check_watcher: (*self.check_watcher.state).clone(),
}
}