aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs70
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs8
-rw-r--r--crates/ra_lsp_server/src/main_loop/pending_requests.rs72
-rw-r--r--crates/ra_lsp_server/src/main_loop/subscriptions.rs12
-rw-r--r--crates/ra_lsp_server/src/server_world.rs32
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 @@
1mod handlers; 1mod handlers;
2mod subscriptions; 2mod subscriptions;
3pub(crate) mod pending_requests;
3 4
4use std::{fmt, path::PathBuf, sync::Arc, time::Instant, any::TypeId}; 5use std::{fmt, path::PathBuf, sync::Arc, time::Instant, any::TypeId};
5 6
@@ -12,16 +13,18 @@ use gen_lsp_server::{
12use lsp_types::NumberOrString; 13use lsp_types::NumberOrString;
13use ra_ide_api::{Canceled, FileId, LibraryData}; 14use ra_ide_api::{Canceled, FileId, LibraryData};
14use ra_vfs::VfsTask; 15use ra_vfs::VfsTask;
15use rustc_hash::FxHashMap;
16use serde::{de::DeserializeOwned, Serialize}; 16use serde::{de::DeserializeOwned, Serialize};
17use threadpool::ThreadPool; 17use threadpool::ThreadPool;
18use ra_prof::profile; 18use ra_prof::profile;
19 19
20use crate::{ 20use 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)]
46enum Task {
47 Respond(RawResponse),
48 Notify(RawNotification),
49}
50
51struct PendingRequest {
52 id: u64,
53 received: Instant,
54 method: String,
55}
56
57impl 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
67pub fn main_loop( 48pub 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)]
112enum Task {
113 Respond(RawResponse),
114 Notify(RawNotification),
115}
116
131enum Event { 117enum 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(
311fn on_task( 298fn 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
332fn on_request( 318fn 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(
383fn on_notification( 367fn 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::{
31pub fn handle_analyzer_status(world: ServerWorld, _: ()) -> Result<String> { 31pub 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 @@
1use std::time::{Duration, Instant};
2
3use rustc_hash::FxHashMap;
4
5#[derive(Debug)]
6pub struct CompletedRequest {
7 pub id: u64,
8 pub method: String,
9 pub duration: Duration,
10}
11
12#[derive(Debug)]
13pub(crate) struct PendingRequest {
14 pub(crate) id: u64,
15 pub(crate) method: String,
16 pub(crate) received: Instant,
17}
18
19impl 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)]
30pub(crate) struct PendingRequests {
31 map: FxHashMap<u64, PendingRequest>,
32}
33
34impl 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
48const N_COMPLETED_REQUESTS: usize = 10;
49
50#[derive(Debug, Default)]
51pub 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
57impl 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 @@
1use ra_ide_api::FileId; 1use ra_ide_api::FileId;
2use rustc_hash::FxHashSet; 2use rustc_hash::FxHashSet;
3 3
4pub struct Subscriptions { 4#[derive(Default)]
5pub(crate) struct Subscriptions {
5 subs: FxHashSet<FileId>, 6 subs: FxHashSet<FileId>,
6} 7}
7 8
8impl Subscriptions { 9impl 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 @@
1use std::{ 1use std::{
2 path::{Path, PathBuf}, 2 path::{Path, PathBuf},
3 sync::Arc, 3 sync::Arc,
4 time::Duration,
5}; 4};
6 5
7use lsp_types::Url; 6use lsp_types::Url;
@@ -16,6 +15,7 @@ use failure::{Error, format_err};
16use gen_lsp_server::ErrorCode; 15use gen_lsp_server::ErrorCode;
17 16
18use crate::{ 17use 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
37const N_COMPLETED_REQUESTS: usize = 10;
38
39pub struct ServerWorld { 35pub 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)]
48pub struct CompletedRequest {
49 pub id: u64,
50 pub method: String,
51 pub duration: Duration,
52} 40}
53 41
54impl ServerWorldState { 42impl 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