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

refactor: remove expensive clones from verify_consistency_of_operations; convert API to slice #285

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
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
107 changes: 46 additions & 61 deletions grovedb/src/batch/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -552,95 +552,78 @@ impl GroveDbOp {
}

/// Verify consistency of operations
pub fn verify_consistency_of_operations(ops: &Vec<GroveDbOp>) -> GroveDbOpConsistencyResults {
let ops_len = ops.len();
pub fn verify_consistency_of_operations(ops: &[GroveDbOp]) -> GroveDbOpConsistencyResults {
// operations should not have any duplicates
let mut repeated_ops = vec![];
for (i, op) in ops.iter().enumerate() {
if i == ops_len {
continue;
} // Don't do last one
let mut same_path_key_ops = vec![];
// Exclude the last item
for (i, op) in ops.iter().take(ops.len() - 1).enumerate() {
let count = ops
.split_at(i + 1)
.1
.iter()
.filter(|&current_op| current_op == op)
.count() as u16;
if count > 1 {
repeated_ops.push((op.clone(), count));
repeated_ops.push((op, count));
}
}

let mut same_path_key_ops = vec![];

// No double insert or delete of same key in same path
for (i, op) in ops.iter().enumerate() {
if i == ops_len {
continue;
} // Don't do last one
// No double insert or delete of same key in same path
let mut doubled_ops = ops
.split_at(i + 1)
.1
.iter()
.filter_map(|current_op| {
if current_op.path == op.path && current_op.key == op.key {
Some(current_op.op.clone())
Some(&current_op.op)
} else {
None
}
})
.collect::<Vec<Op>>();
.collect::<Vec<&Op>>();
if !doubled_ops.is_empty() {
doubled_ops.push(op.op.clone());
same_path_key_ops.push((op.path.clone(), op.key.clone(), doubled_ops));
doubled_ops.push(&op.op);
same_path_key_ops.push((&op.path, &op.key, doubled_ops));
}
}

let inserts = ops
.iter()
.filter_map(|current_op| match current_op.op {
Op::Insert { .. } | Op::Replace { .. } => Some(current_op.clone()),
_ => None,
})
.collect::<Vec<GroveDbOp>>();
.filter(|current_op| matches!(current_op.op, Op::Insert { .. } | Op::Replace { .. }))
.collect::<Vec<&GroveDbOp>>();

let deletes = ops
.iter()
.filter_map(|current_op| {
if let Op::Delete = current_op.op {
Some(current_op.clone())
.filter(|current_op| matches!(current_op.op, Op::Delete))
.collect::<Vec<&GroveDbOp>>();

let insert_ops_below_deleted_ops = deletes
.iter()
.filter_map(|&deleted_op| {
let mut deleted_qualified_path = deleted_op.path.clone();
deleted_qualified_path.push(deleted_op.key.clone());
let inserts_with_deleted_ops_above = inserts
.iter()
.filter_map(|&inserted_op| {
if deleted_op.path.len() < inserted_op.path.len()
&& deleted_qualified_path
.iterator()
.zip(inserted_op.path.iterator())
.all(|(a, b)| a == b)
{
Some(inserted_op)
} else {
None
}
})
.collect::<Vec<&GroveDbOp>>();
if !inserts_with_deleted_ops_above.is_empty() {
Some((deleted_op, inserts_with_deleted_ops_above))
} else {
None
}
})
.collect::<Vec<GroveDbOp>>();

let mut insert_ops_below_deleted_ops = vec![];

// No inserts under a deleted path
for deleted_op in deletes.iter() {
let mut deleted_qualified_path = deleted_op.path.clone();
deleted_qualified_path.push(deleted_op.key.clone());
let inserts_with_deleted_ops_above = inserts
.iter()
.filter_map(|inserted_op| {
if deleted_op.path.len() < inserted_op.path.len()
&& deleted_qualified_path
.iterator()
.zip(inserted_op.path.iterator())
.all(|(a, b)| a == b)
{
Some(inserted_op.clone())
} else {
None
}
})
.collect::<Vec<GroveDbOp>>();
if !inserts_with_deleted_ops_above.is_empty() {
insert_ops_below_deleted_ops
.push((deleted_op.clone(), inserts_with_deleted_ops_above));
}
}
.collect::<Vec<(&GroveDbOp, Vec<&GroveDbOp>)>>();

GroveDbOpConsistencyResults {
repeated_ops,
Expand All @@ -652,14 +635,16 @@ impl GroveDbOp {

/// Results of a consistency check on an operation batch
#[derive(Debug)]
pub struct GroveDbOpConsistencyResults {
repeated_ops: Vec<(GroveDbOp, u16)>, // the u16 is count
same_path_key_ops: Vec<(KeyInfoPath, KeyInfo, Vec<Op>)>,
insert_ops_below_deleted_ops: Vec<(GroveDbOp, Vec<GroveDbOp>)>, /* the deleted op first,
* then inserts under */
pub struct GroveDbOpConsistencyResults<'a> {
repeated_ops: Vec<(&'a GroveDbOp, u16)>, // the u16 is count
same_path_key_ops: Vec<(&'a KeyInfoPath, &'a KeyInfo, Vec<&'a Op>)>,
insert_ops_below_deleted_ops: Vec<(&'a GroveDbOp, Vec<&'a GroveDbOp>)>, /* the deleted op
* first,
* then inserts
* under */
}

impl GroveDbOpConsistencyResults {
impl GroveDbOpConsistencyResults<'_> {
/// Check if results are empty
pub fn is_empty(&self) -> bool {
self.repeated_ops.is_empty()
Expand Down
Loading