mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-23 13:10:19 +00:00
extract register_with_in_progress_thread
helper
This commit is contained in:
parent
29831a7430
commit
cf72c98946
1 changed files with 44 additions and 19 deletions
|
@ -17,7 +17,7 @@ use rustc_hash::FxHashMap;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::mpsc::{self, Sender};
|
use std::sync::mpsc::{self, Receiver, Sender};
|
||||||
|
|
||||||
/// Memoized queries store the result plus a list of the other queries
|
/// Memoized queries store the result plus a list of the other queries
|
||||||
/// that they invoked. This means we can avoid recomputing them when
|
/// that they invoked. This means we can avoid recomputing them when
|
||||||
|
@ -358,26 +358,20 @@ where
|
||||||
match map.get(key) {
|
match map.get(key) {
|
||||||
Some(QueryState::InProgress { id, waiting }) => {
|
Some(QueryState::InProgress { id, waiting }) => {
|
||||||
let other_id = *id;
|
let other_id = *id;
|
||||||
if other_id == runtime.id() {
|
return match self
|
||||||
return ProbeState::UpToDate(Err(CycleDetected));
|
.register_with_in_progress_thread(runtime, descriptor, other_id, waiting)
|
||||||
} else {
|
{
|
||||||
if !runtime.try_block_on(descriptor, other_id) {
|
Ok(rx) => {
|
||||||
return ProbeState::UpToDate(Err(CycleDetected));
|
|
||||||
}
|
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel();
|
|
||||||
|
|
||||||
// The reader of this will have to acquire map
|
|
||||||
// lock, we don't need any particular ordering.
|
|
||||||
waiting.lock().push(tx);
|
|
||||||
|
|
||||||
// Release our lock on `self.map`, so other thread
|
// Release our lock on `self.map`, so other thread
|
||||||
// can complete.
|
// can complete.
|
||||||
std::mem::drop(map);
|
std::mem::drop(map);
|
||||||
|
|
||||||
let value = rx.recv().unwrap();
|
let value = rx.recv().unwrap();
|
||||||
return ProbeState::UpToDate(Ok(value));
|
ProbeState::UpToDate(Ok(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Err(CycleDetected) => ProbeState::UpToDate(Err(CycleDetected)),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(QueryState::Memoized(memo)) => {
|
Some(QueryState::Memoized(memo)) => {
|
||||||
|
@ -413,6 +407,37 @@ where
|
||||||
ProbeState::StaleOrAbsent(map)
|
ProbeState::StaleOrAbsent(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper:
|
||||||
|
///
|
||||||
|
/// When we encounter an `InProgress` indicator, we need to either
|
||||||
|
/// report a cycle or else register ourselves to be notified when
|
||||||
|
/// that work completes. This helper does that; it returns a port
|
||||||
|
/// where you can wait for the final value that wound up being
|
||||||
|
/// computed (but first drop the lock on the map).
|
||||||
|
fn register_with_in_progress_thread(
|
||||||
|
&self,
|
||||||
|
runtime: &Runtime<DB>,
|
||||||
|
descriptor: &DB::QueryDescriptor,
|
||||||
|
other_id: RuntimeId,
|
||||||
|
waiting: &Mutex<SmallVec<[Sender<StampedValue<Q::Value>>; 2]>>,
|
||||||
|
) -> Result<Receiver<StampedValue<Q::Value>>, CycleDetected> {
|
||||||
|
if other_id == runtime.id() {
|
||||||
|
return Err(CycleDetected);
|
||||||
|
} else {
|
||||||
|
if !runtime.try_block_on(descriptor, other_id) {
|
||||||
|
return Err(CycleDetected);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
// The reader of this will have to acquire map
|
||||||
|
// lock, we don't need any particular ordering.
|
||||||
|
waiting.lock().push(tx);
|
||||||
|
|
||||||
|
Ok(rx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Overwrites the `InProgress` placeholder for `key` that we
|
/// Overwrites the `InProgress` placeholder for `key` that we
|
||||||
/// inserted; if others were blocked, waiting for us to finish,
|
/// inserted; if others were blocked, waiting for us to finish,
|
||||||
/// the notify them.
|
/// the notify them.
|
||||||
|
|
Loading…
Reference in a new issue