mirror of
https://github.com/salsa-rs/salsa.git
synced 2025-08-26 21:44:49 +00:00

* Add parallel `maybe_changed_after` shuttle test * Update tests/parallel/cycle_nested_deep_conditional_changed.rs Co-authored-by: Carl Meyer <carl@astral.sh> --------- Co-authored-by: Carl Meyer <carl@astral.sh>
123 lines
3.5 KiB
Rust
123 lines
3.5 KiB
Rust
//! Test a nested-cycle scenario across three threads:
|
|
//!
|
|
//! ```text
|
|
//! Thread T1 Thread T2 Thread T3
|
|
//! --------- --------- ---------
|
|
//! | | |
|
|
//! v | |
|
|
//! query_a() | |
|
|
//! ^ | v |
|
|
//! | +------------> query_b() |
|
|
//! | ^ | v
|
|
//! | | +------------> query_c()
|
|
//! | | |
|
|
//! +------------------+--------------------+
|
|
//! ```
|
|
//!
|
|
//! Specifically, the maybe_changed_after flow.
|
|
|
|
use crate::sync;
|
|
use crate::sync::thread;
|
|
|
|
use salsa::{CycleRecoveryAction, DatabaseImpl, Setter as _};
|
|
|
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, salsa::Update)]
|
|
struct CycleValue(u32);
|
|
|
|
const MIN: CycleValue = CycleValue(0);
|
|
const MAX: CycleValue = CycleValue(3);
|
|
|
|
#[salsa::input]
|
|
struct Input {
|
|
value: u32,
|
|
}
|
|
|
|
// Signal 1: T1 has entered `query_a`
|
|
// Signal 2: T2 has entered `query_b`
|
|
// Signal 3: T3 has entered `query_c`
|
|
|
|
#[salsa::tracked(cycle_fn=cycle_fn, cycle_initial=initial)]
|
|
fn query_a(db: &dyn salsa::Database, input: Input) -> CycleValue {
|
|
query_b(db, input)
|
|
}
|
|
|
|
#[salsa::tracked(cycle_fn=cycle_fn, cycle_initial=initial)]
|
|
fn query_b(db: &dyn salsa::Database, input: Input) -> CycleValue {
|
|
let c_value = query_c(db, input);
|
|
CycleValue(c_value.0 + input.value(db)).min(MAX)
|
|
}
|
|
|
|
#[salsa::tracked(cycle_fn=cycle_fn, cycle_initial=initial)]
|
|
fn query_c(db: &dyn salsa::Database, input: Input) -> CycleValue {
|
|
let a_value = query_a(db, input);
|
|
let b_value = query_b(db, input);
|
|
CycleValue(a_value.0.max(b_value.0))
|
|
}
|
|
|
|
fn cycle_fn(
|
|
_db: &dyn salsa::Database,
|
|
_value: &CycleValue,
|
|
_count: u32,
|
|
_input: Input,
|
|
) -> CycleRecoveryAction<CycleValue> {
|
|
CycleRecoveryAction::Iterate
|
|
}
|
|
|
|
fn initial(_db: &dyn salsa::Database, _input: Input) -> CycleValue {
|
|
MIN
|
|
}
|
|
|
|
#[test_log::test]
|
|
fn the_test() {
|
|
crate::sync::check(move || {
|
|
// This is a bit silly but it works around https://github.com/awslabs/shuttle/issues/192
|
|
static INITIALIZE: sync::Mutex<Option<(salsa::DatabaseImpl, Input)>> =
|
|
sync::Mutex::new(None);
|
|
|
|
fn get_db(f: impl FnOnce(&salsa::DatabaseImpl, Input)) -> (salsa::DatabaseImpl, Input) {
|
|
let mut shared = INITIALIZE.lock().unwrap();
|
|
|
|
if let Some((db, input)) = shared.as_ref() {
|
|
return (db.clone(), *input);
|
|
}
|
|
|
|
let mut db = DatabaseImpl::default();
|
|
|
|
let input = Input::new(&db, 1);
|
|
|
|
f(&db, input);
|
|
|
|
input.set_value(&mut db).to(2);
|
|
|
|
*shared = Some((db.clone(), input));
|
|
|
|
(db, input)
|
|
}
|
|
|
|
let t1 = thread::spawn(|| {
|
|
let (db, input) = get_db(|db, input| {
|
|
query_a(db, input);
|
|
});
|
|
|
|
query_a(&db, input)
|
|
});
|
|
let t2 = thread::spawn(|| {
|
|
let (db, input) = get_db(|db, input| {
|
|
query_b(db, input);
|
|
});
|
|
query_b(&db, input)
|
|
});
|
|
let t3 = thread::spawn(|| {
|
|
let (db, input) = get_db(|db, input| {
|
|
query_c(db, input);
|
|
});
|
|
query_c(&db, input)
|
|
});
|
|
|
|
let r_t1 = t1.join().unwrap();
|
|
let r_t2 = t2.join().unwrap();
|
|
let r_t3 = t3.join().unwrap();
|
|
|
|
assert_eq!((r_t1, r_t2, r_t3), (MAX, MAX, MAX));
|
|
});
|
|
}
|