grovedb/batch/
just_in_time_reference_update.rs1use std::borrow::Cow;
2
3use grovedb_costs::{
4 cost_return_on_error_no_add,
5 storage_cost::{
6 removal::{StorageRemovedBytes, StorageRemovedBytes::BasicStorageRemoval},
7 StorageCost,
8 },
9 CostResult, CostsExt, OperationCost,
10};
11use grovedb_merk::{
12 tree::{kv::KV, value_hash, TreeNode},
13 tree_type::TreeType,
14 CryptoHash, Merk,
15};
16use grovedb_storage::StorageContext;
17use grovedb_version::version::GroveVersion;
18
19use crate::{
20 batch::{MerkError, TreeCacheMerkByPath},
21 Element, ElementFlags, Error,
22};
23
24impl<'db, S, F> TreeCacheMerkByPath<S, F>
25where
26 F: FnMut(&[Vec<u8>], bool) -> CostResult<Merk<S>, Error>,
27 S: StorageContext<'db>,
28{
29 pub(crate) fn process_old_element_flags<G, SR>(
30 key: &[u8],
31 serialized: &[u8],
32 new_element: &mut Element,
33 old_element: Element,
34 old_serialized_element: &[u8],
35 in_tree_type: TreeType,
36 flags_update: &mut G,
37 split_removal_bytes: &mut SR,
38 grove_version: &GroveVersion,
39 ) -> CostResult<CryptoHash, Error>
40 where
41 G: FnMut(&StorageCost, Option<ElementFlags>, &mut ElementFlags) -> Result<bool, Error>,
42 SR: FnMut(
43 &mut ElementFlags,
44 u32,
45 u32,
46 ) -> Result<(StorageRemovedBytes, StorageRemovedBytes), Error>,
47 {
48 let mut cost = OperationCost::default();
49 if old_element.is_sum_item() {
50 return if new_element.is_sum_item() {
51 let maybe_old_flags = old_element.get_flags_owned();
52 if maybe_old_flags.is_some() {
53 let mut updated_new_element_with_old_flags = new_element.clone();
54 updated_new_element_with_old_flags.set_flags(maybe_old_flags.clone());
55 let new_serialized_bytes = cost_return_on_error_no_add!(
57 cost,
58 updated_new_element_with_old_flags.serialize(grove_version)
59 );
60 let val_hash = value_hash(&new_serialized_bytes).unwrap_add_cost(&mut cost);
61 Ok(val_hash).wrap_with_cost(cost)
62 } else {
63 let val_hash = value_hash(serialized).unwrap_add_cost(&mut cost);
64 Ok(val_hash).wrap_with_cost(cost)
65 }
66 } else {
67 Err(Error::NotSupported(
68 "going from a sum item to a not sum item is not supported".to_string(),
69 ))
70 .wrap_with_cost(cost)
71 };
72 } else if new_element.is_sum_item() {
73 return Err(Error::NotSupported(
74 "going from an item to a sum item is not supported".to_string(),
75 ))
76 .wrap_with_cost(cost);
77 }
78 let mut maybe_old_flags = old_element.get_flags_owned();
79
80 let old_storage_cost = KV::node_value_byte_cost_size(
81 key.len() as u32,
82 old_serialized_element.len() as u32,
83 in_tree_type.inner_node_type(),
84 );
85
86 let original_new_element = new_element.clone();
87
88 let mut serialization_to_use = Cow::Borrowed(serialized);
89
90 let mut new_storage_cost = if maybe_old_flags.is_some() {
91 let mut updated_new_element_with_old_flags = original_new_element.clone();
94 updated_new_element_with_old_flags.set_flags(maybe_old_flags.clone());
95
96 let serialized_with_old_flags = cost_return_on_error_no_add!(
97 cost,
98 updated_new_element_with_old_flags.serialize(grove_version)
99 );
100 KV::node_value_byte_cost_size(
101 key.len() as u32,
102 serialized_with_old_flags.len() as u32,
103 in_tree_type.inner_node_type(),
104 )
105 } else {
106 KV::node_value_byte_cost_size(
107 key.len() as u32,
108 serialized.len() as u32,
109 in_tree_type.inner_node_type(),
110 )
111 };
112
113 let mut i = 0;
114
115 loop {
116 let mut storage_costs =
118 TreeNode::storage_cost_for_update(new_storage_cost, old_storage_cost);
119
120 if let Some(old_element_flags) = maybe_old_flags.as_mut() {
121 if let BasicStorageRemoval(removed_bytes) = storage_costs.removed_bytes {
122 let (_, value_removed_bytes) = cost_return_on_error_no_add!(
123 cost,
124 split_removal_bytes(old_element_flags, 0, removed_bytes)
125 );
126 storage_costs.removed_bytes = value_removed_bytes;
127 }
128 }
129
130 let mut new_element_cloned = original_new_element.clone();
131
132 let changed = cost_return_on_error_no_add!(
133 cost,
134 (flags_update)(
135 &storage_costs,
136 maybe_old_flags.clone(),
137 new_element_cloned.get_flags_mut().as_mut().unwrap()
138 )
139 .map_err(|e| match e {
140 Error::JustInTimeElementFlagsClientError(_) => {
141 MerkError::ClientCorruptionError(e.to_string()).into()
142 }
143 _ => MerkError::ClientCorruptionError("non client error".to_string(),).into(),
144 })
145 );
146 if !changed {
147 let val_hash = value_hash(&serialization_to_use).unwrap_add_cost(&mut cost);
150 return Ok(val_hash).wrap_with_cost(cost);
151 } else {
152 let new_serialized_bytes =
154 cost_return_on_error_no_add!(cost, new_element_cloned.serialize(grove_version));
155
156 new_storage_cost = KV::node_value_byte_cost_size(
157 key.len() as u32,
158 new_serialized_bytes.len() as u32,
159 in_tree_type.inner_node_type(),
160 );
161
162 if serialization_to_use == new_serialized_bytes {
163 let val_hash = value_hash(&serialization_to_use).unwrap_add_cost(&mut cost);
165 return Ok(val_hash).wrap_with_cost(cost);
166 }
167
168 serialization_to_use = Cow::Owned(new_serialized_bytes);
169 }
170
171 if i > 8 {
173 return Err(Error::CyclicError(
174 "updated value based on costs too many times in reference",
175 ))
176 .wrap_with_cost(cost);
177 }
178 i += 1;
179 }
180 }
181}