7236: Fix progress token is already registered crash r=matklad a=matklad

bors r+
🤖

Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2021-01-10 15:09:21 +00:00 committed by GitHub
commit 035fed5f9f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 57 additions and 12 deletions

View file

@ -22,6 +22,7 @@ use crate::{
from_proto, from_proto,
line_endings::LineEndings, line_endings::LineEndings,
main_loop::Task, main_loop::Task,
op_queue::OpQueue,
reload::SourceRootConfig, reload::SourceRootConfig,
request_metrics::{LatestRequests, RequestMetrics}, request_metrics::{LatestRequests, RequestMetrics},
thread_pool::TaskPool, thread_pool::TaskPool,
@ -78,6 +79,7 @@ pub(crate) struct GlobalState {
pub(crate) source_root_config: SourceRootConfig, pub(crate) source_root_config: SourceRootConfig,
pub(crate) proc_macro_client: Option<ProcMacroClient>, pub(crate) proc_macro_client: Option<ProcMacroClient>,
pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
pub(crate) fetch_workspaces_queue: OpQueue,
latest_requests: Arc<RwLock<LatestRequests>>, latest_requests: Arc<RwLock<LatestRequests>>,
} }
@ -130,6 +132,7 @@ impl GlobalState {
source_root_config: SourceRootConfig::default(), source_root_config: SourceRootConfig::default(),
proc_macro_client: None, proc_macro_client: None,
workspaces: Arc::new(Vec::new()), workspaces: Arc::new(Vec::new()),
fetch_workspaces_queue: OpQueue::default(),
latest_requests: Default::default(), latest_requests: Default::default(),
} }
} }

View file

@ -35,6 +35,7 @@ mod lsp_utils;
mod thread_pool; mod thread_pool;
mod document; mod document;
mod diff; mod diff;
mod op_queue;
pub mod lsp_ext; pub mod lsp_ext;
pub mod config; pub mod config;

View file

@ -11,7 +11,6 @@ use ide::{Canceled, FileId};
use ide_db::base_db::VfsPath; use ide_db::base_db::VfsPath;
use lsp_server::{Connection, Notification, Request, Response}; use lsp_server::{Connection, Notification, Request, Response};
use lsp_types::notification::Notification as _; use lsp_types::notification::Notification as _;
use project_model::ProjectWorkspace;
use vfs::ChangeKind; use vfs::ChangeKind;
use crate::{ use crate::{
@ -62,7 +61,6 @@ enum Event {
pub(crate) enum Task { pub(crate) enum Task {
Response(Response), Response(Response),
Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>), Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
Workspaces(Vec<anyhow::Result<ProjectWorkspace>>),
PrimeCaches(PrimeCachesProgress), PrimeCaches(PrimeCachesProgress),
FetchWorkspace(ProjectWorkspaceProgress), FetchWorkspace(ProjectWorkspaceProgress),
} }
@ -143,7 +141,8 @@ impl GlobalState {
|_, _| (), |_, _| (),
); );
self.fetch_workspaces(); self.fetch_workspaces_request();
self.fetch_workspaces_if_needed();
while let Some(event) = self.next_event(&inbox) { while let Some(event) = self.next_event(&inbox) {
if let Event::Lsp(lsp_server::Message::Notification(not)) = &event { if let Event::Lsp(lsp_server::Message::Notification(not)) = &event {
@ -204,7 +203,6 @@ impl GlobalState {
self.diagnostics.set_native_diagnostics(file_id, diagnostics) self.diagnostics.set_native_diagnostics(file_id, diagnostics)
} }
} }
Task::Workspaces(workspaces) => self.switch_workspaces(workspaces),
Task::PrimeCaches(progress) => match progress { Task::PrimeCaches(progress) => match progress {
PrimeCachesProgress::Started => prime_caches_progress.push(progress), PrimeCachesProgress::Started => prime_caches_progress.push(progress),
PrimeCachesProgress::StartedOnCrate { .. } => { PrimeCachesProgress::StartedOnCrate { .. } => {
@ -224,7 +222,11 @@ impl GlobalState {
ProjectWorkspaceProgress::Report(msg) => { ProjectWorkspaceProgress::Report(msg) => {
(Progress::Report, Some(msg)) (Progress::Report, Some(msg))
} }
ProjectWorkspaceProgress::End => (Progress::End, None), ProjectWorkspaceProgress::End(workspaces) => {
self.fetch_workspaces_completed();
self.switch_workspaces(workspaces);
(Progress::End, None)
}
}; };
self.report_progress("fetching", state, msg, None); self.report_progress("fetching", state, msg, None);
} }
@ -403,6 +405,8 @@ impl GlobalState {
} }
} }
self.fetch_workspaces_if_needed();
let loop_duration = loop_start.elapsed(); let loop_duration = loop_start.elapsed();
if loop_duration > Duration::from_millis(100) { if loop_duration > Duration::from_millis(100) {
log::warn!("overly long loop turn: {:?}", loop_duration); log::warn!("overly long loop turn: {:?}", loop_duration);
@ -440,7 +444,7 @@ impl GlobalState {
} }
RequestDispatcher { req: Some(req), global_state: self } RequestDispatcher { req: Some(req), global_state: self }
.on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces()))? .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))?
.on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
.on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
.on_sync::<lsp_types::request::Shutdown>(|s, ()| { .on_sync::<lsp_types::request::Shutdown>(|s, ()| {

View file

@ -0,0 +1,25 @@
//! Bookkeeping to make sure only one long-running operation is executed.
#[derive(Default)]
pub(crate) struct OpQueue {
op_scheduled: bool,
op_in_progress: bool,
}
impl OpQueue {
pub(crate) fn request_op(&mut self) {
self.op_scheduled = true;
}
pub(crate) fn should_start_op(&mut self) -> bool {
if !self.op_in_progress && self.op_scheduled {
self.op_in_progress = true;
self.op_scheduled = false;
return true;
}
false
}
pub(crate) fn op_completed(&mut self) {
assert!(self.op_in_progress);
self.op_in_progress = false;
}
}

View file

@ -19,7 +19,7 @@ use lsp_ext::StatusParams;
pub(crate) enum ProjectWorkspaceProgress { pub(crate) enum ProjectWorkspaceProgress {
Begin, Begin,
Report(String), Report(String),
End, End(Vec<anyhow::Result<ProjectWorkspace>>),
} }
impl GlobalState { impl GlobalState {
@ -30,7 +30,7 @@ impl GlobalState {
self.analysis_host.update_lru_capacity(self.config.lru_capacity()); self.analysis_host.update_lru_capacity(self.config.lru_capacity());
} }
if self.config.linked_projects() != old_config.linked_projects() { if self.config.linked_projects() != old_config.linked_projects() {
self.fetch_workspaces() self.fetch_workspaces_request()
} else if self.config.flycheck() != old_config.flycheck() { } else if self.config.flycheck() != old_config.flycheck() {
self.reload_flycheck(); self.reload_flycheck();
} }
@ -44,7 +44,7 @@ impl GlobalState {
Status::Ready | Status::Invalid => (), Status::Ready | Status::Invalid => (),
} }
if self.config.cargo_autoreload() { if self.config.cargo_autoreload() {
self.fetch_workspaces(); self.fetch_workspaces_request();
} else { } else {
self.transition(Status::NeedsReload); self.transition(Status::NeedsReload);
} }
@ -98,8 +98,15 @@ impl GlobalState {
}); });
} }
} }
pub(crate) fn fetch_workspaces(&mut self) {
pub(crate) fn fetch_workspaces_request(&mut self) {
self.fetch_workspaces_queue.request_op()
}
pub(crate) fn fetch_workspaces_if_needed(&mut self) {
log::info!("will fetch workspaces"); log::info!("will fetch workspaces");
if !self.fetch_workspaces_queue.should_start_op() {
return;
}
self.task_pool.handle.spawn_with_sender({ self.task_pool.handle.spawn_with_sender({
let linked_projects = self.config.linked_projects(); let linked_projects = self.config.linked_projects();
@ -133,12 +140,17 @@ impl GlobalState {
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
sender.send(Task::FetchWorkspace(ProjectWorkspaceProgress::End)).unwrap();
log::info!("did fetch workspaces {:?}", workspaces); log::info!("did fetch workspaces {:?}", workspaces);
sender.send(Task::Workspaces(workspaces)).unwrap() sender
.send(Task::FetchWorkspace(ProjectWorkspaceProgress::End(workspaces)))
.unwrap();
} }
}); });
} }
pub(crate) fn fetch_workspaces_completed(&mut self) {
self.fetch_workspaces_queue.op_completed()
}
pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) { pub(crate) fn switch_workspaces(&mut self, workspaces: Vec<anyhow::Result<ProjectWorkspace>>) {
let _p = profile::span("GlobalState::switch_workspaces"); let _p = profile::span("GlobalState::switch_workspaces");
log::info!("will switch workspaces: {:?}", workspaces); log::info!("will switch workspaces: {:?}", workspaces);