rings_core/dht/chord/
storage.rs1use async_trait::async_trait;
2
3use super::PeerRing;
4use super::PeerRingAction;
5use super::RemoteAction;
6use crate::dht::entry::Entry;
7use crate::dht::entry::EntryLookupEvidence;
8use crate::dht::entry::EntryLookupKey;
9use crate::dht::entry::EntryOperation;
10use crate::dht::entry::PlacedEntryOperation;
11use crate::dht::entry::PlacementMiss;
12use crate::dht::types::ChordStorage;
13use crate::dht::types::ChordStorageCache;
14use crate::dht::Did;
15use crate::error::Error;
16use crate::error::Result;
17
18impl PeerRing {
19 pub(crate) async fn join_storage_entry(&self, key: Did, incoming: Entry) -> Result<Entry> {
25 let incoming = incoming.try_into_storage_entry()?;
26 let stored = if let Some(local) = self.storage.get(&key.to_string()).await? {
27 local.join(incoming)?
28 } else {
29 incoming
30 }
31 .try_into_storage_entry()?;
32 self.storage.put(&key.to_string(), &stored).await?;
33 Ok(stored)
34 }
35
36 fn storage_fetch_fallback_successor(&self) -> Result<Option<Did>> {
37 Ok(self
38 .topology_state()?
39 .successors
40 .into_iter()
41 .find(|successor| *successor != self.did))
42 }
43
44 async fn entry_lookup_inner<const REDUNDANT: u16>(
45 &self,
46 entry_key: Did,
47 fallback_on_local_virtual_miss: bool,
48 ) -> Result<PeerRingAction> {
49 let mut ret = vec![];
50 let mut misses = vec![];
51 for placement_key in entry_key.rotate_affine(REDUNDANT)? {
52 let query = EntryLookupKey::new(entry_key, placement_key);
53 let act = match self.find_storage_owner(placement_key) {
54 Ok(PeerRingAction::Some(succ)) => {
55 match self.storage.get(&placement_key.to_string()).await {
56 Ok(Some(value)) => {
57 let observed_misses = std::mem::take(&mut misses);
58 Ok(PeerRingAction::SomeEntry(EntryLookupEvidence::new(
59 value,
60 observed_misses,
61 )))
62 }
63 Ok(None) => {
64 tracing::debug!(
65 "Cannot find entry in local storage, try to query from successor"
66 );
67 if succ == self.did {
68 if fallback_on_local_virtual_miss
69 && self.storage_virtual_nodes_enabled()?
70 {
71 if let Some(next) = self.storage_fetch_fallback_successor()? {
72 Ok(PeerRingAction::RemoteAction(
73 next,
74 RemoteAction::FindEntry(query),
75 ))
76 } else {
77 misses.push(PlacementMiss::new(placement_key, succ));
78 Ok(PeerRingAction::None)
79 }
80 } else {
81 misses.push(PlacementMiss::new(placement_key, succ));
82 Ok(PeerRingAction::None)
83 }
84 } else {
85 Ok(PeerRingAction::RemoteAction(
86 succ,
87 RemoteAction::FindEntry(query),
88 ))
89 }
90 }
91 Err(error) => Err(error),
92 }
93 }
94 Ok(PeerRingAction::RemoteAction(next, RemoteAction::FindSuccessor(id))) => {
95 Ok(PeerRingAction::RemoteAction(
96 next,
97 RemoteAction::FindEntry(EntryLookupKey::new(entry_key, id)),
98 ))
99 }
100 Ok(action) => Err(Error::unexpected_peer_ring_action(action)),
101 Err(error) => Err(error),
102 }?;
103 if act.is_remote() {
104 ret.push(act);
105 } else if act.is_some_entry() {
106 return Ok(act);
107 }
108 }
109 if !misses.is_empty() {
110 ret.push(PeerRingAction::EntryMisses(misses));
111 }
112 Ok(ret.into())
113 }
114
115 pub(crate) async fn entry_lookup_for_fetch<const REDUNDANT: u16>(
124 &self,
125 entry_key: Did,
126 ) -> Result<PeerRingAction> {
127 self.entry_lookup_inner::<REDUNDANT>(entry_key, true).await
128 }
129}
130
131#[cfg_attr(all(feature = "wasm", target_family = "wasm"), async_trait(?Send))]
132#[cfg_attr(not(all(feature = "wasm", target_family = "wasm")), async_trait)]
133impl<const REDUNDANT: u16> ChordStorage<PeerRingAction, REDUNDANT> for PeerRing {
134 async fn entry_lookup(&self, entry_key: Did) -> Result<PeerRingAction> {
135 self.entry_lookup_inner::<REDUNDANT>(entry_key, false).await
136 }
137
138 async fn entry_operate(&self, op: EntryOperation) -> Result<PeerRingAction> {
139 let op = op.stamped(self.did)?;
140 let entry_key = op.did()?;
141 let mut ret = vec![];
142 for entry_key in entry_key.rotate_affine(REDUNDANT)? {
143 let act = match self.find_storage_owner(entry_key) {
144 Ok(PeerRingAction::Some(_)) => {
145 let this = match self.storage.get(&entry_key.to_string()).await? {
146 Some(this) => this,
147 None => op.clone().gen_default_entry()?,
148 };
149 let entry = this.operate(op.clone(), self.did)?;
150 self.join_storage_entry(entry_key, entry).await?;
151 Ok(PeerRingAction::None)
152 }
153 Ok(PeerRingAction::RemoteAction(next, RemoteAction::FindSuccessor(_))) => {
154 Ok(PeerRingAction::RemoteAction(
155 next,
156 RemoteAction::FindEntryForOperate(PlacedEntryOperation {
157 placement: entry_key,
158 op: op.clone(),
159 }),
160 ))
161 }
162 Ok(action) => Err(Error::unexpected_peer_ring_action(action)),
163 Err(error) => Err(error),
164 }?;
165 if act.is_remote() {
166 ret.push(act);
167 }
168 }
169 Ok(ret.into())
170 }
171}
172
173#[cfg_attr(all(feature = "wasm", target_family = "wasm"), async_trait(?Send))]
174#[cfg_attr(not(all(feature = "wasm", target_family = "wasm")), async_trait)]
175impl ChordStorageCache<PeerRingAction> for PeerRing {
176 async fn local_cache_put(&self, entry: Entry) -> Result<()> {
177 self.cache.put(&entry.did.to_string(), &entry).await
178 }
179
180 async fn local_cache_get(&self, entry_key: Did) -> Result<Option<Entry>> {
181 self.cache.get(&entry_key.to_string()).await
182 }
183}