Drop AstIdMap asynchronously

This commit is contained in:
Lukas Wirth 2025-12-28 12:41:09 +01:00
parent 72b409d28b
commit 11df3a0dec
2 changed files with 49 additions and 26 deletions

View file

@ -777,6 +777,48 @@ 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<ArenaId>,
hashbrown::HashTable<ArenaId>,
)>,
> = std::sync::OnceLock::new();
AST_ID_MAP_DROP_THREAD
.get_or_init(|| {
let (sender, receiver) = std::sync::mpsc::channel::<(
Arena<(SyntaxNodePtr, ErasedFileAstId)>,
hashbrown::HashTable<ArenaId>,
hashbrown::HashTable<ArenaId>,
)>();
std::thread::Builder::new()
.name("AstIdMapDropper".to_owned())
.spawn(move || {
loop {
// block on a receive
_ = receiver.recv();
// then drain the entire channel
while let Ok(_) = receiver.try_recv() {}
// 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)

View file

@ -153,26 +153,22 @@ impl SpanMap {
#[cfg(not(no_salsa_async_drops))]
impl Drop for SpanMap {
fn drop(&mut self) {
struct SendPtr(*mut [()]);
unsafe impl Send for SendPtr {}
let spans = std::mem::take(&mut self.spans);
static SPAN_MAP_DROP_THREAD: std::sync::OnceLock<
std::sync::mpsc::Sender<(SendPtr, fn(SendPtr))>,
std::sync::mpsc::Sender<Vec<(TextSize, Span)>>,
> = std::sync::OnceLock::new();
SPAN_MAP_DROP_THREAD
.get_or_init(|| {
let (sender, receiver) = std::sync::mpsc::channel::<(SendPtr, fn(SendPtr))>();
let (sender, receiver) = std::sync::mpsc::channel::<Vec<(TextSize, Span)>>();
std::thread::Builder::new()
.name("SpanMapDropper".to_owned())
.spawn(move || {
loop {
// block on a receive
if let Ok((b, drop)) = receiver.recv() {
drop(b);
}
_ = receiver.recv();
// then drain the entire channel
while let Ok((b, drop)) = receiver.try_recv() {
drop(b);
}
while let Ok(_) = receiver.try_recv() {}
// and sleep for a bit
std::thread::sleep(std::time::Duration::from_millis(100));
}
@ -182,22 +178,7 @@ impl Drop for SpanMap {
.unwrap();
sender
})
.send((
unsafe {
SendPtr(std::mem::transmute::<*mut [(TextSize, Span)], *mut [()]>(Box::<
[(TextSize, Span)],
>::into_raw(
std::mem::take(&mut self.spans).into_boxed_slice(),
)))
},
|b: SendPtr| {
_ = unsafe {
Box::from_raw(std::mem::transmute::<*mut [()], *mut [(TextSize, Span)]>(
b.0,
))
}
},
))
.send(spans)
.unwrap();
}
}