1use std::collections::BTreeMap;
8use std::collections::BTreeSet;
9
10use serde::Deserialize;
11use serde::Serialize;
12
13use super::chord::PeerRing;
14use super::chord::PeerRingAction;
15use super::chord::RemoteAction;
16use super::entry::PlacedEntry;
17use super::topology;
18use super::topology::FindSuccessorStep;
19use super::topology::TopologyState;
20use super::types::Chord;
21use super::virtual_node::StorageVirtualNodes;
22use super::virtual_node::VirtualNode;
23use super::Did;
24use crate::error::Error;
25use crate::error::Result;
26
27mod repair;
28mod sync;
29
30#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
36pub enum StorageSyncPurpose {
37 OwnershipHandoff,
39 AdditiveRepair,
41}
42
43impl StorageSyncPurpose {
44 pub const fn permits_source_cleanup(self) -> bool {
46 matches!(self, Self::OwnershipHandoff)
47 }
48}
49
50#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
62pub enum StorageSyncDestination {
63 PhysicalOwner(Did),
65 PlacementKey(Did),
67}
68
69impl StorageSyncDestination {
70 pub const fn physical_owner(did: Did) -> Self {
72 Self::PhysicalOwner(did)
73 }
74
75 pub const fn placement_key(did: Did) -> Self {
77 Self::PlacementKey(did)
78 }
79
80 pub fn did(self) -> Did {
82 match self {
83 Self::PhysicalOwner(did) | Self::PlacementKey(did) => did,
84 }
85 }
86
87 pub const fn route(self) -> StorageSyncRoute {
89 match self {
90 Self::PhysicalOwner(_) => StorageSyncRoute::PhysicalOwner,
91 Self::PlacementKey(_) => StorageSyncRoute::PlacementKey,
92 }
93 }
94}
95
96#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)]
101pub enum StorageSyncRoute {
102 PhysicalOwner,
104 PlacementKey,
106}
107
108impl StorageSyncRoute {
109 pub const fn destination(self, target: Did) -> StorageSyncDestination {
111 match self {
112 Self::PhysicalOwner => StorageSyncDestination::physical_owner(target),
113 Self::PlacementKey => StorageSyncDestination::placement_key(target),
114 }
115 }
116}
117
118#[derive(Debug, PartialEq, Eq)]
120pub(crate) struct StorageSyncDelivery {
121 purpose: StorageSyncPurpose,
122 destination: StorageSyncDestination,
123 data: Vec<PlacedEntry>,
124}
125
126#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
128pub(crate) struct StorageSyncDeliveryCursor {
129 purpose: StorageSyncPurpose,
130 destination: StorageSyncDestination,
131 placement_keys: Vec<Did>,
132}
133
134impl StorageSyncDelivery {
135 fn from_parts(
136 purpose: StorageSyncPurpose,
137 destination: StorageSyncDestination,
138 data: Vec<PlacedEntry>,
139 ) -> Self {
140 Self {
141 purpose,
142 destination,
143 data,
144 }
145 }
146
147 fn from_route(
148 purpose: StorageSyncPurpose,
149 target: Did,
150 route: StorageSyncRoute,
151 data: Vec<PlacedEntry>,
152 ) -> Self {
153 Self {
158 purpose,
159 destination: route.destination(target),
160 data,
161 }
162 }
163
164 pub(crate) fn into_message_parts(
166 self,
167 ) -> (StorageSyncPurpose, StorageSyncDestination, Vec<PlacedEntry>) {
168 (self.purpose, self.destination, self.data)
169 }
170
171 pub(crate) fn cursor_key(&self) -> StorageSyncDeliveryCursor {
177 let mut placement_keys = self
178 .data
179 .iter()
180 .map(|placed| placed.key)
181 .collect::<Vec<_>>();
182 placement_keys.sort_unstable();
183 StorageSyncDeliveryCursor {
184 purpose: self.purpose,
185 destination: self.destination,
186 placement_keys,
187 }
188 }
189}
190
191pub(super) enum StorageSyncTarget {
192 Local,
193 Remote(StorageSyncDestination),
194}
195
196impl PeerRingAction {
197 pub(crate) fn sync_entries_for_handoff(
198 destination: StorageSyncDestination,
199 data: Vec<PlacedEntry>,
200 ) -> Self {
201 Self::sync_entries(StorageSyncPurpose::OwnershipHandoff, destination, data)
202 }
203
204 pub(crate) fn sync_entries_for_repair(
205 destination: StorageSyncDestination,
206 data: Vec<PlacedEntry>,
207 ) -> Self {
208 Self::sync_entries(StorageSyncPurpose::AdditiveRepair, destination, data)
209 }
210
211 fn sync_entries(
212 purpose: StorageSyncPurpose,
213 destination: StorageSyncDestination,
214 data: Vec<PlacedEntry>,
215 ) -> Self {
216 Self::RemoteAction(destination.did(), RemoteAction::SyncEntriesWithSuccessor {
217 purpose,
218 route: destination.route(),
219 data,
220 })
221 }
222
223 pub(crate) fn storage_sync_deliveries(self) -> Result<Vec<StorageSyncDelivery>> {
225 let mut deliveries = Vec::new();
226 self.collect_storage_sync_deliveries(&mut deliveries)?;
227 Ok(deliveries)
228 }
229
230 pub(crate) fn coalesced_storage_sync_deliveries(self) -> Result<Vec<StorageSyncDelivery>> {
238 let mut by_route =
239 BTreeMap::<(StorageSyncPurpose, StorageSyncDestination), Vec<PlacedEntry>>::new();
240 for delivery in self.storage_sync_deliveries()? {
241 let (purpose, destination, data) = delivery.into_message_parts();
242 by_route
243 .entry((purpose, destination))
244 .or_default()
245 .extend(data);
246 }
247
248 let mut deliveries = Vec::new();
249 for ((purpose, destination), data) in by_route {
250 for batch in sync::sync_entries_batches(data, sync::SYNC_BATCH_MAX_BYTES)? {
251 deliveries.push(StorageSyncDelivery::from_parts(purpose, destination, batch));
252 }
253 }
254 Ok(deliveries)
255 }
256
257 fn collect_storage_sync_deliveries(
258 self,
259 deliveries: &mut Vec<StorageSyncDelivery>,
260 ) -> Result<()> {
261 match self {
262 Self::None => Ok(()),
263 Self::RemoteAction(
264 target,
265 RemoteAction::SyncEntriesWithSuccessor {
266 purpose,
267 route,
268 data,
269 },
270 ) => {
271 deliveries.push(StorageSyncDelivery::from_route(
272 purpose, target, route, data,
273 ));
274 Ok(())
275 }
276 Self::MultiActions(actions) => {
277 for action in actions {
278 action.collect_storage_sync_deliveries(deliveries)?;
279 }
280 Ok(())
281 }
282 action => Err(Error::unexpected_peer_ring_action(action)),
283 }
284 }
285}
286
287impl PeerRing {
288 pub fn storage_virtual_nodes_enabled(&self) -> Result<bool> {
290 Ok(self.storage_virtual_node_config().is_enabled())
291 }
292
293 pub fn storage_virtual_positions(&self, owner: Did) -> Result<Vec<VirtualNode>> {
295 Ok(self.storage_virtual_nodes()?.positions_for_owner(owner))
296 }
297
298 pub(super) fn observed_storage_virtual_owner(&self, placement_key: Did) -> Result<Option<Did>> {
299 Ok(self.storage_virtual_nodes()?.owner_for_key(placement_key))
300 }
301
302 pub(super) fn observed_storage_virtual_owner_registered(&self, owner: Did) -> Result<bool> {
303 Ok(self.storage_virtual_nodes()?.contains_owner(owner))
304 }
305
306 fn storage_virtual_nodes(&self) -> Result<StorageVirtualNodes> {
307 let state = self.topology_state()?;
308 Ok(self.storage_virtual_nodes_for_topology(&state))
309 }
310
311 fn storage_virtual_nodes_for_topology(&self, state: &TopologyState) -> StorageVirtualNodes {
312 let mut owners = BTreeSet::new();
313 owners.insert(state.local);
318 owners.extend(state.successors.iter().copied());
319 owners.extend(state.predecessor);
320 owners.extend(state.fingers.iter().flatten().copied());
321 StorageVirtualNodes::from_owners(self.storage_virtual_node_config(), owners)
322 }
323
324 pub(crate) fn find_storage_owner(&self, placement_key: Did) -> Result<PeerRingAction> {
325 if let Some(owner) = self.observed_storage_virtual_owner(placement_key)? {
326 if owner == self.did {
327 Ok(PeerRingAction::Some(owner))
328 } else {
329 Ok(PeerRingAction::RemoteAction(
330 owner,
331 RemoteAction::FindSuccessor(placement_key),
332 ))
333 }
334 } else {
335 self.find_successor(placement_key)
336 }
337 }
338
339 pub(super) fn storage_sync_target(&self, placement_key: Did) -> Result<StorageSyncTarget> {
340 if let Some(owner) = self.observed_storage_virtual_owner(placement_key)? {
341 if owner == self.did {
342 Ok(StorageSyncTarget::Local)
343 } else {
344 Ok(StorageSyncTarget::Remote(
345 StorageSyncDestination::PhysicalOwner(owner),
346 ))
347 }
348 } else {
349 match self.find_successor(placement_key)? {
350 PeerRingAction::Some(_) => Ok(StorageSyncTarget::Local),
355 PeerRingAction::RemoteAction(_, RemoteAction::FindSuccessor(_)) => Ok(
356 StorageSyncTarget::Remote(StorageSyncDestination::PlacementKey(placement_key)),
357 ),
358 action => Err(Error::unexpected_peer_ring_action(action)),
359 }
360 }
361 }
362
363 pub(crate) fn next_hop_for_storage_sync(
364 &self,
365 destination: StorageSyncDestination,
366 ) -> Result<Option<Did>> {
367 let state = self.topology_state()?;
368 Ok(self.next_hop_for_storage_sync_in(&state, destination))
369 }
370
371 pub(crate) fn storage_sync_route_still_permits(
372 &self,
373 destination: StorageSyncDestination,
374 next_hop: Did,
375 ) -> Result<bool> {
376 self.with_topology_state(|state| {
377 self.storage_sync_route_permits_in(state, destination, next_hop)
378 })
379 }
380
381 pub(crate) fn with_permitted_storage_sync_route<T>(
388 &self,
389 destination: StorageSyncDestination,
390 next_hop: Did,
391 operation: impl FnOnce() -> T,
392 ) -> Result<Option<T>> {
393 self.with_topology_state(|state| {
394 self.storage_sync_route_permits_in(state, destination, next_hop)
395 .then(operation)
396 })
397 }
398
399 fn storage_sync_route_permits_in(
400 &self,
401 state: &TopologyState,
402 destination: StorageSyncDestination,
403 next_hop: Did,
404 ) -> bool {
405 Self::routing_peer_registered_in(state, next_hop)
406 && self.next_hop_for_storage_sync_in(state, destination) == Some(next_hop)
407 }
408
409 fn routing_peer_registered_in(state: &TopologyState, peer: Did) -> bool {
410 peer == state.local
411 || state.successors.contains(&peer)
412 || state.predecessor == Some(peer)
413 || state.fingers.iter().flatten().any(|did| *did == peer)
414 }
415
416 fn next_hop_for_storage_sync_in(
419 &self,
420 state: &TopologyState,
421 destination: StorageSyncDestination,
422 ) -> Option<Did> {
423 match destination {
424 StorageSyncDestination::PhysicalOwner(owner) => {
425 Self::next_hop_to_physical_owner_in(state, owner)
426 }
427 StorageSyncDestination::PlacementKey(key) => {
428 self.next_hop_to_storage_placement_in(state, key)
429 }
430 }
431 }
432
433 fn next_hop_to_physical_owner_in(state: &TopologyState, owner: Did) -> Option<Did> {
434 if owner == state.local {
435 return None;
436 }
437 match topology::find_successor(state, owner) {
438 FindSuccessorStep::Local(next) if next == state.local => Some(owner),
442 FindSuccessorStep::Local(next) | FindSuccessorStep::Remote { next, .. } => Some(next),
443 }
444 }
445
446 fn next_hop_to_storage_placement_in(&self, state: &TopologyState, key: Did) -> Option<Did> {
447 if let Some(owner) = self
448 .storage_virtual_nodes_for_topology(state)
449 .owner_for_key(key)
450 {
451 return (owner != state.local).then_some(owner);
452 }
453 match topology::find_successor(state, key) {
454 FindSuccessorStep::Local(_) => None,
455 FindSuccessorStep::Remote { next, .. } => Some(next),
456 }
457 }
458}
459
460#[cfg(all(not(all(feature = "wasm", target_family = "wasm")), test))]
461mod tests;