use std::ops::DerefMut;
use petgraph::{data::DataMap, visit::GraphBase};
use super::{worklists::PushFnWrapper, *};
#[derive(Clone)]
pub struct ConflictResolvingOperator<Op> {
op: Op,
}
impl<Op> ConflictResolvingOperator<Op> {
pub fn new(op: Op) -> Self {
Self { op }
}
}
impl<G, Op> ReadonlyOperator<G> for ConflictResolvingOperator<Op>
where
Op: LabellingOperator<G>,
G: GraphBase + DataMap,
G::NodeWeight: BorrowDataCell<UserData = Op::NodeWeight>,
Op::WorkItem: Copy,
{
type WorkItem = Op::WorkItem;
fn op(
&self,
work_item: Self::WorkItem,
local_view: LocalGraphView<&G>,
mut worklist: impl WorklistPush<Self::WorkItem>,
) {
let worker_id = worklist.current_worker_id();
let active_node = local_view.active_node();
let local_view = &local_view;
let node_data = local_view
.node_weight(active_node)
.expect("node has no data");
let mut data_guard = match node_data.borrow_data_cell().try_write(0) {
Ok(g) => g,
Err(e) => {
match e {
id_rwlock::IdLockWriteErr::CurrentWriter(other_worker_id) => {
let responsible_worker_id =
worklist.current_worker_id().min(other_worker_id);
worklist.push_to(work_item, responsible_worker_id);
}
id_rwlock::IdLockWriteErr::NumberOfReaders(_) => {
worklist.push(work_item);
}
};
return;
}
};
let node_data = data_guard.deref_mut();
let local_view_mut = LocalGraphView::new(local_view.base_graph(), active_node);
let push = PushFnWrapper::new(|item| worklist.push(item), worker_id);
let op_result = self.op.op(work_item, local_view_mut, node_data, push);
if let Err(data_conflict_err) = op_result {
match data_conflict_err.err {
LockingErr::ReadErr(read_err) => match read_err {
id_rwlock::IdLockReadErr::CurrentWriter(other_worker_id) => {
worklist.push_to(work_item, other_worker_id);
}
id_rwlock::IdLockReadErr::LocksExhausted(_) => {
worklist.push(work_item);
}
},
LockingErr::WriteErr(_write_err) => {
unreachable!("unexpected write conflict")
}
}
}
}
}