From b322d0415a9b7ac7c29082d9a8b38561bce2ba15 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Sun, 3 May 2026 17:11:07 +0300 Subject: [PATCH] Do not drop `ExpansionSpanMap` and `AstIdMap` asynchronously They do not contain things that require looping when dropping, only `Vec`/`Arena`/`HashTable` of non-`Drop` types. Therefore sending to an external channel is likely to be slower than just dropping. --- crates/span/src/ast_id.rs | 42 --------------------------------------- crates/span/src/map.rs | 33 ------------------------------ 2 files changed, 75 deletions(-) diff --git a/crates/span/src/ast_id.rs b/crates/span/src/ast_id.rs index f6500a9b4dbe..2193f70d47d0 100644 --- a/crates/span/src/ast_id.rs +++ b/crates/span/src/ast_id.rs @@ -810,48 +810,6 @@ impl AstIdMap { } } -#[cfg(not(no_salsa_async_drops))] -impl Drop for AstIdMap { - fn drop(&mut self) { - let arena = std::mem::take(&mut self.arena); - let ptr_map = std::mem::take(&mut self.ptr_map); - let id_map = std::mem::take(&mut self.id_map); - static AST_ID_MAP_DROP_THREAD: std::sync::OnceLock< - std::sync::mpsc::Sender<( - Arena<(SyntaxNodePtr, ErasedFileAstId)>, - hashbrown::HashTable, - hashbrown::HashTable, - )>, - > = std::sync::OnceLock::new(); - AST_ID_MAP_DROP_THREAD - .get_or_init(|| { - let (sender, receiver) = std::sync::mpsc::channel::<( - Arena<(SyntaxNodePtr, ErasedFileAstId)>, - hashbrown::HashTable, - hashbrown::HashTable, - )>(); - std::thread::Builder::new() - .name("AstIdMapDropper".to_owned()) - .spawn(move || { - loop { - // block on a receive - _ = receiver.recv(); - // then drain the entire channel - while receiver.try_recv().is_ok() {} - // and sleep for a bit - std::thread::sleep(std::time::Duration::from_millis(100)); - } - // why do this over just a `receiver.iter().for_each(drop)`? To reduce contention on the channel lock. - // otherwise this thread will constantly wake up and sleep again. - }) - .unwrap(); - sender - }) - .send((arena, ptr_map, id_map)) - .unwrap(); - } -} - #[inline] fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 { FxBuildHasher.hash_one(ptr) diff --git a/crates/span/src/map.rs b/crates/span/src/map.rs index dc7d471aa03a..5b92096ef87b 100644 --- a/crates/span/src/map.rs +++ b/crates/span/src/map.rs @@ -150,39 +150,6 @@ impl SpanMap { } } -#[cfg(not(no_salsa_async_drops))] -impl Drop for SpanMap { - fn drop(&mut self) { - let spans = std::mem::take(&mut self.spans); - static SPAN_MAP_DROP_THREAD: std::sync::OnceLock< - std::sync::mpsc::Sender>, - > = std::sync::OnceLock::new(); - - SPAN_MAP_DROP_THREAD - .get_or_init(|| { - let (sender, receiver) = std::sync::mpsc::channel::>(); - std::thread::Builder::new() - .name("SpanMapDropper".to_owned()) - .spawn(move || { - loop { - // block on a receive - _ = receiver.recv(); - // then drain the entire channel - while receiver.try_recv().is_ok() {} - // and sleep for a bit - std::thread::sleep(std::time::Duration::from_millis(100)); - } - // why do this over just a `receiver.iter().for_each(drop)`? To reduce contention on the channel lock. - // otherwise this thread will constantly wake up and sleep again. - }) - .unwrap(); - sender - }) - .send(spans) - .unwrap(); - } -} - #[derive(PartialEq, Eq, Hash, Debug)] pub struct RealSpanMap { file_id: EditionedFileId,