|
1 | | -pub(crate) use maybe_changed_after::{VerifyCycleHeads, VerifyResult}; |
| 1 | +pub(crate) use maybe_changed_after::VerifyResult; |
2 | 2 | pub(crate) use sync::{ClaimGuard, ClaimResult, Reentrancy, SyncGuard, SyncOwner, SyncTable}; |
3 | 3 |
|
4 | 4 | use std::any::Any; |
@@ -322,11 +322,10 @@ where |
322 | 322 | db: RawDatabase<'_>, |
323 | 323 | input: Id, |
324 | 324 | revision: Revision, |
325 | | - cycle_heads: &mut VerifyCycleHeads, |
326 | 325 | ) -> VerifyResult { |
327 | 326 | // SAFETY: The `db` belongs to the ingredient as per caller invariant |
328 | 327 | let db = unsafe { self.view_caster().downcast_unchecked(db) }; |
329 | | - self.maybe_changed_after(db, input, revision, cycle_heads) |
| 328 | + self.maybe_changed_after(db, input, revision) |
330 | 329 | } |
331 | 330 |
|
332 | 331 | fn collect_minimum_serialized_edges( |
@@ -420,6 +419,55 @@ where |
420 | 419 | memo.revisions.verified_final.store(true, Ordering::Release); |
421 | 420 | } |
422 | 421 |
|
| 422 | + fn flatten_cycle_head_dependencies( |
| 423 | + &self, |
| 424 | + zalsa: &Zalsa, |
| 425 | + id: Id, |
| 426 | + flattened_input_outputs: &mut FxIndexSet<QueryEdge>, |
| 427 | + seen: &mut FxHashSet<DatabaseKeyIndex>, |
| 428 | + ) { |
| 429 | + let memo_index = self.memo_ingredient_index(zalsa, id); |
| 430 | + let Some(memo) = self.get_memo_from_table_for(zalsa, id, memo_index) else { |
| 431 | + return; |
| 432 | + }; |
| 433 | + |
| 434 | + let database_key_index = self.database_key_index(id); |
| 435 | + |
| 436 | + // Only flatten dependencies of provisional queries, because only those |
| 437 | + // contain cyclic dependencies. |
| 438 | + if !memo.may_be_provisional() { |
| 439 | + flattened_input_outputs.insert(QueryEdge::input(database_key_index)); |
| 440 | + return; |
| 441 | + } |
| 442 | + |
| 443 | + // There's nothing to do if we've visited this query before. |
| 444 | + if !seen.insert(database_key_index) { |
| 445 | + return; |
| 446 | + } |
| 447 | + |
| 448 | + let inputs = memo.revisions.origin.as_ref().inputs(); |
| 449 | + |
| 450 | + match C::CYCLE_STRATEGY { |
| 451 | + // For queries with cycle handling, simply extend the input/outputs, because |
| 452 | + // they already flattened their own dependencies when completing the query. |
| 453 | + CycleRecoveryStrategy::FallbackImmediate | CycleRecoveryStrategy::Fixpoint => { |
| 454 | + flattened_input_outputs.extend(inputs.map(QueryEdge::input)); |
| 455 | + } |
| 456 | + // For regular queries, recurse |
| 457 | + CycleRecoveryStrategy::Panic => { |
| 458 | + for input in inputs { |
| 459 | + let ingredient = zalsa.lookup_ingredient(input.ingredient_index()); |
| 460 | + ingredient.flatten_cycle_head_dependencies( |
| 461 | + zalsa, |
| 462 | + input.key_index(), |
| 463 | + flattened_input_outputs, |
| 464 | + seen, |
| 465 | + ); |
| 466 | + } |
| 467 | + } |
| 468 | + } |
| 469 | + } |
| 470 | + |
423 | 471 | fn cycle_converged(&self, zalsa: &Zalsa, input: Id) -> bool { |
424 | 472 | let Some(memo) = |
425 | 473 | self.get_memo_from_table_for(zalsa, input, self.memo_ingredient_index(zalsa, input)) |
|
0 commit comments