Skip to content

Commit f208a55

Browse files
committed
update insertion
1 parent 88b0186 commit f208a55

File tree

3 files changed

+204
-13
lines changed

3 files changed

+204
-13
lines changed

grovedb/src/element/insert.rs

Lines changed: 148 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,74 @@ impl Element {
330330
.map_err(|e| Error::CorruptedData(e.to_string()))
331331
}
332332

333+
#[cfg(feature = "full")]
334+
/// Insert a reference element in Merk under a key returning a delta.
335+
pub fn insert_reference_if_changed_value<'db, K: AsRef<[u8]>, S: StorageContext<'db>>(
336+
&self,
337+
merk: &mut Merk<S>,
338+
key: K,
339+
referenced_value: Hash,
340+
options: Option<MerkOptions>,
341+
grove_version: &GroveVersion,
342+
) -> CostResult<Delta, Error> {
343+
check_grovedb_v0_with_cost!(
344+
"insert_reference",
345+
grove_version.grovedb_versions.element.insert_reference
346+
);
347+
348+
let serialized = match self.serialize(grove_version) {
349+
Ok(s) => s,
350+
Err(e) => return Err(e).wrap_with_cost(Default::default()),
351+
};
352+
353+
let mut cost = OperationCost::default();
354+
355+
let previous_element = cost_return_on_error!(
356+
&mut cost,
357+
Self::get_optional(&merk, &key, true, grove_version)
358+
);
359+
let delta = Delta {
360+
new: self,
361+
old: previous_element,
362+
};
363+
364+
if delta.has_changed() {
365+
let merk_feature_type = cost_return_on_error!(
366+
&mut cost,
367+
self.get_feature_type(merk.is_sum_tree)
368+
.wrap_with_cost(OperationCost::default())
369+
);
370+
371+
let batch_operations = [(
372+
key,
373+
Op::PutCombinedReference(serialized, referenced_value, merk_feature_type),
374+
)];
375+
let uses_sum_nodes = merk.is_sum_tree;
376+
cost_return_on_error!(
377+
&mut cost,
378+
merk.apply_with_specialized_costs::<_, Vec<u8>>(
379+
&batch_operations,
380+
&[],
381+
options,
382+
&|key, value| {
383+
Self::specialized_costs_for_key_value(
384+
key,
385+
value,
386+
uses_sum_nodes,
387+
grove_version,
388+
)
389+
.map_err(|e| MerkError::ClientCorruptionError(e.to_string()))
390+
},
391+
Some(&Element::value_defined_cost_for_serialized_value),
392+
grove_version,
393+
)
394+
.map_err(|e| Error::CorruptedData(e.to_string()))
395+
);
396+
}
397+
398+
Ok(delta).wrap_with_cost(cost)
399+
}
400+
333401
#[cfg(feature = "full")]
334402
/// Adds a "Put" op to batch operations with reference and key. Returns
335403
/// CostResult.
@@ -363,11 +431,7 @@ impl Element {
363431
}
364432

365433
#[cfg(feature = "full")]
366-
/// Insert a tree element in Merk under a key; path should be resolved
367-
/// and proper Merk should be loaded by this moment
368-
/// If transaction is not passed, the batch will be written immediately.
369-
/// If transaction is passed, the operation will be committed on the
370-
/// transaction commit.
434+
/// Insert a tree element in Merk under a key.
371435
pub fn insert_subtree<'db, K: AsRef<[u8]>, S: StorageContext<'db>>(
372436
&self,
373437
merk: &mut Merk<S>,
@@ -417,6 +481,85 @@ impl Element {
417481
.map_err(|e| Error::CorruptedData(e.to_string()))
418482
}
419483

484+
#[cfg(feature = "full")]
485+
/// Insert a tree element in Merk under a key, returning delta.
486+
pub fn insert_subtree_if_changed<'db, K: AsRef<[u8]>, S: StorageContext<'db>>(
487+
&self,
488+
merk: &mut Merk<S>,
489+
key: K,
490+
subtree_root_hash: Hash,
491+
options: Option<MerkOptions>,
492+
grove_version: &GroveVersion,
493+
) -> CostResult<Delta, Error> {
494+
check_grovedb_v0_with_cost!(
495+
"insert_subtree",
496+
grove_version.grovedb_versions.element.insert_subtree
497+
);
498+
499+
let serialized = match self.serialize(grove_version) {
500+
Ok(s) => s,
501+
Err(e) => return Err(e).wrap_with_cost(Default::default()),
502+
};
503+
504+
let mut cost = OperationCost::default();
505+
506+
let previous_element = cost_return_on_error!(
507+
&mut cost,
508+
Self::get_optional(&merk, &key, true, grove_version)
509+
);
510+
511+
let delta = Delta {
512+
new: self,
513+
old: previous_element,
514+
};
515+
516+
if delta.has_changed() {
517+
let merk_feature_type =
518+
cost_return_on_error_no_add!(cost, self.get_feature_type(merk.is_sum_tree));
519+
520+
let tree_cost =
521+
cost_return_on_error_no_add!(cost, self.get_specialized_cost(grove_version));
522+
523+
let specialized_cost = tree_cost
524+
+ self.get_flags().as_ref().map_or(0, |flags| {
525+
let flags_len = flags.len() as u32;
526+
flags_len + flags_len.required_space() as u32
527+
});
528+
let batch_operations = [(
529+
key,
530+
Op::PutLayeredReference(
531+
serialized,
532+
specialized_cost,
533+
subtree_root_hash,
534+
merk_feature_type,
535+
),
536+
)];
537+
let uses_sum_nodes = merk.is_sum_tree;
538+
cost_return_on_error!(
539+
&mut cost,
540+
merk.apply_with_specialized_costs::<_, Vec<u8>>(
541+
&batch_operations,
542+
&[],
543+
options,
544+
&|key, value| {
545+
Self::specialized_costs_for_key_value(
546+
key,
547+
value,
548+
uses_sum_nodes,
549+
grove_version,
550+
)
551+
.map_err(|e| MerkError::ClientCorruptionError(e.to_string()))
552+
},
553+
Some(&Element::value_defined_cost_for_serialized_value),
554+
grove_version,
555+
)
556+
.map_err(|e| Error::CorruptedData(e.to_string()))
557+
);
558+
}
559+
560+
Ok(delta).wrap_with_cost(cost)
561+
}
562+
420563
#[cfg(feature = "full")]
421564
/// Adds a "Put" op to batch operations for a subtree and key
422565
pub fn insert_subtree_into_batch_operations<K: AsRef<[u8]>>(

grovedb/src/merk_cache.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ impl<'db, 'b, B: AsRef<[u8]>> MerkCache<'db, 'b, B> {
165165
}
166166

167167
/// Wrapper over `Merk` tree to manage unqiue borrow dynamically.
168+
#[derive(Clone)]
168169
pub(crate) struct MerkHandle<'db, 'c> {
169170
merk: *mut TxMerk<'db>,
170171
taken_handle: &'c Cell<bool>,

grovedb/src/operations/insert/mod.rs

Lines changed: 55 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ use grovedb_storage::Storage;
1111
use grovedb_version::{check_grovedb_v0_with_cost, version::GroveVersion};
1212

1313
use crate::{
14+
bidirectional_references::{
15+
process_bidirectional_reference_insertion, process_update_element_with_backward_references,
16+
},
1417
merk_cache::{MerkCache, MerkHandle},
1518
util::{self, TxRef},
1619
Element, Error, GroveDb, TransactionArg,
@@ -184,16 +187,27 @@ impl GroveDb {
184187
.wrap_with_cost(cost);
185188
}
186189

187-
cost_return_on_error!(
190+
let delta = cost_return_on_error!(
188191
&mut cost,
189-
subtree_to_insert_into.for_merk(|m| element.insert_reference(
192+
subtree_to_insert_into.for_merk(|m| element.insert_reference_if_changed_value(
190193
m,
191194
key,
192195
resolved_reference.target_node_value_hash,
193196
Some(options.as_merk_options()),
194197
grove_version,
195198
))
196199
);
200+
201+
cost_return_on_error!(
202+
&mut cost,
203+
process_update_element_with_backward_references(
204+
merk_cache,
205+
subtree_to_insert_into.clone(),
206+
path,
207+
key,
208+
delta
209+
)
210+
);
197211
}
198212

199213
Element::Tree(ref value, _) | Element::SumTree(ref value, ..) => {
@@ -203,28 +217,61 @@ impl GroveDb {
203217
))
204218
.wrap_with_cost(cost);
205219
} else {
206-
cost_return_on_error!(
220+
let delta = cost_return_on_error!(
207221
&mut cost,
208-
subtree_to_insert_into.for_merk(|m| element.insert_subtree(
222+
subtree_to_insert_into.for_merk(|m| element.insert_subtree_if_changed(
209223
m,
210224
key,
211225
NULL_HASH,
212226
Some(options.as_merk_options()),
213227
grove_version
214228
))
215229
);
230+
231+
cost_return_on_error!(
232+
&mut cost,
233+
process_update_element_with_backward_references(
234+
merk_cache,
235+
subtree_to_insert_into.clone(),
236+
path,
237+
key,
238+
delta
239+
)
240+
);
216241
}
217242
}
218-
_ => {
243+
Element::BidirectionalReference(reference) => {
219244
cost_return_on_error!(
220245
&mut cost,
221-
subtree_to_insert_into.for_merk(|m| element.insert(
246+
process_bidirectional_reference_insertion(
247+
merk_cache,
248+
path,
249+
key,
250+
reference,
251+
Some(options)
252+
)
253+
);
254+
}
255+
_ => {
256+
let delta = cost_return_on_error!(
257+
&mut cost,
258+
subtree_to_insert_into.for_merk(|m| element.insert_if_changed_value(
222259
m,
223260
key,
224261
Some(options.as_merk_options()),
225262
grove_version
226263
))
227264
);
265+
cost_return_on_error!(
266+
&mut cost,
267+
process_update_element_with_backward_references(
268+
merk_cache,
269+
subtree_to_insert_into.clone(),
270+
path,
271+
key,
272+
delta
273+
)
274+
);
228275
}
229276
}
230277

@@ -1821,13 +1868,13 @@ mod tests {
18211868
assert_eq!(
18221869
cost,
18231870
OperationCost {
1824-
seek_count: 9, // todo: verify this
1871+
seek_count: 10, // todo: verify this
18251872
storage_cost: StorageCost {
18261873
added_bytes: 0,
18271874
replaced_bytes: 409, // todo: verify this
18281875
removed_bytes: NoStorageRemoval
18291876
},
1830-
storage_loaded_bytes: 487, // todo verify this
1877+
storage_loaded_bytes: 558, // todo verify this
18311878
hash_node_calls: 11,
18321879
}
18331880
);

0 commit comments

Comments
 (0)