rings_core/dht/
stabilization.rs1use std::sync::Arc;
4
5use rings_transport::core::transport::WebrtcConnectionState;
6
7use crate::dht::entry::PlacedEntry;
8use crate::dht::successor::SuccessorReader;
9use crate::dht::types::ChordStorageRepair;
10use crate::dht::types::CorrectChord;
11use crate::dht::Chord;
12use crate::dht::Did;
13use crate::dht::PeerRing;
14use crate::dht::PeerRingAction;
15use crate::dht::PeerRingRemoteAction;
16use crate::error::Error;
17use crate::error::Result;
18use crate::message::FindSuccessorReportHandler;
19use crate::message::FindSuccessorSend;
20use crate::message::FindSuccessorThen;
21use crate::message::Message;
22use crate::message::MessagePayload;
23use crate::message::NotifyPredecessorSend;
24use crate::message::PayloadSender;
25use crate::message::QueryForTopoInfoSend;
26use crate::message::SyncEntriesWithSuccessor;
27use crate::swarm::transport::SwarmTransport;
28
29#[derive(Clone)]
31pub struct Stabilizer {
32 transport: Arc<SwarmTransport>,
33 dht: Arc<PeerRing>,
34}
35
36impl Stabilizer {
37 pub fn new(transport: Arc<SwarmTransport>) -> Self {
39 let dht = transport.dht.clone();
40 Self { transport, dht }
41 }
42
43 pub async fn stabilize(&self) -> Result<()> {
45 tracing::debug!("STABILIZATION notify_predecessor start");
46 if let Err(e) = self.notify_predecessor().await {
47 tracing::error!("[stabilize] Failed on notify predecessor {:?}", e);
48 }
49 tracing::debug!("STABILIZATION notify_predecessor end");
50 tracing::debug!("STABILIZATION fix_fingers start");
51 if let Err(e) = self.fix_fingers().await {
52 tracing::error!("[stabilize] Failed on fix_finger {:?}", e);
53 }
54 tracing::debug!("STABILIZATION fix_fingers end");
55 tracing::debug!("STABILIZATION clean_unavailable_connections start");
56 if let Err(e) = self.clean_unavailable_connections().await {
57 tracing::error!(
58 "[stabilize] Failed on clean unavailable connections {:?}",
59 e
60 );
61 }
62 tracing::debug!("STABILIZATION clean_unavailable_connections end");
63 tracing::debug!("STABILIZATION correct_stabilize start");
66 if let Err(e) = self.correct_stabilize().await {
67 tracing::error!("[stabilize] Failed on call correct stabilize {:?}", e);
68 }
69 tracing::debug!("STABILIZATION correct_stabilize end");
70 tracing::debug!("STABILIZATION repair_storage start");
71 if let Err(e) = self.repair_storage().await {
72 tracing::error!("[stabilize] Failed on repair storage {:?}", e);
73 }
74 tracing::debug!("STABILIZATION repair_storage end");
75 Ok(())
76 }
77
78 fn collect_storage_repair_actions(
79 act: PeerRingAction,
80 out: &mut Vec<(Did, Vec<PlacedEntry>)>,
81 ) -> Result<()> {
82 match act {
83 PeerRingAction::None => Ok(()),
84 PeerRingAction::RemoteAction(
85 destination,
86 PeerRingRemoteAction::SyncEntriesWithSuccessor(data),
87 ) => {
88 out.push((destination, data));
89 Ok(())
90 }
91 PeerRingAction::MultiActions(actions) => {
92 for action in actions {
93 Self::collect_storage_repair_actions(action, out)?;
94 }
95 Ok(())
96 }
97 action => {
98 tracing::error!("Invalid storage repair action: {action:?}");
99 Err(crate::error::Error::unexpected_peer_ring_action(action))
100 }
101 }
102 }
103
104 async fn handle_storage_repair_action(&self, act: PeerRingAction) -> Result<()> {
105 let mut messages = Vec::new();
106 Self::collect_storage_repair_actions(act, &mut messages)?;
107 for (destination, data) in messages {
108 self.transport
109 .send_message(
110 Message::SyncEntriesWithSuccessor(SyncEntriesWithSuccessor { data }),
111 destination,
112 )
113 .await?;
114 }
115 Ok(())
116 }
117
118 pub async fn repair_storage(&self) -> Result<()> {
120 let action = self
121 .dht
122 .republish_local_entries(self.transport.storage_redundancy())
123 .await?;
124 self.handle_storage_repair_action(action).await
125 }
126
127 pub async fn clean_unavailable_connections(&self) -> Result<()> {
129 let conns = self.transport.get_connections();
130
131 for (did, conn) in conns.into_iter() {
132 if matches!(
138 conn.webrtc_connection_state(),
139 WebrtcConnectionState::Failed | WebrtcConnectionState::Closed
140 ) {
141 tracing::info!("STABILIZATION clean_unavailable_transports: {:?}", did);
142 let should_repair = self
143 .dht
144 .peer_may_share_storage_responsibility(did, self.transport.storage_redundancy())
145 .await?;
146 self.transport.disconnect(did).await?;
147 if should_repair {
148 self.repair_storage().await?;
149 }
150 }
151 }
152
153 Ok(())
154 }
155
156 pub async fn notify_predecessor(&self) -> Result<()> {
158 let (successor_min, successor_list) = {
159 let successor = self.dht.successors();
160 (successor.min()?, successor.list()?)
161 };
162
163 let msg = Message::NotifyPredecessorSend(NotifyPredecessorSend { did: self.dht.did });
164 if self.dht.did != successor_min {
165 for s in successor_list {
166 tracing::debug!("STABILIZATION notify_predecessor: {:?}", s);
167 let payload =
168 MessagePayload::new_send(msg.clone(), self.transport.session_sk(), s, s)?;
169 self.transport.send_payload(payload).await?;
170 }
171 Ok(())
172 } else {
173 Ok(())
174 }
175 }
176
177 async fn fix_fingers(&self) -> Result<()> {
179 match self.dht.fix_fingers() {
180 Ok(action) => match action {
181 PeerRingAction::None => Ok(()),
182 PeerRingAction::RemoteAction(
183 closest_predecessor,
184 PeerRingRemoteAction::FindSuccessorForFix {
185 did: finger_did,
186 index,
187 },
188 ) => {
189 tracing::debug!("STABILIZATION fix_fingers: {:?}", finger_did);
190 let msg = Message::FindSuccessorSend(FindSuccessorSend {
191 did: finger_did,
192 then: FindSuccessorThen::Report(
193 FindSuccessorReportHandler::FixFingerTable { index },
194 ),
195 strict: false,
196 });
197 let payload = MessagePayload::new_send(
198 msg.clone(),
199 self.transport.session_sk(),
200 closest_predecessor,
201 closest_predecessor,
202 )?;
203 self.transport.send_payload(payload).await?;
204 Ok(())
205 }
206 _ => {
207 tracing::error!("Invalid PeerRing Action");
208 Err(Error::PeerRingInvalidAction)
209 }
210 },
211 Err(e) => {
212 tracing::error!("{:?}", e);
213 Err(e)
214 }
215 }
216 }
217
218 pub async fn correct_stabilize(&self) -> Result<()> {
220 if let PeerRingAction::RemoteAction(
221 next,
222 PeerRingRemoteAction::QueryForSuccessorListAndPred,
223 ) = self.dht.pre_stabilize()?
224 {
225 self.transport
226 .send_direct_message(
227 Message::QueryForTopoInfoSend(QueryForTopoInfoSend::new_for_stab(next)),
228 next,
229 )
230 .await?;
231 }
232 Ok(())
233 }
234}
235
236#[cfg(not(feature = "wasm"))]
237mod stabilizer {
238 use std::sync::Arc;
239 use std::time::Duration;
240
241 use futures::future::FutureExt;
242 use futures::pin_mut;
243 use futures::select;
244 use futures_timer::Delay;
245
246 use super::*;
247
248 impl Stabilizer {
249 pub async fn wait(self: Arc<Self>, interval: Duration) {
251 loop {
252 let timeout = Delay::new(interval).fuse();
253 pin_mut!(timeout);
254 select! {
255 _ = timeout => self
256 .stabilize()
257 .await
258 .unwrap_or_else(|e| tracing::error!("failed to stabilize {:?}", e)),
259 }
260 }
261 }
262 }
263}
264
265#[cfg(feature = "wasm")]
266mod stabilizer {
267 use std::sync::Arc;
268 use std::time::Duration;
269
270 use super::*;
271 use crate::poll;
272
273 impl Stabilizer {
274 pub async fn wait(self: Arc<Self>, interval: Duration) {
276 let millis = i32::try_from(interval.as_millis()).unwrap_or(i32::MAX);
277 let stabilizer = self;
278 poll!(
279 {
280 let stabilizer = Arc::clone(&stabilizer);
281 async move {
282 stabilizer
283 .stabilize()
284 .await
285 .unwrap_or_else(|e| tracing::error!("failed to stabilize {:?}", e));
286 }
287 },
288 millis
289 );
290 }
291 }
292}