use nodedb_physical::physical_plan::{DocumentOp, PhysicalPlan};
use crate::bridge::scan_filter::ScanFilter;
use crate::data::executor::core_loop::CoreLoop;
use crate::data::executor::handlers::bulk_dml::scan::{
ollp_edges_match, ollp_predicted_doc_ids, ollp_surrogates_match,
};
use crate::data::executor::task::ExecutionTask;
impl CoreLoop {
pub(in crate::data::executor) fn verify_calvin_active_ollp(
&self,
task: &ExecutionTask,
tid: u64,
plans: &[PhysicalPlan],
) -> crate::Result<bool> {
if !self.ollp_is_group_leader {
return Ok(true);
}
let database_id = task.request.database_id.as_u64();
for plan in plans {
let (collection, filter_bytes, predicted_surrogates, predicted_edges) = match plan {
PhysicalPlan::Document(DocumentOp::BulkDelete {
collection,
filters,
ollp_predicted_surrogates,
ollp_predicted_edges,
..
})
| PhysicalPlan::Document(DocumentOp::BulkUpdate {
collection,
filters,
ollp_predicted_surrogates,
ollp_predicted_edges,
..
}) => (
collection,
filters,
ollp_predicted_surrogates,
ollp_predicted_edges,
),
_ => continue,
};
let Some(predicted) = predicted_surrogates.as_deref() else {
continue;
};
let filters: Vec<ScanFilter> = if filter_bytes.is_empty() {
Vec::new()
} else {
zerompk::from_msgpack(filter_bytes).map_err(|e| crate::Error::Serialization {
format: "msgpack".to_string(),
detail: format!("calvin active ollp verify: deserialize filters: {e}"),
})?
};
let matching_ids =
self.scan_matching_documents(database_id, tid, collection, &filters)?;
if !ollp_surrogates_match(&matching_ids, predicted) {
return Ok(false);
}
if let Some(predicted_edges) = predicted_edges.as_deref() {
let apply_ids = ollp_predicted_doc_ids(predicted);
let actual = self.ollp_actual_edges(database_id, tid, collection, &apply_ids);
if !ollp_edges_match(actual, predicted_edges) {
return Ok(false);
}
}
}
Ok(true)
}
}