diff --git a/src/derived.rs b/src/derived.rs index e5f7b81e..c30ddea5 100644 --- a/src/derived.rs +++ b/src/derived.rs @@ -480,7 +480,7 @@ where }, }); - let value = rx.recv().unwrap(); + let value = rx.recv().unwrap_or_else(|_| db.on_propagated_panic()); ProbeState::UpToDate(Ok(value)) } @@ -731,7 +731,7 @@ where // can complete. std::mem::drop(map); - let value = rx.recv().unwrap(); + let value = rx.recv().unwrap_or_else(|_| db.on_propagated_panic()); return value.changed_at.changed_since(revision); } diff --git a/src/lib.rs b/src/lib.rs index 12c74e8d..b42581a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,6 +104,12 @@ pub trait Database: plumbing::DatabaseStorageTypes + plumbing::DatabaseOps { fn salsa_event(&self, event_fn: impl Fn() -> Event) { #![allow(unused_variables)] } + + /// This function is invoked when a depndent query is being computed by the + /// other thread, and that thread panics. + fn on_propagated_panic(&self) -> ! { + panic!("concurrent salsa query paniced") + } } /// The `Event` struct identifies various notable things that can diff --git a/src/runtime.rs b/src/runtime.rs index 4f0e6d08..5eeb701a 100644 --- a/src/runtime.rs +++ b/src/runtime.rs @@ -223,6 +223,16 @@ where } } + /// Calls the callback if the current revision is cancelled. + /// + /// Observing cancellation may lead to inconsistencies in database storage, + /// so the callback must panic. + pub fn if_current_revision_is_canceled(&self, cb: fn() -> !) { + if self.pending_revision() > self.current_revision() { + cb() + } + } + /// Acquires the **global query write lock** (ensuring that no /// queries are executing) and then increments the current /// revision counter; invokes `op` with the global query write