@@ -2,6 +2,7 @@ use crate::durability::Durability;
2
2
use crate :: id:: AsId ;
3
3
use crate :: ingredient:: fmt_index;
4
4
use crate :: plumbing:: { Jar , JarAux } ;
5
+ use crate :: revision:: AtomicRevision ;
5
6
use crate :: table:: memo:: MemoTable ;
6
7
use crate :: table:: sync:: SyncTable ;
7
8
use crate :: table:: Slot ;
67
68
data : C :: Data < ' static > ,
68
69
memos : MemoTable ,
69
70
syncs : SyncTable ,
71
+ // The revision the value was first interned in.
72
+ first_interned_at : Revision ,
73
+ // The most recent interned revision.
74
+ last_interned_at : AtomicRevision ,
70
75
}
71
76
72
77
impl < C : Configuration > Default for JarImpl < C > {
@@ -120,7 +125,8 @@ where
120
125
db : & ' db dyn crate :: Database ,
121
126
data : impl Lookup < C :: Data < ' db > > ,
122
127
) -> C :: Struct < ' db > {
123
- let zalsa_local = db. zalsa_local ( ) ;
128
+ let ( zalsa, zalsa_local) = db. zalsas ( ) ;
129
+ let current_revision = zalsa. current_revision ( ) ;
124
130
125
131
// Optimisation to only get read lock on the map if the data has already
126
132
// been interned.
@@ -142,9 +148,13 @@ where
142
148
// SAFETY: Read lock on map is held during this block
143
149
let id = unsafe { * bucket. as_ref ( ) . 1 . get ( ) } ;
144
150
151
+ // Sync the value's revision.
152
+ let value = zalsa. table ( ) . get :: < Value < C > > ( id) ;
153
+ value. last_interned_at . store ( current_revision) ;
154
+
145
155
// Record a dependency on this value.
146
156
let index = self . database_key_index ( id) ;
147
- zalsa_local. report_tracked_read ( index, Durability :: MAX , Revision :: start ( ) ) ;
157
+ zalsa_local. report_tracked_read ( index, Durability :: MAX , value . first_interned_at ) ;
148
158
149
159
return C :: struct_from_id ( id) ;
150
160
}
@@ -160,9 +170,13 @@ where
160
170
let id = * entry. get ( ) ;
161
171
drop ( entry) ;
162
172
173
+ // Sync the value's revision.
174
+ let value = zalsa. table ( ) . get :: < Value < C > > ( id) ;
175
+ value. last_interned_at . store ( current_revision) ;
176
+
163
177
// Record a dependency on this value.
164
178
let index = self . database_key_index ( id) ;
165
- zalsa_local. report_tracked_read ( index, Durability :: MAX , Revision :: start ( ) ) ;
179
+ zalsa_local. report_tracked_read ( index, Durability :: MAX , value . first_interned_at ) ;
166
180
167
181
C :: struct_from_id ( id)
168
182
}
@@ -175,12 +189,14 @@ where
175
189
data : internal_data,
176
190
memos : Default :: default ( ) ,
177
191
syncs : Default :: default ( ) ,
192
+ first_interned_at : current_revision,
193
+ last_interned_at : AtomicRevision :: from ( current_revision) ,
178
194
} ) ;
179
195
entry. insert ( next_id) ;
180
196
181
197
// Record a dependency on this value.
182
198
let index = self . database_key_index ( next_id) ;
183
- zalsa_local. report_tracked_read ( index, Durability :: MAX , Revision :: start ( ) ) ;
199
+ zalsa_local. report_tracked_read ( index, Durability :: MAX , current_revision ) ;
184
200
185
201
C :: struct_from_id ( next_id)
186
202
}
@@ -199,15 +215,25 @@ where
199
215
/// Rarely used since end-users generally carry a struct with a pointer directly
200
216
/// to the interned item.
201
217
pub fn data < ' db > ( & ' db self , db : & ' db dyn Database , id : Id ) -> & ' db C :: Data < ' db > {
202
- let internal_data = db. zalsa ( ) . table ( ) . get :: < Value < C > > ( id) ;
203
- unsafe { Self :: from_internal_data ( & internal_data. data ) }
218
+ let value = db. zalsa ( ) . table ( ) . get :: < Value < C > > ( id) ;
219
+ assert ! (
220
+ value. last_interned_at. load( ) >= db. zalsa( ) . current_revision( ) ,
221
+ "Data was not interned in the current revision."
222
+ ) ;
223
+ unsafe { Self :: from_internal_data ( & value. data ) }
204
224
}
205
225
206
226
/// Lookup the fields from an interned struct.
207
227
/// Note that this is not "leaking" since no dependency edge is required.
208
228
pub fn fields < ' db > ( & ' db self , db : & ' db dyn Database , s : C :: Struct < ' db > ) -> & ' db C :: Data < ' db > {
209
229
self . data ( db, C :: deref_struct ( s) )
210
230
}
231
+
232
+ pub fn reset ( & mut self , db : & mut dyn Database ) {
233
+ // Trigger a new revision.
234
+ let _zalsa_mut = db. zalsa_mut ( ) ;
235
+ self . key_map . clear ( ) ;
236
+ }
211
237
}
212
238
213
239
impl < C > Ingredient for IngredientImpl < C >
@@ -218,8 +244,18 @@ where
218
244
self . ingredient_index
219
245
}
220
246
221
- fn maybe_changed_after ( & self , _db : & dyn Database , _input : Id , _revision : Revision ) -> bool {
222
- // Interned data currently never changes.
247
+ fn maybe_changed_after ( & self , db : & dyn Database , input : Id , revision : Revision ) -> bool {
248
+ let value = db. zalsa ( ) . table ( ) . get :: < Value < C > > ( input) ;
249
+ if value. first_interned_at > revision {
250
+ // The slot was reused.
251
+ return true ;
252
+ }
253
+
254
+ if value. first_interned_at < revision {
255
+ // The slot is valid in this revision but we have to sync the value's revision.
256
+ value. last_interned_at . store ( db. zalsa ( ) . current_revision ( ) ) ;
257
+ }
258
+
223
259
false
224
260
}
225
261
0 commit comments