Skip to content

Commit d746081

Browse files
committed
starknet_patricia_storage: two layer storage
1 parent 6d471bd commit d746081

2 files changed

Lines changed: 123 additions & 0 deletions

File tree

crates/starknet_patricia_storage/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@ pub mod short_key_storage;
1515
#[cfg(test)]
1616
pub mod storage_test;
1717
pub mod storage_trait;
18+
pub mod two_layer_storage;
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use crate::storage_trait::{
2+
DbKey,
3+
DbValue,
4+
ImmutableReadOnlyStorage,
5+
PatriciaStorageResult,
6+
ReadOnlyStorage,
7+
};
8+
9+
/// Overlay reads on top of a borrowed base [`ImmutableReadOnlyStorage`]: `overlay` is consulted
10+
/// first via [`ImmutableReadOnlyStorage::get`] / [`ImmutableReadOnlyStorage::mget`]; on miss,
11+
/// reads relay to `base`.
12+
///
13+
/// [`ReadOnlyStorage::get_mut`] / [`ReadOnlyStorage::mget_mut`] use the same immutable overlay and
14+
/// base paths on overlay misses so the composite implements [`ReadOnlyStorage`] while holding
15+
/// `&'a Base`. Patricia paths reads do not mutate the underlying storage.
16+
/// This allows passing `TwoLayerStorage` to `fetch_all_patricia_paths`, which requires `&mut`
17+
/// [`ReadOnlyStorage`].
18+
pub struct TwoLayerStorage<'a, Overlay, Base>
19+
where
20+
Overlay: ImmutableReadOnlyStorage + Sync,
21+
Base: ImmutableReadOnlyStorage + Sync + ?Sized,
22+
{
23+
pub overlay: Overlay,
24+
pub base: &'a Base,
25+
}
26+
27+
impl<'a, Overlay, Base> TwoLayerStorage<'a, Overlay, Base>
28+
where
29+
Overlay: ImmutableReadOnlyStorage + Sync,
30+
Base: ImmutableReadOnlyStorage + Sync + ?Sized,
31+
{
32+
pub fn new(overlay: Overlay, base: &'a Base) -> Self {
33+
Self { overlay, base }
34+
}
35+
}
36+
37+
impl<'a, Overlay, Base> ReadOnlyStorage for TwoLayerStorage<'a, Overlay, Base>
38+
where
39+
Overlay: ImmutableReadOnlyStorage + Sync,
40+
Base: ImmutableReadOnlyStorage + Sync + ?Sized,
41+
{
42+
async fn get_mut(&mut self, key: &DbKey) -> PatriciaStorageResult<Option<DbValue>> {
43+
Ok(match self.overlay.get(key).await? {
44+
Some(v) => Some(v),
45+
None => self.base.get(key).await?,
46+
})
47+
}
48+
49+
async fn mget_mut(&mut self, keys: &[&DbKey]) -> PatriciaStorageResult<Vec<Option<DbValue>>> {
50+
let mut out = self.overlay.mget(keys).await?;
51+
let mut miss_indices = Vec::new();
52+
let mut miss_keys = Vec::new();
53+
for (i, v) in out.iter().enumerate() {
54+
if v.is_none() {
55+
miss_indices.push(i);
56+
miss_keys.push(keys[i]);
57+
}
58+
}
59+
if !miss_keys.is_empty() {
60+
let fetched = self.base.mget(&miss_keys).await?;
61+
for (idx, val) in miss_indices.into_iter().zip(fetched) {
62+
out[idx] = val;
63+
}
64+
}
65+
Ok(out)
66+
}
67+
}
68+
69+
#[cfg(test)]
70+
mod tests {
71+
use super::TwoLayerStorage;
72+
use crate::map_storage::MapStorage;
73+
use crate::storage_trait::{DbKey, DbValue, ReadOnlyStorage, Storage};
74+
75+
#[tokio::test]
76+
async fn read_falls_through_to_base() {
77+
let key = DbKey(vec![1, 2, 3]);
78+
let val = DbValue(vec![9]);
79+
let mut base = MapStorage::default();
80+
base.0.insert(key.clone(), val.clone());
81+
82+
let mut two = TwoLayerStorage::new(MapStorage::default(), &base);
83+
assert_eq!(two.get_mut(&key).await.unwrap(), Some(val));
84+
}
85+
86+
#[tokio::test]
87+
async fn overlay_shadows_base() {
88+
let key = DbKey(vec![1]);
89+
let base_val = DbValue(vec![1]);
90+
let over_val = DbValue(vec![2]);
91+
let mut base = MapStorage::default();
92+
base.0.insert(key.clone(), base_val);
93+
94+
let mut two = TwoLayerStorage::new(MapStorage::default(), &base);
95+
two.overlay.set(key.clone(), over_val.clone()).await.unwrap();
96+
assert_eq!(two.get_mut(&key).await.unwrap(), Some(over_val));
97+
}
98+
99+
#[tokio::test]
100+
async fn delete_drops_overlay_entry_and_sees_base() {
101+
let key = DbKey(vec![7]);
102+
let base_val = DbValue(vec![42]);
103+
let mut base = MapStorage::default();
104+
base.0.insert(key.clone(), base_val.clone());
105+
106+
let mut two = TwoLayerStorage::new(MapStorage::default(), &base);
107+
two.overlay.set(key.clone(), DbValue(vec![99])).await.unwrap();
108+
two.overlay.delete(&key).await.unwrap();
109+
assert_eq!(two.get_mut(&key).await.unwrap(), Some(base_val));
110+
}
111+
112+
#[tokio::test]
113+
async fn mget_mut_uses_immutable_base_mget_on_miss() {
114+
let key = DbKey(vec![3]);
115+
let val = DbValue(vec![11]);
116+
let mut base = MapStorage::default();
117+
base.0.insert(key.clone(), val.clone());
118+
119+
let mut layered = TwoLayerStorage::new(MapStorage::default(), &base);
120+
assert_eq!(layered.get_mut(&key).await.unwrap(), Some(val));
121+
}
122+
}

0 commit comments

Comments
 (0)