1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use arc_swap::Guard;
use crate::{database::AsSalsaDatabase, runtime::StampedValue, storage::HasJarsDyn, AsId};
use super::{Configuration, DynDb, FunctionIngredient};
impl<C> FunctionIngredient<C>
where
C: Configuration,
{
pub fn fetch(&self, db: &DynDb<C>, key: C::Key) -> &C::Value {
let runtime = db.runtime();
runtime.unwind_if_revision_cancelled(db);
let StampedValue {
value,
durability,
changed_at,
} = self.compute_value(db, key);
if let Some(evicted) = self.lru.record_use(key.as_id()) {
self.evict(AsId::from_id(evicted));
}
db.runtime().report_tracked_read(
self.database_key_index(key).into(),
durability,
changed_at,
);
value
}
#[inline]
fn compute_value(&self, db: &DynDb<C>, key: C::Key) -> StampedValue<&C::Value> {
loop {
if let Some(value) = self.fetch_hot(db, key).or_else(|| self.fetch_cold(db, key)) {
return value;
}
}
}
#[inline]
fn fetch_hot(&self, db: &DynDb<C>, key: C::Key) -> Option<StampedValue<&C::Value>> {
let memo_guard = self.memo_map.get(key);
if let Some(memo) = &memo_guard {
if memo.value.is_some() {
let runtime = db.runtime();
if self.shallow_verify_memo(db, runtime, self.database_key_index(key), memo) {
let value = unsafe {
self.extend_memo_lifetime(memo).unwrap()
};
return Some(memo.revisions.stamped_value(value));
}
}
}
None
}
fn fetch_cold(&self, db: &DynDb<C>, key: C::Key) -> Option<StampedValue<&C::Value>> {
let runtime = db.runtime();
let database_key_index = self.database_key_index(key);
let _claim_guard = self
.sync_map
.claim(db.as_salsa_database(), database_key_index)?;
let active_query = runtime.push_query(database_key_index);
let opt_old_memo = self.memo_map.get(key).map(Guard::into_inner);
if let Some(old_memo) = &opt_old_memo {
if old_memo.value.is_some() && self.deep_verify_memo(db, old_memo, &active_query) {
let value = unsafe {
self.extend_memo_lifetime(old_memo).unwrap()
};
return Some(old_memo.revisions.stamped_value(value));
}
}
Some(self.execute(db, active_query, opt_old_memo))
}
fn evict(&self, key: C::Key) {
self.memo_map.evict(key);
}
}