Skip to content

Commit

Permalink
added a callback method to be able to get the value defined costs
Browse files Browse the repository at this point in the history
  • Loading branch information
QuantumExplorer committed Sep 27, 2023
1 parent 986df1b commit 7d0899c
Show file tree
Hide file tree
Showing 37 changed files with 1,317 additions and 617 deletions.
97 changes: 63 additions & 34 deletions grovedb/src/batch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ use grovedb_merk::{
value_hash, NULL_HASH,
},
CryptoHash, Error as MerkError, Merk, MerkType, RootHashKeyAndSum,
TreeFeatureType::{BasicMerk, SummedMerk},
TreeFeatureType::{BasicMerkNode, SummedMerkNode},
};
use grovedb_path::SubtreePath;
use grovedb_storage::{
Expand Down Expand Up @@ -766,8 +766,12 @@ where
if recursions_allowed == 1 {
let referenced_element_value_hash_opt = cost_return_on_error!(
&mut cost,
merk.get_value_hash(key.as_ref(), true)
.map_err(|e| Error::CorruptedData(e.to_string()))
merk.get_value_hash(
key.as_ref(),
true,
Some(Element::value_defined_cost_for_serialized_value)
)
.map_err(|e| Error::CorruptedData(e.to_string()))
);

let referenced_element_value_hash = cost_return_on_error!(
Expand Down Expand Up @@ -806,8 +810,12 @@ where
// change in the batch.
let referenced_element = cost_return_on_error!(
&mut cost,
merk.get(key.as_ref(), true)
.map_err(|e| Error::CorruptedData(e.to_string()))
merk.get(
key.as_ref(),
true,
Some(Element::value_defined_cost_for_serialized_value)
)
.map_err(|e| Error::CorruptedData(e.to_string()))
);

let referenced_element = cost_return_on_error_no_add!(
Expand Down Expand Up @@ -1130,14 +1138,18 @@ where
} else {
let value = cost_return_on_error!(
&mut cost,
merk.get(key_info.as_slice(), true)
.map(|result_value| result_value
.map_err(Error::MerkError)
.and_then(|maybe_value| maybe_value.ok_or(
Error::InvalidInput(
"trying to refresh a non existing reference",
)
)))
merk.get(
key_info.as_slice(),
true,
Some(Element::value_defined_cost_for_serialized_value)
)
.map(
|result_value| result_value.map_err(Error::MerkError).and_then(
|maybe_value| maybe_value.ok_or(Error::InvalidInput(
"trying to refresh a non existing reference",
))
)
)
);
cost_return_on_error_no_add!(
&cost,
Expand All @@ -1155,9 +1167,9 @@ where
};

let merk_feature_type = if is_sum_tree {
SummedMerk(0)
SummedMerkNode(0)
} else {
BasicMerk
BasicMerkNode
};

let path_reference = cost_return_on_error!(
Expand Down Expand Up @@ -1276,14 +1288,15 @@ where
}
cost_return_on_error!(
&mut cost,
merk.apply_unchecked::<_, Vec<u8>, _, _, _>(
merk.apply_unchecked::<_, Vec<u8>, _, _, _, _>(
&batch_operations,
&[],
Some(batch_apply_options.as_merk_options()),
&|key, value| {
Element::specialized_costs_for_key_value(key, value, is_sum_tree)
.map_err(|e| MerkError::ClientCorruptionError(e.to_string()))
},
Some(&Element::value_defined_cost_for_serialized_value),
&mut |storage_costs, old_value, new_value| {
// todo: change the flags without full deserialization
let old_element = Element::deserialize(old_value.as_slice())
Expand Down Expand Up @@ -1779,13 +1792,16 @@ impl GroveDb {
);
let is_sum_tree = element.is_sum_tree();
if let Element::Tree(root_key, _) | Element::SumTree(root_key, ..) = element {
Merk::open_layered_with_root_key(storage, root_key, is_sum_tree)
.map_err(|_| {
Error::CorruptedData(
"cannot open a subtree with given root key".to_owned(),
)
})
.add_cost(cost)
Merk::open_layered_with_root_key(
storage,
root_key,
is_sum_tree,
Some(&Element::value_defined_cost_for_serialized_value),
)
.map_err(|_| {
Error::CorruptedData("cannot open a subtree with given root key".to_owned())
})
.add_cost(cost)
} else {
Err(Error::CorruptedPath(
"cannot open a subtree as parent exists but is not a tree",
Expand All @@ -1797,9 +1813,13 @@ impl GroveDb {
if new_merk {
Ok(Merk::open_empty(storage, MerkType::BaseMerk, false)).wrap_with_cost(cost)
} else {
Merk::open_base(storage, false)
.map_err(|_| Error::CorruptedData("cannot open a the root subtree".to_owned()))
.add_cost(cost)
Merk::open_base(
storage,
false,
Some(&Element::value_defined_cost_for_serialized_value),
)
.map_err(|_| Error::CorruptedData("cannot open a the root subtree".to_owned()))
.add_cost(cost)
}
}
}
Expand Down Expand Up @@ -1835,21 +1855,30 @@ impl GroveDb {
);
let is_sum_tree = element.is_sum_tree();
if let Element::Tree(root_key, _) | Element::SumTree(root_key, ..) = element {
Merk::open_layered_with_root_key(storage, root_key, is_sum_tree)
.map_err(|_| {
Error::CorruptedData("cannot open a subtree with given root key".to_owned())
})
.add_cost(local_cost)
Merk::open_layered_with_root_key(
storage,
root_key,
is_sum_tree,
Some(&Element::value_defined_cost_for_serialized_value),
)
.map_err(|_| {
Error::CorruptedData("cannot open a subtree with given root key".to_owned())
})
.add_cost(local_cost)
} else {
Err(Error::CorruptedData(
"cannot open a subtree as parent exists but is not a tree".to_owned(),
))
.wrap_with_cost(local_cost)
}
} else {
Merk::open_base(storage, false)
.map_err(|_| Error::CorruptedData("cannot open a subtree".to_owned()))
.add_cost(local_cost)
Merk::open_base(
storage,
false,
Some(&Element::value_defined_cost_for_serialized_value),
)
.map_err(|_| Error::CorruptedData("cannot open a subtree".to_owned()))
.add_cost(local_cost)
}
}

Expand Down
15 changes: 11 additions & 4 deletions grovedb/src/element/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,16 @@ impl Element {
};
let batch = [(key, op)];
let uses_sum_nodes = merk.is_sum_tree;
merk.apply_with_specialized_costs::<_, Vec<u8>>(&batch, &[], merk_options, &|key, value| {
Self::specialized_costs_for_key_value(key, value, uses_sum_nodes)
.map_err(|e| MerkError::ClientCorruptionError(e.to_string()))
})
merk.apply_with_specialized_costs::<_, Vec<u8>>(
&batch,
&[],
merk_options,
&|key, value| {
Self::specialized_costs_for_key_value(key, value, uses_sum_nodes)
.map_err(|e| MerkError::ClientCorruptionError(e.to_string()))
},
Some(&Element::value_defined_cost_for_serialized_value),
)
.map_err(|e| Error::CorruptedData(e.to_string()))
}

Expand Down Expand Up @@ -97,6 +103,7 @@ impl Element {
Self::specialized_costs_for_key_value(key, value, uses_sum_nodes)
.map_err(|e| MerkError::ClientCorruptionError(e.to_string()))
},
Some(&Element::value_defined_cost_for_serialized_value),
&mut |_costs, _old_value, _value| Ok((false, None)),
sectioned_removal,
)
Expand Down
7 changes: 5 additions & 2 deletions grovedb/src/element/exists.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ impl Element {
merk: &mut Merk<S>,
key: K,
) -> CostResult<bool, Error> {
merk.exists(key.as_ref())
.map_err(|e| Error::CorruptedData(e.to_string()))
merk.exists(
key.as_ref(),
Some(&Element::value_defined_cost_for_serialized_value),
)
.map_err(|e| Error::CorruptedData(e.to_string()))
}
}
32 changes: 26 additions & 6 deletions grovedb/src/element/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,12 @@ impl Element {

let value_opt = cost_return_on_error!(
&mut cost,
merk.get(key.as_ref(), allow_cache)
.map_err(|e| Error::CorruptedData(e.to_string()))
merk.get(
key.as_ref(),
allow_cache,
Some(&Element::value_defined_cost_for_serialized_value)
)
.map_err(|e| Error::CorruptedData(e.to_string()))
);
let element = cost_return_on_error_no_add!(
&cost,
Expand Down Expand Up @@ -230,8 +234,12 @@ impl Element {

let value_hash = cost_return_on_error!(
&mut cost,
merk.get_value_hash(key.as_ref(), allow_cache)
.map_err(|e| Error::CorruptedData(e.to_string()))
merk.get_value_hash(
key.as_ref(),
allow_cache,
Some(&Element::value_defined_cost_for_serialized_value)
)
.map_err(|e| Error::CorruptedData(e.to_string()))
);

Ok(value_hash).wrap_with_cost(cost)
Expand All @@ -253,7 +261,13 @@ mod tests {
let ctx = storage
.get_storage_context(SubtreePath::empty(), Some(&batch))
.unwrap();
let mut merk = Merk::open_base(ctx, false).unwrap().unwrap();
let mut merk = Merk::open_base(
ctx,
false,
Some(&Element::value_defined_cost_for_serialized_value),
)
.unwrap()
.unwrap();
Element::empty_tree()
.insert(&mut merk, b"mykey", None)
.unwrap()
Expand All @@ -271,7 +285,13 @@ mod tests {
let ctx = storage
.get_storage_context(SubtreePath::empty(), None)
.unwrap();
let mut merk = Merk::open_base(ctx, false).unwrap().unwrap();
let mut merk = Merk::open_base(
ctx,
false,
Some(&Element::value_defined_cost_for_serialized_value),
)
.unwrap()
.unwrap();

assert_eq!(
Element::get(&merk, b"another-key", true)
Expand Down
45 changes: 40 additions & 5 deletions grovedb/src/element/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@
//! Helpers
//! Implements helper functions in Element
use grovedb_merk::tree::kv::{
ValueDefinedCostType,
ValueDefinedCostType::{LayeredValueDefinedCost, SpecializedValueDefinedCost},
};
#[cfg(feature = "full")]
use grovedb_merk::{
tree::{kv::KV, TreeNode},
TreeFeatureType,
TreeFeatureType::{BasicMerk, SummedMerk},
TreeFeatureType::{BasicMerkNode, SummedMerkNode},
};
#[cfg(feature = "full")]
use integer_encoding::VarInt;
Expand Down Expand Up @@ -114,8 +118,8 @@ impl Element {
/// Get the tree feature type
pub fn get_feature_type(&self, parent_is_sum_tree: bool) -> Result<TreeFeatureType, Error> {
match parent_is_sum_tree {
true => Ok(SummedMerk(self.sum_value_or_default())),
false => Ok(BasicMerk),
true => Ok(SummedMerkNode(self.sum_value_or_default())),
false => Ok(BasicMerkNode),
}
}

Expand Down Expand Up @@ -307,13 +311,44 @@ impl Element {
)),
}
}

#[cfg(feature = "full")]
/// Get the value defined cost for a serialized value
pub fn value_defined_cost(&self) -> Option<ValueDefinedCostType> {
let Some(value_cost) = self.get_specialized_cost().ok() else {
return None;
};

let cost = value_cost
+ self.get_flags().as_ref().map_or(0, |flags| {
let flags_len = flags.len() as u32;
flags_len + flags_len.required_space() as u32
});
match self {
Element::Tree(..) => Some(LayeredValueDefinedCost(cost)),
Element::SumTree(..) => Some(LayeredValueDefinedCost(cost)),
Element::SumItem(..) => Some(SpecializedValueDefinedCost(cost)),
_ => None,
}
}

#[cfg(feature = "full")]
/// Get the value defined cost for a serialized value
pub fn value_defined_cost_for_serialized_value(value: &[u8]) -> Option<ValueDefinedCostType> {
let element = Element::deserialize(value).ok()?;
element.value_defined_cost()
}
}

#[cfg(feature = "full")]
/// Decode from bytes
pub fn raw_decode(bytes: &[u8]) -> Result<Element, Error> {
let tree =
TreeNode::decode_raw(bytes, vec![]).map_err(|e| Error::CorruptedData(e.to_string()))?;
let tree = TreeNode::decode_raw(
bytes,
vec![],
Some(Element::value_defined_cost_for_serialized_value),
)
.map_err(|e| Error::CorruptedData(e.to_string()))?;
let element: Element = Element::deserialize(tree.value_as_slice())?;
Ok(element)
}
3 changes: 3 additions & 0 deletions grovedb/src/element/insert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ impl Element {
Self::specialized_costs_for_key_value(key, value, uses_sum_nodes)
.map_err(|e| MerkError::ClientCorruptionError(e.to_string()))
},
Some(&Element::value_defined_cost_for_serialized_value),
)
.map_err(|e| Error::CorruptedData(e.to_string()))
}
Expand Down Expand Up @@ -287,6 +288,7 @@ impl Element {
Self::specialized_costs_for_key_value(key, value, uses_sum_nodes)
.map_err(|e| MerkError::ClientCorruptionError(e.to_string()))
},
Some(&Element::value_defined_cost_for_serialized_value),
)
.map_err(|e| Error::CorruptedData(e.to_string()))
}
Expand Down Expand Up @@ -356,6 +358,7 @@ impl Element {
Self::specialized_costs_for_key_value(key, value, uses_sum_nodes)
.map_err(|e| MerkError::ClientCorruptionError(e.to_string()))
},
Some(&Element::value_defined_cost_for_serialized_value),
)
.map_err(|e| Error::CorruptedData(e.to_string()))
}
Expand Down
Loading

0 comments on commit 7d0899c

Please sign in to comment.