use std::any::Any;
use std::sync::Arc;
use anyhow::{anyhow, Result};
use lora_store::{
GraphStorage, GraphStorageMut, InMemoryGraph, MutationEvent, MutationRecorder,
MutationWriteSet, NodeRecord, RelationshipRecord,
};
pub(crate) fn install_recorder_if_inmemory<S: GraphStorage + Any + Sized>(
store: &mut S,
recorder: Option<Arc<dyn MutationRecorder>>,
) {
let any: &mut dyn Any = store;
if let Some(graph) = any.downcast_mut::<InMemoryGraph>() {
graph.set_mutation_recorder(recorder);
}
}
pub(crate) fn validate_write_set_unchanged<S: GraphStorage + Any + Sized>(
snapshot: &S,
current: &S,
write_set: &MutationWriteSet,
) -> bool {
if write_set.cleared {
return false;
}
let snap_any: &dyn Any = snapshot;
let cur_any: &dyn Any = current;
let snap_im = snap_any.downcast_ref::<InMemoryGraph>();
let cur_im = cur_any.downcast_ref::<InMemoryGraph>();
let (snap, cur) = match (snap_im, cur_im) {
(Some(s), Some(c)) => (s, c),
_ => return std::ptr::eq(snapshot as *const S, current as *const S),
};
for &id in &write_set.nodes {
let snap_ptr = snap.with_node(id, |n| n as *const NodeRecord);
let cur_ptr = cur.with_node(id, |n| n as *const NodeRecord);
match (snap_ptr, cur_ptr) {
(Some(a), Some(b)) if std::ptr::eq(a, b) => {}
(None, None) => {}
_ => return false,
}
}
for &id in &write_set.rels {
let snap_ptr = snap.with_relationship(id, |r| r as *const RelationshipRecord);
let cur_ptr = cur.with_relationship(id, |r| r as *const RelationshipRecord);
match (snap_ptr, cur_ptr) {
(Some(a), Some(b)) if std::ptr::eq(a, b) => {}
(None, None) => {}
_ => return false,
}
}
true
}
pub(crate) fn merge_events_into<S: GraphStorage + Any + Sized>(
publish_state: &mut S,
events: &[MutationEvent],
) -> bool {
let any: &mut dyn Any = publish_state;
let Some(graph) = any.downcast_mut::<InMemoryGraph>() else {
return true;
};
for event in events {
if !apply_event(graph, event) {
return false;
}
}
true
}
pub(crate) fn apply_event(graph: &mut InMemoryGraph, event: &MutationEvent) -> bool {
match event {
MutationEvent::CreateNode {
id,
labels,
properties,
} => graph
.replay_create_node(*id, labels.clone(), properties.clone())
.is_ok(),
MutationEvent::CreateRelationship {
id,
src,
dst,
rel_type,
properties,
} => graph
.replay_create_relationship(*id, *src, *dst, rel_type, properties.clone())
.is_ok(),
MutationEvent::SetNodeProperty {
node_id,
key,
value,
} => graph.set_node_property(*node_id, key.clone(), value.clone()),
MutationEvent::RemoveNodeProperty { node_id, key } => {
graph.remove_node_property(*node_id, key)
}
MutationEvent::AddNodeLabel { node_id, label } => graph.add_node_label(*node_id, label),
MutationEvent::RemoveNodeLabel { node_id, label } => {
graph.remove_node_label(*node_id, label)
}
MutationEvent::SetRelationshipProperty { rel_id, key, value } => {
graph.set_relationship_property(*rel_id, key.clone(), value.clone())
}
MutationEvent::RemoveRelationshipProperty { rel_id, key } => {
graph.remove_relationship_property(*rel_id, key)
}
MutationEvent::DeleteRelationship { rel_id } => graph.delete_relationship(*rel_id),
MutationEvent::DeleteNode { node_id } => graph.delete_node(*node_id),
MutationEvent::DetachDeleteNode { node_id } => graph.detach_delete_node(*node_id),
MutationEvent::Clear => {
graph.clear();
true
}
}
}
pub(crate) fn replay_into(graph: &mut InMemoryGraph, events: Vec<MutationEvent>) -> Result<()> {
for (idx, event) in events.into_iter().enumerate() {
match event {
MutationEvent::CreateNode {
id,
labels,
properties,
} => {
graph
.replay_create_node(id, labels, properties)
.map_err(|e| anyhow!("WAL replay failed at event {idx}: {e}"))?;
}
MutationEvent::CreateRelationship {
id,
src,
dst,
rel_type,
properties,
} => {
graph
.replay_create_relationship(id, src, dst, &rel_type, properties)
.map_err(|e| anyhow!("WAL replay failed at event {idx}: {e}"))?;
}
MutationEvent::SetNodeProperty {
node_id,
key,
value,
} => {
if !graph.set_node_property(node_id, key, value) {
return Err(anyhow!(
"WAL replay failed at event {idx}: missing node {node_id} for property set"
));
}
}
MutationEvent::RemoveNodeProperty { node_id, key } => {
if !graph.remove_node_property(node_id, &key) {
return Err(anyhow!(
"WAL replay failed at event {idx}: missing node {node_id} for property removal"
));
}
}
MutationEvent::AddNodeLabel { node_id, label } => {
if !graph.add_node_label(node_id, &label) {
return Err(anyhow!(
"WAL replay failed at event {idx}: missing node {node_id} for label add"
));
}
}
MutationEvent::RemoveNodeLabel { node_id, label } => {
if !graph.remove_node_label(node_id, &label) {
return Err(anyhow!(
"WAL replay failed at event {idx}: missing node {node_id} for label removal"
));
}
}
MutationEvent::SetRelationshipProperty { rel_id, key, value } => {
if !graph.set_relationship_property(rel_id, key, value) {
return Err(anyhow!(
"WAL replay failed at event {idx}: missing relationship {rel_id} for property set"
));
}
}
MutationEvent::RemoveRelationshipProperty { rel_id, key } => {
if !graph.remove_relationship_property(rel_id, &key) {
return Err(anyhow!(
"WAL replay failed at event {idx}: missing relationship {rel_id} for property removal"
));
}
}
MutationEvent::DeleteRelationship { rel_id } => {
if !graph.delete_relationship(rel_id) {
return Err(anyhow!(
"WAL replay failed at event {idx}: missing relationship {rel_id} for delete"
));
}
}
MutationEvent::DeleteNode { node_id } => {
if !graph.delete_node(node_id) {
return Err(anyhow!(
"WAL replay failed at event {idx}: missing or attached node {node_id} for delete"
));
}
}
MutationEvent::DetachDeleteNode { node_id } => {
graph.detach_delete_node(node_id);
}
MutationEvent::Clear => {
graph.clear();
}
}
}
Ok(())
}