2021-05-25 13:08:23 +00:00
|
|
|
use crate::setup::{CancellationFlag, Knobs, ParDatabase, ParDatabaseImpl, WithValue};
|
|
|
|
use salsa::{Cancelled, ParallelDatabase};
|
2018-10-12 10:03:09 +00:00
|
|
|
|
2021-05-25 13:08:23 +00:00
|
|
|
macro_rules! assert_cancelled {
|
2021-05-17 16:59:28 +00:00
|
|
|
($thread:expr) => {
|
|
|
|
match $thread.join() {
|
2021-05-25 13:08:23 +00:00
|
|
|
Ok(value) => panic!("expected cancellation, got {:?}", value),
|
|
|
|
Err(payload) => match payload.downcast::<Cancelled>() {
|
2021-05-17 16:59:28 +00:00
|
|
|
Ok(_) => {}
|
|
|
|
Err(payload) => ::std::panic::resume_unwind(payload),
|
|
|
|
},
|
2019-01-10 10:32:52 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-05-25 13:08:23 +00:00
|
|
|
/// Add test where a call to `sum` is cancelled by a simultaneous
|
2018-10-13 09:24:34 +00:00
|
|
|
/// write. Check that we recompute the result in next revision, even
|
|
|
|
/// though none of the inputs have changed.
|
2018-10-12 10:03:09 +00:00
|
|
|
#[test]
|
2021-05-25 13:08:23 +00:00
|
|
|
fn in_par_get_set_cancellation_immediate() {
|
2021-05-17 16:59:28 +00:00
|
|
|
let mut db = ParDatabaseImpl::default();
|
|
|
|
|
|
|
|
db.set_input('a', 100);
|
|
|
|
db.set_input('b', 010);
|
|
|
|
db.set_input('c', 001);
|
|
|
|
db.set_input('d', 0);
|
|
|
|
|
|
|
|
let thread1 = std::thread::spawn({
|
|
|
|
let db = db.snapshot();
|
|
|
|
move || {
|
2021-05-25 13:08:23 +00:00
|
|
|
// This will not return until it sees cancellation is
|
2021-05-17 16:59:28 +00:00
|
|
|
// signaled.
|
|
|
|
db.knobs().sum_signal_on_entry.with_value(1, || {
|
|
|
|
db.knobs()
|
2021-05-25 13:08:23 +00:00
|
|
|
.sum_wait_for_cancellation
|
|
|
|
.with_value(CancellationFlag::Panic, || db.sum("abc"))
|
2021-05-17 16:59:28 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Wait until we have entered `sum` in the other thread.
|
|
|
|
db.wait_for(1);
|
|
|
|
|
2021-05-25 13:08:23 +00:00
|
|
|
// Try to set the input. This will signal cancellation.
|
2021-05-17 16:59:28 +00:00
|
|
|
db.set_input('d', 1000);
|
|
|
|
|
|
|
|
// This should re-compute the value (even though no input has changed).
|
|
|
|
let thread2 = std::thread::spawn({
|
|
|
|
let db = db.snapshot();
|
|
|
|
move || db.sum("abc")
|
|
|
|
});
|
|
|
|
|
|
|
|
assert_eq!(db.sum("d"), 1000);
|
2021-05-25 13:08:23 +00:00
|
|
|
assert_cancelled!(thread1);
|
2021-05-17 16:59:28 +00:00
|
|
|
assert_eq!(thread2.join().unwrap(), 111);
|
2018-10-12 10:03:09 +00:00
|
|
|
}
|
2018-10-25 14:06:55 +00:00
|
|
|
|
2021-05-25 13:08:23 +00:00
|
|
|
/// Here, we check that `sum`'s cancellation is propagated
|
2018-10-25 14:06:55 +00:00
|
|
|
/// to `sum2` properly.
|
|
|
|
#[test]
|
2021-05-25 13:08:23 +00:00
|
|
|
fn in_par_get_set_cancellation_transitive() {
|
2021-05-17 16:59:28 +00:00
|
|
|
let mut db = ParDatabaseImpl::default();
|
|
|
|
|
|
|
|
db.set_input('a', 100);
|
|
|
|
db.set_input('b', 010);
|
|
|
|
db.set_input('c', 001);
|
|
|
|
db.set_input('d', 0);
|
|
|
|
|
|
|
|
let thread1 = std::thread::spawn({
|
|
|
|
let db = db.snapshot();
|
|
|
|
move || {
|
2021-05-25 13:08:23 +00:00
|
|
|
// This will not return until it sees cancellation is
|
2021-05-17 16:59:28 +00:00
|
|
|
// signaled.
|
|
|
|
db.knobs().sum_signal_on_entry.with_value(1, || {
|
|
|
|
db.knobs()
|
2021-05-25 13:08:23 +00:00
|
|
|
.sum_wait_for_cancellation
|
|
|
|
.with_value(CancellationFlag::Panic, || db.sum2("abc"))
|
2021-05-17 16:59:28 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Wait until we have entered `sum` in the other thread.
|
|
|
|
db.wait_for(1);
|
|
|
|
|
2021-05-25 13:08:23 +00:00
|
|
|
// Try to set the input. This will signal cancellation.
|
2021-05-17 16:59:28 +00:00
|
|
|
db.set_input('d', 1000);
|
|
|
|
|
|
|
|
// This should re-compute the value (even though no input has changed).
|
|
|
|
let thread2 = std::thread::spawn({
|
|
|
|
let db = db.snapshot();
|
|
|
|
move || db.sum2("abc")
|
|
|
|
});
|
|
|
|
|
|
|
|
assert_eq!(db.sum2("d"), 1000);
|
2021-05-25 13:08:23 +00:00
|
|
|
assert_cancelled!(thread1);
|
2021-05-17 16:59:28 +00:00
|
|
|
assert_eq!(thread2.join().unwrap(), 111);
|
2018-10-25 14:06:55 +00:00
|
|
|
}
|
2018-12-30 07:50:20 +00:00
|
|
|
|
|
|
|
/// https://github.com/salsa-rs/salsa/issues/66
|
|
|
|
#[test]
|
2021-05-25 13:08:23 +00:00
|
|
|
fn no_back_dating_in_cancellation() {
|
2019-01-04 18:39:18 +00:00
|
|
|
let mut db = ParDatabaseImpl::default();
|
|
|
|
|
2019-01-27 21:06:14 +00:00
|
|
|
db.set_input('a', 1);
|
2019-01-04 18:39:18 +00:00
|
|
|
let thread1 = std::thread::spawn({
|
|
|
|
let db = db.snapshot();
|
|
|
|
move || {
|
|
|
|
// Here we compute a long-chain of queries,
|
2021-05-25 13:08:23 +00:00
|
|
|
// but the last one gets cancelled.
|
2019-01-04 18:39:18 +00:00
|
|
|
db.knobs().sum_signal_on_entry.with_value(1, || {
|
|
|
|
db.knobs()
|
2021-05-25 13:08:23 +00:00
|
|
|
.sum_wait_for_cancellation
|
|
|
|
.with_value(CancellationFlag::Panic, || db.sum3("a"))
|
2019-01-04 18:39:18 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
db.wait_for(1);
|
|
|
|
|
2021-05-17 16:59:28 +00:00
|
|
|
// Set unrelated input to bump revision
|
2019-01-27 21:06:14 +00:00
|
|
|
db.set_input('b', 2);
|
2019-01-04 18:39:18 +00:00
|
|
|
|
2021-05-25 13:08:23 +00:00
|
|
|
// Here we should recompuet the whole chain again, clearing the cancellation
|
2021-05-17 16:59:28 +00:00
|
|
|
// state. If we get `usize::max()` here, it is a bug!
|
|
|
|
assert_eq!(db.sum3("a"), 1);
|
|
|
|
|
2021-05-25 13:08:23 +00:00
|
|
|
assert_cancelled!(thread1);
|
2019-01-04 18:39:18 +00:00
|
|
|
|
2021-05-17 16:59:28 +00:00
|
|
|
db.set_input('a', 3);
|
|
|
|
db.set_input('a', 4);
|
|
|
|
assert_eq!(db.sum3("ab"), 6);
|
2019-01-04 18:39:18 +00:00
|
|
|
}
|