@@ -6,7 +6,7 @@ use std::{
6
6
use crossbeam:: queue:: SegQueue ;
7
7
use dashmap:: mapref:: one:: RefMut ;
8
8
9
- use crate :: { alloc:: Alloc , hash:: FxDashMap , Id , Revision } ;
9
+ use crate :: { alloc:: Alloc , hash:: FxDashMap , zalsa :: Zalsa , Id , Revision } ;
10
10
11
11
use super :: { Configuration , KeyStruct , Value } ;
12
12
@@ -100,14 +100,22 @@ where
100
100
}
101
101
102
102
pub fn validate ( & self , current_revision : Revision , id : Id ) {
103
- let mut data = self . map . get_mut ( & id) . unwrap ( ) ;
103
+ Self :: validate_in_map ( & self . map , current_revision, id)
104
+ }
105
+
106
+ pub fn validate_in_map (
107
+ map : & FxDashMap < Id , Alloc < Value < C > > > ,
108
+ current_revision : Revision ,
109
+ id : Id ,
110
+ ) {
111
+ let mut data = map. get_mut ( & id) . unwrap ( ) ;
104
112
105
113
// UNSAFE: We never permit `&`-access in the current revision until data.created_at
106
114
// has been updated to the current revision (which we check below).
107
115
let data = unsafe { data. as_mut ( ) } ;
108
116
109
117
// Never update a struct twice in the same revision.
110
- assert ! ( data. created_at < current_revision) ;
118
+ assert ! ( data. created_at <= current_revision) ;
111
119
data. created_at = current_revision;
112
120
}
113
121
@@ -185,7 +193,7 @@ where
185
193
let data_ref: & Value < C > = unsafe { data. as_ref ( ) } ;
186
194
187
195
// Before we drop the lock, check that the value has
188
- // been updated in this revision. This is what allows us to return a ``
196
+ // been updated in this revision. This is what allows us to return a Struct
189
197
let created_at = data_ref. created_at ;
190
198
assert ! (
191
199
created_at == current_revision,
@@ -200,6 +208,56 @@ where
200
208
unsafe { C :: struct_from_raw ( data. as_raw ( ) ) }
201
209
}
202
210
211
+ /// Lookup an existing tracked struct from the map, maybe validating it to current revision.
212
+ ///
213
+ /// Validates to current revision if the struct was last created/validated in a revision that
214
+ /// is still current for the struct's durability. That is, if the struct is HIGH durability
215
+ /// (created by a HIGH durability query) and was created in R2, and we are now at R3 but no
216
+ /// HIGH durability input has changed since R2, the struct is still valid and we can validate
217
+ /// it to R3.
218
+ ///
219
+ /// # Panics
220
+ ///
221
+ /// * If the value is not present in the map.
222
+ /// * If the value has not been updated in the last-changed revision for its durability.
223
+ fn get_and_validate_last_changed < ' db > (
224
+ map : & ' db FxDashMap < Id , Alloc < Value < C > > > ,
225
+ zalsa : & Zalsa ,
226
+ id : Id ,
227
+ ) -> C :: Struct < ' db > {
228
+ let data = map. get ( & id) . unwrap ( ) ;
229
+
230
+ // UNSAFE: We permit `&`-access in the current revision once data.created_at
231
+ // has been updated to the current revision (which we ensure below).
232
+ let data_ref: & Value < C > = unsafe { data. as_ref ( ) } ;
233
+
234
+ // Before we drop the lock, check that the value has been updated in the most recent
235
+ // version in which the query that created it could have changed (based on durability).
236
+ let created_at = data_ref. created_at ;
237
+ let last_changed = zalsa. last_changed_revision ( data_ref. durability ) ;
238
+ assert ! (
239
+ created_at >= last_changed,
240
+ "access to tracked struct from obsolete revision"
241
+ ) ;
242
+
243
+ // Unsafety clause:
244
+ //
245
+ // * Value will not be updated again in this revision,
246
+ // and revision will not change so long as runtime is shared
247
+ // * We only remove values from the map when we have `&mut self`
248
+ let ret = unsafe { C :: struct_from_raw ( data. as_raw ( ) ) } ;
249
+
250
+ drop ( data) ;
251
+
252
+ // Validate in current revision, if necessary.
253
+ let current_revision = zalsa. current_revision ( ) ;
254
+ if last_changed < current_revision {
255
+ Self :: validate_in_map ( map, current_revision, id) ;
256
+ }
257
+
258
+ ret
259
+ }
260
+
203
261
/// Remove the entry for `id` from the map.
204
262
///
205
263
/// NB. the data won't actually be freed until `drop_deleted_entries` is called.
@@ -233,6 +291,10 @@ where
233
291
pub fn get ( & self , current_revision : Revision , id : Id ) -> C :: Struct < ' _ > {
234
292
StructMap :: get_from_map ( & self . map , current_revision, id)
235
293
}
294
+
295
+ pub fn get_and_validate_last_changed < ' db > ( & ' db self , zalsa : & Zalsa , id : Id ) -> C :: Struct < ' db > {
296
+ StructMap :: get_and_validate_last_changed ( & self . map , zalsa, id)
297
+ }
236
298
}
237
299
238
300
/// A mutable reference to the data for a single struct.
0 commit comments