From 0e542936beda5a5e3125ae400fc2630768945ba6 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 31 May 2019 19:17:46 +0300 Subject: minor --- crates/ra_lsp_server/src/main_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index d29ba94e7..00cea10df 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -15,6 +15,7 @@ use ra_vfs::VfsTask; use rustc_hash::FxHashMap; use serde::{de::DeserializeOwned, Serialize}; use threadpool::ThreadPool; +use ra_prof::profile; use crate::{ main_loop::subscriptions::Subscriptions, @@ -24,7 +25,6 @@ use crate::{ Result, InitializationOptions, }; -use ra_prof::profile; #[derive(Debug, Fail)] #[fail(display = "Language Server request failed with {}. ({})", code, message)] -- cgit v1.2.3 From 8bb02859e8656b57b90a95076f559003b015f39b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 31 May 2019 19:20:22 +0300 Subject: introduce constant --- crates/ra_lsp_server/src/main_loop.rs | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 00cea10df..95b69cd6e 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -26,6 +26,9 @@ use crate::{ InitializationOptions, }; +const THREADPOOL_SIZE: usize = 8; +const MAX_IN_FLIGHT_LIBS: usize = THREADPOOL_SIZE - 3; + #[derive(Debug, Fail)] #[fail(display = "Language Server request failed with {}. ({})", code, message)] pub struct LspError { @@ -46,18 +49,21 @@ enum Task { } struct PendingRequest { + id: u64, received: Instant, method: String, } -impl From<(u64, PendingRequest)> for CompletedRequest { - fn from((id, pending): (u64, PendingRequest)) -> CompletedRequest { - CompletedRequest { id, method: pending.method, duration: pending.received.elapsed() } +impl From for CompletedRequest { + fn from(pending: PendingRequest) -> CompletedRequest { + CompletedRequest { + id: pending.id, + method: pending.method, + duration: pending.received.elapsed(), + } } } -const THREADPOOL_SIZE: usize = 8; - pub fn main_loop( ws_roots: Vec, options: InitializationOptions, @@ -175,7 +181,7 @@ fn main_loop_inner( pending_requests: &mut FxHashMap, subs: &mut Subscriptions, ) -> Result<()> { - // We try not to index more than THREADPOOL_SIZE - 3 libraries at the same + // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same // time to always have a thread ready to react to input. let mut in_flight_libraries = 0; let mut pending_libraries = Vec::new(); @@ -264,7 +270,7 @@ fn main_loop_inner( }; pending_libraries.extend(state.process_changes()); - while in_flight_libraries < THREADPOOL_SIZE - 3 && !pending_libraries.is_empty() { + while in_flight_libraries < MAX_IN_FLIGHT_LIBS && !pending_libraries.is_empty() { let (root, files) = pending_libraries.pop().unwrap(); in_flight_libraries += 1; let sender = libdata_sender.clone(); -- cgit v1.2.3 From 838915c9a29987f7c62abfdc6ae0664c21de4b7f Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 31 May 2019 19:24:33 +0300 Subject: simplify --- crates/ra_lsp_server/src/main_loop.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 95b69cd6e..0184c8546 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -317,7 +317,7 @@ fn on_task( match task { Task::Respond(response) => { if let Some(pending) = pending_requests.remove(&response.id) { - let completed = CompletedRequest::from((response.id, pending)); + let completed = CompletedRequest::from(pending); log::info!("handled req#{} in {:?}", completed.id, completed.duration); state.complete_request(completed); msg_sender.send(response.into()).unwrap(); @@ -371,8 +371,8 @@ fn on_request( .finish(); match req { Ok(id) => { - let prev = - pending_requests.insert(id, PendingRequest { method, received: request_received }); + let prev = pending_requests + .insert(id, PendingRequest { id, method, received: request_received }); assert!(prev.is_none(), "duplicate request: {}", id); Ok(None) } -- cgit v1.2.3 From e1bda6aeda084e6e913b80959dbf6ce6260d1db2 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 31 May 2019 20:14:54 +0300 Subject: move completed requests to a separate file --- crates/ra_lsp_server/src/main_loop.rs | 70 ++++++++------------- crates/ra_lsp_server/src/main_loop/handlers.rs | 8 +-- .../src/main_loop/pending_requests.rs | 72 ++++++++++++++++++++++ .../ra_lsp_server/src/main_loop/subscriptions.rs | 12 ++-- crates/ra_lsp_server/src/server_world.rs | 32 ++-------- 5 files changed, 114 insertions(+), 80 deletions(-) create mode 100644 crates/ra_lsp_server/src/main_loop/pending_requests.rs (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 0184c8546..e3cae94f4 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -1,5 +1,6 @@ mod handlers; mod subscriptions; +pub(crate) mod pending_requests; use std::{fmt, path::PathBuf, sync::Arc, time::Instant, any::TypeId}; @@ -12,16 +13,18 @@ use gen_lsp_server::{ use lsp_types::NumberOrString; use ra_ide_api::{Canceled, FileId, LibraryData}; use ra_vfs::VfsTask; -use rustc_hash::FxHashMap; use serde::{de::DeserializeOwned, Serialize}; use threadpool::ThreadPool; use ra_prof::profile; use crate::{ - main_loop::subscriptions::Subscriptions, + main_loop::{ + subscriptions::Subscriptions, + pending_requests::{PendingRequests, PendingRequest}, + }, project_model::workspace_loader, req, - server_world::{ServerWorld, ServerWorldState, CompletedRequest}, + server_world::{ServerWorld, ServerWorldState}, Result, InitializationOptions, }; @@ -42,37 +45,12 @@ impl LspError { } } -#[derive(Debug)] -enum Task { - Respond(RawResponse), - Notify(RawNotification), -} - -struct PendingRequest { - id: u64, - received: Instant, - method: String, -} - -impl From for CompletedRequest { - fn from(pending: PendingRequest) -> CompletedRequest { - CompletedRequest { - id: pending.id, - method: pending.method, - duration: pending.received.elapsed(), - } - } -} - pub fn main_loop( ws_roots: Vec, options: InitializationOptions, msg_receiver: &Receiver, msg_sender: &Sender, ) -> Result<()> { - let pool = ThreadPool::new(THREADPOOL_SIZE); - let (task_sender, task_receiver) = unbounded::(); - // FIXME: support dynamic workspace loading. let workspaces = { let ws_worker = workspace_loader(); @@ -97,10 +75,12 @@ pub fn main_loop( let mut state = ServerWorldState::new(ws_roots, workspaces); - log::info!("server initialized, serving requests"); + let pool = ThreadPool::new(THREADPOOL_SIZE); + let (task_sender, task_receiver) = unbounded::(); + let mut pending_requests = PendingRequests::default(); + let mut subs = Subscriptions::default(); - let mut pending_requests = FxHashMap::default(); - let mut subs = Subscriptions::new(); + log::info!("server initialized, serving requests"); let main_res = main_loop_inner( options, &pool, @@ -128,6 +108,12 @@ pub fn main_loop( main_res } +#[derive(Debug)] +enum Task { + Respond(RawResponse), + Notify(RawNotification), +} + enum Event { Msg(RawMessage), Task(Task), @@ -178,7 +164,7 @@ fn main_loop_inner( task_sender: Sender, task_receiver: Receiver, state: &mut ServerWorldState, - pending_requests: &mut FxHashMap, + pending_requests: &mut PendingRequests, subs: &mut Subscriptions, ) -> Result<()> { // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same @@ -202,15 +188,16 @@ fn main_loop_inner( }, recv(libdata_receiver) -> data => Event::Lib(data.unwrap()) }; - // NOTE: don't count blocking select! call as a loop-turn time - let _p = profile("main_loop_inner/loop-turn"); let loop_start = Instant::now(); + // NOTE: don't count blocking select! call as a loop-turn time + let _p = profile("main_loop_inner/loop-turn"); log::info!("loop turn = {:?}", event); let queue_count = pool.queued_count(); if queue_count > 0 { log::info!("queued count = {}", queue_count); } + let mut state_changed = false; match event { Event::Task(task) => { @@ -311,13 +298,12 @@ fn main_loop_inner( fn on_task( task: Task, msg_sender: &Sender, - pending_requests: &mut FxHashMap, + pending_requests: &mut PendingRequests, state: &mut ServerWorldState, ) { match task { Task::Respond(response) => { - if let Some(pending) = pending_requests.remove(&response.id) { - let completed = CompletedRequest::from(pending); + if let Some(completed) = pending_requests.finish(response.id) { log::info!("handled req#{} in {:?}", completed.id, completed.duration); state.complete_request(completed); msg_sender.send(response.into()).unwrap(); @@ -331,7 +317,7 @@ fn on_task( fn on_request( world: &mut ServerWorldState, - pending_requests: &mut FxHashMap, + pending_requests: &mut PendingRequests, pool: &ThreadPool, sender: &Sender, request_received: Instant, @@ -371,9 +357,7 @@ fn on_request( .finish(); match req { Ok(id) => { - let prev = pending_requests - .insert(id, PendingRequest { id, method, received: request_received }); - assert!(prev.is_none(), "duplicate request: {}", id); + pending_requests.start(PendingRequest { id, method, received: request_received }); Ok(None) } Err(req) => Ok(Some(req)), @@ -383,7 +367,7 @@ fn on_request( fn on_notification( msg_sender: &Sender, state: &mut ServerWorldState, - pending_requests: &mut FxHashMap, + pending_requests: &mut PendingRequests, subs: &mut Subscriptions, not: RawNotification, ) -> Result<()> { @@ -395,7 +379,7 @@ fn on_notification( panic!("string id's not supported: {:?}", id); } }; - if pending_requests.remove(&id).is_some() { + if pending_requests.cancel(id) { let response = RawResponse::err( id, ErrorCode::RequestCanceled as i32, diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 0ebfd641d..8cfb6a192 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -31,10 +31,10 @@ use crate::{ pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result { let mut buf = world.status(); writeln!(buf, "\n\nrequests:").unwrap(); - let requests = world.latest_completed_requests.read(); - for (idx, r) in requests.iter().enumerate() { - let current = if idx == world.request_idx { "*" } else { " " }; - writeln!(buf, "{:4}{}{:<36}{}ms", r.id, current, r.method, r.duration.as_millis()).unwrap(); + let requests = world.latest_requests.read(); + for (is_last, r) in requests.iter() { + let mark = if is_last { "*" } else { " " }; + writeln!(buf, "{}{:4} {:<36}{}ms", mark, r.id, r.method, r.duration.as_millis()).unwrap(); } Ok(buf) } diff --git a/crates/ra_lsp_server/src/main_loop/pending_requests.rs b/crates/ra_lsp_server/src/main_loop/pending_requests.rs new file mode 100644 index 000000000..741770e45 --- /dev/null +++ b/crates/ra_lsp_server/src/main_loop/pending_requests.rs @@ -0,0 +1,72 @@ +use std::time::{Duration, Instant}; + +use rustc_hash::FxHashMap; + +#[derive(Debug)] +pub struct CompletedRequest { + pub id: u64, + pub method: String, + pub duration: Duration, +} + +#[derive(Debug)] +pub(crate) struct PendingRequest { + pub(crate) id: u64, + pub(crate) method: String, + pub(crate) received: Instant, +} + +impl From for CompletedRequest { + fn from(pending: PendingRequest) -> CompletedRequest { + CompletedRequest { + id: pending.id, + method: pending.method, + duration: pending.received.elapsed(), + } + } +} + +#[derive(Debug, Default)] +pub(crate) struct PendingRequests { + map: FxHashMap, +} + +impl PendingRequests { + pub(crate) fn start(&mut self, request: PendingRequest) { + let id = request.id; + let prev = self.map.insert(id, request); + assert!(prev.is_none(), "duplicate request with id {}", id); + } + pub(crate) fn cancel(&mut self, id: u64) -> bool { + self.map.remove(&id).is_some() + } + pub(crate) fn finish(&mut self, id: u64) -> Option { + self.map.remove(&id).map(CompletedRequest::from) + } +} + +const N_COMPLETED_REQUESTS: usize = 10; + +#[derive(Debug, Default)] +pub struct LatestRequests { + // hand-rolling VecDeque here to print things in a nicer way + buf: [Option; N_COMPLETED_REQUESTS], + idx: usize, +} + +impl LatestRequests { + pub(crate) fn record(&mut self, request: CompletedRequest) { + // special case: don't track status request itself + if request.method == "rust-analyzer/analyzerStatus" { + return; + } + let idx = self.idx; + self.buf[idx] = Some(request); + self.idx = (idx + 1) % N_COMPLETED_REQUESTS; + } + + pub(crate) fn iter(&self) -> impl Iterator { + let idx = self.idx; + self.buf.iter().enumerate().filter_map(move |(i, req)| Some((i == idx, req.as_ref()?))) + } +} diff --git a/crates/ra_lsp_server/src/main_loop/subscriptions.rs b/crates/ra_lsp_server/src/main_loop/subscriptions.rs index 11bd952d9..470bc1205 100644 --- a/crates/ra_lsp_server/src/main_loop/subscriptions.rs +++ b/crates/ra_lsp_server/src/main_loop/subscriptions.rs @@ -1,21 +1,19 @@ use ra_ide_api::FileId; use rustc_hash::FxHashSet; -pub struct Subscriptions { +#[derive(Default)] +pub(crate) struct Subscriptions { subs: FxHashSet, } impl Subscriptions { - pub fn new() -> Subscriptions { - Subscriptions { subs: FxHashSet::default() } - } - pub fn add_sub(&mut self, file_id: FileId) { + pub(crate) fn add_sub(&mut self, file_id: FileId) { self.subs.insert(file_id); } - pub fn remove_sub(&mut self, file_id: FileId) { + pub(crate) fn remove_sub(&mut self, file_id: FileId) { self.subs.remove(&file_id); } - pub fn subscriptions(&self) -> Vec { + pub(crate) fn subscriptions(&self) -> Vec { self.subs.iter().cloned().collect() } } diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 7eb4d3e56..8c7951e13 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -1,7 +1,6 @@ use std::{ path::{Path, PathBuf}, sync::Arc, - time::Duration, }; use lsp_types::Url; @@ -16,6 +15,7 @@ use failure::{Error, format_err}; use gen_lsp_server::ErrorCode; use crate::{ + main_loop::pending_requests::{CompletedRequest, LatestRequests}, project_model::ProjectWorkspace, vfs_filter::IncludeRustFiles, Result, @@ -29,26 +29,14 @@ pub struct ServerWorldState { pub workspaces: Arc>, pub analysis_host: AnalysisHost, pub vfs: Arc>, - // hand-rolling VecDeque here to print things in a nicer way - pub latest_completed_requests: Arc>, - pub request_idx: usize, + pub latest_requests: Arc>, } -const N_COMPLETED_REQUESTS: usize = 10; - pub struct ServerWorld { pub workspaces: Arc>, pub analysis: Analysis, pub vfs: Arc>, - pub latest_completed_requests: Arc>, - pub request_idx: usize, -} - -#[derive(Debug, Default)] -pub struct CompletedRequest { - pub id: u64, - pub method: String, - pub duration: Duration, + pub latest_requests: Arc>, } impl ServerWorldState { @@ -88,8 +76,7 @@ impl ServerWorldState { workspaces: Arc::new(workspaces), analysis_host, vfs: Arc::new(RwLock::new(vfs)), - latest_completed_requests: Default::default(), - request_idx: 0, + latest_requests: Default::default(), } } @@ -158,8 +145,7 @@ impl ServerWorldState { workspaces: Arc::clone(&self.workspaces), analysis: self.analysis_host.analysis(), vfs: Arc::clone(&self.vfs), - latest_completed_requests: Arc::clone(&self.latest_completed_requests), - request_idx: self.request_idx.checked_sub(1).unwrap_or(N_COMPLETED_REQUESTS - 1), + latest_requests: Arc::clone(&self.latest_requests), } } @@ -172,13 +158,7 @@ impl ServerWorldState { } pub fn complete_request(&mut self, request: CompletedRequest) { - // special case: don't track status request itself - if request.method == "rust-analyzer/analyzerStatus" { - return; - } - let idx = self.request_idx; - self.latest_completed_requests.write()[idx] = request; - self.request_idx = (idx + 1) % N_COMPLETED_REQUESTS; + self.latest_requests.write().record(request) } } -- cgit v1.2.3 From 2d773a46c91cd38862f2324de2bdf8a4fbbf1683 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 31 May 2019 20:23:56 +0300 Subject: simplify --- crates/ra_lsp_server/src/main_loop.rs | 103 +++++++++++++++++----------------- 1 file changed, 52 insertions(+), 51 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index e3cae94f4..9fc392749 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -452,59 +452,60 @@ impl<'a> PoolDispatcher<'a> { None => return Ok(self), Some(req) => req, }; - match req.cast::() { - Ok((id, params)) => { - // Real time requests block user typing, so we should react quickly to them. - // Currently this means that we try to cancel background jobs if we don't have - // a spare thread. - let is_real_time = TypeId::of::() == TypeId::of::() - || TypeId::of::() == TypeId::of::(); - if self.pool.queued_count() > 0 && is_real_time { - self.world.cancel_requests(); - } - - let world = self.world.snapshot(); - let sender = self.sender.clone(); - self.pool.execute(move || { - let response = match f(world, params) { - Ok(resp) => RawResponse::ok::(id, &resp), - Err(e) => match e.downcast::() { - Ok(lsp_error) => { - RawResponse::err(id, lsp_error.code, lsp_error.message) - } - Err(e) => { - if is_canceled(&e) { - // FIXME: When https://github.com/Microsoft/vscode-languageserver-node/issues/457 - // gets fixed, we can return the proper response. - // This works around the issue where "content modified" error would continuously - // show an message pop-up in VsCode - // RawResponse::err( - // id, - // ErrorCode::ContentModified as i32, - // "content modified".to_string(), - // ) - RawResponse { - id, - result: Some(serde_json::to_value(&()).unwrap()), - error: None, - } - } else { - RawResponse::err( - id, - ErrorCode::InternalError as i32, - format!("{}\n{}", e, e.backtrace()), - ) - } - } - }, - }; - let task = Task::Respond(response); - sender.send(task).unwrap(); - }); - self.res = Some(id); + let (id, params) = match req.cast::() { + Ok(it) => it, + Err(req) => { + self.req = Some(req); + return Ok(self); } - Err(req) => self.req = Some(req), + }; + self.res = Some(id); + + // Real time requests block user typing, so we should react quickly to them. + // Currently this means that we try to cancel background jobs if we don't have + // a spare thread. + let is_real_time = TypeId::of::() == TypeId::of::() + || TypeId::of::() == TypeId::of::(); + if self.pool.queued_count() > 0 && is_real_time { + self.world.cancel_requests(); } + + let world = self.world.snapshot(); + let sender = self.sender.clone(); + self.pool.execute(move || { + let response = match f(world, params) { + Ok(resp) => RawResponse::ok::(id, &resp), + Err(e) => match e.downcast::() { + Ok(lsp_error) => RawResponse::err(id, lsp_error.code, lsp_error.message), + Err(e) => { + if is_canceled(&e) { + // FIXME: When https://github.com/Microsoft/vscode-languageserver-node/issues/457 + // gets fixed, we can return the proper response. + // This works around the issue where "content modified" error would continuously + // show an message pop-up in VsCode + // RawResponse::err( + // id, + // ErrorCode::ContentModified as i32, + // "content modified".to_string(), + // ) + RawResponse { + id, + result: Some(serde_json::to_value(&()).unwrap()), + error: None, + } + } else { + RawResponse::err( + id, + ErrorCode::InternalError as i32, + format!("{}\n{}", e, e.backtrace()), + ) + } + } + }, + }; + let task = Task::Respond(response); + sender.send(task).unwrap(); + }); Ok(self) } -- cgit v1.2.3 From 15efd58274855b755c99e5c088102920b70f3d80 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 31 May 2019 20:30:14 +0300 Subject: cleanup --- crates/ra_lsp_server/src/main_loop.rs | 83 ++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 35 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 9fc392749..ab22052d9 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -470,42 +470,16 @@ impl<'a> PoolDispatcher<'a> { self.world.cancel_requests(); } - let world = self.world.snapshot(); - let sender = self.sender.clone(); - self.pool.execute(move || { - let response = match f(world, params) { - Ok(resp) => RawResponse::ok::(id, &resp), - Err(e) => match e.downcast::() { - Ok(lsp_error) => RawResponse::err(id, lsp_error.code, lsp_error.message), - Err(e) => { - if is_canceled(&e) { - // FIXME: When https://github.com/Microsoft/vscode-languageserver-node/issues/457 - // gets fixed, we can return the proper response. - // This works around the issue where "content modified" error would continuously - // show an message pop-up in VsCode - // RawResponse::err( - // id, - // ErrorCode::ContentModified as i32, - // "content modified".to_string(), - // ) - RawResponse { - id, - result: Some(serde_json::to_value(&()).unwrap()), - error: None, - } - } else { - RawResponse::err( - id, - ErrorCode::InternalError as i32, - format!("{}\n{}", e, e.backtrace()), - ) - } - } - }, - }; - let task = Task::Respond(response); - sender.send(task).unwrap(); + self.pool.execute({ + let world = self.world.snapshot(); + let sender = self.sender.clone(); + move || { + let result = f(world, params); + let task = result_to_task::(id, result); + sender.send(task).unwrap(); + } }); + Ok(self) } @@ -518,6 +492,45 @@ impl<'a> PoolDispatcher<'a> { } } +fn result_to_task(id: u64, result: Result) -> Task +where + R: req::Request + 'static, + R::Params: DeserializeOwned + Send + 'static, + R::Result: Serialize + 'static, +{ + let response = match result { + Ok(resp) => RawResponse::ok::(id, &resp), + Err(e) => match e.downcast::() { + Ok(lsp_error) => RawResponse::err(id, lsp_error.code, lsp_error.message), + Err(e) => { + if is_canceled(&e) { + // FIXME: When https://github.com/Microsoft/vscode-languageserver-node/issues/457 + // gets fixed, we can return the proper response. + // This works around the issue where "content modified" error would continuously + // show an message pop-up in VsCode + // RawResponse::err( + // id, + // ErrorCode::ContentModified as i32, + // "content modified".to_string(), + // ) + RawResponse { + id, + result: Some(serde_json::to_value(&()).unwrap()), + error: None, + } + } else { + RawResponse::err( + id, + ErrorCode::InternalError as i32, + format!("{}\n{}", e, e.backtrace()), + ) + } + } + }, + }; + Task::Respond(response) +} + fn update_file_notifications_on_threadpool( pool: &ThreadPool, world: ServerWorld, -- cgit v1.2.3 From 9697d8afadd96a8b18684e4967346f01a4343819 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 31 May 2019 20:42:53 +0300 Subject: cleanup --- crates/ra_lsp_server/src/main_loop.rs | 81 ++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 39 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index ab22052d9..8f41937dc 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -225,27 +225,15 @@ fn main_loop_inner( let resp = RawResponse::ok::(id, &()); msg_sender.send(resp.into()).unwrap() } - Err(req) => { - match on_request( - state, - pending_requests, - pool, - &task_sender, - loop_start, - req, - )? { - None => (), - Some(req) => { - log::error!("unknown request: {:?}", req); - let resp = RawResponse::err( - req.id, - ErrorCode::MethodNotFound as i32, - "unknown request".to_string(), - ); - msg_sender.send(resp.into()).unwrap() - } - } - } + Err(req) => on_request( + state, + pending_requests, + pool, + &task_sender, + msg_sender, + loop_start, + req, + )?, } } RawMessage::Notification(not) => { @@ -320,12 +308,20 @@ fn on_request( pending_requests: &mut PendingRequests, pool: &ThreadPool, sender: &Sender, + msg_sender: &Sender, request_received: Instant, req: RawRequest, -) -> Result> { - let method = req.method.clone(); - let mut pool_dispatcher = PoolDispatcher { req: Some(req), res: None, pool, world, sender }; - let req = pool_dispatcher +) -> Result<()> { + let mut pool_dispatcher = PoolDispatcher { + req: Some(req), + pool, + world, + sender, + msg_sender, + pending_requests, + request_received, + }; + pool_dispatcher .on::(handlers::handle_analyzer_status)? .on::(handlers::handle_syntax_tree)? .on::(handlers::handle_extend_selection)? @@ -355,13 +351,7 @@ fn on_request( .on::(handlers::handle_formatting)? .on::(handlers::handle_document_highlight)? .finish(); - match req { - Ok(id) => { - pending_requests.start(PendingRequest { id, method, received: request_received }); - Ok(None) - } - Err(req) => Ok(Some(req)), - } + Ok(()) } fn on_notification( @@ -435,10 +425,12 @@ fn on_notification( struct PoolDispatcher<'a> { req: Option, - res: Option, pool: &'a ThreadPool, world: &'a mut ServerWorldState, + pending_requests: &'a mut PendingRequests, + msg_sender: &'a Sender, sender: &'a Sender, + request_received: Instant, } impl<'a> PoolDispatcher<'a> { @@ -459,7 +451,11 @@ impl<'a> PoolDispatcher<'a> { return Ok(self); } }; - self.res = Some(id); + self.pending_requests.start(PendingRequest { + id, + method: R::METHOD.to_string(), + received: self.request_received, + }); // Real time requests block user typing, so we should react quickly to them. // Currently this means that we try to cancel background jobs if we don't have @@ -483,11 +479,18 @@ impl<'a> PoolDispatcher<'a> { Ok(self) } - fn finish(&mut self) -> std::result::Result { - match (self.res.take(), self.req.take()) { - (Some(res), None) => Ok(res), - (None, Some(req)) => Err(req), - _ => unreachable!(), + fn finish(&mut self) { + match self.req.take() { + None => (), + Some(req) => { + log::error!("unknown request: {:?}", req); + let resp = RawResponse::err( + req.id, + ErrorCode::MethodNotFound as i32, + "unknown request".to_string(), + ); + self.msg_sender.send(resp.into()).unwrap(); + } } } } -- cgit v1.2.3 From c6537c3280ba1c5df27c1ced9d4944a2acb02b6c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 31 May 2019 20:50:16 +0300 Subject: add sync requests --- crates/ra_lsp_server/src/main_loop.rs | 95 +++++++++++++++++++------------- crates/ra_lsp_server/src/server_world.rs | 4 -- 2 files changed, 56 insertions(+), 43 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 8f41937dc..8a7c53d2c 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -2,7 +2,7 @@ mod handlers; mod subscriptions; pub(crate) mod pending_requests; -use std::{fmt, path::PathBuf, sync::Arc, time::Instant, any::TypeId}; +use std::{fmt, path::PathBuf, sync::Arc, time::Instant}; use crossbeam_channel::{select, unbounded, Receiver, RecvError, Sender}; use failure::{bail, format_err}; @@ -219,22 +219,15 @@ fn main_loop_inner( Some(req) => req, None => return Ok(()), }; - match req.cast::() { - Ok((id, ())) => { - state.collect_garbage(); - let resp = RawResponse::ok::(id, &()); - msg_sender.send(resp.into()).unwrap() - } - Err(req) => on_request( - state, - pending_requests, - pool, - &task_sender, - msg_sender, - loop_start, - req, - )?, - } + on_request( + state, + pending_requests, + pool, + &task_sender, + msg_sender, + loop_start, + req, + )? } RawMessage::Notification(not) => { on_notification(msg_sender, state, pending_requests, subs, not)?; @@ -322,6 +315,7 @@ fn on_request( request_received, }; pool_dispatcher + .on_sync::(|state, ()| Ok(state.collect_garbage()))? .on::(handlers::handle_analyzer_status)? .on::(handlers::handle_syntax_tree)? .on::(handlers::handle_extend_selection)? @@ -434,37 +428,39 @@ struct PoolDispatcher<'a> { } impl<'a> PoolDispatcher<'a> { - fn on(&mut self, f: fn(ServerWorld, R::Params) -> Result) -> Result<&mut Self> + fn on_sync( + &mut self, + f: fn(&mut ServerWorldState, R::Params) -> Result, + ) -> Result<&mut Self> where R: req::Request + 'static, R::Params: DeserializeOwned + Send + 'static, R::Result: Serialize + 'static, { - let req = match self.req.take() { - None => return Ok(self), - Some(req) => req, - }; - let (id, params) = match req.cast::() { - Ok(it) => it, - Err(req) => { - self.req = Some(req); + let (id, params) = match self.parse::() { + Some(it) => it, + None => { return Ok(self); } }; - self.pending_requests.start(PendingRequest { - id, - method: R::METHOD.to_string(), - received: self.request_received, - }); + let result = f(self.world, params); + let task = result_to_task::(id, result); + on_task(task, self.msg_sender, self.pending_requests, self.world); + Ok(self) + } - // Real time requests block user typing, so we should react quickly to them. - // Currently this means that we try to cancel background jobs if we don't have - // a spare thread. - let is_real_time = TypeId::of::() == TypeId::of::() - || TypeId::of::() == TypeId::of::(); - if self.pool.queued_count() > 0 && is_real_time { - self.world.cancel_requests(); - } + fn on(&mut self, f: fn(ServerWorld, R::Params) -> Result) -> Result<&mut Self> + where + R: req::Request + 'static, + R::Params: DeserializeOwned + Send + 'static, + R::Result: Serialize + 'static, + { + let (id, params) = match self.parse::() { + Some(it) => it, + None => { + return Ok(self); + } + }; self.pool.execute({ let world = self.world.snapshot(); @@ -479,6 +475,27 @@ impl<'a> PoolDispatcher<'a> { Ok(self) } + fn parse(&mut self) -> Option<(u64, R::Params)> + where + R: req::Request + 'static, + R::Params: DeserializeOwned + Send + 'static, + { + let req = self.req.take()?; + let (id, params) = match req.cast::() { + Ok(it) => it, + Err(req) => { + self.req = Some(req); + return None; + } + }; + self.pending_requests.start(PendingRequest { + id, + method: R::METHOD.to_string(), + received: self.request_received, + }); + Some((id, params)) + } + fn finish(&mut self) { match self.req.take() { None => (), diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 8c7951e13..6076a6cd6 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs @@ -136,10 +136,6 @@ impl ServerWorldState { self.analysis_host.apply_change(change); } - pub fn cancel_requests(&mut self) { - self.analysis_host.apply_change(AnalysisChange::new()); - } - pub fn snapshot(&self) -> ServerWorld { ServerWorld { workspaces: Arc::clone(&self.workspaces), -- cgit v1.2.3 From 78e17f65cfa0013ea51d94f0142ca6d4bcc5d088 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Fri, 31 May 2019 20:52:09 +0300 Subject: use sync queries for join lines and friends --- crates/ra_lsp_server/src/main_loop.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'crates/ra_lsp_server') diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs index 8a7c53d2c..452499497 100644 --- a/crates/ra_lsp_server/src/main_loop.rs +++ b/crates/ra_lsp_server/src/main_loop.rs @@ -315,14 +315,18 @@ fn on_request( request_received, }; pool_dispatcher - .on_sync::(|state, ()| Ok(state.collect_garbage()))? + .on_sync::(|s, ()| Ok(s.collect_garbage()))? + .on_sync::(|s, p| handlers::handle_join_lines(s.snapshot(), p))? + .on_sync::(|s, p| handlers::handle_on_enter(s.snapshot(), p))? + .on_sync::(|s, p| { + handlers::handle_selection_range(s.snapshot(), p) + })? + .on_sync::(|s, p| { + handlers::handle_find_matching_brace(s.snapshot(), p) + })? .on::(handlers::handle_analyzer_status)? .on::(handlers::handle_syntax_tree)? .on::(handlers::handle_extend_selection)? - .on::(handlers::handle_selection_range)? - .on::(handlers::handle_find_matching_brace)? - .on::(handlers::handle_join_lines)? - .on::(handlers::handle_on_enter)? .on::(handlers::handle_on_type_formatting)? .on::(handlers::handle_document_symbol)? .on::(handlers::handle_workspace_symbol)? @@ -428,6 +432,7 @@ struct PoolDispatcher<'a> { } impl<'a> PoolDispatcher<'a> { + /// Dispatches the request onto the current thread fn on_sync( &mut self, f: fn(&mut ServerWorldState, R::Params) -> Result, @@ -449,6 +454,7 @@ impl<'a> PoolDispatcher<'a> { Ok(self) } + /// Dispatches the request onto thread pool fn on(&mut self, f: fn(ServerWorld, R::Params) -> Result) -> Result<&mut Self> where R: req::Request + 'static, -- cgit v1.2.3