Skip to content

Commit 3f53ead

Browse files
committed
Drop AstIdMap asynchronously
1 parent a3bf20f commit 3f53ead

2 files changed

Lines changed: 49 additions & 26 deletions

File tree

crates/span/src/ast_id.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,48 @@ impl AstIdMap {
777777
}
778778
}
779779

780+
#[cfg(not(no_salsa_async_drops))]
781+
impl Drop for AstIdMap {
782+
fn drop(&mut self) {
783+
let arena = std::mem::take(&mut self.arena);
784+
let ptr_map = std::mem::take(&mut self.ptr_map);
785+
let id_map = std::mem::take(&mut self.id_map);
786+
static AST_ID_MAP_DROP_THREAD: std::sync::OnceLock<
787+
std::sync::mpsc::Sender<(
788+
Arena<(SyntaxNodePtr, ErasedFileAstId)>,
789+
hashbrown::HashTable<ArenaId>,
790+
hashbrown::HashTable<ArenaId>,
791+
)>,
792+
> = std::sync::OnceLock::new();
793+
AST_ID_MAP_DROP_THREAD
794+
.get_or_init(|| {
795+
let (sender, receiver) = std::sync::mpsc::channel::<(
796+
Arena<(SyntaxNodePtr, ErasedFileAstId)>,
797+
hashbrown::HashTable<ArenaId>,
798+
hashbrown::HashTable<ArenaId>,
799+
)>();
800+
std::thread::Builder::new()
801+
.name("AstIdMapDropper".to_owned())
802+
.spawn(move || {
803+
loop {
804+
// block on a receive
805+
_ = receiver.recv();
806+
// then drain the entire channel
807+
while let Ok(_) = receiver.try_recv() {}
808+
// and sleep for a bit
809+
std::thread::sleep(std::time::Duration::from_millis(100));
810+
}
811+
// why do this over just a `receiver.iter().for_each(drop)`? To reduce contention on the channel lock.
812+
// otherwise this thread will constantly wake up and sleep again.
813+
})
814+
.unwrap();
815+
sender
816+
})
817+
.send((arena, ptr_map, id_map))
818+
.unwrap();
819+
}
820+
}
821+
780822
#[inline]
781823
fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 {
782824
FxBuildHasher.hash_one(ptr)

crates/span/src/map.rs

Lines changed: 7 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -153,26 +153,22 @@ impl SpanMap {
153153
#[cfg(not(no_salsa_async_drops))]
154154
impl Drop for SpanMap {
155155
fn drop(&mut self) {
156-
struct SendPtr(*mut [()]);
157-
unsafe impl Send for SendPtr {}
156+
let spans = std::mem::take(&mut self.spans);
158157
static SPAN_MAP_DROP_THREAD: std::sync::OnceLock<
159-
std::sync::mpsc::Sender<(SendPtr, fn(SendPtr))>,
158+
std::sync::mpsc::Sender<Vec<(TextSize, Span)>>,
160159
> = std::sync::OnceLock::new();
160+
161161
SPAN_MAP_DROP_THREAD
162162
.get_or_init(|| {
163-
let (sender, receiver) = std::sync::mpsc::channel::<(SendPtr, fn(SendPtr))>();
163+
let (sender, receiver) = std::sync::mpsc::channel::<Vec<(TextSize, Span)>>();
164164
std::thread::Builder::new()
165165
.name("SpanMapDropper".to_owned())
166166
.spawn(move || {
167167
loop {
168168
// block on a receive
169-
if let Ok((b, drop)) = receiver.recv() {
170-
drop(b);
171-
}
169+
_ = receiver.recv();
172170
// then drain the entire channel
173-
while let Ok((b, drop)) = receiver.try_recv() {
174-
drop(b);
175-
}
171+
while let Ok(_) = receiver.try_recv() {}
176172
// and sleep for a bit
177173
std::thread::sleep(std::time::Duration::from_millis(100));
178174
}
@@ -182,22 +178,7 @@ impl Drop for SpanMap {
182178
.unwrap();
183179
sender
184180
})
185-
.send((
186-
unsafe {
187-
SendPtr(std::mem::transmute::<*mut [(TextSize, Span)], *mut [()]>(Box::<
188-
[(TextSize, Span)],
189-
>::into_raw(
190-
std::mem::take(&mut self.spans).into_boxed_slice(),
191-
)))
192-
},
193-
|b: SendPtr| {
194-
_ = unsafe {
195-
Box::from_raw(std::mem::transmute::<*mut [()], *mut [(TextSize, Span)]>(
196-
b.0,
197-
))
198-
}
199-
},
200-
))
181+
.send(spans)
201182
.unwrap();
202183
}
203184
}

0 commit comments

Comments
 (0)