linkrs_storage/edge/single_mutable_csr/
write.rs1use linkrs_core::{StorageError, StorageResult};
4
5use super::super::csr_shared::{
6 can_revert_delete, decide_slot_delete, decode_endpoint_pair, DeleteSlotOutcome,
7};
8use super::super::{EdgeId, Timestamp, VertexId, INVALID_EDGE_ID};
9use super::{empty_slot, SingleMutableCsr};
10
11impl SingleMutableCsr {
12 pub fn insert_edge(
13 &mut self,
14 src: u32,
15 dst: VertexId,
16 edge_id: EdgeId,
17 _ts: Timestamp,
18 ) -> StorageResult<()> {
19 let src_idx = src as usize;
20
21 if src_idx >= self.vertex_capacity() {
22 self.ensure_vertex_capacity(src_idx + 1);
23 }
24
25 let (existing_hot, existing_cold) = match self.slot_at(src_idx) {
26 Some(probe) => (probe.hot(), probe.cold()),
27 None => (
28 super::super::HotNbr::dead_gap(),
29 super::super::ColdStamps::dead_gap(),
30 ),
31 };
32
33 if existing_cold.is_live() && existing_hot.edge_id != INVALID_EDGE_ID {
38 return Err(StorageError::conflict(format!(
39 "[SingleMutableCsr] insert conflict on src={}: slot holds live edge {:?}",
40 src, existing_hot.edge_id
41 )));
42 }
43
44 let was_empty = existing_hot.edge_id == INVALID_EDGE_ID || !existing_cold.is_live();
45 let (decoded_endpoint, rank) = decode_endpoint_pair(dst).ok_or_else(|| {
46 StorageError::invalid_input(format!("Malformed edge endpoint key: {}", dst))
47 })?;
48 let segment = self.slot_mut_or_alloc(src_idx);
49 let (_, off) = Self::locate(src_idx);
50 segment.hot[off] = super::super::HotNbr {
51 endpoint: decoded_endpoint,
52 rank,
53 edge_id,
54 };
55 segment.cold[off] = super::super::ColdStamps {
56 delete_ts: Timestamp::MAX,
57 };
58 self.set_present(src_idx, true);
59
60 if was_empty {
61 self.edge_count += 1;
62 }
63
64 Ok(())
65 }
66
67 pub fn delete_edge(&mut self, src: u32, edge_id: EdgeId, ts: Timestamp) -> StorageResult<bool> {
68 let src_idx = src as usize;
69
70 if src_idx >= self.vertex_capacity() {
71 return Ok(false);
72 }
73
74 let probe = match self.slot_at(src_idx) {
75 Some(probe) => probe,
76 None => return Ok(false),
77 };
78
79 if probe.edge_id == INVALID_EDGE_ID {
80 return Ok(false);
81 }
82
83 if probe.edge_id != edge_id {
84 return Ok(false);
85 }
86
87 if matches!(
88 decide_slot_delete(&probe, probe.edge_id, ts)?,
89 DeleteSlotOutcome::AlreadyStamped
90 ) {
91 return Ok(false);
92 }
93
94 self.stamp_delete(src_idx, ts);
95 self.edge_count -= 1;
96 Ok(true)
97 }
98
99 pub fn delete_edge_by_dst_reporting(
105 &mut self,
106 src: u32,
107 dst: VertexId,
108 ts: Timestamp,
109 on_deleted: &mut dyn FnMut(EdgeId),
110 ) -> usize {
111 let src_idx = src as usize;
112
113 if src_idx >= self.vertex_capacity() {
114 return 0;
115 }
116
117 let (dst_ep, dst_rank) = match decode_endpoint_pair(dst) {
118 Some(pair) => pair,
119 None => return 0,
120 };
121 let probe = match self.slot_at(src_idx) {
122 Some(probe) => probe,
123 None => return 0,
124 };
125
126 if probe.edge_id == INVALID_EDGE_ID
127 || probe.endpoint != dst_ep
128 || probe.rank != dst_rank
129 || !self.cold_is_live_at(src_idx)
130 {
131 return 0;
132 }
133
134 self.stamp_delete(src_idx, ts);
135 self.edge_count -= 1;
136 on_deleted(probe.edge_id);
137 1
138 }
139
140 pub fn delete_edge_by_dst(&mut self, src: u32, dst: VertexId, ts: Timestamp) -> usize {
144 let mut noop = |_: EdgeId| {};
145 self.delete_edge_by_dst_reporting(src, dst, ts, &mut noop)
146 }
147
148 pub fn revert_delete_by_offset(&mut self, src: u32, offset: i32, ts: Timestamp) -> bool {
149 if offset != 0 {
150 return false;
151 }
152
153 let src_idx = src as usize;
154
155 if src_idx >= self.vertex_capacity() {
156 return false;
157 }
158
159 let probe = match self.slot_at(src_idx) {
160 Some(probe) => probe,
161 None => return false,
162 };
163
164 if can_revert_delete(&probe, ts) {
166 self.clear_delete(src_idx);
167 self.edge_count += 1;
168 return true;
169 }
170
171 false
172 }
173
174 pub fn delete_edge_by_offset(
175 &mut self,
176 src: u32,
177 offset: i32,
178 ts: Timestamp,
179 ) -> StorageResult<bool> {
180 if offset != 0 {
181 return Ok(false);
182 }
183 let src_idx = src as usize;
184 if src_idx >= self.vertex_capacity() {
185 return Ok(false);
186 }
187 let edge_id = self
188 .hot_at(src_idx)
189 .map(|hot| hot.edge_id)
190 .unwrap_or(INVALID_EDGE_ID);
191 self.delete_edge(src, edge_id, ts)
192 }
193
194 pub fn rollback_insert(&mut self, src: u32, edge_id: EdgeId) -> bool {
195 let src_idx = src as usize;
196 if src_idx >= self.vertex_capacity() {
197 return false;
198 }
199 let hot = match self.hot_at(src_idx) {
200 Some(h) => h,
201 None => return false,
202 };
203 if hot.edge_id == INVALID_EDGE_ID {
204 return false;
205 }
206 if hot.edge_id != edge_id {
207 return false;
208 }
209 let was_live = self.cold_is_live_at(src_idx);
210 self.set_slot(src_idx, empty_slot());
211 if was_live {
212 self.edge_count -= 1;
213 }
214 true
215 }
216
217 pub fn revert_delete_by_edge_id(&mut self, src: u32, edge_id: EdgeId, ts: Timestamp) -> bool {
218 let src_idx = src as usize;
219 if src_idx >= self.vertex_capacity() {
220 return false;
221 }
222 let probe = match self.slot_at(src_idx) {
223 Some(probe) => probe,
224 None => return false,
225 };
226 if probe.edge_id == INVALID_EDGE_ID {
227 return false;
228 }
229 if probe.edge_id != edge_id {
230 return false;
231 }
232 if can_revert_delete(&probe, ts) {
233 self.clear_delete(src_idx);
234 self.edge_count += 1;
235 return true;
236 }
237 false
238 }
239}