Skip to main content

rings_core/dht/chord/
action.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4use super::PeerRing;
5use crate::dht::entry::EntryLookupEvidence;
6use crate::dht::entry::EntryLookupKey;
7use crate::dht::entry::PlacedEntry;
8use crate::dht::entry::PlacedEntryOperation;
9use crate::dht::entry::PlacementMiss;
10use crate::dht::storage::StorageSyncPurpose;
11use crate::dht::storage::StorageSyncRoute;
12use crate::dht::Did;
13use crate::error::Error;
14use crate::error::Result;
15
16/// Describes either a completed peer-ring operation or work to continue remotely.
17#[derive(Clone, Debug, PartialEq)]
18pub enum PeerRingAction {
19    /// No result, the whole manipulation is done internally.
20    None,
21    /// Found an entry together with lookup evidence.
22    SomeEntry(EntryLookupEvidence),
23    /// Observed placement misses without a hit.
24    EntryMisses(Vec<PlacementMiss>),
25    /// Found some node.
26    Some(Did),
27    /// Trigger a remote action.
28    RemoteAction(Did, RemoteAction),
29    /// Trigger multiple remote actions.
30    MultiActions(Vec<PeerRingAction>),
31}
32
33/// Describes the remote continuation required by a peer-ring operation.
34///
35/// The DID in [`PeerRingAction::RemoteAction`] is the recipient; DIDs stored in
36/// this enum are the operation's payload.
37#[derive(Clone, Debug, PartialEq, Eq)]
38pub enum RemoteAction {
39    /// Ask the recipient to find this DID's successor.
40    FindSuccessor(Did),
41    /// Ask the recipient to find one entry placement.
42    FindEntry(EntryLookupKey),
43    /// Ask the recipient to find one placement for operating.
44    FindEntryForOperate(PlacedEntryOperation),
45    /// Send a predecessor notification to the recipient.
46    Notify(Did),
47    /// Copy placed entries to one storage sync destination.
48    SyncEntriesWithSuccessor {
49        /// Sync transition kind.
50        purpose: StorageSyncPurpose,
51        /// Routing semantics for the outer action target.
52        route: StorageSyncRoute,
53        /// Entries to copy at their placement keys.
54        data: Vec<PlacedEntry>,
55    },
56    /// Find a successor and report it for connection establishment.
57    FindSuccessorForConnect(Did),
58    /// Find a successor and report it for one finger-table slot.
59    FindSuccessorForFix {
60        /// DID whose successor should populate the finger slot.
61        did: Did,
62        /// Finger slot that should be updated by the report.
63        index: usize,
64    },
65    /// Fetch the recipient's successor list.
66    QueryForSuccessorList,
67    /// Fetch the recipient's successor list and predecessor.
68    QueryForSuccessorListAndPred,
69    /// Try to connect to the recipient.
70    TryConnect,
71}
72
73/// Information about a node's successors and predecessor.
74#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Clone)]
75pub struct TopoInfo {
76    /// Successor list.
77    pub successors: Vec<Did>,
78    /// Predecessor.
79    pub predecessor: Option<Did>,
80}
81
82impl TopoInfo {
83    /// Retain only peers supported by the caller's current routing evidence.
84    pub(crate) fn confirmed_by(&self, mut is_routable: impl FnMut(Did) -> bool) -> Self {
85        Self {
86            successors: self
87                .successors
88                .iter()
89                .copied()
90                .filter(|peer| is_routable(*peer))
91                .collect(),
92            predecessor: self.predecessor.filter(|peer| is_routable(*peer)),
93        }
94    }
95
96    /// Return whether any reported topology position survived confirmation.
97    pub(crate) fn has_confirmed_peer(&self) -> bool {
98        self.predecessor.is_some() || !self.successors.is_empty()
99    }
100}
101
102impl TryFrom<&PeerRing> for TopoInfo {
103    type Error = Error;
104
105    fn try_from(dht: &PeerRing) -> Result<Self> {
106        let state = dht.topology_state()?;
107        Ok(Self {
108            successors: state.successors,
109            predecessor: state.predecessor,
110        })
111    }
112}
113
114impl PeerRingAction {
115    /// Returns `true` if the action is [`PeerRingAction::None`].
116    pub fn is_none(&self) -> bool {
117        matches!(self, Self::None)
118    }
119
120    /// Returns `true` if the action is [`PeerRingAction::Some`].
121    pub fn is_some(&self) -> bool {
122        matches!(self, Self::Some(_))
123    }
124
125    /// Returns `true` if the action is [`PeerRingAction::SomeEntry`].
126    pub fn is_some_entry(&self) -> bool {
127        matches!(self, Self::SomeEntry(_))
128    }
129
130    /// Returns `true` if the action is [`PeerRingAction::RemoteAction`].
131    pub fn is_remote(&self) -> bool {
132        matches!(self, Self::RemoteAction(..))
133    }
134
135    /// Returns `true` if the action is [`PeerRingAction::MultiActions`].
136    pub fn is_multi(&self) -> bool {
137        matches!(self, Self::MultiActions(..))
138    }
139}
140
141impl From<Vec<PeerRingAction>> for PeerRingAction {
142    fn from(actions: Vec<PeerRingAction>) -> Self {
143        if actions.is_empty() {
144            Self::None
145        } else {
146            Self::MultiActions(actions)
147        }
148    }
149}