@@ -187,12 +187,27 @@ where
187187
188188 let mut cycle_heads = std:: mem:: take ( cycle_heads) ;
189189
190+ // Recursively resolve all cycle heads that this head depends on.
191+ // This isn't required in a single-threaded execution but it's not guaranteed that all nested cycles are listed
192+ // in cycle heads in a multi-threaded execution:
193+ //
194+ // t1: a -> b
195+ // t2: c -> b (blocks on t1)
196+ // t1: a -> b -> c (cycle, returns fixpoint initial with c(0) in heads)
197+ // t1: a -> b (completes b, b has c(0) in its cycle heads, releases `b`, which resumes `t2`, and `retry_provisional` blocks on `c` (t2))
198+ // t2: c -> a (cycle, returns fixpoint initial for a with a(0) in heads)
199+ // t2: completes c, `provisional_retry` blocks on `a` (t2)
200+ // t1: a (complets `b` with `c` in heads)
201+ //
202+ // Note how `a` only depends on `c` but not `a`. This is because `a` only saw the initial value of `c` and wasn't updated when `c` completed.
203+ // That's why we need to resolve the cycle heads recursively to `cycle_heads` contains all cycle heads at the moment this query completed.
190204 let mut queue: SmallVec < [ DatabaseKeyIndex ; 4 ] > = cycle_heads
191205 . iter ( )
192206 . map ( |head| head. database_key_index )
193207 . filter ( |head| * head != database_key_index)
194208 . collect ( ) ;
195209
210+ // TODO: Can we also resolve whether the cycles have converged here?
196211 while let Some ( head) = queue. pop ( ) {
197212 let ingredient = zalsa. lookup_ingredient ( head. ingredient_index ( ) ) ;
198213 let nested_heads = ingredient. cycle_heads ( zalsa, head. key_index ( ) ) ;
@@ -230,10 +245,9 @@ where
230245 memo. value . as_ref ( )
231246 } ;
232247
233-
234248 let last_provisional_value = last_provisional_value. expect (
235- "`fetch_cold_cycle` should have inserted a provisional memo with Cycle::initial" ,
236- ) ;
249+ "`fetch_cold_cycle` should have inserted a provisional memo with Cycle::initial" ,
250+ ) ;
237251 crate :: tracing:: debug!(
238252 "{database_key_index:?}: execute: \
239253 I am a cycle head, comparing last provisional value with new value"
@@ -487,6 +501,10 @@ impl<C: Configuration> Drop for ClearCycleHeadIfPanicking<'_, C> {
487501 if std:: thread:: panicking ( ) {
488502 let revisions =
489503 QueryRevisions :: fixpoint_initial ( self . ingredient . database_key_index ( self . id ) ) ;
504+ revisions. update_iteration_count_mut (
505+ self . ingredient . database_key_index ( self . id ) ,
506+ IterationCount :: panicked ( ) ,
507+ ) ;
490508
491509 let memo = Memo :: new ( None , self . zalsa . current_revision ( ) , revisions) ;
492510 self . ingredient
0 commit comments