From 131e9a5ba0b9cec4c675f5422e63c1fe7a11a6dc Mon Sep 17 00:00:00 2001 From: Evgeny Fomin Date: Tue, 26 Nov 2024 23:07:09 +0100 Subject: [PATCH] wip --- grovedb/src/element/insert.rs | 15 +- grovedb/src/merk_cache.rs | 669 ++++++++++++++++++++++------------ 2 files changed, 434 insertions(+), 250 deletions(-) diff --git a/grovedb/src/element/insert.rs b/grovedb/src/element/insert.rs index 1d418d56..17a44d4d 100644 --- a/grovedb/src/element/insert.rs +++ b/grovedb/src/element/insert.rs @@ -248,7 +248,6 @@ impl Element { /// be loaded by this moment If transaction is not passed, the batch /// will be written immediately. If transaction is passed, the operation /// will be committed on the transaction commit. - /// The bool represents whether a propagation of references is needed. /// If the value changed, it returns the old element under `Some`. pub fn insert_if_changed_value<'db, S: StorageContext<'db>>( self, @@ -256,7 +255,7 @@ impl Element { key: &[u8], options: Option, grove_version: &GroveVersion, - ) -> CostResult<(bool, Option), Error> { + ) -> CostResult, Error> { check_grovedb_v0_with_cost!( "insert_if_changed_value", grove_version @@ -282,14 +281,13 @@ impl Element { .unwrap_or(true); if changed { - let has_references = to_insert.has_backward_references(); cost_return_on_error!( &mut cost, to_insert.insert(merk, key, options, grove_version) ); - Ok((has_references, previous_element)).wrap_with_cost(cost) + Ok(previous_element).wrap_with_cost(cost) } else { - Ok((false, None)).wrap_with_cost(cost) + Ok(None).wrap_with_cost(cost) } } @@ -636,14 +634,13 @@ mod tests { merk.commit(grove_version); - let (inserted, previous) = Element::new_item(b"value".to_vec()) + let previous = Element::new_item(b"value".to_vec()) .insert_if_changed_value(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); merk.commit(grove_version); - assert!(!inserted); assert_eq!(previous, None); assert_eq!( Element::get(&merk, b"another-key", true, grove_version) @@ -678,7 +675,7 @@ mod tests { let batch = StorageBatch::new(); let mut merk = empty_path_merk(&*storage, &batch, &tx, grove_version); - let (_, previous) = Element::new_item(b"value2".to_vec()) + let previous = Element::new_item(b"value2".to_vec()) .insert_if_changed_value(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); @@ -707,7 +704,7 @@ mod tests { .insert(&mut merk, b"mykey", None, grove_version) .unwrap() .expect("expected successful insertion"); - let (_, previous) = Element::new_item(b"value2".to_vec()) + let previous = Element::new_item(b"value2".to_vec()) .insert_if_changed_value(&mut merk, b"another-key", None, grove_version) .unwrap() .expect("expected successful insertion 2"); diff --git a/grovedb/src/merk_cache.rs b/grovedb/src/merk_cache.rs index bdd6bc05..27aca594 100644 --- a/grovedb/src/merk_cache.rs +++ b/grovedb/src/merk_cache.rs @@ -14,7 +14,10 @@ use grovedb_path::SubtreePath; use grovedb_storage::{rocksdb_storage::PrefixedRocksDbTransactionContext, StorageBatch}; use grovedb_version::version::GroveVersion; -use crate::{reference_path::ReferencePathType, Element, Error, GroveDb, Transaction}; +use crate::{ + element::CascadeOnUpdate, reference_path::ReferencePathType, Element, Error, GroveDb, + Transaction, +}; type TxMerk<'db> = Merk>; @@ -25,7 +28,7 @@ struct CachedMerk<'db> { merk: TxMerk<'db>, } -type UpdatedReferences<'b, B> = RefCell, Vec)>>; +// type UpdatedReferences<'b, B> = RefCell, Vec)>>; /// Helper struct to split `MerkCache` into independent parts to allow splitting /// borrows, meaning a dependency on the storage part that shall have a certain @@ -96,9 +99,6 @@ impl<'db, 'b, B: AsRef<[u8]>> MerkCacheStorage<'db, 'b, B> { // SAFETY: please consult with other safety docs here before doing any changes pub(crate) struct MerkCache<'db, 'b, B> { storage: MerkCacheStorage<'db, 'b, B>, - /// References require different kind of propagation and we track pointed to - /// values to update references. - updated_references: UpdatedReferences<'b, B>, version: &'db GroveVersion, } @@ -111,7 +111,7 @@ impl<'db, 'b, B: AsRef<[u8]>> MerkCache<'db, 'b, B> { MerkCache { storage: MerkCacheStorage::new(db, tx), version, - updated_references: Default::default(), + // updated_references: Default::default(), } } @@ -125,8 +125,8 @@ impl<'db, 'b, B: AsRef<[u8]>> MerkCache<'db, 'b, B> { pub(crate) fn get_multi_mut<'c, const N: usize>( &'c mut self, paths: [SubtreePath<'b, B>; N], - ) -> CostResult<[MerkHandle<'db, 'c, 'b, B>; N], Error> { - let mut result_uninit = [const { MaybeUninit::>::uninit() }; N]; + ) -> CostResult<[MerkHandle<'db, 'c>; N], Error> { + let mut result_uninit = [const { MaybeUninit::>::uninit() }; N]; let mut cost = Default::default(); let unique_args: HashSet<_> = paths.iter().collect(); @@ -149,10 +149,10 @@ impl<'db, 'b, B: AsRef<[u8]>> MerkCache<'db, 'b, B> { ) as *mut CachedMerk<'db>) .as_mut::<'c>() .expect("not a null pointer"), - UpdatedReferenceHandle { - path, - updated_references: &self.updated_references, - }, + // UpdatedReferenceHandle { + // path, + // updated_references: &self.updated_references, + // }, &self.version, ) }; @@ -164,9 +164,8 @@ impl<'db, 'b, B: AsRef<[u8]>> MerkCache<'db, 'b, B> { // N in our case. `mem::transmute` would represent it better, however, // due to poor support of const generics in stable Rust we bypass // compile-time size checks with pointer casts. - let result = unsafe { - (&result_uninit as *const _ as *const [MerkHandle<'db, 'c, 'b, B>; N]).read() - }; + let result = + unsafe { (&result_uninit as *const _ as *const [MerkHandle<'db, 'c>; N]).read() }; mem::forget(result_uninit); Ok(result).wrap_with_cost(cost) @@ -179,7 +178,10 @@ impl<'db, 'b, B: AsRef<[u8]>> MerkCache<'db, 'b, B> { // Propagate updated subtrees' hashes up to the root and dropping all possible // batch users: - let propagation_result = self.propagate_updated_merks(); + let propagation_result = { + self.propagate_updated_references() + .flat_map_ok(|_| self.propagate_updated_merks()) + }; // SAFETY: The batch reference was created by `Box::leak` and restored into a // `Box` form. No shared usage of that memory exists because the @@ -191,86 +193,86 @@ impl<'db, 'b, B: AsRef<[u8]>> MerkCache<'db, 'b, B> { propagation_result.map_ok(|_| result_batch) } - /// Inserts a reference into a cached Merk. - /// The reason why this has to be a whole `MerkCache` method is that - /// references involve opening and modifying several Merks at once, this - /// makes it out of scope for a single `MerkHandle`. - pub(crate) fn insert_reference<'c>( - &'c mut self, - path: SubtreePath<'b, B>, - key: &[u8], - ref_element: ReferenceElement, - cascade_on_update: bool, - options: Option, - ) -> CostResult<(), Error> { - let mut cost = Default::default(); - - let follow_reference_result = cost_return_on_error!( - &mut cost, - self.follow_reference(path.clone(), key, ref_element.get_ref_path()) - ); - - let value_hash = cost_return_on_error!( - &mut cost, - follow_reference_result - .last_element - .value_hash(&self.version) - ); - - // The insertion of a reference requires that its hash value be equal to the - // hash value of the item in the end of the reference's chain: - let [mut merk] = cost_return_on_error!(&mut cost, self.get_multi_mut([path])); - cost_return_on_error!( - &mut cost, - merk.insert_internal(key, ref_element.0.clone(), options, Some(value_hash)) - ); - - let version = self.version.clone(); // TODO - - // The closest referenced item's backward references list of the chain shall be - // updated with a new entry: - let [mut closest_merk] = cost_return_on_error!( - &mut cost, - self.get_multi_mut([follow_reference_result.first_path]) - ); - let mut closest_element = cost_return_on_error!( - &mut cost, - Element::get( - closest_merk.deref(), - &follow_reference_result.first_key, - true, - &version - ) - ); - // Updated backward references information: - closest_element = cost_return_on_error_no_add!( - cost, - closest_element.referenced_from(ref_element.to_ref_path(), cascade_on_update) - ); - // And write it back: - cost_return_on_error!( - &mut cost, - closest_merk.insert_internal( - &follow_reference_result.first_key, - closest_element, - None, - Some(value_hash), - ) - ); - - todo!() - } - - /// Follows a reference returning the first link in the references chain and - /// also the referenced item at the end of it. - fn follow_reference( - &mut self, - self_path: SubtreePath<'b, B>, - self_key: &[u8], - reference_path: &ReferencePathType, - ) -> CostResult, Error> { - todo!() - } + // /// Inserts a reference into a cached Merk. + // /// The reason why this has to be a whole `MerkCache` method is that + // /// references involve opening and modifying several Merks at once, this + // /// makes it out of scope for a single `MerkHandle`. + // pub(crate) fn insert_reference<'c>( + // &'c mut self, + // path: SubtreePath<'b, B>, + // key: &[u8], + // ref_element: ReferenceElement, + // cascade_on_update: bool, + // options: Option, + // ) -> CostResult<(), Error> { + // let mut cost = Default::default(); + + // let follow_reference_result = cost_return_on_error!( + // &mut cost, + // self.follow_reference(path.clone(), key, ref_element.get_ref_path()) + // ); + + // let value_hash = cost_return_on_error!( + // &mut cost, + // follow_reference_result + // .last_element + // .value_hash(&self.version) + // ); + + // // The insertion of a reference requires that its hash value be equal to the + // // hash value of the item in the end of the reference's chain: + // let [mut merk] = cost_return_on_error!(&mut cost, self.get_multi_mut([path])); + // cost_return_on_error!( + // &mut cost, + // merk.insert_internal(key, ref_element.0.clone(), options, Some(value_hash)) + // ); + + // let version = self.version.clone(); // TODO + + // // The closest referenced item's backward references list of the chain shall be + // // updated with a new entry: + // let [mut closest_merk] = cost_return_on_error!( + // &mut cost, + // self.get_multi_mut([follow_reference_result.first_path]) + // ); + // let mut closest_element = cost_return_on_error!( + // &mut cost, + // Element::get( + // closest_merk.deref(), + // &follow_reference_result.first_key, + // true, + // &version + // ) + // ); + // // Updated backward references information: + // closest_element = cost_return_on_error_no_add!( + // cost, + // closest_element.referenced_from(ref_element.to_ref_path(), cascade_on_update) + // ); + // // And write it back: + // cost_return_on_error!( + // &mut cost, + // closest_merk.insert_internal( + // &follow_reference_result.first_key, + // closest_element, + // None, + // Some(value_hash), + // ) + // ); + + // todo!() + // } + + // /// Follows a reference returning the first link in the references chain and + // /// also the referenced item at the end of it. + // fn follow_reference( + // &mut self, + // self_path: SubtreePath<'b, B>, + // self_key: &[u8], + // reference_path: &ReferencePathType, + // ) -> CostResult, Error> { + // todo!() + // } /// Perform propagation of references' chains marked as changed. fn propagate_updated_references(&mut self) -> CostResult<(), Error> { @@ -328,81 +330,82 @@ struct FollowReferenceResult<'b, B> { last_element: Element, } -/// A wrapper type to ensure `Element` is a reference wherever it is required. -pub(crate) struct ReferenceElement(Element); - -impl ReferenceElement { - fn get_ref_path(&self) -> &ReferencePathType { - match &self.0 { - Element::Reference(ref_path, ..) | Element::BidirectionalReference(ref_path, ..) => { - ref_path - } - _ => unreachable!(), - } - } - - fn to_ref_path(self) -> ReferencePathType { - match self.0 { - Element::Reference(ref_path, ..) | Element::BidirectionalReference(ref_path, ..) => { - ref_path - } - _ => unreachable!(), - } - } -} - -impl TryFrom for ReferenceElement { - type Error = (); - - fn try_from(value: Element) -> Result { - match value { - element @ Element::Reference(..) | element @ Element::BidirectionalReference(..) => { - Ok(Self(element)) - } - _ => Err(()), - } - } -} - -/// A wrapper type to ensure `Element` is not a reference. -pub(crate) struct NonReferenceElement(Element); - -impl TryFrom for NonReferenceElement { - type Error = (); - - fn try_from(value: Element) -> Result { - match value { - Element::Reference(..) | Element::BidirectionalReference(..) => Err(()), - element => Ok(Self(element)), - } - } -} +// /// A wrapper type to ensure `Element` is a reference wherever it is required. +// pub(crate) struct ReferenceElement(Element); + +// impl ReferenceElement { +// fn get_ref_path(&self) -> &ReferencePathType { +// match &self.0 { +// Element::Reference(ref_path, ..) | Element::BidirectionalReference(ref_path, ..) => { +// ref_path +// } +// _ => unreachable!(), +// } +// } + +// fn to_ref_path(self) -> ReferencePathType { +// match self.0 { +// Element::Reference(ref_path, ..) | Element::BidirectionalReference(ref_path, ..) => { +// ref_path +// } +// _ => unreachable!(), +// } +// } +// } + +// impl TryFrom for ReferenceElement { +// type Error = (); + +// fn try_from(value: Element) -> Result { +// match value { +// element @ Element::Reference(..) | element @ Element::BidirectionalReference(..) => { +// Ok(Self(element)) +// } +// _ => Err(()), +// } +// } +// } + +// /// A wrapper type to ensure `Element` is not a reference. +// pub(crate) struct NonReferenceElement(Element); + +// impl TryFrom for NonReferenceElement { +// type Error = (); + +// fn try_from(value: Element) -> Result { +// match value { +// Element::Reference(..) | Element::BidirectionalReference(..) => Err(()), +// element => Ok(Self(element)), +// } +// } +// } /// Handle to a cached Merk. -pub(crate) struct MerkHandle<'db, 'c, 'b, B> { +pub(crate) struct MerkHandle<'db, 'c> { + /// Reference to an opened Merk tree with transactional batch storage context merk: &'c mut TxMerk<'db>, version: &'db GroveVersion, + /// Mark this subtree as a subject to propagate to_propagate: &'c mut bool, - updated_reference_handle: UpdatedReferenceHandle<'c, 'b, B>, } -/// Helper struct to signal `MerkCache` about updated references. -struct UpdatedReferenceHandle<'c, 'b, B> { - path: SubtreePath<'b, B>, - updated_references: &'c UpdatedReferences<'b, B>, -} +// /// Helper struct to signal `MerkCache` about updated references. +// struct UpdatedReferenceHandle<'c, 'b, B> { +// path: SubtreePath<'b, B>, +// updated_references: &'c UpdatedReferences<'b, B>, +// } -impl<'c, 'b, B: AsRef<[u8]>> UpdatedReferenceHandle<'c, 'b, B> { - fn mark_updated_reference(&self, key: Key) { - self.updated_references - .borrow_mut() - .insert((self.path.clone(), key)); - } -} +// impl<'c, 'b, B: AsRef<[u8]>> UpdatedReferenceHandle<'c, 'b, B> { +// fn mark_updated_reference(&self, key: Key) { +// self.updated_references +// .borrow_mut() +// .insert((self.path.clone(), key)); +// } +// } /// It is allowed to dereference `MerkHandle` to regular Merks but in a /// non-mutable way since we want to track what have been done to those Merks. -impl<'db, 'c, 'b, B> Deref for MerkHandle<'db, 'c, 'b, B> { +impl<'db, 'c> Deref for MerkHandle<'db, 'c> { type Target = TxMerk<'db>; fn deref(&self) -> &Self::Target { @@ -410,77 +413,261 @@ impl<'db, 'c, 'b, B> Deref for MerkHandle<'db, 'c, 'b, B> { } } -impl<'db, 'c, 'b, B: AsRef<[u8]>> MerkHandle<'db, 'c, 'b, B> { - pub(crate) fn insert( - &mut self, - key: &[u8], - NonReferenceElement(element): NonReferenceElement, - options: Option, - ) -> CostResult<(), Error> { - self.insert_internal(key, element, options, None) +/// This type represents changes made to a particular element, a difference between its initial +/// state and eventual state +enum Delta { + AddItem, + RemoveItem { + backward_references: Vec<(ReferencePathType, CascadeOnUpdate)>, + }, + UpdateItemToReference { + backward_references: Vec<(ReferencePathType, CascadeOnUpdate)>, + new_forward_reference: ReferencePathType, + }, + UpdateItemToItem { + backward_references: Vec<(ReferencePathType, CascadeOnUpdate)>, + }, + AddReference { + new_forward_reference: ReferencePathType, + }, + RemoveReference { + backward_references: Vec<(ReferencePathType, CascadeOnUpdate)>, + ex_forward_reference: ReferencePathType, + }, + UpdateReferenceToItem { + backward_references: Vec<(ReferencePathType, CascadeOnUpdate)>, + ex_forward_reference: ReferencePathType, + }, + UpdateReferenceToReference { + backward_references: Vec<(ReferencePathType, CascadeOnUpdate)>, + new_forward_reference: ReferencePathType, + ex_forward_reference: ReferencePathType, + }, +} + +impl Delta { + fn new(old_element: Option, new_element: Element) -> Option { + match (old_element, new_element) { + ( + None | Some(Element::Tree(..) | Element::SumTree(..)), + Element::Item(..) + | Element::ItemWithBackwardsReferences(..) + | Element::SumItem(..) + | Element::SumItemWithBackwardsReferences(..), + ) => Some(Self::AddItem), + ( + None | Some(Element::Tree(..) | Element::SumTree(..)), + Element::Reference(new_forward_reference, ..) + | Element::BidirectionalReference(new_forward_reference, ..), + ) => Some(Self::AddReference { + new_forward_reference, + }), + (_, Element::Tree(..) | Element::SumTree(..)) => None, + + ( + Some( + Element::ItemWithBackwardsReferences(_, backward_references, _) + | Element::SumItemWithBackwardsReferences(_, backward_references, _), + ), + Element::Item(..) + | Element::ItemWithBackwardsReferences(..) + | Element::SumItem(..) + | Element::SumItemWithBackwardsReferences(..), + ) => Some(Self::UpdateItemToItem { + backward_references, + }), + ( + Some(Element::Item(..) | Element::SumItem(..)), + Element::Item(..) + | Element::ItemWithBackwardsReferences(..) + | Element::SumItem(..) + | Element::SumItemWithBackwardsReferences(..), + ) => Some(Self::UpdateItemToItem { + backward_references: Vec::new(), + }), + ( + Some( + Element::ItemWithBackwardsReferences(_, backward_references, _) + | Element::SumItemWithBackwardsReferences(_, backward_references, _), + ), + Element::Reference(new_forward_reference, ..) + | Element::BidirectionalReference(new_forward_reference, ..), + ) => Some(Self::UpdateItemToReference { + backward_references, + new_forward_reference, + }), + ( + Some(Element::Item(..) | Element::SumItem(..)), + Element::Reference(new_forward_reference, ..) + | Element::BidirectionalReference(new_forward_reference, ..), + ) => Some(Self::UpdateItemToReference { + backward_references: Vec::new(), + new_forward_reference, + }), + ( + Some(Element::Reference(ex_forward_reference, ..)), + Element::Item(..) + | Element::ItemWithBackwardsReferences(..) + | Element::SumItem(..) + | Element::SumItemWithBackwardsReferences(..), + ) => Some(Self::UpdateReferenceToItem { + backward_references: Vec::new(), + ex_forward_reference, + }), + ( + Some(Element::BidirectionalReference( + ex_forward_reference, + backward_references, + .., + )), + Element::Item(..) + | Element::ItemWithBackwardsReferences(..) + | Element::SumItem(..) + | Element::SumItemWithBackwardsReferences(..), + ) => Some(Self::UpdateReferenceToItem { + backward_references, + ex_forward_reference, + }), + ( + Some(Element::Reference(ex_forward_reference, ..)), + Element::Reference(new_forward_reference, ..) + | Element::BidirectionalReference(new_forward_reference, ..), + ) => Some(Self::UpdateReferenceToReference { + backward_references: Vec::new(), + new_forward_reference, + ex_forward_reference, + }), + ( + Some(Element::BidirectionalReference( + ex_forward_reference, + backward_references, + .., + )), + Element::Reference(new_forward_reference, ..) + | Element::BidirectionalReference(new_forward_reference, ..), + ) => Some(Self::UpdateReferenceToReference { + backward_references, + new_forward_reference, + ex_forward_reference, + }), + } } - fn insert_internal( + fn new_from_delete(element: Element) -> Option { + match element { + Element::Item(..) | Element::SumItem(..) => Some(Self::RemoveItem { + backward_references: Vec::new(), + }), + Element::ItemWithBackwardsReferences(_, backward_references, ..) + | Element::SumItemWithBackwardsReferences(_, backward_references, ..) => { + Some(Self::RemoveItem { + backward_references, + }) + } + Element::Reference(ex_forward_reference, ..) => Some(Self::RemoveReference { + backward_references: Vec::new(), + ex_forward_reference, + }), + Element::BidirectionalReference(ex_forward_reference, backward_references, ..) => { + Some(Self::RemoveReference { + backward_references, + ex_forward_reference, + }) + } + Element::Tree(..) | Element::SumTree(..) => None, + } + } +} + +impl<'db, 'c> MerkHandle<'db, 'c> { + pub(crate) fn insert( &mut self, key: &[u8], element: Element, options: Option, - referenced_value_hash: Option, ) -> CostResult<(), Error> { let mut costs = Default::default(); - // In case the item that was changed has been referenced, we indicate that - // references should be propagated after - if cost_return_on_error!( + let old_value = cost_return_on_error!( &mut costs, match element { - Element::Item(..) - | Element::SumItem(..) - | Element::ItemWithBackwardsReferences(..) - | Element::SumItemWithBackwardsReferences(..) => element - .insert_if_changed_value(self.merk, key, options, self.version) - .map_ok(|r| r.0), - Element::Reference(..) | Element::BidirectionalReference(..) => element - .insert_reference( - self.merk, - key, - referenced_value_hash.expect("todo"), - options, - self.version - ), Element::Tree(ref value, ..) | Element::SumTree(ref value, ..) => if value.is_some() { Err(Error::InvalidCodeExecution( "a tree should be empty at the moment of insertion when not using \ - batches", + batches", )) .wrap_with_cost(Default::default()) } else { element .insert_subtree(self.merk, key, NULL_HASH, options, self.version) - .map_ok(|_| false) + .map_ok(|_| None) }, + _ => element.insert_if_changed_value(self.merk, key, options, self.version), } - ) { - self.updated_reference_handle - .mark_updated_reference(key.to_vec()); - } + ); *self.to_propagate = true; Ok(()).wrap_with_cost(costs) } - fn new( - cached_merk: &'c mut CachedMerk<'db>, - updated_reference_handle: UpdatedReferenceHandle<'c, 'b, B>, - version: &'db GroveVersion, - ) -> Self { + // fn insert_internal( + // &mut self, + // key: &[u8], + // element: Element, + // options: Option, + // referenced_value_hash: Option, + // ) -> CostResult<(), Error> { + // let mut costs = Default::default(); + + // // In case the item that was changed has been referenced, we indicate that + // // references should be propagated after + // if cost_return_on_error!( + // &mut costs, + // match element { + // Element::Item(..) + // | Element::SumItem(..) + // | Element::ItemWithBackwardsReferences(..) + // | Element::SumItemWithBackwardsReferences(..) => element + // .insert_if_changed_value(self.merk, key, options, self.version) + // .map_ok(|r| r.0), + // Element::Reference(..) | Element::BidirectionalReference(..) => element + // .insert_reference( + // self.merk, + // key, + // referenced_value_hash.expect("todo"), + // options, + // self.version + // ), + // Element::Tree(ref value, ..) | Element::SumTree(ref value, ..) => + // if value.is_some() { + // Err(Error::InvalidCodeExecution( + // "a tree should be empty at the moment of insertion when not using \ + // batches", + // )) + // .wrap_with_cost(Default::default()) + // } else { + // element + // .insert_subtree(self.merk, key, NULL_HASH, options, self.version) + // .map_ok(|_| false) + // }, + // } + // ) { + // self.updated_reference_handle + // .mark_updated_reference(key.to_vec()); + // } + + // *self.to_propagate = true; + + // Ok(()).wrap_with_cost(costs) + // } + + fn new(cached_merk: &'c mut CachedMerk<'db>, version: &'db GroveVersion) -> Self { Self { merk: &mut cached_merk.merk, version, to_propagate: &mut cached_merk.to_propagate, - updated_reference_handle, } } } @@ -617,46 +804,46 @@ mod tests { ) } - #[test] - fn changes_to_referenced_values_are_marked_uncommitted() { - let version = GroveVersion::latest(); - let db = make_deep_tree(&version); - let tx = db.start_transaction(); - - let mut cache = MerkCache::new(&db, &tx, version); - cache - .insert_reference( - SubtreePath::from(&[TEST_LEAF, b"innertree"]), - b"ayy", - Element::new_reference(ReferencePathType::AbsolutePathReference(vec![ - ANOTHER_TEST_LEAF.to_vec(), - b"innertree2".to_vec(), - b"k3".to_vec(), - ])) - .try_into() - .unwrap(), - false, - None, - ) - .unwrap() - .unwrap(); - - assert!(cache.updated_references.borrow().is_empty()); - - let [mut subtree] = cache - .get_multi_mut([SubtreePath::from(&[ANOTHER_TEST_LEAF, b"innertree2"])]) - .unwrap() - .unwrap(); - - subtree - .insert( - b"k3", - Element::new_item(b"huh".to_vec()).try_into().unwrap(), - None, - ) - .unwrap() - .unwrap(); - - assert!(!cache.updated_references.borrow().is_empty()); - } + // #[test] + // fn changes_to_referenced_values_are_marked_uncommitted() { + // let version = GroveVersion::latest(); + // let db = make_deep_tree(&version); + // let tx = db.start_transaction(); + + // let mut cache = MerkCache::new(&db, &tx, version); + // cache + // .insert_reference( + // SubtreePath::from(&[TEST_LEAF, b"innertree"]), + // b"ayy", + // Element::new_reference(ReferencePathType::AbsolutePathReference(vec![ + // ANOTHER_TEST_LEAF.to_vec(), + // b"innertree2".to_vec(), + // b"k3".to_vec(), + // ])) + // .try_into() + // .unwrap(), + // false, + // None, + // ) + // .unwrap() + // .unwrap(); + + // assert!(cache.updated_references.borrow().is_empty()); + + // let [mut subtree] = cache + // .get_multi_mut([SubtreePath::from(&[ANOTHER_TEST_LEAF, b"innertree2"])]) + // .unwrap() + // .unwrap(); + + // subtree + // .insert( + // b"k3", + // Element::new_item(b"huh".to_vec()).try_into().unwrap(), + // None, + // ) + // .unwrap() + // .unwrap(); + + // assert!(!cache.updated_references.borrow().is_empty()); + // } }