Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: various helper functions and fixes for platform contested resources PR #307

Merged
merged 45 commits into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c4201ed
feat: added new method to query item value or sum
QuantumExplorer May 18, 2024
a81de5e
feat: added new method to query item value or sum
QuantumExplorer May 18, 2024
8b09e18
feat: added new method to query item value or sum
QuantumExplorer May 18, 2024
a8f02d2
feat: added new method to query item value or sum
QuantumExplorer May 18, 2024
a62699d
feat: extra helpers
QuantumExplorer May 18, 2024
2c0712b
feat: allow to refer to sum trees
QuantumExplorer May 19, 2024
9cd00f3
changed lifetimes
QuantumExplorer May 22, 2024
6af586b
changed lifetimes
QuantumExplorer May 22, 2024
9fd8410
more fixes
QuantumExplorer May 22, 2024
1c7d13d
fix
ogabrielides May 22, 2024
761d45a
more fixes
QuantumExplorer May 22, 2024
1601625
sync session manages its transaction
fominok May 25, 2024
a4c65ba
Merge branch 'fix/ChunkLifetimes' of github.com:dashevo/grovedb into …
QuantumExplorer May 26, 2024
5f75f85
more fixes
ogabrielides May 26, 2024
d23d181
fmt
ogabrielides May 27, 2024
44a357c
Merge branch 'fix/ChunkLifetimes' into feat/QuerySumTree
QuantumExplorer May 27, 2024
56b824c
small helper
QuantumExplorer May 30, 2024
17e9193
additional helpers
QuantumExplorer May 30, 2024
229b7f2
added new reference type
QuantumExplorer May 31, 2024
d7474f4
some fixes
QuantumExplorer Jun 3, 2024
3e581c8
some fixes
QuantumExplorer Jun 3, 2024
c3d78a3
some fixes
QuantumExplorer Jun 3, 2024
ca40298
added convenience method
QuantumExplorer Jun 4, 2024
b297918
added a new function
QuantumExplorer Jun 5, 2024
07a5a19
made a struct copyable
QuantumExplorer Jun 6, 2024
b2483a0
added a little more information for an error
QuantumExplorer Jun 13, 2024
c66cb90
added a few more helper methods
QuantumExplorer Jun 17, 2024
964809f
added a few more helper methods
QuantumExplorer Jun 18, 2024
0b32606
fmt
QuantumExplorer Jun 18, 2024
8664b72
better internal error fix
QuantumExplorer Jun 24, 2024
31b5d21
fix
ogabrielides Jun 25, 2024
ea4bf6a
fixed import
QuantumExplorer Jun 25, 2024
8886695
fmt
QuantumExplorer Jun 25, 2024
c46194e
small fixes
QuantumExplorer Jun 25, 2024
cb03383
some clippy fixes
QuantumExplorer Jun 25, 2024
adb8fd1
query sum tree
fominok Jun 25, 2024
d77bbf5
qfix
fominok Jun 25, 2024
c0d810e
better error messages for proof errors
QuantumExplorer Jun 27, 2024
61dc98a
Merge branch 'feat/QuerySumTree' of github.com:dashevo/grovedb into f…
QuantumExplorer Jun 27, 2024
1696c2e
added debug
QuantumExplorer Jun 27, 2024
53642ed
make hex required
QuantumExplorer Jun 27, 2024
36eb5a9
a few improvements
QuantumExplorer Jun 30, 2024
c44aec6
a few improvements
QuantumExplorer Jun 30, 2024
5fb76c0
a few improvements
QuantumExplorer Jun 30, 2024
27e9a67
a few improvements
QuantumExplorer Jun 30, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions costs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ pub struct OperationCost {
}

impl OperationCost {
/// Is Nothing
pub fn is_nothing(&self) -> bool {
self == &Self::default()
}

/// Helper function to build default `OperationCost` with different
/// `seek_count`.
pub fn with_seek_count(seek_count: u16) -> Self {
Expand Down
8 changes: 6 additions & 2 deletions grovedb/src/element/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,12 @@ impl Element {
let value = result?;
value.ok_or_else(|| {
Error::PathKeyNotFound(format!(
"key not found in Merk for get: {}",
hex::encode(key)
"get: key \"{}\" not found in Merk that has a root key [{}] and is of type {}",
hex::encode(key),
merk.root_key()
.map(|key| hex::encode(key))
.unwrap_or("None".to_string()),
merk.merk_type
))
})
})
Expand Down
48 changes: 45 additions & 3 deletions grovedb/src/element/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,13 @@ use grovedb_merk::{
#[cfg(feature = "full")]
use integer_encoding::VarInt;

#[cfg(any(feature = "full", feature = "verify"))]
use crate::reference_path::{path_from_reference_path_type, ReferencePathType};
#[cfg(any(feature = "full", feature = "verify"))]
use crate::{element::SUM_ITEM_COST_SIZE, Element, Error};
#[cfg(feature = "full")]
use crate::{
element::{SUM_TREE_COST_SIZE, TREE_COST_SIZE},
reference_path::{path_from_reference_path_type, ReferencePathType},
ElementFlags,
};

Expand All @@ -64,15 +65,41 @@ impl Element {
}

#[cfg(any(feature = "full", feature = "verify"))]
/// Decoded the integer value in the SumItem element type, returns 0 for
/// everything else
/// Decoded the integer value in the SumItem element type
pub fn as_sum_item_value(&self) -> Result<i64, Error> {
match self {
Element::SumItem(value, _) => Ok(*value),
_ => Err(Error::WrongElementType("expected a sum item")),
}
}

#[cfg(any(feature = "full", feature = "verify"))]
/// Decoded the integer value in the SumItem element type
pub fn into_sum_item_value(self) -> Result<i64, Error> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the purpose of this method? as_sum_item_value is just fine because i64 is Copy

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still should be faster right as you are not copying memory. I agree it's not very important though.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It returns from the function so the stack frame is cleared and memory will be copied from there anyways, we're not avoiding memory copies by using self unless we doing so to avoid doing explicit clonings

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look, it really doesn't matter, we have a lot of into and as. While I could remove this, I just don't think it matters, so I prefer to keep it.

match self {
Element::SumItem(value, _) => Ok(value),
_ => Err(Error::WrongElementType("expected a sum item")),
}
}

#[cfg(any(feature = "full", feature = "verify"))]
/// Decoded the integer value in the SumTree element type
pub fn as_sum_tree_value(&self) -> Result<i64, Error> {
match self {
Element::SumTree(_, value, _) => Ok(*value),
_ => Err(Error::WrongElementType("expected a sum tree")),
}
}

#[cfg(any(feature = "full", feature = "verify"))]
/// Decoded the integer value in the SumTree element type
pub fn into_sum_tree_value(self) -> Result<i64, Error> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as_sum_tree_value is fine

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

match self {
Element::SumTree(_, value, _) => Ok(value),
_ => Err(Error::WrongElementType("expected a sum tree")),
}
}

#[cfg(any(feature = "full", feature = "verify"))]
/// Gives the item value in the Item element type
pub fn as_item_bytes(&self) -> Result<&[u8], Error> {
Expand All @@ -91,6 +118,15 @@ impl Element {
}
}

#[cfg(any(feature = "full", feature = "verify"))]
/// Gives the reference path type in the Reference element type
pub fn into_reference_path_type(self) -> Result<ReferencePathType, Error> {
match self {
Element::Reference(value, ..) => Ok(value),
_ => Err(Error::WrongElementType("expected a reference")),
}
}

#[cfg(any(feature = "full", feature = "verify"))]
/// Check if the element is a sum tree
pub fn is_sum_tree(&self) -> bool {
Expand All @@ -103,6 +139,12 @@ impl Element {
matches!(self, Element::SumTree(..) | Element::Tree(..))
}

#[cfg(any(feature = "full", feature = "verify"))]
/// Check if the element is a reference
pub fn is_reference(&self) -> bool {
matches!(self, Element::Reference(..))
}

#[cfg(any(feature = "full", feature = "verify"))]
/// Check if the element is an item
pub fn is_item(&self) -> bool {
Expand Down
4 changes: 2 additions & 2 deletions grovedb/src/element/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ use crate::{
QueryPathKeyElementTrioResultType,
},
},
util::{merk_optional_tx, storage_context_optional_tx},
util::{merk_optional_tx, merk_optional_tx_internal_error, storage_context_optional_tx},
Error, PathQuery, TransactionArg,
};
#[cfg(any(feature = "full", feature = "verify"))]
Expand Down Expand Up @@ -563,7 +563,7 @@ impl Element {
if !item.is_range() {
// this is a query on a key
if let QueryItem::Key(key) = item {
let element_res = merk_optional_tx!(
let element_res = merk_optional_tx_internal_error!(
&mut cost,
storage,
subtree_path,
Expand Down
1 change: 0 additions & 1 deletion grovedb/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ pub mod replication;
mod tests;
#[cfg(feature = "full")]
mod util;
#[cfg(any(feature = "full", feature = "verify"))]
mod versioning;
#[cfg(feature = "full")]
mod visualize;
Expand Down
3 changes: 3 additions & 0 deletions grovedb/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,6 @@ pub mod insert;
pub(crate) mod is_empty_tree;
#[cfg(any(feature = "full", feature = "verify"))]
pub mod proof;

#[cfg(feature = "full")]
pub use get::{QueryItemOrSumReturnType, MAX_REFERENCE_HOPS};
2 changes: 2 additions & 0 deletions grovedb/src/operations/get/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
mod average_case;
#[cfg(feature = "full")]
mod query;
#[cfg(feature = "full")]
pub use query::QueryItemOrSumReturnType;
#[cfg(feature = "estimated_costs")]
mod worst_case;

Expand Down
106 changes: 102 additions & 4 deletions grovedb/src/operations/get/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ use grovedb_costs::{
#[cfg(feature = "full")]
use integer_encoding::VarInt;

#[cfg(feature = "full")]
use crate::element::SumValue;
use crate::{element::QueryOptions, query_result_type::PathKeyOptionalElementTrio};
#[cfg(feature = "full")]
use crate::{
Expand All @@ -44,6 +46,16 @@ use crate::{
Element, Error, GroveDb, PathQuery, TransactionArg,
};

#[cfg(feature = "full")]
#[derive(Debug, Eq, PartialEq, Clone)]
/// A return type for query_item_value_or_sum
pub enum QueryItemOrSumReturnType {
/// an Item in serialized form
ItemData(Vec<u8>),
/// A sum item or a sum tree value
SumValue(SumValue),
}

#[cfg(feature = "full")]
impl GroveDb {
/// Encoded query for multiple path queries
Expand Down Expand Up @@ -190,10 +202,8 @@ where {
)),
}
}
Element::Item(..) | Element::SumItem(..) => Ok(element),
Element::Tree(..) | Element::SumTree(..) => Err(Error::InvalidQuery(
"path_queries can only refer to items and references",
)),
Element::Item(..) | Element::SumItem(..) | Element::SumTree(..) => Ok(element),
Element::Tree(..) => Err(Error::InvalidQuery("path_queries can not refer to trees")),
}
}

Expand Down Expand Up @@ -309,6 +319,94 @@ where {
Ok((results, skipped)).wrap_with_cost(cost)
}

/// Queries the backing store and returns element items by their value,
/// Sum Items are returned
pub fn query_item_value_or_sum(
&self,
path_query: &PathQuery,
allow_cache: bool,
decrease_limit_on_range_with_no_sub_elements: bool,
error_if_intermediate_path_tree_not_present: bool,
transaction: TransactionArg,
) -> CostResult<(Vec<QueryItemOrSumReturnType>, u16), Error> {
let mut cost = OperationCost::default();

let (elements, skipped) = cost_return_on_error!(
&mut cost,
self.query_raw(
path_query,
allow_cache,
decrease_limit_on_range_with_no_sub_elements,
error_if_intermediate_path_tree_not_present,
QueryResultType::QueryElementResultType,
transaction
)
);

let results_wrapped = elements
.into_iterator()
.map(|result_item| match result_item {
QueryResultElement::ElementResultItem(element) => {
match element {
Element::Reference(reference_path, ..) => {
match reference_path {
ReferencePathType::AbsolutePathReference(absolute_path) => {
// While `map` on iterator is lazy, we should accumulate costs
// even if `collect` will
// end in `Err`, so we'll use
// external costs accumulator instead of
// returning costs from `map` call.
let maybe_item = self
.follow_reference(
absolute_path.as_slice().into(),
allow_cache,
transaction,
)
.unwrap_add_cost(&mut cost)?;

match maybe_item {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we shall stop with maybe_item there and reuse the following code intended for non-references, because it's the same and reference will be already resolved

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't understand this comment.

Element::Item(item, _) => {
Ok(QueryItemOrSumReturnType::ItemData(item))
}
Element::SumItem(sum_value, _) => {
Ok(QueryItemOrSumReturnType::SumValue(sum_value))
}
Element::SumTree(_, sum_value, _) => {
Ok(QueryItemOrSumReturnType::SumValue(sum_value))
}
_ => Err(Error::InvalidQuery(
"the reference must result in an item",
)),
}
}
_ => Err(Error::CorruptedCodeExecution(
"reference after query must have absolute paths",
)),
}
}
Element::Item(item, _) => Ok(QueryItemOrSumReturnType::ItemData(item)),
Element::SumItem(sum_value, _) => {
Ok(QueryItemOrSumReturnType::SumValue(sum_value))
}
Element::SumTree(_, sum_value, _) => {
Ok(QueryItemOrSumReturnType::SumValue(sum_value))
}
Element::Tree(..) => Err(Error::InvalidQuery(
"path_queries can only refer to items, sum items, references and sum \
trees",
)),
}
}
_ => Err(Error::CorruptedCodeExecution(
"query returned incorrect result type",
)),
})
.collect::<Result<Vec<QueryItemOrSumReturnType>, Error>>();

let results = cost_return_on_error_no_add!(&cost, results_wrapped);
Ok((results, skipped)).wrap_with_cost(cost)
}

/// Retrieves only SumItem elements that match a path query
pub fn query_sums(
&self,
Expand Down
2 changes: 1 addition & 1 deletion grovedb/src/operations/proof/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@
#[cfg(any(feature = "full", feature = "verify"))]
use integer_encoding::{VarInt, VarIntReader};

use crate::operations::proof::verify::ProvedKeyValues;
#[cfg(any(feature = "full", feature = "verify"))]
use crate::Error;
use crate::{operations::proof::verify::ProvedKeyValues, reference_path::ReferencePathType};

Check warning on line 43 in grovedb/src/operations/proof/util.rs

View workflow job for this annotation

GitHub Actions / clippy

unused import: `reference_path::ReferencePathType`

warning: unused import: `reference_path::ReferencePathType` --> grovedb/src/operations/proof/util.rs:43:57 | 43 | use crate::{operations::proof::verify::ProvedKeyValues, reference_path::ReferencePathType}; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

#[cfg(any(feature = "full", feature = "verify"))]
pub const EMPTY_TREE_HASH: [u8; 32] = [0; 32];
Expand Down
79 changes: 79 additions & 0 deletions grovedb/src/query_result_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,85 @@ impl QueryResultElements {
})
.collect()
}

/// To last path to keys btree map
/// This is useful if for example the element is a sum item and isn't
/// important Used in Platform Drive for getting voters for multiple
/// contenders
pub fn to_last_path_to_keys_btree_map(self) -> BTreeMap<Key, Vec<Key>> {
let mut map: BTreeMap<Vec<u8>, Vec<Key>> = BTreeMap::new();

for result_item in self.elements.into_iter() {
if let QueryResultElement::PathKeyElementTrioResultItem((mut path, key, _)) =
result_item
{
if let Some(last) = path.pop() {
map.entry(last).or_insert_with(Vec::new).push(key);
}
}
}

map
}

/// To last path to key, elements btree map
pub fn to_last_path_to_key_elements_btree_map(self) -> BTreeMap<Key, BTreeMap<Key, Element>> {
let mut map: BTreeMap<Vec<u8>, BTreeMap<Key, Element>> = BTreeMap::new();

for result_item in self.elements.into_iter() {
if let QueryResultElement::PathKeyElementTrioResultItem((mut path, key, element)) =
result_item
{
if let Some(last) = path.pop() {
map.entry(last)
.or_insert_with(BTreeMap::new)
.insert(key, element);
}
}
}

map
}

/// To last path to elements btree map
/// This is useful if the key is not import
pub fn to_last_path_to_elements_btree_map(self) -> BTreeMap<Key, Vec<Element>> {
let mut map: BTreeMap<Vec<u8>, Vec<Element>> = BTreeMap::new();

for result_item in self.elements.into_iter() {
if let QueryResultElement::PathKeyElementTrioResultItem((mut path, _, element)) =
result_item
{
if let Some(last) = path.pop() {
map.entry(last).or_insert_with(Vec::new).push(element);
}
}
}

map
}

/// To last path to keys btree map
/// This is useful if for example the element is a sum item and isn't
/// important Used in Platform Drive for getting voters for multiple
/// contenders
pub fn to_previous_of_last_path_to_keys_btree_map(self) -> BTreeMap<Key, Vec<Key>> {
let mut map: BTreeMap<Vec<u8>, Vec<Key>> = BTreeMap::new();

for result_item in self.elements.into_iter() {
if let QueryResultElement::PathKeyElementTrioResultItem((mut path, key, _)) =
result_item
{
if let Some(_) = path.pop() {
if let Some(last) = path.pop() {
map.entry(last).or_insert_with(Vec::new).push(key);
}
}
}
}

map
}
}

impl Default for QueryResultElements {
Expand Down
Loading
Loading