Skip to content

Commit e0acd6f

Browse files
committed
Added Cell caching of length to improve efficiency
1 parent dc4f792 commit e0acd6f

File tree

4 files changed

+111
-50
lines changed

4 files changed

+111
-50
lines changed

packages/storage/Readme.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ The same conventions from `Item` also apply here, that is:
9898
To import and intialize this storage object as a constant in `state.rs`, do the following:
9999

100100
```rust
101-
use secret_toolkit_storage::{AppendStore}
101+
use secret_toolkit::storage::{AppendStore}
102102
```
103103

104104
```rust
@@ -121,7 +121,7 @@ The main user facing methods to read/write to AppendStore are `pop`, `push`, `ge
121121
AppendStore also implements a readonly iterator feature. This feature is also used to create a paging wrapper method called `paging`. The way you create the iterator is:
122122

123123
```rust
124-
let iter = user_count_store.iter(&deps.storage)?
124+
let iter = user_count_store.iter(&deps.storage)?;
125125
```
126126

127127
More examples can be found in the unit tests. And the paging wrapper is used in the following manner:
@@ -133,6 +133,19 @@ let page_size: u32 = 5;
133133
let values = user_count_store.paging(&deps.storage, start_page, page_size)?;
134134
```
135135

136+
> ❗ When using any iterators in any of the storage objects, the following will result in a compiling error.
137+
138+
```rust
139+
let iterator = COUNT_STORE.iter(&deps.storage)?;
140+
```
141+
142+
However, the follwoing will not result in an error:
143+
144+
```rust
145+
let append_store = COUNT_STORE
146+
let iterator = append_store.iter(&deps.storage)?;
147+
```
148+
136149
### **DequeStore**
137150

138151
This is a storage wrapper based on AppendStore that replicates a double ended list. This storage object allows the user to efficiently pop/push items to either end of the list.

packages/storage/src/append_store.rs

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! This is achieved by storing each item in a separate storage entry. A special key is reserved
55
//! for storing the length of the collection so far.
66
use std::any::type_name;
7+
use std::cell::Cell;
78
use std::{convert::TryInto};
89
use std::marker::PhantomData;
910

@@ -25,6 +26,7 @@ pub struct AppendStore<'a, T, Ser = Bincode2>
2526
/// needed if any suffixes were added to the original namespace.
2627
/// therefore it is not necessarily same as the namespace.
2728
prefix: Option<Vec<u8>>,
29+
length: Cell<Option<u32>>,
2830
item_type: PhantomData<T>,
2931
serialization_type: PhantomData<Ser>,
3032
}
@@ -35,6 +37,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser>{
3537
Self {
3638
namespace: prefix,
3739
prefix: None,
40+
length: Cell::new(None),
3841
item_type: PhantomData,
3942
serialization_type: PhantomData,
4043
}
@@ -50,6 +53,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser>{
5053
Self {
5154
namespace: self.namespace,
5255
prefix: Some(prefix),
56+
length: Cell::new(None),
5357
item_type: self.item_type,
5458
serialization_type: self.serialization_type,
5559
}
@@ -59,13 +63,20 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser>{
5963
impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> {
6064
/// gets the length from storage, and otherwise sets it to 0
6165
pub fn get_len<S: ReadonlyStorage>(&self, storage: &S) -> StdResult<u32> {
62-
let len_key = [self.as_slice(), LEN_KEY].concat();
63-
if let Some(len_vec) = storage.get(&len_key) {
64-
let len_bytes = len_vec.as_slice().try_into().map_err(|err| StdError::parse_err("u32", err))?;
65-
let len = u32::from_be_bytes(len_bytes);
66-
Ok(len)
67-
} else {
68-
Ok(0)
66+
match self.length.get() {
67+
Some(len) => { Ok(len) },
68+
None => {
69+
let len_key = [self.as_slice(), LEN_KEY].concat();
70+
if let Some(len_vec) = storage.get(&len_key) {
71+
let len_bytes = len_vec.as_slice().try_into().map_err(|err| StdError::parse_err("u32", err))?;
72+
let len = u32::from_be_bytes(len_bytes);
73+
self.length.set(Some(len));
74+
Ok(len)
75+
} else {
76+
self.length.set(Some(0));
77+
Ok(0)
78+
}
79+
},
6980
}
7081
}
7182
/// checks if the collection has any elements
@@ -87,6 +98,7 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> {
8798
/// Set the length of the collection
8899
fn set_len<S: Storage>(&self, storage: &mut S, len: u32) {
89100
let len_key = [self.as_slice(), LEN_KEY].concat();
101+
self.length.set(Some(len));
90102
storage.set(&len_key, &len.to_be_bytes());
91103
}
92104
/// Clear the collection
@@ -194,25 +206,14 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> AppendStore<'a, T, Ser> {
194206
}
195207
}
196208

197-
impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for AppendStore<'a, T, Ser> {
198-
fn clone(&self) -> Self {
199-
Self {
200-
namespace: self.namespace.clone(),
201-
prefix: self.prefix.clone(),
202-
item_type: self.item_type.clone(),
203-
serialization_type: self.serialization_type.clone()
204-
}
205-
}
206-
}
207-
208209
/// An iterator over the contents of the append store.
209210
pub struct AppendStoreIter<'a, T, S, Ser>
210211
where
211212
T: Serialize + DeserializeOwned,
212213
S: ReadonlyStorage,
213214
Ser: Serde,
214215
{
215-
append_store: AppendStore<'a, T, Ser>,
216+
append_store: &'a AppendStore<'a, T, Ser>,
216217
storage: &'a S,
217218
start: u32,
218219
end: u32,
@@ -232,7 +233,7 @@ impl<'a, T, S, Ser> AppendStoreIter<'a, T, S, Ser>
232233
end: u32
233234
) -> Self {
234235
Self {
235-
append_store: append_store.clone(),
236+
append_store,
236237
storage,
237238
start,
238239
end,
@@ -336,6 +337,39 @@ mod tests {
336337
Ok(())
337338
}
338339

340+
#[test]
341+
fn test_length() -> StdResult<()> {
342+
let mut storage = MockStorage::new();
343+
let append_store: AppendStore<i32> = AppendStore::new(b"test");
344+
345+
assert_eq!(append_store.length, Cell::new(None));
346+
assert_eq!(append_store.get_len(&mut storage)?, 0);
347+
assert_eq!(append_store.length, Cell::new(Some(0)));
348+
349+
append_store.push(&mut storage, &1234)?;
350+
append_store.push(&mut storage, &2143)?;
351+
append_store.push(&mut storage, &3412)?;
352+
append_store.push(&mut storage, &4321)?;
353+
assert_eq!(append_store.length, Cell::new(Some(4)));
354+
assert_eq!(append_store.get_len(&mut storage)?, 4);
355+
356+
assert_eq!(append_store.pop(&mut storage), Ok(4321));
357+
assert_eq!(append_store.pop(&mut storage), Ok(3412));
358+
assert_eq!(append_store.length, Cell::new(Some(2)));
359+
assert_eq!(append_store.get_len(&mut storage)?, 2);
360+
361+
assert_eq!(append_store.pop(&mut storage), Ok(2143));
362+
assert_eq!(append_store.pop(&mut storage), Ok(1234));
363+
assert_eq!(append_store.length, Cell::new(Some(0)));
364+
assert_eq!(append_store.get_len(&mut storage)?, 0);
365+
366+
assert!(append_store.pop(&mut storage).is_err());
367+
assert_eq!(append_store.length, Cell::new(Some(0)));
368+
assert_eq!(append_store.get_len(&mut storage)?, 0);
369+
370+
Ok(())
371+
}
372+
339373
#[test]
340374
fn test_iterator() -> StdResult<()> {
341375
let mut storage = MockStorage::new();

packages/storage/src/deque_store.rs

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
//! A special key is reserved for storing the length of the collection so far.
66
//! Another special key is reserved for storing the offset of the collection.
77
use std::any::type_name;
8+
use std::cell::Cell;
89
use std::{convert::TryInto};
910
use std::marker::PhantomData;
1011

@@ -27,6 +28,8 @@ pub struct DequeStore<'a, T, Ser = Bincode2>
2728
/// needed if any suffixes were added to the original namespace.
2829
/// therefore it is not necessarily same as the namespace.
2930
prefix: Option<Vec<u8>>,
31+
length: Cell<Option<u32>>,
32+
offset: Cell<Option<u32>>,
3033
item_type: PhantomData<T>,
3134
serialization_type: PhantomData<Ser>,
3235
}
@@ -37,6 +40,8 @@ impl<'a, 'b, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser>
3740
Self {
3841
namespace: prefix,
3942
prefix: None,
43+
length: Cell::new(None),
44+
offset: Cell::new(None),
4045
item_type: PhantomData,
4146
serialization_type: PhantomData,
4247
}
@@ -52,6 +57,8 @@ impl<'a, 'b, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser>
5257
Self {
5358
namespace: self.namespace,
5459
prefix: Some(prefix),
60+
length: Cell::new(None),
61+
offset: Cell::new(None),
5562
item_type: self.item_type,
5663
serialization_type: self.serialization_type,
5764
}
@@ -61,11 +68,33 @@ impl<'a, 'b, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser>
6168
impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> {
6269
/// gets the length from storage, and otherwise sets it to 0
6370
pub fn get_len<S: ReadonlyStorage>(&self, storage: &S) -> StdResult<u32> {
64-
self._get_u32(storage, LEN_KEY)
71+
match self.length.get() {
72+
Some(len) => { Ok(len) },
73+
None => {
74+
match self._get_u32(storage, LEN_KEY) {
75+
Ok(len) => {
76+
self.length.set(Some(len));
77+
Ok(len)
78+
},
79+
Err(e) => { Err(e) },
80+
}
81+
},
82+
}
6583
}
6684
/// gets the offset from storage, and otherwise sets it to 0
6785
pub fn get_off<S: ReadonlyStorage>(&self, storage: &S) -> StdResult<u32> {
68-
self._get_u32(storage, OFFSET_KEY)
86+
match self.offset.get() {
87+
Some(len) => { Ok(len) },
88+
None => {
89+
match self._get_u32(storage, OFFSET_KEY) {
90+
Ok(len) => {
91+
self.offset.set(Some(len));
92+
Ok(len)
93+
},
94+
Err(e) => { Err(e) },
95+
}
96+
},
97+
}
6998
}
7099
/// gets offset or length
71100
fn _get_u32<S: ReadonlyStorage>(&self, storage: &S, key: &[u8]) -> StdResult<u32> {
@@ -99,10 +128,12 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> {
99128
}
100129
/// Set the length of the collection
101130
fn set_len<S: Storage>(&self, storage: &mut S, len: u32) {
131+
self.length.set(Some(len));
102132
self._set_u32(storage, LEN_KEY, len)
103133
}
104134
/// Set the offset of the collection
105135
fn set_off<S: Storage>(&self, storage: &mut S, off: u32) {
136+
self.offset.set(Some(off));
106137
self._set_u32(storage, OFFSET_KEY, off)
107138
}
108139
/// Set the length or offset of the collection
@@ -248,25 +279,14 @@ impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> DequeStore<'a, T, Ser> {
248279
}
249280
}
250281

251-
impl<'a, T: Serialize + DeserializeOwned, Ser: Serde> Clone for DequeStore<'a, T, Ser> {
252-
fn clone(&self) -> Self {
253-
Self {
254-
namespace: self.namespace.clone(),
255-
prefix: self.prefix.clone(),
256-
item_type: self.item_type.clone(),
257-
serialization_type: self.serialization_type.clone()
258-
}
259-
}
260-
}
261-
262282
/// An iterator over the contents of the deque store.
263283
pub struct DequeStoreIter<'a, T, S, Ser>
264284
where
265285
T: Serialize + DeserializeOwned,
266286
S: ReadonlyStorage,
267287
Ser: Serde,
268288
{
269-
deque_store: DequeStore<'a, T, Ser>,
289+
deque_store: &'a DequeStore<'a, T, Ser>,
270290
storage: &'a S,
271291
start: u32,
272292
end: u32,
@@ -286,7 +306,7 @@ impl<'a, T, S, Ser> DequeStoreIter<'a, T, S, Ser>
286306
end: u32
287307
) -> Self {
288308
Self {
289-
deque_store: deque_store.clone(),
309+
deque_store,
290310
storage,
291311
start,
292312
end,

packages/storage/src/keymap.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -366,19 +366,6 @@ impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser:
366366
}
367367
}
368368

369-
impl<'a, K: Serialize + DeserializeOwned, T: Serialize + DeserializeOwned, Ser: Serde> Clone for Keymap<'a, K, T, Ser> {
370-
fn clone(&self) -> Self {
371-
Self {
372-
namespace: self.namespace.clone(),
373-
prefix: self.prefix.clone(),
374-
length: Cell::new(None),
375-
key_type: self.key_type.clone(),
376-
item_type: self.item_type.clone(),
377-
serialization_type: self.serialization_type.clone()
378-
}
379-
}
380-
}
381-
382369
/// An iterator over the keys of the Keymap.
383370
pub struct KeyIter<'a, K, T, S, Ser>
384371
where
@@ -1275,29 +1262,36 @@ mod tests {
12751262
number: 1111,
12761263
};
12771264

1265+
assert_eq!(keymap.length, Cell::new(None));
12781266
assert_eq!(keymap.get_len(&storage)?, 0);
1267+
assert_eq!(keymap.length, Cell::new(Some(0)));
12791268

12801269
let key1 = "k1".to_string();
12811270
let key2 = "k2".to_string();
12821271

12831272
keymap.insert(&mut storage, &key1, foo1.clone())?;
12841273
assert_eq!(keymap.get_len(&storage)?, 1);
1274+
assert_eq!(keymap.length, Cell::new(Some(1)));
12851275

12861276
// add another item
12871277
keymap.insert(&mut storage, &key2, foo2.clone())?;
12881278
assert_eq!(keymap.get_len(&storage)?, 2);
1279+
assert_eq!(keymap.length, Cell::new(Some(2)));
12891280

12901281
// remove item and check length
12911282
keymap.remove(&mut storage, &key1)?;
12921283
assert_eq!(keymap.get_len(&storage)?, 1);
1284+
assert_eq!(keymap.length, Cell::new(Some(1)));
12931285

12941286
// override item (should not change length)
12951287
keymap.insert(&mut storage, &key2, foo1)?;
12961288
assert_eq!(keymap.get_len(&storage)?, 1);
1289+
assert_eq!(keymap.length, Cell::new(Some(1)));
12971290

12981291
// remove item and check length
12991292
keymap.remove(&mut storage, &key2)?;
13001293
assert_eq!(keymap.get_len(&storage)?, 0);
1294+
assert_eq!(keymap.length, Cell::new(Some(0)));
13011295

13021296
Ok(())
13031297
}

0 commit comments

Comments
 (0)