1 use salsa
::{ParallelDatabase, Snapshot}
;
3 #[derive(PartialEq, Eq, Hash, Clone, Debug)]
8 #[salsa::database(GroupStruct)]
11 runtime
: salsa
::Runtime
<DatabaseImpl
>,
14 impl salsa
::Database
for DatabaseImpl
{
15 fn salsa_runtime(&self) -> &salsa
::Runtime
<Self> {
19 fn salsa_runtime_mut(&mut self) -> &mut salsa
::Runtime
<Self> {
24 impl ParallelDatabase
for DatabaseImpl
{
25 fn snapshot(&self) -> Snapshot
<Self> {
26 Snapshot
::new(DatabaseImpl
{
27 runtime
: self.runtime
.snapshot(self),
32 #[salsa::query_group(GroupStruct)]
33 trait Database
: salsa
::Database
{
34 // `a` and `b` depend on each other and form a cycle
35 fn memoized_a(&self) -> ();
36 fn memoized_b(&self) -> ();
37 fn volatile_a(&self) -> ();
38 fn volatile_b(&self) -> ();
40 fn cycle_leaf(&self) -> ();
42 #[salsa::cycle(recover_a)]
43 fn cycle_a(&self) -> Result
<(), Error
>;
44 #[salsa::cycle(recover_b)]
45 fn cycle_b(&self) -> Result
<(), Error
>;
47 fn cycle_c(&self) -> Result
<(), Error
>;
50 fn recover_a(_db
: &impl Database
, cycle
: &[String
]) -> Result
<(), Error
> {
52 cycle
: cycle
.to_owned(),
56 fn recover_b(_db
: &impl Database
, cycle
: &[String
]) -> Result
<(), Error
> {
58 cycle
: cycle
.to_owned(),
62 fn memoized_a(db
: &impl Database
) -> () {
66 fn memoized_b(db
: &impl Database
) -> () {
70 fn volatile_a(db
: &impl Database
) -> () {
71 db
.salsa_runtime().report_untracked_read();
75 fn volatile_b(db
: &impl Database
) -> () {
76 db
.salsa_runtime().report_untracked_read();
80 fn cycle_leaf(_db
: &impl Database
) -> () {}
82 fn cycle_a(db
: &impl Database
) -> Result
<(), Error
> {
87 fn cycle_b(db
: &impl Database
) -> Result
<(), Error
> {
93 fn cycle_c(db
: &impl Database
) -> Result
<(), Error
> {
98 #[should_panic(expected = "cycle detected")]
100 let query
= DatabaseImpl
::default();
105 #[should_panic(expected = "cycle detected")]
106 fn cycle_volatile() {
107 let query
= DatabaseImpl
::default();
113 let query
= DatabaseImpl
::default();
114 assert
!(query
.cycle_a().is_err());
119 let query
= DatabaseImpl
::default();
120 let err
= query
.cycle_c();
121 assert
!(err
.is_err());
122 let cycle
= err
.unwrap_err().cycle
;
126 .zip(&["cycle_b", "cycle_a"])
127 .all(|(l
, r
)| l
.contains(r
)),
134 fn parallel_cycle() {
135 let _
= env_logger
::try_init();
137 let db
= DatabaseImpl
::default();
138 let thread1
= std
::thread
::spawn({
139 let db
= db
.snapshot();
141 let result
= db
.cycle_a();
142 assert
!(result
.is_err(), "Expected cycle error");
143 let cycle
= result
.unwrap_err().cycle
;
147 .all(|l
| ["cycle_b", "cycle_a"].iter().any(|r
| l
.contains(r
))),
154 let thread2
= std
::thread
::spawn(move || {
155 let result
= db
.cycle_c();
156 assert
!(result
.is_err(), "Expected cycle error");
157 let cycle
= result
.unwrap_err().cycle
;
161 .all(|l
| ["cycle_b", "cycle_a"].iter().any(|r
| l
.contains(r
))),
167 thread1
.join().unwrap();
168 thread2
.join().unwrap();