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 struct SuggestedFix {
pub title: String, pub title: String,
pub location: Location, pub location: Location,

View file

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

View file

@ -586,12 +586,14 @@ fn on_notification(
fn on_check_task( fn on_check_task(
task: CheckTask, task: CheckTask,
world_state: &WorldState, world_state: &mut WorldState,
task_sender: &Sender<Task>, task_sender: &Sender<Task>,
) -> Result<()> { ) -> Result<()> {
match task { match task {
CheckTask::ClearDiagnostics => { 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 // Send updated diagnostics for each cleared file
for url in cleared_files { for url in cleared_files {
@ -600,11 +602,9 @@ fn on_check_task(
} }
CheckTask::AddDiagnostic(url, diagnostic) => { CheckTask::AddDiagnostic(url, diagnostic) => {
world_state let state = Arc::get_mut(&mut world_state.check_watcher.state)
.check_watcher .expect("couldn't get check watcher state as mutable");
.state state.add_diagnostic_with_fixes(url.clone(), diagnostic);
.write()
.add_diagnostic_with_fixes(url.clone(), diagnostic);
// We manually send a diagnostic update when the watcher asks // We manually send a diagnostic update when the watcher asks
// us to, to avoid the issue of having to change the file to // 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()); 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); let fix_range = fix.location.range.conv_with(&line_index);
if fix_range.intersection(&range).is_none() { if fix_range.intersection(&range).is_none() {
continue; continue;
@ -895,7 +894,7 @@ pub fn publish_diagnostics(
tags: None, tags: None,
}) })
.collect(); .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()); diagnostics.extend(check_diags.iter().cloned());
} }
Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None }) Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None })

View file

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