use linkrs_core::{StorageError, StorageResult};
use super::super::csr_shared::{
can_revert_delete, decide_slot_delete, decode_endpoint_pair, DeleteSlotOutcome,
};
use super::super::{EdgeId, Timestamp, VertexId, INVALID_EDGE_ID};
use super::{empty_slot, SingleMutableCsr};
impl SingleMutableCsr {
pub fn insert_edge(
&mut self,
src: u32,
dst: VertexId,
edge_id: EdgeId,
_ts: Timestamp,
) -> StorageResult<()> {
let src_idx = src as usize;
if src_idx >= self.vertex_capacity() {
self.ensure_vertex_capacity(src_idx + 1);
}
let (existing_hot, existing_cold) = match self.slot_at(src_idx) {
Some(probe) => (probe.hot(), probe.cold()),
None => (
super::super::HotNbr::dead_gap(),
super::super::ColdStamps::dead_gap(),
),
};
if existing_cold.is_live() && existing_hot.edge_id != INVALID_EDGE_ID {
return Err(StorageError::conflict(format!(
"[SingleMutableCsr] insert conflict on src={}: slot holds live edge {:?}",
src, existing_hot.edge_id
)));
}
let was_empty = existing_hot.edge_id == INVALID_EDGE_ID || !existing_cold.is_live();
let (decoded_endpoint, rank) = decode_endpoint_pair(dst).ok_or_else(|| {
StorageError::invalid_input(format!("Malformed edge endpoint key: {}", dst))
})?;
let segment = self.slot_mut_or_alloc(src_idx);
let (_, off) = Self::locate(src_idx);
segment.hot[off] = super::super::HotNbr {
endpoint: decoded_endpoint,
rank,
edge_id,
};
segment.cold[off] = super::super::ColdStamps {
delete_ts: Timestamp::MAX,
};
self.set_present(src_idx, true);
if was_empty {
self.edge_count += 1;
}
Ok(())
}
pub fn delete_edge(&mut self, src: u32, edge_id: EdgeId, ts: Timestamp) -> StorageResult<bool> {
let src_idx = src as usize;
if src_idx >= self.vertex_capacity() {
return Ok(false);
}
let probe = match self.slot_at(src_idx) {
Some(probe) => probe,
None => return Ok(false),
};
if probe.edge_id == INVALID_EDGE_ID {
return Ok(false);
}
if probe.edge_id != edge_id {
return Ok(false);
}
if matches!(
decide_slot_delete(&probe, probe.edge_id, ts)?,
DeleteSlotOutcome::AlreadyStamped
) {
return Ok(false);
}
self.stamp_delete(src_idx, ts);
self.edge_count -= 1;
Ok(true)
}
pub fn delete_edge_by_dst_reporting(
&mut self,
src: u32,
dst: VertexId,
ts: Timestamp,
on_deleted: &mut dyn FnMut(EdgeId),
) -> usize {
let src_idx = src as usize;
if src_idx >= self.vertex_capacity() {
return 0;
}
let (dst_ep, dst_rank) = match decode_endpoint_pair(dst) {
Some(pair) => pair,
None => return 0,
};
let probe = match self.slot_at(src_idx) {
Some(probe) => probe,
None => return 0,
};
if probe.edge_id == INVALID_EDGE_ID
|| probe.endpoint != dst_ep
|| probe.rank != dst_rank
|| !self.cold_is_live_at(src_idx)
{
return 0;
}
self.stamp_delete(src_idx, ts);
self.edge_count -= 1;
on_deleted(probe.edge_id);
1
}
pub fn delete_edge_by_dst(&mut self, src: u32, dst: VertexId, ts: Timestamp) -> usize {
let mut noop = |_: EdgeId| {};
self.delete_edge_by_dst_reporting(src, dst, ts, &mut noop)
}
pub fn revert_delete_by_offset(&mut self, src: u32, offset: i32, ts: Timestamp) -> bool {
if offset != 0 {
return false;
}
let src_idx = src as usize;
if src_idx >= self.vertex_capacity() {
return false;
}
let probe = match self.slot_at(src_idx) {
Some(probe) => probe,
None => return false,
};
if can_revert_delete(&probe, ts) {
self.clear_delete(src_idx);
self.edge_count += 1;
return true;
}
false
}
pub fn delete_edge_by_offset(
&mut self,
src: u32,
offset: i32,
ts: Timestamp,
) -> StorageResult<bool> {
if offset != 0 {
return Ok(false);
}
let src_idx = src as usize;
if src_idx >= self.vertex_capacity() {
return Ok(false);
}
let edge_id = self
.hot_at(src_idx)
.map(|hot| hot.edge_id)
.unwrap_or(INVALID_EDGE_ID);
self.delete_edge(src, edge_id, ts)
}
pub fn rollback_insert(&mut self, src: u32, edge_id: EdgeId) -> bool {
let src_idx = src as usize;
if src_idx >= self.vertex_capacity() {
return false;
}
let hot = match self.hot_at(src_idx) {
Some(h) => h,
None => return false,
};
if hot.edge_id == INVALID_EDGE_ID {
return false;
}
if hot.edge_id != edge_id {
return false;
}
let was_live = self.cold_is_live_at(src_idx);
self.set_slot(src_idx, empty_slot());
if was_live {
self.edge_count -= 1;
}
true
}
pub fn revert_delete_by_edge_id(&mut self, src: u32, edge_id: EdgeId, ts: Timestamp) -> bool {
let src_idx = src as usize;
if src_idx >= self.vertex_capacity() {
return false;
}
let probe = match self.slot_at(src_idx) {
Some(probe) => probe,
None => return false,
};
if probe.edge_id == INVALID_EDGE_ID {
return false;
}
if probe.edge_id != edge_id {
return false;
}
if can_revert_delete(&probe, ts) {
self.clear_delete(src_idx);
self.edge_count += 1;
return true;
}
false
}
}