@@ -13,6 +13,7 @@ use std::fmt;
13
13
use std:: hash:: { BuildHasher , Hash , Hasher } ;
14
14
use std:: marker:: PhantomData ;
15
15
use std:: path:: { Path , PathBuf } ;
16
+ use std:: sync:: atomic:: { AtomicU8 , Ordering } ;
16
17
17
18
use super :: hash:: FxDashMap ;
18
19
use super :: ingredient:: Ingredient ;
@@ -68,10 +69,27 @@ where
68
69
data : C :: Data < ' static > ,
69
70
memos : MemoTable ,
70
71
syncs : SyncTable ,
72
+
71
73
/// The revision the value was first interned in.
72
74
first_interned_at : Revision ,
75
+
73
76
/// The most recent interned revision.
74
77
last_interned_at : AtomicRevision ,
78
+
79
+ /// The minimum durability of all inputs consumed by the creator
80
+ /// query prior to creating this tracked struct. If any of those
81
+ /// inputs changes, then the creator query may create this struct
82
+ /// with different values.
83
+ durability : AtomicU8 ,
84
+ }
85
+
86
+ impl < C > Value < C >
87
+ where
88
+ C : Configuration ,
89
+ {
90
+ fn durability ( & self ) -> Durability {
91
+ Durability :: from_u8 ( self . durability . load ( Ordering :: Acquire ) )
92
+ }
75
93
}
76
94
77
95
impl < C : Configuration > Default for JarImpl < C > {
@@ -148,13 +166,25 @@ where
148
166
// SAFETY: Read lock on map is held during this block
149
167
let id = unsafe { * bucket. as_ref ( ) . 1 . get ( ) } ;
150
168
151
- // Sync the value's revision.
152
169
let value = zalsa. table ( ) . get :: < Value < C > > ( id) ;
170
+
171
+ // Sync the value's revision.
153
172
value. last_interned_at . store ( current_revision) ;
154
173
174
+ let durability = if let Some ( ( _, stamp) ) = zalsa_local. active_query ( ) {
175
+ // Record the maximum durability across all queries that intern this value.
176
+ let previous_durability = value
177
+ . durability
178
+ . fetch_max ( stamp. durability . as_u8 ( ) , Ordering :: AcqRel ) ;
179
+
180
+ Durability :: from_u8 ( previous_durability) . max ( stamp. durability )
181
+ } else {
182
+ value. durability ( )
183
+ } ;
184
+
155
185
// Record a dependency on this value.
156
186
let index = self . database_key_index ( id) ;
157
- zalsa_local. report_tracked_read ( index, Durability :: MAX , current_revision) ;
187
+ zalsa_local. report_tracked_read ( index, durability , current_revision) ;
158
188
159
189
return C :: struct_from_id ( id) ;
160
190
}
@@ -170,13 +200,25 @@ where
170
200
let id = * entry. get ( ) ;
171
201
drop ( entry) ;
172
202
173
- // Sync the value's revision.
174
203
let value = zalsa. table ( ) . get :: < Value < C > > ( id) ;
204
+
205
+ // Sync the value's revision.
175
206
value. last_interned_at . store ( current_revision) ;
176
207
208
+ let durability = if let Some ( ( _, stamp) ) = zalsa_local. active_query ( ) {
209
+ // Record the maximum durability across all queries that intern this value.
210
+ let previous_durability = value
211
+ . durability
212
+ . fetch_max ( stamp. durability . as_u8 ( ) , Ordering :: AcqRel ) ;
213
+
214
+ Durability :: from_u8 ( previous_durability) . max ( stamp. durability )
215
+ } else {
216
+ value. durability ( )
217
+ } ;
218
+
177
219
// Record a dependency on this value.
178
220
let index = self . database_key_index ( id) ;
179
- zalsa_local. report_tracked_read ( index, Durability :: MAX , current_revision) ;
221
+ zalsa_local. report_tracked_read ( index, durability , current_revision) ;
180
222
181
223
C :: struct_from_id ( id)
182
224
}
@@ -186,18 +228,30 @@ where
186
228
let zalsa = db. zalsa ( ) ;
187
229
let table = zalsa. table ( ) ;
188
230
231
+ let ( durability, last_interned_at) = match zalsa_local. active_query ( ) {
232
+ // Record the durability of the current query, along with the revision
233
+ // we are interning in.
234
+ Some ( ( _, stamp) ) => ( stamp. durability , current_revision) ,
235
+
236
+ // An interned value created outside of a query is considered immortal.
237
+ // The durability in this case doesn't really matter.
238
+ None => ( Durability :: MAX , Revision :: from ( usize:: MAX ) ) ,
239
+ } ;
240
+
189
241
let next_id = zalsa_local. allocate ( table, self . ingredient_index , || Value :: < C > {
190
242
data : internal_data,
191
243
memos : Default :: default ( ) ,
192
244
syncs : Default :: default ( ) ,
193
245
first_interned_at : current_revision,
194
- last_interned_at : AtomicRevision :: from ( current_revision) ,
246
+ durability : AtomicU8 :: new ( durability. as_u8 ( ) ) ,
247
+ last_interned_at : AtomicRevision :: from ( last_interned_at) ,
195
248
} ) ;
249
+
196
250
entry. insert ( next_id) ;
197
251
198
252
// Record a dependency on this value.
199
253
let index = self . database_key_index ( next_id) ;
200
- zalsa_local. report_tracked_read ( index, Durability :: MAX , current_revision) ;
254
+ zalsa_local. report_tracked_read ( index, durability , current_revision) ;
201
255
202
256
C :: struct_from_id ( next_id)
203
257
}
@@ -217,9 +271,10 @@ where
217
271
/// to the interned item.
218
272
pub fn data < ' db > ( & ' db self , db : & ' db dyn Database , id : Id ) -> & ' db C :: Data < ' db > {
219
273
let value = db. zalsa ( ) . table ( ) . get :: < Value < C > > ( id) ;
274
+ let last_changed_revision = db. zalsa ( ) . last_changed_revision ( value. durability ( ) ) ;
220
275
assert ! (
221
- value. last_interned_at. load( ) >= db . zalsa ( ) . current_revision ( ) ,
222
- "Data was not interned in the current revision."
276
+ value. last_interned_at. load( ) >= last_changed_revision ,
277
+ "Data was not interned in the latest revision for its durability ."
223
278
) ;
224
279
unsafe { Self :: from_internal_data ( & value. data ) }
225
280
}
0 commit comments