Auto merge of #17850 - Veykril:rust-analyzer-crate, r=Veykril

internal: Reply to requests with defaults when vfs is still loading

There is no reason for us to hit the database with queries when we certainly haven't reached a stable state yet. Instead we just reply with default request results until we are in a state where we can do meaningful work. This should save us from wasting resources while starting up at worst, and at best save us from creating query and interning entries that are non-meaningful which ultimately just end up wasting memory.
This commit is contained in:
bors 2024-08-12 10:21:06 +00:00
commit 59c6eae5cc
5 changed files with 71 additions and 27 deletions

View file

@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
resolver = "2"
[workspace.package]
rust-version = "1.78"
rust-version = "1.80"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["rust-analyzer team"]

View file

@ -97,16 +97,45 @@ impl RequestDispatcher<'_> {
self
}
/// Dispatches a non-latency-sensitive request onto the thread pool.
/// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
/// ready this will return a default constructed [`R::Result`].
pub(crate) fn on<const ALLOW_RETRYING: bool, R>(
&mut self,
f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
) -> &mut Self
where
R: lsp_types::request::Request + 'static,
R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
R::Result: Serialize,
R: lsp_types::request::Request<
Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
Result: Serialize + Default,
> + 'static,
{
if !self.global_state.vfs_done {
if let Some(lsp_server::Request { id, .. }) =
self.req.take_if(|it| it.method == R::METHOD)
{
self.global_state.respond(lsp_server::Response::new_ok(id, R::Result::default()));
}
return self;
}
self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
}
/// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
/// ready this will return the parameter as is.
pub(crate) fn on_identity<const ALLOW_RETRYING: bool, R, Params>(
&mut self,
f: fn(GlobalStateSnapshot, Params) -> anyhow::Result<R::Result>,
) -> &mut Self
where
R: lsp_types::request::Request<Params = Params, Result = Params> + 'static,
Params: Serialize + DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
{
if !self.global_state.vfs_done {
if let Some((request, params, _)) = self.parse::<R>() {
self.global_state.respond(lsp_server::Response::new_ok(request.id, &params))
}
return self;
}
self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
}
@ -198,11 +227,7 @@ impl RequestDispatcher<'_> {
R: lsp_types::request::Request,
R::Params: DeserializeOwned + fmt::Debug,
{
let req = match &self.req {
Some(req) if req.method == R::METHOD => self.req.take()?,
_ => return None,
};
let req = self.req.take_if(|it| it.method == R::METHOD)?;
let res = crate::from_json(R::METHOD, &req.params);
match res {
Ok(params) => {

View file

@ -61,7 +61,7 @@ impl Request for FetchDependencyList {
#[serde(rename_all = "camelCase")]
pub struct FetchDependencyListParams {}
#[derive(Deserialize, Serialize, Debug)]
#[derive(Deserialize, Serialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct FetchDependencyListResult {
pub crates: Vec<CrateInfoResult>,
@ -194,7 +194,7 @@ pub struct TestItem {
pub runnable: Option<Runnable>,
}
#[derive(Deserialize, Serialize, Debug)]
#[derive(Deserialize, Serialize, Debug, Default)]
#[serde(rename_all = "camelCase")]
pub struct DiscoverTestResults {
pub tests: Vec<TestItem>,
@ -690,6 +690,12 @@ pub enum ExternalDocsResponse {
WithLocal(ExternalDocsPair),
}
impl Default for ExternalDocsResponse {
fn default() -> Self {
ExternalDocsResponse::Simple(None)
}
}
#[derive(Debug, Default, PartialEq, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ExternalDocsPair {

View file

@ -173,8 +173,10 @@ impl GlobalState {
}
if self.config.discover_workspace_config().is_none() {
let req = FetchWorkspaceRequest { path: None, force_crate_graph_reload: false };
self.fetch_workspaces_queue.request_op("startup".to_owned(), req);
self.fetch_workspaces_queue.request_op(
"startup".to_owned(),
FetchWorkspaceRequest { path: None, force_crate_graph_reload: false },
);
if let Some((cause, FetchWorkspaceRequest { path, force_crate_graph_reload })) =
self.fetch_workspaces_queue.should_start_op()
{
@ -545,6 +547,10 @@ impl GlobalState {
let snapshot = self.snapshot();
self.task_pool.handle.spawn_with_sender(ThreadIntent::LatencySensitive, {
let subscriptions = subscriptions.clone();
// Do not fetch semantic diagnostics (and populate query results) if we haven't even
// loaded the initial workspace yet.
let fetch_semantic =
self.vfs_done && self.fetch_workspaces_queue.last_op_result().is_some();
move |sender| {
let diags = fetch_native_diagnostics(
&snapshot,
@ -556,6 +562,7 @@ impl GlobalState {
.send(Task::Diagnostics(DiagnosticsTaskKind::Syntax(generation, diags)))
.unwrap();
if fetch_semantic {
let diags = fetch_native_diagnostics(
&snapshot,
subscriptions,
@ -563,15 +570,21 @@ impl GlobalState {
NativeDiagnosticsFetchKind::Semantic,
);
sender
.send(Task::Diagnostics(DiagnosticsTaskKind::Semantic(generation, diags)))
.send(Task::Diagnostics(DiagnosticsTaskKind::Semantic(
generation, diags,
)))
.unwrap();
}
}
});
start = end;
}
}
fn update_tests(&mut self) {
if !self.vfs_done {
return;
}
let db = self.analysis_host.raw_database();
let subscriptions = self
.mem_docs
@ -1052,9 +1065,9 @@ impl GlobalState {
.on::<NO_RETRY, lsp_request::GotoImplementation>(handlers::handle_goto_implementation)
.on::<NO_RETRY, lsp_request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
.on::<NO_RETRY, lsp_request::InlayHintRequest>(handlers::handle_inlay_hints)
.on::<NO_RETRY, lsp_request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
.on_identity::<NO_RETRY, lsp_request::InlayHintResolveRequest, _>(handlers::handle_inlay_hints_resolve)
.on::<NO_RETRY, lsp_request::CodeLensRequest>(handlers::handle_code_lens)
.on::<NO_RETRY, lsp_request::CodeLensResolve>(handlers::handle_code_lens_resolve)
.on_identity::<NO_RETRY, lsp_request::CodeLensResolve, _>(handlers::handle_code_lens_resolve)
.on::<NO_RETRY, lsp_request::PrepareRenameRequest>(handlers::handle_prepare_rename)
.on::<NO_RETRY, lsp_request::Rename>(handlers::handle_rename)
.on::<NO_RETRY, lsp_request::References>(handlers::handle_references)
@ -1081,7 +1094,7 @@ impl GlobalState {
.on::<NO_RETRY, lsp_ext::Runnables>(handlers::handle_runnables)
.on::<NO_RETRY, lsp_ext::RelatedTests>(handlers::handle_related_tests)
.on::<NO_RETRY, lsp_ext::CodeActionRequest>(handlers::handle_code_action)
.on::<RETRY, lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve)
.on_identity::<RETRY, lsp_ext::CodeActionResolveRequest, _>(handlers::handle_code_action_resolve)
.on::<NO_RETRY, lsp_ext::HoverRequest>(handlers::handle_hover)
.on::<NO_RETRY, lsp_ext::ExternalDocs>(handlers::handle_open_docs)
.on::<NO_RETRY, lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)

View file

@ -1,5 +1,5 @@
<!---
lsp/ext.rs hash: e92e1f12229b0071
lsp/ext.rs hash: 3429c08745984b3d
If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue: