Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Entry API for storage2::LazyHashMap #480

Merged
merged 30 commits into from Sep 10, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
98fe682
[core] Rename Entry to Internal Entry
cmichi Jul 22, 2020
660adef
[core] Add Entry API for storage2::LazyHashMap
cmichi Jul 22, 2020
e3149a0
[core] Add storage2::LazyHashMap::len()
cmichi Jul 22, 2020
94775ab
[core] Migrate tests to use storage2::LazyHashMap::len()
cmichi Jul 22, 2020
0384579
[core] Implement FromIterator and Extend for storage2::LazyHashMap
cmichi Jul 23, 2020
7460c5d
[core] Implement macro to generate LazyHashMap + HashMap Entry API tests
cmichi Jul 23, 2020
5dc160f
[core] Remove redundant storage2::HashMap Entry API tests
cmichi Jul 23, 2020
3f7c8d6
[core] Make storage2::HashMap Entry API use storage2::LazyHashMap's E…
cmichi Jul 24, 2020
0e7ebff
[core] Move parameterized Entry API tests into separate file
cmichi Jul 24, 2020
465f73c
[core] Rename InternalEntry to StorageEntry
cmichi Jul 24, 2020
e3a561c
[core] Make lazy_hmap module public
cmichi Jul 24, 2020
6748f60
[core] Generate Entry API benches for LazyHashMap and HashMap from macro
cmichi Jul 24, 2020
2a94f64
[core] Minor streamlining
cmichi Jul 24, 2020
5fe1bec
[core] Display hashmap variant in benchmark description
cmichi Jul 24, 2020
6be446a
[core] Fix comment
cmichi Jul 24, 2020
6bbc5e4
[core] Fix typos
cmichi Jul 31, 2020
f21e3d0
[core] Make more use of BTreeMap Entry API
cmichi Jul 31, 2020
5a39bd3
[core] Replace unwrap with expect
cmichi Jul 31, 2020
b0471e0
[core] Improve comment
cmichi Jul 31, 2020
093a814
[core] Handle loading from storage
cmichi Jul 31, 2020
dc33fc3
[core] Restrict unsafe
cmichi Jul 31, 2020
bc8a1ad
[core] Less ops for case "entry not in cache, but in storage"
cmichi Aug 28, 2020
7292c29
[core] Rename len()
cmichi Aug 31, 2020
c45ad81
[core] Fix typo
cmichi Aug 31, 2020
5a6cefb
[core] Fix visibility
cmichi Aug 31, 2020
debb98e
[core] Address comments
cmichi Sep 1, 2020
f5d011d
[core] Add test to verify that cache is marked as 'Mutated'
cmichi Sep 2, 2020
d64972c
Merge branch 'master' into cmichi-implement-lazyhashmap-entry-api
cmichi Sep 2, 2020
ee66762
[core] Shorten code with utility function
cmichi Sep 2, 2020
758643c
[core] Improve naming
cmichi Sep 2, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 10 additions & 10 deletions core/src/storage2/lazy/entry.rs
Expand Up @@ -39,7 +39,7 @@ use ink_primitives::Key;

/// The entry of a single cached value of a lazy storage data structure.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Entry<T> {
pub struct InternalEntry<T> {
/// The value or `None` if the value has been removed.
value: Option<T>,
/// This is [`EntryState::Mutated`] if the value has been mutated and is in
Expand All @@ -49,7 +49,7 @@ pub struct Entry<T> {
state: Cell<EntryState>,
}

impl<T> Debug for Entry<T>
impl<T> Debug for InternalEntry<T>
where
T: Debug,
{
Expand All @@ -63,12 +63,12 @@ where

#[test]
fn debug_impl_works() {
let e1 = <Entry<i32>>::new(None, EntryState::Preserved);
let e1 = <InternalEntry<i32>>::new(None, EntryState::Preserved);
assert_eq!(
format!("{:?}", &e1),
"Entry { value: None, state: Preserved }",
);
let e2 = Entry::new(Some(42), EntryState::Mutated);
let e2 = InternalEntry::new(Some(42), EntryState::Mutated);
assert_eq!(
format!("{:?}", &e2),
"Entry { value: Some(42), state: Mutated }",
Expand Down Expand Up @@ -99,7 +99,7 @@ impl EntryState {
}
}

impl<T> SpreadLayout for Entry<T>
impl<T> SpreadLayout for InternalEntry<T>
where
T: SpreadLayout,
{
Expand All @@ -124,7 +124,7 @@ where
}
}

impl<T> scale::Encode for Entry<T>
impl<T> scale::Encode for InternalEntry<T>
where
T: scale::Encode,
{
Expand All @@ -149,7 +149,7 @@ where
}
}

impl<T> scale::Decode for Entry<T>
impl<T> scale::Decode for InternalEntry<T>
where
T: scale::Decode,
{
Expand All @@ -161,7 +161,7 @@ where
}
}

impl<T> PackedLayout for Entry<T>
impl<T> PackedLayout for InternalEntry<T>
where
T: PackedLayout,
{
Expand All @@ -181,7 +181,7 @@ where
}
}

impl<T> Entry<T>
impl<T> InternalEntry<T>
where
T: PackedLayout,
{
Expand Down Expand Up @@ -220,7 +220,7 @@ where
}
}

impl<T> Entry<T> {
impl<T> InternalEntry<T> {
/// Creates a new entry with the value and state.
pub fn new(value: Option<T>, state: EntryState) -> Self {
Self {
Expand Down
132 changes: 71 additions & 61 deletions core/src/storage2/lazy/lazy_array.rs
Expand Up @@ -14,8 +14,8 @@

use super::{
CacheCell,
Entry,
EntryState,
InternalEntry,
};
use crate::storage2::traits::{
clear_packed_root,
Expand Down Expand Up @@ -49,12 +49,18 @@ pub type Index = u32;

/// Utility trait for helping with lazy array construction.
pub trait LazyArrayLength<T>:
ArrayLength<CacheCell<Option<Entry<T>>>> + Unsigned
ArrayLength<CacheCell<Option<InternalEntry<T>>>> + Unsigned
{
}
impl<T> LazyArrayLength<T> for UTerm {}
impl<T, N: ArrayLength<CacheCell<Option<Entry<T>>>>> LazyArrayLength<T> for UInt<N, B0> {}
impl<T, N: ArrayLength<CacheCell<Option<Entry<T>>>>> LazyArrayLength<T> for UInt<N, B1> {}
impl<T, N: ArrayLength<CacheCell<Option<InternalEntry<T>>>>> LazyArrayLength<T>
for UInt<N, B0>
{
}
impl<T, N: ArrayLength<CacheCell<Option<InternalEntry<T>>>>> LazyArrayLength<T>
for UInt<N, B1>
{
}

/// A lazy storage array that spans over N storage cells.
///
Expand Down Expand Up @@ -202,12 +208,12 @@ where
N: LazyArrayLength<T>,
{
/// The cache entries of the entry array.
entries: GenericArray<CacheCell<Option<Entry<T>>>, N>,
entries: GenericArray<CacheCell<Option<InternalEntry<T>>>, N>,
}

#[derive(Debug)]
pub struct EntriesIter<'a, T> {
iter: core::slice::Iter<'a, CacheCell<Option<Entry<T>>>>,
iter: core::slice::Iter<'a, CacheCell<Option<InternalEntry<T>>>>,
}

impl<'a, T> EntriesIter<'a, T> {
Expand All @@ -222,7 +228,7 @@ impl<'a, T> EntriesIter<'a, T> {
}

impl<'a, T> Iterator for EntriesIter<'a, T> {
type Item = &'a Option<Entry<T>>;
type Item = &'a Option<InternalEntry<T>>;

fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|cell| cell.as_inner())
Expand Down Expand Up @@ -284,15 +290,19 @@ where
fn put(&self, at: Index, new_value: Option<T>) -> Option<T> {
mem::replace(
unsafe { self.entries.as_slice()[at as usize].get_ptr().as_mut() },
Some(Entry::new(new_value, EntryState::Mutated)),
Some(InternalEntry::new(new_value, EntryState::Mutated)),
)
.map(Entry::into_value)
.map(InternalEntry::into_value)
.flatten()
}

/// Inserts a new entry into the cache and returns an exclusive reference to it.
unsafe fn insert_entry(&self, at: Index, new_entry: Entry<T>) -> NonNull<Entry<T>> {
let entry: &mut Option<Entry<T>> =
unsafe fn insert_entry(
&self,
at: Index,
new_entry: InternalEntry<T>,
) -> NonNull<InternalEntry<T>> {
let entry: &mut Option<InternalEntry<T>> =
&mut *CacheCell::get_ptr(&self.entries[at as usize]).as_ptr();
*entry = Some(new_entry);
entry
Expand All @@ -302,7 +312,7 @@ where
}

/// Returns an exclusive reference to the entry at the given index if any.
unsafe fn get_entry_mut(&self, at: Index) -> Option<&mut Entry<T>> {
unsafe fn get_entry_mut(&self, at: Index) -> Option<&mut InternalEntry<T>> {
if at >= Self::capacity() {
return None
}
Expand Down Expand Up @@ -470,7 +480,7 @@ where
///
/// Tries to load the entry from cache and falls back to lazily load the
/// entry from the contract storage.
fn load_through_cache(&self, at: Index) -> NonNull<Entry<T>> {
fn load_through_cache(&self, at: Index) -> NonNull<InternalEntry<T>> {
assert!(at < self.capacity(), "index is out of bounds");
match unsafe { self.cached_entries.get_entry_mut(at) } {
Some(entry) => {
Expand All @@ -484,7 +494,7 @@ where
.key_at(at)
.map(|key| pull_packed_root_opt::<T>(&key))
.unwrap_or(None);
let entry = Entry::new(value, EntryState::Preserved);
let entry = InternalEntry::new(value, EntryState::Preserved);
unsafe { self.cached_entries.insert_entry(at, entry) }
}
}
Expand All @@ -499,7 +509,7 @@ where
///
/// - If the lazy array is in a state that forbids lazy loading.
/// - If the given index is out of bounds.
fn load_through_cache_mut(&mut self, index: Index) -> &mut Entry<T> {
fn load_through_cache_mut(&mut self, index: Index) -> &mut InternalEntry<T> {
// SAFETY:
// Returning a `&mut Entry<T>` from within a `&mut self` function
// won't allow creating aliasing between exclusive references.
Expand Down Expand Up @@ -589,8 +599,8 @@ where
mod tests {
use super::{
super::{
Entry,
EntryState,
InternalEntry,
},
Index,
LazyArray,
Expand All @@ -609,7 +619,7 @@ mod tests {
/// Asserts that the cached entries of the given `imap` is equal to the `expected` slice.
fn assert_cached_entries<N>(
larray: &LazyArray<u8, N>,
expected: &[(Index, Entry<u8>)],
expected: &[(Index, InternalEntry<u8>)],
) where
N: LazyArrayLength<u8>,
{
Expand Down Expand Up @@ -666,10 +676,10 @@ mod tests {
fn get_works() {
let mut larray = <LazyArray<u8, U4>>::new();
let nothing_changed = &[
(0, Entry::new(None, EntryState::Preserved)),
(1, Entry::new(Some(b'B'), EntryState::Mutated)),
(2, Entry::new(None, EntryState::Preserved)),
(3, Entry::new(Some(b'D'), EntryState::Mutated)),
(0, InternalEntry::new(None, EntryState::Preserved)),
(1, InternalEntry::new(Some(b'B'), EntryState::Mutated)),
(2, InternalEntry::new(None, EntryState::Preserved)),
(3, InternalEntry::new(Some(b'D'), EntryState::Mutated)),
];
// Put some values.
assert_eq!(larray.put_get(0, None), None);
Expand Down Expand Up @@ -710,9 +720,9 @@ mod tests {
assert_cached_entries(
&larray,
&[
(0, Entry::new(None, EntryState::Preserved)),
(1, Entry::new(None, EntryState::Preserved)),
(3, Entry::new(None, EntryState::Preserved)),
(0, InternalEntry::new(None, EntryState::Preserved)),
(1, InternalEntry::new(None, EntryState::Preserved)),
(3, InternalEntry::new(None, EntryState::Preserved)),
],
);
// Override with some values.
Expand All @@ -722,9 +732,9 @@ mod tests {
assert_cached_entries(
&larray,
&[
(0, Entry::new(Some(b'A'), EntryState::Mutated)),
(1, Entry::new(Some(b'B'), EntryState::Mutated)),
(3, Entry::new(None, EntryState::Preserved)),
(0, InternalEntry::new(Some(b'A'), EntryState::Mutated)),
(1, InternalEntry::new(Some(b'B'), EntryState::Mutated)),
(3, InternalEntry::new(None, EntryState::Preserved)),
],
);
// Override some values with none.
Expand All @@ -733,9 +743,9 @@ mod tests {
assert_cached_entries(
&larray,
&[
(0, Entry::new(Some(b'A'), EntryState::Mutated)),
(1, Entry::new(None, EntryState::Mutated)),
(3, Entry::new(None, EntryState::Preserved)),
(0, InternalEntry::new(Some(b'A'), EntryState::Mutated)),
(1, InternalEntry::new(None, EntryState::Mutated)),
(3, InternalEntry::new(None, EntryState::Preserved)),
],
);
}
Expand All @@ -761,9 +771,9 @@ mod tests {
assert_cached_entries(
&larray,
&[
(0, Entry::new(None, EntryState::Mutated)),
(1, Entry::new(Some(b'B'), EntryState::Mutated)),
(3, Entry::new(None, EntryState::Mutated)),
(0, InternalEntry::new(None, EntryState::Mutated)),
(1, InternalEntry::new(Some(b'B'), EntryState::Mutated)),
(3, InternalEntry::new(None, EntryState::Mutated)),
],
);
// Overwrite entries:
Expand All @@ -774,10 +784,10 @@ mod tests {
assert_cached_entries(
&larray,
&[
(0, Entry::new(Some(b'A'), EntryState::Mutated)),
(1, Entry::new(None, EntryState::Mutated)),
(2, Entry::new(Some(b'C'), EntryState::Mutated)),
(3, Entry::new(None, EntryState::Mutated)),
(0, InternalEntry::new(Some(b'A'), EntryState::Mutated)),
(1, InternalEntry::new(None, EntryState::Mutated)),
(2, InternalEntry::new(Some(b'C'), EntryState::Mutated)),
(3, InternalEntry::new(None, EntryState::Mutated)),
],
);
}
Expand All @@ -793,10 +803,10 @@ mod tests {
fn swap_works() {
let mut larray = <LazyArray<u8, U4>>::new();
let nothing_changed = &[
(0, Entry::new(Some(b'A'), EntryState::Mutated)),
(1, Entry::new(Some(b'B'), EntryState::Mutated)),
(2, Entry::new(None, EntryState::Preserved)),
(3, Entry::new(None, EntryState::Preserved)),
(0, InternalEntry::new(Some(b'A'), EntryState::Mutated)),
(1, InternalEntry::new(Some(b'B'), EntryState::Mutated)),
(2, InternalEntry::new(None, EntryState::Preserved)),
(3, InternalEntry::new(None, EntryState::Preserved)),
];
// Put some values.
assert_eq!(larray.put_get(0, Some(b'A')), None);
Expand All @@ -818,21 +828,21 @@ mod tests {
assert_cached_entries(
&larray,
&[
(0, Entry::new(None, EntryState::Mutated)),
(1, Entry::new(Some(b'B'), EntryState::Mutated)),
(2, Entry::new(Some(b'A'), EntryState::Mutated)),
(3, Entry::new(None, EntryState::Preserved)),
(0, InternalEntry::new(None, EntryState::Mutated)),
(1, InternalEntry::new(Some(b'B'), EntryState::Mutated)),
(2, InternalEntry::new(Some(b'A'), EntryState::Mutated)),
(3, InternalEntry::new(None, EntryState::Preserved)),
],
);
// Swap `Some` and `Some`:
larray.swap(1, 2);
assert_cached_entries(
&larray,
&[
(0, Entry::new(None, EntryState::Mutated)),
(1, Entry::new(Some(b'A'), EntryState::Mutated)),
(2, Entry::new(Some(b'B'), EntryState::Mutated)),
(3, Entry::new(None, EntryState::Preserved)),
(0, InternalEntry::new(None, EntryState::Mutated)),
(1, InternalEntry::new(Some(b'A'), EntryState::Mutated)),
(2, InternalEntry::new(Some(b'B'), EntryState::Mutated)),
(3, InternalEntry::new(None, EntryState::Preserved)),
],
);
}
Expand All @@ -856,10 +866,10 @@ mod tests {
env::test::run_test::<env::DefaultEnvTypes, _>(|_| {
let mut larray = <LazyArray<u8, U4>>::new();
let nothing_changed = &[
(0, Entry::new(Some(b'A'), EntryState::Mutated)),
(1, Entry::new(Some(b'B'), EntryState::Mutated)),
(2, Entry::new(None, EntryState::Preserved)),
(3, Entry::new(None, EntryState::Preserved)),
(0, InternalEntry::new(Some(b'A'), EntryState::Mutated)),
(1, InternalEntry::new(Some(b'B'), EntryState::Mutated)),
(2, InternalEntry::new(None, EntryState::Preserved)),
(3, InternalEntry::new(None, EntryState::Preserved)),
];
// Put some values.
assert_eq!(larray.put_get(0, Some(b'A')), None);
Expand All @@ -883,10 +893,10 @@ mod tests {
assert_cached_entries(
&larray2,
&[
(0, Entry::new(Some(b'A'), EntryState::Preserved)),
(1, Entry::new(Some(b'B'), EntryState::Preserved)),
(2, Entry::new(None, EntryState::Preserved)),
(3, Entry::new(None, EntryState::Preserved)),
(0, InternalEntry::new(Some(b'A'), EntryState::Preserved)),
(1, InternalEntry::new(Some(b'B'), EntryState::Preserved)),
(2, InternalEntry::new(None, EntryState::Preserved)),
(3, InternalEntry::new(None, EntryState::Preserved)),
],
);
// Clear the first lazy index map instance and reload another instance
Expand All @@ -912,10 +922,10 @@ mod tests {
assert_cached_entries(
&larray3,
&[
(0, Entry::new(None, EntryState::Preserved)),
(1, Entry::new(None, EntryState::Preserved)),
(2, Entry::new(None, EntryState::Preserved)),
(3, Entry::new(None, EntryState::Preserved)),
(0, InternalEntry::new(None, EntryState::Preserved)),
(1, InternalEntry::new(None, EntryState::Preserved)),
(2, InternalEntry::new(None, EntryState::Preserved)),
(3, InternalEntry::new(None, EntryState::Preserved)),
],
);
Ok(())
Expand Down