@@ -4,7 +4,7 @@ use crate::function::sync::ClaimResult;
44use crate :: function:: { Configuration , IngredientImpl , VerifyResult } ;
55use crate :: zalsa:: { MemoIngredientIndex , Zalsa } ;
66use crate :: zalsa_local:: { QueryRevisions , ZalsaLocal } ;
7- use crate :: Id ;
7+ use crate :: { DatabaseKeyIndex , Id } ;
88
99impl < C > IngredientImpl < C >
1010where
@@ -130,6 +130,7 @@ where
130130 let database_key_index = self . database_key_index ( id) ;
131131 // Try to claim this query: if someone else has claimed it already, go back and start again.
132132 let claim_guard = match self . sync_table . try_claim ( zalsa, id) {
133+ ClaimResult :: Claimed ( guard) => guard,
133134 ClaimResult :: Running ( blocked_on) => {
134135 blocked_on. block_on ( zalsa) ;
135136
@@ -146,75 +147,15 @@ where
146147 return None ;
147148 }
148149 ClaimResult :: Cycle { .. } => {
149- // check if there's a provisional value for this query
150- // Note we don't `validate_may_be_provisional` the memo here as we want to reuse an
151- // existing provisional memo if it exists
152- let memo_guard = self . get_memo_from_table_for ( zalsa, id, memo_ingredient_index) ;
153- if let Some ( memo) = memo_guard {
154- if memo. value . is_some ( )
155- && memo. revisions . cycle_heads ( ) . contains ( & database_key_index)
156- {
157- let can_shallow_update =
158- self . shallow_verify_memo ( zalsa, database_key_index, memo) ;
159- if can_shallow_update. yes ( ) {
160- self . update_shallow (
161- zalsa,
162- database_key_index,
163- memo,
164- can_shallow_update,
165- ) ;
166- // SAFETY: memo is present in memo_map.
167- return unsafe { Some ( self . extend_memo_lifetime ( memo) ) } ;
168- }
169- }
170- }
171- // no provisional value; create/insert/return initial provisional value
172- return match C :: CYCLE_STRATEGY {
173- // SAFETY: We do not access the query stack reentrantly.
174- CycleRecoveryStrategy :: Panic => unsafe {
175- zalsa_local. with_query_stack_unchecked ( |stack| {
176- panic ! (
177- "dependency graph cycle when querying {database_key_index:#?}, \
178- set cycle_fn/cycle_initial to fixpoint iterate.\n \
179- Query stack:\n {stack:#?}",
180- ) ;
181- } )
182- } ,
183- CycleRecoveryStrategy :: Fixpoint => {
184- crate :: tracing:: debug!(
185- "hit cycle at {database_key_index:#?}, \
186- inserting and returning fixpoint initial value"
187- ) ;
188- let revisions = QueryRevisions :: fixpoint_initial ( database_key_index) ;
189- let initial_value = C :: cycle_initial ( db, C :: id_to_input ( zalsa, id) ) ;
190- Some ( self . insert_memo (
191- zalsa,
192- id,
193- Memo :: new ( Some ( initial_value) , zalsa. current_revision ( ) , revisions) ,
194- memo_ingredient_index,
195- ) )
196- }
197- CycleRecoveryStrategy :: FallbackImmediate => {
198- crate :: tracing:: debug!(
199- "hit a `FallbackImmediate` cycle at {database_key_index:#?}"
200- ) ;
201- let active_query =
202- zalsa_local. push_query ( database_key_index, IterationCount :: initial ( ) ) ;
203- let fallback_value = C :: cycle_initial ( db, C :: id_to_input ( zalsa, id) ) ;
204- let mut revisions = active_query. pop ( ) ;
205- revisions. set_cycle_heads ( CycleHeads :: initial ( database_key_index) ) ;
206- // We need this for `cycle_heads()` to work. We will unset this in the outer `execute()`.
207- * revisions. verified_final . get_mut ( ) = false ;
208- Some ( self . insert_memo (
209- zalsa,
210- id,
211- Memo :: new ( Some ( fallback_value) , zalsa. current_revision ( ) , revisions) ,
212- memo_ingredient_index,
213- ) )
214- }
215- } ;
150+ return Some ( self . fetch_cold_cycle (
151+ zalsa,
152+ zalsa_local,
153+ db,
154+ id,
155+ database_key_index,
156+ memo_ingredient_index,
157+ ) ) ;
216158 }
217- ClaimResult :: Claimed ( guard) => guard,
218159 } ;
219160
220161 // Now that we've claimed the item, check again to see if there's a "hot" value.
@@ -272,4 +213,77 @@ where
272213
273214 Some ( memo)
274215 }
216+
217+ #[ cold]
218+ #[ inline( never) ]
219+ fn fetch_cold_cycle < ' db > (
220+ & ' db self ,
221+ zalsa : & ' db Zalsa ,
222+ zalsa_local : & ' db ZalsaLocal ,
223+ db : & ' db C :: DbView ,
224+ id : Id ,
225+ database_key_index : DatabaseKeyIndex ,
226+ memo_ingredient_index : MemoIngredientIndex ,
227+ ) -> & ' db Memo < ' db , C > {
228+ // check if there's a provisional value for this query
229+ // Note we don't `validate_may_be_provisional` the memo here as we want to reuse an
230+ // existing provisional memo if it exists
231+ let memo_guard = self . get_memo_from_table_for ( zalsa, id, memo_ingredient_index) ;
232+ if let Some ( memo) = memo_guard {
233+ if memo. value . is_some ( ) && memo. revisions . cycle_heads ( ) . contains ( & database_key_index) {
234+ let can_shallow_update = self . shallow_verify_memo ( zalsa, database_key_index, memo) ;
235+ if can_shallow_update. yes ( ) {
236+ self . update_shallow ( zalsa, database_key_index, memo, can_shallow_update) ;
237+ // SAFETY: memo is present in memo_map.
238+ return unsafe { self . extend_memo_lifetime ( memo) } ;
239+ }
240+ }
241+ }
242+
243+ // no provisional value; create/insert/return initial provisional value
244+ match C :: CYCLE_STRATEGY {
245+ // SAFETY: We do not access the query stack reentrantly.
246+ CycleRecoveryStrategy :: Panic => unsafe {
247+ zalsa_local. with_query_stack_unchecked ( |stack| {
248+ panic ! (
249+ "dependency graph cycle when querying {database_key_index:#?}, \
250+ set cycle_fn/cycle_initial to fixpoint iterate.\n \
251+ Query stack:\n {stack:#?}",
252+ ) ;
253+ } )
254+ } ,
255+ CycleRecoveryStrategy :: Fixpoint => {
256+ crate :: tracing:: debug!(
257+ "hit cycle at {database_key_index:#?}, \
258+ inserting and returning fixpoint initial value"
259+ ) ;
260+ let revisions = QueryRevisions :: fixpoint_initial ( database_key_index) ;
261+ let initial_value = C :: cycle_initial ( db, C :: id_to_input ( zalsa, id) ) ;
262+ self . insert_memo (
263+ zalsa,
264+ id,
265+ Memo :: new ( Some ( initial_value) , zalsa. current_revision ( ) , revisions) ,
266+ memo_ingredient_index,
267+ )
268+ }
269+ CycleRecoveryStrategy :: FallbackImmediate => {
270+ crate :: tracing:: debug!(
271+ "hit a `FallbackImmediate` cycle at {database_key_index:#?}"
272+ ) ;
273+ let active_query =
274+ zalsa_local. push_query ( database_key_index, IterationCount :: initial ( ) ) ;
275+ let fallback_value = C :: cycle_initial ( db, C :: id_to_input ( zalsa, id) ) ;
276+ let mut revisions = active_query. pop ( ) ;
277+ revisions. set_cycle_heads ( CycleHeads :: initial ( database_key_index) ) ;
278+ // We need this for `cycle_heads()` to work. We will unset this in the outer `execute()`.
279+ * revisions. verified_final . get_mut ( ) = false ;
280+ self . insert_memo (
281+ zalsa,
282+ id,
283+ Memo :: new ( Some ( fallback_value) , zalsa. current_revision ( ) , revisions) ,
284+ memo_ingredient_index,
285+ )
286+ }
287+ }
288+ }
275289}
0 commit comments