From add15d83eaa865571cd33e60b2eb611a366ca3ff Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 10 Jan 2019 11:57:24 +0300 Subject: [PATCH] add panic hooks To implement cancellation via unwinding, one needs to throw `Canceled` value in `if_current_revision_is_canceled` and `on_propagated_panic`. --- src/derived.rs | 4 ++-- src/lib.rs | 6 ++++++ src/runtime.rs | 10 ++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) 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