@@ -16,13 +16,15 @@ use crate::key::DatabaseKeyIndex;
1616use crate :: plumbing:: { self , MemoIngredientMap } ;
1717use crate :: salsa_struct:: SalsaStructInDb ;
1818use crate :: sync:: Arc ;
19- use crate :: table:: memo:: MemoTableTypes ;
19+ use crate :: table:: memo:: { Either , MemoTableTypes } ;
2020use crate :: table:: Table ;
2121use crate :: views:: DatabaseDownCaster ;
2222use crate :: zalsa:: { IngredientIndex , JarKind , MemoIngredientIndex , Zalsa } ;
2323use crate :: zalsa_local:: { QueryEdge , QueryOriginRef } ;
2424use crate :: { Cycle , Durability , Id , Revision } ;
2525
26+ pub use crate :: function:: memo:: AmbiguousMemo ;
27+
2628#[ cfg( feature = "accumulator" ) ]
2729mod accumulated;
2830mod backdate;
@@ -37,7 +39,9 @@ mod memo;
3739mod specify;
3840mod sync;
3941
40- pub type Memo < C > = memo:: Memo < ' static , C > ;
42+ type EitherMemoNonNull < ' db , C > =
43+ Either < NonNull < memo:: Memo < ' db , C > > , NonNull < memo:: NeverChangeMemo < ' db , C > > > ;
44+ type EitherMemoRef < ' a , ' db , C > = Either < & ' a memo:: Memo < ' db , C > , & ' a memo:: NeverChangeMemo < ' db , C > > ;
4145
4246pub trait Configuration : Any {
4347 const DEBUG_NAME : & ' static str ;
@@ -246,6 +250,7 @@ where
246250 /// when this function is called and (b) ensuring that any entries
247251 /// removed from the memo-map are added to `deleted_entries`, which is
248252 /// only cleared with `&mut self`.
253+ #[ inline]
249254 unsafe fn extend_memo_lifetime < ' this > (
250255 & ' this self ,
251256 memo : & memo:: Memo < ' this , C > ,
@@ -254,6 +259,15 @@ where
254259 unsafe { std:: mem:: transmute ( memo) }
255260 }
256261
262+ #[ inline]
263+ unsafe fn extend_either_memo_lifetime < ' this > (
264+ & ' this self ,
265+ memo : EitherMemoRef < ' _ , ' this , C > ,
266+ ) -> EitherMemoRef < ' this , ' this , C > {
267+ // SAFETY: the caller must guarantee that the memo will not be released before `&self`
268+ unsafe { std:: mem:: transmute ( memo) }
269+ }
270+
257271 fn insert_memo < ' db > (
258272 & ' db self ,
259273 zalsa : & ' db Zalsa ,
@@ -284,6 +298,39 @@ where
284298 unsafe { self . extend_memo_lifetime ( memo. as_ref ( ) ) }
285299 }
286300
301+ fn insert_never_change_memo < ' db > (
302+ & ' db self ,
303+ zalsa : & ' db Zalsa ,
304+ id : Id ,
305+ memo : memo:: NeverChangeMemo < ' db , C > ,
306+ memo_ingredient_index : MemoIngredientIndex ,
307+ ) -> EitherMemoRef < ' db , ' db , C > {
308+ // We convert to a `NonNull` here as soon as possible because we are going to alias
309+ // into the `Box`, which is a `noalias` type.
310+ // SAFETY: memo is not null
311+ let memo = unsafe { NonNull :: new_unchecked ( Box :: into_raw ( Box :: new ( memo) ) ) } ;
312+
313+ // SAFETY: memo must be in the map (it's not yet, but it will be by the time this
314+ // value is returned) and anything removed from map is added to deleted entries (ensured elsewhere).
315+ let db_memo = unsafe { self . extend_either_memo_lifetime ( Either :: Right ( memo. as_ref ( ) ) ) } ;
316+
317+ if let Some ( old_value) =
318+ // SAFETY: We delay the drop of `old_value` until a new revision starts which ensures no
319+ // references will exist for the memo contents.
320+ unsafe {
321+ self . insert_never_change_memo_into_table_for ( zalsa, id, memo, memo_ingredient_index)
322+ }
323+ {
324+ // In case there is a reference to the old memo out there, we have to store it
325+ // in the deleted entries. This will get cleared when a new revision starts.
326+ //
327+ // SAFETY: Once the revision starts, there will be no outstanding borrows to the
328+ // memo contents, and so it will be safe to free.
329+ unsafe { self . deleted_entries . push ( old_value) } ;
330+ }
331+ db_memo
332+ }
333+
287334 #[ inline]
288335 fn memo_ingredient_index ( & self , zalsa : & Zalsa , id : Id ) -> MemoIngredientIndex {
289336 self . memo_ingredient_indices . get_zalsa_id ( zalsa, id)
@@ -335,6 +382,7 @@ where
335382 else {
336383 return ;
337384 } ;
385+ let Either :: Left ( memo) = memo else { todo ! ( ) } ;
338386
339387 let origin = memo. revisions . origin . as_ref ( ) ;
340388
@@ -371,8 +419,11 @@ where
371419 zalsa : & ' db Zalsa ,
372420 input : Id ,
373421 ) -> Option < ProvisionalStatus < ' db > > {
374- let memo =
375- self . get_memo_from_table_for ( zalsa, input, self . memo_ingredient_index ( zalsa, input) ) ?;
422+ let Either :: Left ( memo) =
423+ self . get_memo_from_table_for ( zalsa, input, self . memo_ingredient_index ( zalsa, input) ) ?
424+ else {
425+ return Some ( ProvisionalStatus :: FinalNeverChange ) ;
426+ } ;
376427
377428 let iteration = memo. revisions . iteration ( ) ;
378429 let verified_final = memo. revisions . verified_final . load ( Ordering :: Relaxed ) ;
@@ -396,7 +447,7 @@ where
396447 }
397448
398449 fn set_cycle_iteration_count ( & self , zalsa : & Zalsa , input : Id , iteration_count : IterationCount ) {
399- let Some ( memo) =
450+ let Some ( Either :: Left ( memo) ) =
400451 self . get_memo_from_table_for ( zalsa, input, self . memo_ingredient_index ( zalsa, input) )
401452 else {
402453 return ;
@@ -407,7 +458,7 @@ where
407458 }
408459
409460 fn finalize_cycle_head ( & self , zalsa : & Zalsa , input : Id ) {
410- let Some ( memo) =
461+ let Some ( Either :: Left ( memo) ) =
411462 self . get_memo_from_table_for ( zalsa, input, self . memo_ingredient_index ( zalsa, input) )
412463 else {
413464 return ;
@@ -417,7 +468,7 @@ where
417468 }
418469
419470 fn cycle_converged ( & self , zalsa : & Zalsa , input : Id ) -> bool {
420- let Some ( memo) =
471+ let Some ( Either :: Left ( memo) ) =
421472 self . get_memo_from_table_for ( zalsa, input, self . memo_ingredient_index ( zalsa, input) )
422473 else {
423474 return true ;
@@ -534,7 +585,12 @@ where
534585 let memo =
535586 self . get_memo_from_table_for ( zalsa, entry. key_index ( ) , memo_ingredient_index) ;
536587
537- if memo. is_some_and ( |memo| memo. should_serialize ( ) ) {
588+ let should_serialize = match memo {
589+ Some ( Either :: Left ( memo) ) => memo. should_serialize ( ) ,
590+ Some ( Either :: Right ( memo) ) => memo. should_serialize ( ) ,
591+ None => false ,
592+ } ;
593+ if should_serialize {
538594 return true ;
539595 }
540596 }
0 commit comments