diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_lsp_server/src/main_loop.rs | 70 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 8 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/pending_requests.rs | 72 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/subscriptions.rs | 12 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/server_world.rs | 32 |
5 files changed, 114 insertions, 80 deletions
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 @@ | |||
1 | mod handlers; | 1 | mod handlers; |
2 | mod subscriptions; | 2 | mod subscriptions; |
3 | pub(crate) mod pending_requests; | ||
3 | 4 | ||
4 | use std::{fmt, path::PathBuf, sync::Arc, time::Instant, any::TypeId}; | 5 | use std::{fmt, path::PathBuf, sync::Arc, time::Instant, any::TypeId}; |
5 | 6 | ||
@@ -12,16 +13,18 @@ use gen_lsp_server::{ | |||
12 | use lsp_types::NumberOrString; | 13 | use lsp_types::NumberOrString; |
13 | use ra_ide_api::{Canceled, FileId, LibraryData}; | 14 | use ra_ide_api::{Canceled, FileId, LibraryData}; |
14 | use ra_vfs::VfsTask; | 15 | use ra_vfs::VfsTask; |
15 | use rustc_hash::FxHashMap; | ||
16 | use serde::{de::DeserializeOwned, Serialize}; | 16 | use serde::{de::DeserializeOwned, Serialize}; |
17 | use threadpool::ThreadPool; | 17 | use threadpool::ThreadPool; |
18 | use ra_prof::profile; | 18 | use ra_prof::profile; |
19 | 19 | ||
20 | use crate::{ | 20 | use crate::{ |
21 | main_loop::subscriptions::Subscriptions, | 21 | main_loop::{ |
22 | subscriptions::Subscriptions, | ||
23 | pending_requests::{PendingRequests, PendingRequest}, | ||
24 | }, | ||
22 | project_model::workspace_loader, | 25 | project_model::workspace_loader, |
23 | req, | 26 | req, |
24 | server_world::{ServerWorld, ServerWorldState, CompletedRequest}, | 27 | server_world::{ServerWorld, ServerWorldState}, |
25 | Result, | 28 | Result, |
26 | InitializationOptions, | 29 | InitializationOptions, |
27 | }; | 30 | }; |
@@ -42,37 +45,12 @@ impl LspError { | |||
42 | } | 45 | } |
43 | } | 46 | } |
44 | 47 | ||
45 | #[derive(Debug)] | ||
46 | enum Task { | ||
47 | Respond(RawResponse), | ||
48 | Notify(RawNotification), | ||
49 | } | ||
50 | |||
51 | struct PendingRequest { | ||
52 | id: u64, | ||
53 | received: Instant, | ||
54 | method: String, | ||
55 | } | ||
56 | |||
57 | impl From<PendingRequest> for CompletedRequest { | ||
58 | fn from(pending: PendingRequest) -> CompletedRequest { | ||
59 | CompletedRequest { | ||
60 | id: pending.id, | ||
61 | method: pending.method, | ||
62 | duration: pending.received.elapsed(), | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | |||
67 | pub fn main_loop( | 48 | pub fn main_loop( |
68 | ws_roots: Vec<PathBuf>, | 49 | ws_roots: Vec<PathBuf>, |
69 | options: InitializationOptions, | 50 | options: InitializationOptions, |
70 | msg_receiver: &Receiver<RawMessage>, | 51 | msg_receiver: &Receiver<RawMessage>, |
71 | msg_sender: &Sender<RawMessage>, | 52 | msg_sender: &Sender<RawMessage>, |
72 | ) -> Result<()> { | 53 | ) -> Result<()> { |
73 | let pool = ThreadPool::new(THREADPOOL_SIZE); | ||
74 | let (task_sender, task_receiver) = unbounded::<Task>(); | ||
75 | |||
76 | // FIXME: support dynamic workspace loading. | 54 | // FIXME: support dynamic workspace loading. |
77 | let workspaces = { | 55 | let workspaces = { |
78 | let ws_worker = workspace_loader(); | 56 | let ws_worker = workspace_loader(); |
@@ -97,10 +75,12 @@ pub fn main_loop( | |||
97 | 75 | ||
98 | let mut state = ServerWorldState::new(ws_roots, workspaces); | 76 | let mut state = ServerWorldState::new(ws_roots, workspaces); |
99 | 77 | ||
100 | log::info!("server initialized, serving requests"); | 78 | let pool = ThreadPool::new(THREADPOOL_SIZE); |
79 | let (task_sender, task_receiver) = unbounded::<Task>(); | ||
80 | let mut pending_requests = PendingRequests::default(); | ||
81 | let mut subs = Subscriptions::default(); | ||
101 | 82 | ||
102 | let mut pending_requests = FxHashMap::default(); | 83 | log::info!("server initialized, serving requests"); |
103 | let mut subs = Subscriptions::new(); | ||
104 | let main_res = main_loop_inner( | 84 | let main_res = main_loop_inner( |
105 | options, | 85 | options, |
106 | &pool, | 86 | &pool, |
@@ -128,6 +108,12 @@ pub fn main_loop( | |||
128 | main_res | 108 | main_res |
129 | } | 109 | } |
130 | 110 | ||
111 | #[derive(Debug)] | ||
112 | enum Task { | ||
113 | Respond(RawResponse), | ||
114 | Notify(RawNotification), | ||
115 | } | ||
116 | |||
131 | enum Event { | 117 | enum Event { |
132 | Msg(RawMessage), | 118 | Msg(RawMessage), |
133 | Task(Task), | 119 | Task(Task), |
@@ -178,7 +164,7 @@ fn main_loop_inner( | |||
178 | task_sender: Sender<Task>, | 164 | task_sender: Sender<Task>, |
179 | task_receiver: Receiver<Task>, | 165 | task_receiver: Receiver<Task>, |
180 | state: &mut ServerWorldState, | 166 | state: &mut ServerWorldState, |
181 | pending_requests: &mut FxHashMap<u64, PendingRequest>, | 167 | pending_requests: &mut PendingRequests, |
182 | subs: &mut Subscriptions, | 168 | subs: &mut Subscriptions, |
183 | ) -> Result<()> { | 169 | ) -> Result<()> { |
184 | // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same | 170 | // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same |
@@ -202,15 +188,16 @@ fn main_loop_inner( | |||
202 | }, | 188 | }, |
203 | recv(libdata_receiver) -> data => Event::Lib(data.unwrap()) | 189 | recv(libdata_receiver) -> data => Event::Lib(data.unwrap()) |
204 | }; | 190 | }; |
205 | // NOTE: don't count blocking select! call as a loop-turn time | ||
206 | let _p = profile("main_loop_inner/loop-turn"); | ||
207 | let loop_start = Instant::now(); | 191 | let loop_start = Instant::now(); |
208 | 192 | ||
193 | // NOTE: don't count blocking select! call as a loop-turn time | ||
194 | let _p = profile("main_loop_inner/loop-turn"); | ||
209 | log::info!("loop turn = {:?}", event); | 195 | log::info!("loop turn = {:?}", event); |
210 | let queue_count = pool.queued_count(); | 196 | let queue_count = pool.queued_count(); |
211 | if queue_count > 0 { | 197 | if queue_count > 0 { |
212 | log::info!("queued count = {}", queue_count); | 198 | log::info!("queued count = {}", queue_count); |
213 | } | 199 | } |
200 | |||
214 | let mut state_changed = false; | 201 | let mut state_changed = false; |
215 | match event { | 202 | match event { |
216 | Event::Task(task) => { | 203 | Event::Task(task) => { |
@@ -311,13 +298,12 @@ fn main_loop_inner( | |||
311 | fn on_task( | 298 | fn on_task( |
312 | task: Task, | 299 | task: Task, |
313 | msg_sender: &Sender<RawMessage>, | 300 | msg_sender: &Sender<RawMessage>, |
314 | pending_requests: &mut FxHashMap<u64, PendingRequest>, | 301 | pending_requests: &mut PendingRequests, |
315 | state: &mut ServerWorldState, | 302 | state: &mut ServerWorldState, |
316 | ) { | 303 | ) { |
317 | match task { | 304 | match task { |
318 | Task::Respond(response) => { | 305 | Task::Respond(response) => { |
319 | if let Some(pending) = pending_requests.remove(&response.id) { | 306 | if let Some(completed) = pending_requests.finish(response.id) { |
320 | let completed = CompletedRequest::from(pending); | ||
321 | log::info!("handled req#{} in {:?}", completed.id, completed.duration); | 307 | log::info!("handled req#{} in {:?}", completed.id, completed.duration); |
322 | state.complete_request(completed); | 308 | state.complete_request(completed); |
323 | msg_sender.send(response.into()).unwrap(); | 309 | msg_sender.send(response.into()).unwrap(); |
@@ -331,7 +317,7 @@ fn on_task( | |||
331 | 317 | ||
332 | fn on_request( | 318 | fn on_request( |
333 | world: &mut ServerWorldState, | 319 | world: &mut ServerWorldState, |
334 | pending_requests: &mut FxHashMap<u64, PendingRequest>, | 320 | pending_requests: &mut PendingRequests, |
335 | pool: &ThreadPool, | 321 | pool: &ThreadPool, |
336 | sender: &Sender<Task>, | 322 | sender: &Sender<Task>, |
337 | request_received: Instant, | 323 | request_received: Instant, |
@@ -371,9 +357,7 @@ fn on_request( | |||
371 | .finish(); | 357 | .finish(); |
372 | match req { | 358 | match req { |
373 | Ok(id) => { | 359 | Ok(id) => { |
374 | let prev = pending_requests | 360 | pending_requests.start(PendingRequest { id, method, received: request_received }); |
375 | .insert(id, PendingRequest { id, method, received: request_received }); | ||
376 | assert!(prev.is_none(), "duplicate request: {}", id); | ||
377 | Ok(None) | 361 | Ok(None) |
378 | } | 362 | } |
379 | Err(req) => Ok(Some(req)), | 363 | Err(req) => Ok(Some(req)), |
@@ -383,7 +367,7 @@ fn on_request( | |||
383 | fn on_notification( | 367 | fn on_notification( |
384 | msg_sender: &Sender<RawMessage>, | 368 | msg_sender: &Sender<RawMessage>, |
385 | state: &mut ServerWorldState, | 369 | state: &mut ServerWorldState, |
386 | pending_requests: &mut FxHashMap<u64, PendingRequest>, | 370 | pending_requests: &mut PendingRequests, |
387 | subs: &mut Subscriptions, | 371 | subs: &mut Subscriptions, |
388 | not: RawNotification, | 372 | not: RawNotification, |
389 | ) -> Result<()> { | 373 | ) -> Result<()> { |
@@ -395,7 +379,7 @@ fn on_notification( | |||
395 | panic!("string id's not supported: {:?}", id); | 379 | panic!("string id's not supported: {:?}", id); |
396 | } | 380 | } |
397 | }; | 381 | }; |
398 | if pending_requests.remove(&id).is_some() { | 382 | if pending_requests.cancel(id) { |
399 | let response = RawResponse::err( | 383 | let response = RawResponse::err( |
400 | id, | 384 | id, |
401 | ErrorCode::RequestCanceled as i32, | 385 | 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::{ | |||
31 | pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result<String> { | 31 | pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result<String> { |
32 | let mut buf = world.status(); | 32 | let mut buf = world.status(); |
33 | writeln!(buf, "\n\nrequests:").unwrap(); | 33 | writeln!(buf, "\n\nrequests:").unwrap(); |
34 | let requests = world.latest_completed_requests.read(); | 34 | let requests = world.latest_requests.read(); |
35 | for (idx, r) in requests.iter().enumerate() { | 35 | for (is_last, r) in requests.iter() { |
36 | let current = if idx == world.request_idx { "*" } else { " " }; | 36 | let mark = if is_last { "*" } else { " " }; |
37 | writeln!(buf, "{:4}{}{:<36}{}ms", r.id, current, r.method, r.duration.as_millis()).unwrap(); | 37 | writeln!(buf, "{}{:4} {:<36}{}ms", mark, r.id, r.method, r.duration.as_millis()).unwrap(); |
38 | } | 38 | } |
39 | Ok(buf) | 39 | Ok(buf) |
40 | } | 40 | } |
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 @@ | |||
1 | use std::time::{Duration, Instant}; | ||
2 | |||
3 | use rustc_hash::FxHashMap; | ||
4 | |||
5 | #[derive(Debug)] | ||
6 | pub struct CompletedRequest { | ||
7 | pub id: u64, | ||
8 | pub method: String, | ||
9 | pub duration: Duration, | ||
10 | } | ||
11 | |||
12 | #[derive(Debug)] | ||
13 | pub(crate) struct PendingRequest { | ||
14 | pub(crate) id: u64, | ||
15 | pub(crate) method: String, | ||
16 | pub(crate) received: Instant, | ||
17 | } | ||
18 | |||
19 | impl From<PendingRequest> for CompletedRequest { | ||
20 | fn from(pending: PendingRequest) -> CompletedRequest { | ||
21 | CompletedRequest { | ||
22 | id: pending.id, | ||
23 | method: pending.method, | ||
24 | duration: pending.received.elapsed(), | ||
25 | } | ||
26 | } | ||
27 | } | ||
28 | |||
29 | #[derive(Debug, Default)] | ||
30 | pub(crate) struct PendingRequests { | ||
31 | map: FxHashMap<u64, PendingRequest>, | ||
32 | } | ||
33 | |||
34 | impl PendingRequests { | ||
35 | pub(crate) fn start(&mut self, request: PendingRequest) { | ||
36 | let id = request.id; | ||
37 | let prev = self.map.insert(id, request); | ||
38 | assert!(prev.is_none(), "duplicate request with id {}", id); | ||
39 | } | ||
40 | pub(crate) fn cancel(&mut self, id: u64) -> bool { | ||
41 | self.map.remove(&id).is_some() | ||
42 | } | ||
43 | pub(crate) fn finish(&mut self, id: u64) -> Option<CompletedRequest> { | ||
44 | self.map.remove(&id).map(CompletedRequest::from) | ||
45 | } | ||
46 | } | ||
47 | |||
48 | const N_COMPLETED_REQUESTS: usize = 10; | ||
49 | |||
50 | #[derive(Debug, Default)] | ||
51 | pub struct LatestRequests { | ||
52 | // hand-rolling VecDeque here to print things in a nicer way | ||
53 | buf: [Option<CompletedRequest>; N_COMPLETED_REQUESTS], | ||
54 | idx: usize, | ||
55 | } | ||
56 | |||
57 | impl LatestRequests { | ||
58 | pub(crate) fn record(&mut self, request: CompletedRequest) { | ||
59 | // special case: don't track status request itself | ||
60 | if request.method == "rust-analyzer/analyzerStatus" { | ||
61 | return; | ||
62 | } | ||
63 | let idx = self.idx; | ||
64 | self.buf[idx] = Some(request); | ||
65 | self.idx = (idx + 1) % N_COMPLETED_REQUESTS; | ||
66 | } | ||
67 | |||
68 | pub(crate) fn iter(&self) -> impl Iterator<Item = (bool, &CompletedRequest)> { | ||
69 | let idx = self.idx; | ||
70 | self.buf.iter().enumerate().filter_map(move |(i, req)| Some((i == idx, req.as_ref()?))) | ||
71 | } | ||
72 | } | ||
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 @@ | |||
1 | use ra_ide_api::FileId; | 1 | use ra_ide_api::FileId; |
2 | use rustc_hash::FxHashSet; | 2 | use rustc_hash::FxHashSet; |
3 | 3 | ||
4 | pub struct Subscriptions { | 4 | #[derive(Default)] |
5 | pub(crate) struct Subscriptions { | ||
5 | subs: FxHashSet<FileId>, | 6 | subs: FxHashSet<FileId>, |
6 | } | 7 | } |
7 | 8 | ||
8 | impl Subscriptions { | 9 | impl Subscriptions { |
9 | pub fn new() -> Subscriptions { | 10 | pub(crate) fn add_sub(&mut self, file_id: FileId) { |
10 | Subscriptions { subs: FxHashSet::default() } | ||
11 | } | ||
12 | pub fn add_sub(&mut self, file_id: FileId) { | ||
13 | self.subs.insert(file_id); | 11 | self.subs.insert(file_id); |
14 | } | 12 | } |
15 | pub fn remove_sub(&mut self, file_id: FileId) { | 13 | pub(crate) fn remove_sub(&mut self, file_id: FileId) { |
16 | self.subs.remove(&file_id); | 14 | self.subs.remove(&file_id); |
17 | } | 15 | } |
18 | pub fn subscriptions(&self) -> Vec<FileId> { | 16 | pub(crate) fn subscriptions(&self) -> Vec<FileId> { |
19 | self.subs.iter().cloned().collect() | 17 | self.subs.iter().cloned().collect() |
20 | } | 18 | } |
21 | } | 19 | } |
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 @@ | |||
1 | use std::{ | 1 | use std::{ |
2 | path::{Path, PathBuf}, | 2 | path::{Path, PathBuf}, |
3 | sync::Arc, | 3 | sync::Arc, |
4 | time::Duration, | ||
5 | }; | 4 | }; |
6 | 5 | ||
7 | use lsp_types::Url; | 6 | use lsp_types::Url; |
@@ -16,6 +15,7 @@ use failure::{Error, format_err}; | |||
16 | use gen_lsp_server::ErrorCode; | 15 | use gen_lsp_server::ErrorCode; |
17 | 16 | ||
18 | use crate::{ | 17 | use crate::{ |
18 | main_loop::pending_requests::{CompletedRequest, LatestRequests}, | ||
19 | project_model::ProjectWorkspace, | 19 | project_model::ProjectWorkspace, |
20 | vfs_filter::IncludeRustFiles, | 20 | vfs_filter::IncludeRustFiles, |
21 | Result, | 21 | Result, |
@@ -29,26 +29,14 @@ pub struct ServerWorldState { | |||
29 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 29 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
30 | pub analysis_host: AnalysisHost, | 30 | pub analysis_host: AnalysisHost, |
31 | pub vfs: Arc<RwLock<Vfs>>, | 31 | pub vfs: Arc<RwLock<Vfs>>, |
32 | // hand-rolling VecDeque here to print things in a nicer way | 32 | pub latest_requests: Arc<RwLock<LatestRequests>>, |
33 | pub latest_completed_requests: Arc<RwLock<[CompletedRequest; N_COMPLETED_REQUESTS]>>, | ||
34 | pub request_idx: usize, | ||
35 | } | 33 | } |
36 | 34 | ||
37 | const N_COMPLETED_REQUESTS: usize = 10; | ||
38 | |||
39 | pub struct ServerWorld { | 35 | pub struct ServerWorld { |
40 | pub workspaces: Arc<Vec<ProjectWorkspace>>, | 36 | pub workspaces: Arc<Vec<ProjectWorkspace>>, |
41 | pub analysis: Analysis, | 37 | pub analysis: Analysis, |
42 | pub vfs: Arc<RwLock<Vfs>>, | 38 | pub vfs: Arc<RwLock<Vfs>>, |
43 | pub latest_completed_requests: Arc<RwLock<[CompletedRequest; N_COMPLETED_REQUESTS]>>, | 39 | pub latest_requests: Arc<RwLock<LatestRequests>>, |
44 | pub request_idx: usize, | ||
45 | } | ||
46 | |||
47 | #[derive(Debug, Default)] | ||
48 | pub struct CompletedRequest { | ||
49 | pub id: u64, | ||
50 | pub method: String, | ||
51 | pub duration: Duration, | ||
52 | } | 40 | } |
53 | 41 | ||
54 | impl ServerWorldState { | 42 | impl ServerWorldState { |
@@ -88,8 +76,7 @@ impl ServerWorldState { | |||
88 | workspaces: Arc::new(workspaces), | 76 | workspaces: Arc::new(workspaces), |
89 | analysis_host, | 77 | analysis_host, |
90 | vfs: Arc::new(RwLock::new(vfs)), | 78 | vfs: Arc::new(RwLock::new(vfs)), |
91 | latest_completed_requests: Default::default(), | 79 | latest_requests: Default::default(), |
92 | request_idx: 0, | ||
93 | } | 80 | } |
94 | } | 81 | } |
95 | 82 | ||
@@ -158,8 +145,7 @@ impl ServerWorldState { | |||
158 | workspaces: Arc::clone(&self.workspaces), | 145 | workspaces: Arc::clone(&self.workspaces), |
159 | analysis: self.analysis_host.analysis(), | 146 | analysis: self.analysis_host.analysis(), |
160 | vfs: Arc::clone(&self.vfs), | 147 | vfs: Arc::clone(&self.vfs), |
161 | latest_completed_requests: Arc::clone(&self.latest_completed_requests), | 148 | latest_requests: Arc::clone(&self.latest_requests), |
162 | request_idx: self.request_idx.checked_sub(1).unwrap_or(N_COMPLETED_REQUESTS - 1), | ||
163 | } | 149 | } |
164 | } | 150 | } |
165 | 151 | ||
@@ -172,13 +158,7 @@ impl ServerWorldState { | |||
172 | } | 158 | } |
173 | 159 | ||
174 | pub fn complete_request(&mut self, request: CompletedRequest) { | 160 | pub fn complete_request(&mut self, request: CompletedRequest) { |
175 | // special case: don't track status request itself | 161 | self.latest_requests.write().record(request) |
176 | if request.method == "rust-analyzer/analyzerStatus" { | ||
177 | return; | ||
178 | } | ||
179 | let idx = self.request_idx; | ||
180 | self.latest_completed_requests.write()[idx] = request; | ||
181 | self.request_idx = (idx + 1) % N_COMPLETED_REQUESTS; | ||
182 | } | 162 | } |
183 | } | 163 | } |
184 | 164 | ||