mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-01-22 21:05:11 +00:00
add a test for the revision lock
This commit is contained in:
parent
e348c21528
commit
c94db84945
2 changed files with 73 additions and 0 deletions
|
@ -3,5 +3,6 @@ mod setup;
|
|||
mod cancellation;
|
||||
mod independent;
|
||||
mod race;
|
||||
mod revision_lock;
|
||||
mod signal;
|
||||
mod true_parallel;
|
||||
|
|
72
tests/parallel/revision_lock.rs
Normal file
72
tests/parallel/revision_lock.rs
Normal file
|
@ -0,0 +1,72 @@
|
|||
use crate::setup::{Input, ParDatabase, ParDatabaseImpl};
|
||||
use crate::signal::Signal;
|
||||
use salsa::{Database, ParallelDatabase};
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Add test where a call to `sum` is cancelled by a simultaneous
|
||||
/// write. Check that we recompute the result in next revision, even
|
||||
/// though none of the inputs have changed.
|
||||
#[test]
|
||||
fn in_par_get_set_cancellation() {
|
||||
let db = ParDatabaseImpl::default();
|
||||
|
||||
db.query(Input).set('a', 1);
|
||||
|
||||
let signal = Arc::new(Signal::default());
|
||||
|
||||
let lock = db.salsa_runtime().lock_revision();
|
||||
let thread1 = std::thread::spawn({
|
||||
let db = db.fork();
|
||||
let signal = signal.clone();
|
||||
move || {
|
||||
// Check that cancellation flag is not yet set, because
|
||||
// `set` cannot have been called yet.
|
||||
assert!(!db.salsa_runtime().is_current_revision_canceled());
|
||||
|
||||
// Signal other thread to proceed.
|
||||
signal.signal(1);
|
||||
|
||||
// Wait for other thread to signal cancellation
|
||||
while !db.salsa_runtime().is_current_revision_canceled() {
|
||||
std::thread::yield_now();
|
||||
}
|
||||
|
||||
// Since we have not yet released revision lock, we should
|
||||
// see 1 here.
|
||||
let v = db.input('a');
|
||||
|
||||
// Release the lock.
|
||||
std::mem::drop(lock);
|
||||
|
||||
// This could come before or after the `set` in the other
|
||||
// thread.
|
||||
let w = db.input('a');
|
||||
|
||||
(v, w)
|
||||
}
|
||||
});
|
||||
|
||||
let thread2 = std::thread::spawn({
|
||||
let db = db.fork();
|
||||
let signal = signal.clone();
|
||||
move || {
|
||||
// Wait until thread 1 has asserted that they are not cancelled
|
||||
// before we invoke `set.`
|
||||
signal.wait_for(1);
|
||||
|
||||
// This will block until thread1 drops the revision lock.
|
||||
db.query(Input).set('a', 2);
|
||||
|
||||
db.input('a')
|
||||
}
|
||||
});
|
||||
|
||||
// The first read is done with the revision lock, so it *must* see
|
||||
// `1`; the second read could see either `1` or `2`.
|
||||
let (a, b) = thread1.join().unwrap();
|
||||
assert_eq!(a, 1);
|
||||
assert!(b == 1 || b == 2, "saw unexpected value for b: {}", b);
|
||||
|
||||
let c = thread2.join().unwrap();
|
||||
assert_eq!(c, 2);
|
||||
}
|
Loading…
Reference in a new issue