Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 6 additions & 102 deletions linera-views/src/views/key_value_store_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ use serde::{Deserialize, Serialize};
use crate::{
batch::{Batch, WriteOperation},
common::{
from_bytes_option, from_bytes_option_or_default, get_key_range_for_prefix, get_upper_bound,
DeletionSet, HasherOutput, SuffixClosedSetIterator, Update,
from_bytes_option, get_key_range_for_prefix, get_upper_bound, DeletionSet, HasherOutput,
SuffixClosedSetIterator, Update,
},
context::Context,
hashable_wrapper::WrappedHashableContainerView,
historical_hash_wrapper::HistoricallyHashableView,
map_view::ByteMapView,
store::ReadableKeyValueStore,
views::{ClonableView, HashableView, Hasher, ReplaceContext, View, ViewError, MIN_VIEW_TAG},
};
Expand Down Expand Up @@ -141,12 +140,8 @@ use {
enum KeyTag {
/// Prefix for the indices of the view.
Index = MIN_VIEW_TAG,
/// The total stored size
TotalSize,
/// The prefix where the sizes are being stored
Sizes,
/// Prefix for the hash.
Hash,
/// Prefix for the hash. We fix the index for compatibility with existing contracts.
Hash = MIN_VIEW_TAG + 3,
}

/// A pair containing the key and value size.
Expand Down Expand Up @@ -211,12 +206,6 @@ pub struct KeyValueStoreView<C> {
deletion_set: DeletionSet,
/// Pending changes not yet persisted to storage.
updates: BTreeMap<Vec<u8>, Update<Vec<u8>>>,
/// The total size of keys and values persisted in storage.
stored_total_size: SizeData,
/// The total size of keys and values including pending changes.
total_size: SizeData,
/// Map of key to value size for tracking storage usage.
sizes: ByteMapView<C, u32>,
/// The hash persisted in storage.
#[allocative(visit = visit_allocative_simple)]
stored_hash: Option<HasherOutput>,
Expand All @@ -237,17 +226,14 @@ impl<C: Context, C2: Context> ReplaceContext<C2> for KeyValueStoreView<C> {
context: ctx.clone()(self.context()),
deletion_set: self.deletion_set.clone(),
updates: self.updates.clone(),
stored_total_size: self.stored_total_size,
total_size: self.total_size,
sizes: self.sizes.with_context(ctx.clone()).await,
stored_hash: self.stored_hash,
hash: Mutex::new(hash),
}
}
}

impl<C: Context> View for KeyValueStoreView<C> {
const NUM_INIT_KEYS: usize = 2 + ByteMapView::<C, u32>::NUM_INIT_KEYS;
const NUM_INIT_KEYS: usize = 1;

type Context = C;

Expand All @@ -257,31 +243,16 @@ impl<C: Context> View for KeyValueStoreView<C> {

fn pre_load(context: &C) -> Result<Vec<Vec<u8>>, ViewError> {
let key_hash = context.base_key().base_tag(KeyTag::Hash as u8);
let key_total_size = context.base_key().base_tag(KeyTag::TotalSize as u8);
let mut v = vec![key_hash, key_total_size];
let base_key = context.base_key().base_tag(KeyTag::Sizes as u8);
let context_sizes = context.clone_with_base_key(base_key);
v.extend(ByteMapView::<C, u32>::pre_load(&context_sizes)?);
let v = vec![key_hash];
Ok(v)
}

fn post_load(context: C, values: &[Option<Vec<u8>>]) -> Result<Self, ViewError> {
let hash = from_bytes_option(values.first().ok_or(ViewError::PostLoadValuesError)?)?;
let total_size =
from_bytes_option_or_default(values.get(1).ok_or(ViewError::PostLoadValuesError)?)?;
let base_key = context.base_key().base_tag(KeyTag::Sizes as u8);
let context_sizes = context.clone_with_base_key(base_key);
let sizes = ByteMapView::post_load(
context_sizes,
values.get(2..).ok_or(ViewError::PostLoadValuesError)?,
)?;
Ok(Self {
context,
deletion_set: DeletionSet::new(),
updates: BTreeMap::new(),
stored_total_size: total_size,
total_size,
sizes,
stored_hash: hash,
hash: Mutex::new(hash),
})
Expand All @@ -290,8 +261,6 @@ impl<C: Context> View for KeyValueStoreView<C> {
fn rollback(&mut self) {
self.deletion_set.rollback();
self.updates.clear();
self.total_size = self.stored_total_size;
self.sizes.rollback();
*self.hash.get_mut().unwrap() = self.stored_hash;
}

Expand All @@ -302,12 +271,6 @@ impl<C: Context> View for KeyValueStoreView<C> {
if !self.updates.is_empty() {
return true;
}
if self.stored_total_size != self.total_size {
return true;
}
if self.sizes.has_pending_changes().await {
return true;
}
let hash = self.hash.lock().unwrap();
self.stored_hash != *hash
}
Expand Down Expand Up @@ -346,7 +309,6 @@ impl<C: Context> View for KeyValueStoreView<C> {
}
}
}
self.sizes.pre_save(batch)?;
let hash = *self.hash.lock().unwrap();
if self.stored_hash != hash {
let key = self.context.base_key().base_tag(KeyTag::Hash as u8);
Expand All @@ -355,28 +317,20 @@ impl<C: Context> View for KeyValueStoreView<C> {
Some(hash) => batch.put_key_value(key, &hash)?,
}
}
if self.stored_total_size != self.total_size {
let key = self.context.base_key().base_tag(KeyTag::TotalSize as u8);
batch.put_key_value(key, &self.total_size)?;
}
Ok(delete_view)
}

fn post_save(&mut self) {
self.deletion_set.delete_storage_first = false;
self.deletion_set.deleted_prefixes.clear();
self.updates.clear();
self.sizes.post_save();
let hash = *self.hash.lock().unwrap();
self.stored_hash = hash;
self.stored_total_size = self.total_size;
}

fn clear(&mut self) {
self.deletion_set.clear();
self.updates.clear();
self.total_size = SizeData::default();
self.sizes.clear();
*self.hash.get_mut().unwrap() = None;
}
}
Expand All @@ -387,9 +341,6 @@ impl<C: Context> ClonableView for KeyValueStoreView<C> {
context: self.context.clone(),
deletion_set: self.deletion_set.clone(),
updates: self.updates.clone(),
stored_total_size: self.stored_total_size,
total_size: self.total_size,
sizes: self.sizes.clone_unchecked()?,
stored_hash: self.stored_hash,
hash: Mutex::new(*self.hash.get_mut().unwrap()),
})
Expand All @@ -402,22 +353,6 @@ impl<C: Context> KeyValueStoreView<C> {
<C::Store as ReadableKeyValueStore>::MAX_KEY_SIZE - 1 - prefix_len
}

/// Getting the total sizes that will be used for keys and values when stored
/// ```rust
/// # tokio_test::block_on(async {
/// # use linera_views::context::MemoryContext;
/// # use linera_views::key_value_store_view::{KeyValueStoreView, SizeData};
/// # use linera_views::views::View;
/// # let context = MemoryContext::new_for_testing(());
/// let mut view = KeyValueStoreView::load(context).await.unwrap();
/// let total_size = view.total_size();
/// assert_eq!(total_size, SizeData::default());
/// # })
/// ```
pub fn total_size(&self) -> SizeData {
self.total_size
}

/// Applies the function f over all indices. If the function f returns
/// false, then the loop ends prematurely.
/// ```rust
Expand Down Expand Up @@ -891,14 +826,6 @@ impl<C: Context> KeyValueStoreView<C> {
match operation {
WriteOperation::Delete { key } => {
ensure!(key.len() <= max_key_size, ViewError::KeyTooLong);
if let Some(value) = self.sizes.get(&key).await? {
let entry_size = SizeData {
key: u32::try_from(key.len()).map_err(|_| ArithmeticError::Overflow)?,
value,
};
self.total_size.sub_assign(entry_size);
}
self.sizes.remove(key.clone());
if self.deletion_set.contains_prefix_of(&key) {
// Optimization: No need to mark `short_key` for deletion as we are going to remove all the keys at once.
self.updates.remove(&key);
Expand All @@ -908,19 +835,6 @@ impl<C: Context> KeyValueStoreView<C> {
}
WriteOperation::Put { key, value } => {
ensure!(key.len() <= max_key_size, ViewError::KeyTooLong);
let entry_size = SizeData {
key: key.len() as u32,
value: value.len() as u32,
};
self.total_size.add_assign(entry_size)?;
if let Some(value) = self.sizes.get(&key).await? {
let entry_size = SizeData {
key: key.len() as u32,
value,
};
self.total_size.sub_assign(entry_size);
}
self.sizes.insert(key.clone(), entry_size.value);
self.updates.insert(key, Update::Set(value));
}
WriteOperation::DeletePrefix { key_prefix } => {
Expand All @@ -933,16 +847,6 @@ impl<C: Context> KeyValueStoreView<C> {
for key in key_list {
self.updates.remove(&key);
}
let key_values = self.sizes.key_values_by_prefix(key_prefix.clone()).await?;
for (key, value) in key_values {
let entry_size = SizeData {
key: key.len() as u32,
value,
};
self.total_size.sub_assign(entry_size);
self.sizes.remove(key);
}
self.sizes.remove_by_prefix(key_prefix.clone());
self.deletion_set.insert_key_prefix(key_prefix);
}
}
Expand Down
19 changes: 2 additions & 17 deletions linera-views/tests/random_container_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use linera_views::{
bucket_queue_view::HashedBucketQueueView,
collection_view::{CollectionView, HashedCollectionView},
context::{Context, MemoryContext},
key_value_store_view::{KeyValueStoreView, SizeData},
key_value_store_view::KeyValueStoreView,
map_view::{HashedByteMapView, MapView},
queue_view::HashedQueueView,
random::make_deterministic_rng,
Expand Down Expand Up @@ -140,19 +140,6 @@ fn remove_by_prefix<V>(map: &mut BTreeMap<Vec<u8>, V>, key_prefix: Vec<u8>) {
map.retain(|key, _| !key.starts_with(&key_prefix));
}

fn total_size(vec: &Vec<(Vec<u8>, Vec<u8>)>) -> SizeData {
let mut total_key_size = 0;
let mut total_value_size = 0;
for (key, value) in vec {
total_key_size += key.len();
total_value_size += value.len();
}
SizeData {
key: total_key_size as u32,
value: total_value_size as u32,
}
}

#[tokio::test]
async fn key_value_store_view_mutability() -> Result<()> {
let context = MemoryContext::new_for_testing(());
Expand All @@ -166,7 +153,6 @@ async fn key_value_store_view_mutability() -> Result<()> {
let read_state = view.store.index_values().await?;
let state_vec = state_map.clone().into_iter().collect::<Vec<_>>();
assert!(read_state.iter().map(|kv| (&kv.0, &kv.1)).eq(&state_map));
assert_eq!(total_size(&state_vec), view.store.total_size());

let count_oper = rng.gen_range(0..15);
let mut new_state_map = state_map.clone();
Expand All @@ -191,7 +177,6 @@ async fn key_value_store_view_mutability() -> Result<()> {
new_state_vec = new_state_map.clone().into_iter().collect();
let new_key_values = view.store.index_values().await?;
assert_eq!(new_state_vec, new_key_values);
assert_eq!(total_size(&new_state_vec), view.store.total_size());
}
}
if choice == 1 && entry_count > 0 {
Expand Down Expand Up @@ -225,7 +210,7 @@ async fn key_value_store_view_mutability() -> Result<()> {
new_state_vec = new_state_map.clone().into_iter().collect();
let new_key_values = view.store.index_values().await?;
assert_eq!(new_state_vec, new_key_values);
assert_eq!(total_size(&new_state_vec), view.store.total_size());

let all_keys_vec = all_keys.clone().into_iter().collect::<Vec<_>>();
let tests_multi_get = view.store.multi_get(&all_keys_vec).await?;
for (i, key) in all_keys.clone().into_iter().enumerate() {
Expand Down
Loading