From eaeb10cee123b8184148c957151be226fb865bd2 Mon Sep 17 00:00:00 2001 From: Nayeem Rahman Date: Thu, 12 Oct 2023 15:37:56 +0100 Subject: [PATCH] perf(lsp): fix redundant file reads (#20802) --- cli/lsp/documents.rs | 55 ++++++++++++++++++++++++++++---------- cli/lsp/language_server.rs | 12 ++++----- 2 files changed, 47 insertions(+), 20 deletions(-) diff --git a/cli/lsp/documents.rs b/cli/lsp/documents.rs index 90d0d0f888..748b5b11cc 100644 --- a/cli/lsp/documents.rs +++ b/cli/lsp/documents.rs @@ -422,6 +422,7 @@ impl Document { version: i32, language_id: LanguageId, content: Arc, + cache: &Arc, resolver: &dyn deno_graph::source::Resolver, ) -> Self { let maybe_headers = language_id.as_headers(); @@ -441,7 +442,8 @@ impl Document { let line_index = Arc::new(LineIndex::new(text_info.text_str())); Self(Arc::new(DocumentInner { dependencies, - fs_version: "1".to_string(), + fs_version: calculate_fs_version(cache, &specifier) + .unwrap_or_else(|| "1".to_string()), line_index, maybe_language_id: Some(language_id), maybe_lsp_version: Some(version), @@ -523,6 +525,23 @@ impl Document { }))) } + pub fn saved(&self, cache: &Arc) -> Document { + Document(Arc::new(DocumentInner { + specifier: self.0.specifier.clone(), + fs_version: calculate_fs_version(cache, &self.0.specifier) + .unwrap_or_else(|| "1".to_string()), + maybe_language_id: self.0.maybe_language_id, + dependencies: self.0.dependencies.clone(), + text_info: self.0.text_info.clone(), + line_index: self.0.line_index.clone(), + maybe_headers: self.0.maybe_headers.clone(), + maybe_module: self.0.maybe_module.clone(), + maybe_parsed_source: self.0.maybe_parsed_source.clone(), + maybe_lsp_version: self.0.maybe_lsp_version, + maybe_navigation_tree: Mutex::new(None), + })) + } + pub fn specifier(&self) -> &ModuleSpecifier { &self.0.specifier } @@ -953,6 +972,7 @@ impl Documents { version, language_id, content, + &self.cache, resolver, ); let mut file_system_docs = self.file_system_docs.lock(); @@ -991,24 +1011,28 @@ impl Documents { Ok(doc) } + pub fn save(&mut self, specifier: &ModuleSpecifier) { + let doc = self.open_docs.get(specifier).cloned().or_else(|| { + let mut file_system_docs = self.file_system_docs.lock(); + file_system_docs.docs.remove(specifier) + }); + let Some(doc) = doc else { + return; + }; + self.dirty = true; + let doc = doc.saved(&self.cache); + self.open_docs.insert(doc.specifier().clone(), doc.clone()); + } + /// Close an open document, this essentially clears any editor state that is /// being held, and the document store will revert to the file system if /// information about the document is required. pub fn close(&mut self, specifier: &ModuleSpecifier) -> Result<(), AnyError> { - if self.open_docs.remove(specifier).is_some() { - self.dirty = true; - } else { + if let Some(document) = self.open_docs.remove(specifier) { let mut file_system_docs = self.file_system_docs.lock(); - if file_system_docs.docs.remove(specifier).is_some() { - file_system_docs.dirty = true; - } else { - return Err(custom_error( - "NotFound", - format!("The specifier \"{specifier}\" was not found."), - )); - } + file_system_docs.docs.insert(specifier.clone(), document); + self.dirty = true; } - Ok(()) } @@ -1496,7 +1520,10 @@ impl Documents { let resolver = self.get_resolver(); while let Some(specifier) = doc_analyzer.pending_specifiers.pop_front() { - if let Some(doc) = file_system_docs.get(&self.cache, resolver, &specifier) + if let Some(doc) = self.open_docs.get(&specifier) { + doc_analyzer.analyze_doc(&specifier, doc); + } else if let Some(doc) = + file_system_docs.get(&self.cache, resolver, &specifier) { doc_analyzer.analyze_doc(&specifier, &doc); } diff --git a/cli/lsp/language_server.rs b/cli/lsp/language_server.rs index b19b00b4aa..485eef9386 100644 --- a/cli/lsp/language_server.rs +++ b/cli/lsp/language_server.rs @@ -1373,18 +1373,17 @@ impl Inner { let specifier = self .url_map .normalize_url(¶ms.text_document.uri, LspUrlKind::File); - - if let Err(err) = self.documents.close(&specifier) { - error!("{}", err); - } if self.is_diagnosable(&specifier) { self.refresh_npm_specifiers().await; let mut specifiers = self.documents.dependents(&specifier); - specifiers.push(specifier); + specifiers.push(specifier.clone()); self.diagnostics_server.invalidate(&specifiers); self.send_diagnostics_update(); self.send_testing_update(); } + if let Err(err) = self.documents.close(&specifier) { + error!("{}", err); + } self.performance.measure(mark); } @@ -3214,8 +3213,9 @@ impl tower_lsp::LanguageServer for LanguageServer { async fn did_save(&self, params: DidSaveTextDocumentParams) { let uri = ¶ms.text_document.uri; { - let inner = self.0.read().await; + let mut inner = self.0.write().await; let specifier = inner.url_map.normalize_url(uri, LspUrlKind::File); + inner.documents.save(&specifier); if !inner.config.workspace_settings().cache_on_save || !inner.config.specifier_enabled(&specifier) || !inner.diagnostics_state.has_no_cache_diagnostics(&specifier)