@@ -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 , current_revision ) ;
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 , current_revision ) ;
166
180
167
181
C :: struct_from_id ( id)
168
182
}
@@ -171,43 +185,56 @@ where
171
185
dashmap:: mapref:: entry:: Entry :: Vacant ( entry) => {
172
186
let zalsa = db. zalsa ( ) ;
173
187
let table = zalsa. table ( ) ;
188
+
174
189
let next_id = zalsa_local. allocate ( table, self . ingredient_index , || Value :: < C > {
175
190
data : internal_data,
176
191
memos : Default :: default ( ) ,
177
192
syncs : Default :: default ( ) ,
193
+ first_interned_at : current_revision,
194
+ last_interned_at : AtomicRevision :: from ( current_revision) ,
178
195
} ) ;
179
196
entry. insert ( next_id) ;
180
197
181
198
// Record a dependency on this value.
182
199
let index = self . database_key_index ( next_id) ;
183
- zalsa_local. report_tracked_read ( index, Durability :: MAX , Revision :: start ( ) ) ;
200
+ zalsa_local. report_tracked_read ( index, Durability :: MAX , current_revision ) ;
184
201
185
202
C :: struct_from_id ( next_id)
186
203
}
187
204
}
188
205
}
189
206
190
207
/// Returns the database key index for an interned value with the given id.
191
- pub fn database_key_index ( & self , id : Id ) -> DatabaseKeyIndex {
208
+ pub fn database_key_index ( & self , key_index : Id ) -> DatabaseKeyIndex {
192
209
DatabaseKeyIndex {
210
+ key_index,
193
211
ingredient_index : self . ingredient_index ,
194
- key_index : id,
195
212
}
196
213
}
197
214
198
215
/// Lookup the data for an interned value based on its id.
199
216
/// Rarely used since end-users generally carry a struct with a pointer directly
200
217
/// to the interned item.
201
218
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 ) }
219
+ let value = db. zalsa ( ) . table ( ) . get :: < Value < C > > ( id) ;
220
+ assert ! (
221
+ value. last_interned_at. load( ) >= db. zalsa( ) . current_revision( ) ,
222
+ "Data was not interned in the current revision."
223
+ ) ;
224
+ unsafe { Self :: from_internal_data ( & value. data ) }
204
225
}
205
226
206
227
/// Lookup the fields from an interned struct.
207
228
/// Note that this is not "leaking" since no dependency edge is required.
208
229
pub fn fields < ' db > ( & ' db self , db : & ' db dyn Database , s : C :: Struct < ' db > ) -> & ' db C :: Data < ' db > {
209
230
self . data ( db, C :: deref_struct ( s) )
210
231
}
232
+
233
+ pub fn reset ( & mut self , db : & mut dyn Database ) {
234
+ // Trigger a new revision.
235
+ let _zalsa_mut = db. zalsa_mut ( ) ;
236
+ self . key_map . clear ( ) ;
237
+ }
211
238
}
212
239
213
240
impl < C > Ingredient for IngredientImpl < C >
@@ -218,8 +245,16 @@ where
218
245
self . ingredient_index
219
246
}
220
247
221
- fn maybe_changed_after ( & self , _db : & dyn Database , _input : Id , _revision : Revision ) -> bool {
222
- // Interned data currently never changes.
248
+ fn maybe_changed_after ( & self , db : & dyn Database , input : Id , revision : Revision ) -> bool {
249
+ let value = db. zalsa ( ) . table ( ) . get :: < Value < C > > ( input) ;
250
+ if value. first_interned_at > revision {
251
+ // The slot was reused.
252
+ return true ;
253
+ }
254
+
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
+
223
258
false
224
259
}
225
260
0 commit comments