diff --git a/linera-views/src/views/key_value_store_view.rs b/linera-views/src/views/key_value_store_view.rs index a506e09eabb2..e7fe499c2b87 100644 --- a/linera-views/src/views/key_value_store_view.rs +++ b/linera-views/src/views/key_value_store_view.rs @@ -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}, }; @@ -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. @@ -211,12 +206,6 @@ pub struct KeyValueStoreView { deletion_set: DeletionSet, /// Pending changes not yet persisted to storage. updates: BTreeMap, Update>>, - /// 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, /// The hash persisted in storage. #[allocative(visit = visit_allocative_simple)] stored_hash: Option, @@ -237,9 +226,6 @@ impl ReplaceContext for KeyValueStoreView { 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), } @@ -247,7 +233,7 @@ impl ReplaceContext for KeyValueStoreView { } impl View for KeyValueStoreView { - const NUM_INIT_KEYS: usize = 2 + ByteMapView::::NUM_INIT_KEYS; + const NUM_INIT_KEYS: usize = 1; type Context = C; @@ -257,31 +243,16 @@ impl View for KeyValueStoreView { fn pre_load(context: &C) -> Result>, 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::::pre_load(&context_sizes)?); + let v = vec![key_hash]; Ok(v) } fn post_load(context: C, values: &[Option>]) -> Result { 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), }) @@ -290,8 +261,6 @@ impl View for KeyValueStoreView { 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; } @@ -302,12 +271,6 @@ impl View for KeyValueStoreView { 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 } @@ -346,7 +309,6 @@ impl View for KeyValueStoreView { } } } - 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); @@ -355,10 +317,6 @@ impl View for KeyValueStoreView { 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) } @@ -366,17 +324,13 @@ impl View for KeyValueStoreView { 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; } } @@ -387,9 +341,6 @@ impl ClonableView for KeyValueStoreView { 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()), }) @@ -402,22 +353,6 @@ impl KeyValueStoreView { ::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 @@ -891,14 +826,6 @@ impl KeyValueStoreView { 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); @@ -908,19 +835,6 @@ impl KeyValueStoreView { } 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 } => { @@ -933,16 +847,6 @@ impl KeyValueStoreView { 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); } } diff --git a/linera-views/tests/random_container_tests.rs b/linera-views/tests/random_container_tests.rs index 6910059575fb..c074ba9b58f6 100644 --- a/linera-views/tests/random_container_tests.rs +++ b/linera-views/tests/random_container_tests.rs @@ -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, @@ -140,19 +140,6 @@ fn remove_by_prefix(map: &mut BTreeMap, V>, key_prefix: Vec) { map.retain(|key, _| !key.starts_with(&key_prefix)); } -fn total_size(vec: &Vec<(Vec, Vec)>) -> 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(()); @@ -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::>(); 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(); @@ -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 { @@ -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::>(); let tests_multi_get = view.store.multi_get(&all_keys_vec).await?; for (i, key) in all_keys.clone().into_iter().enumerate() {