1use super::memory_upload::MemoryStart;
2use super::*;
3
4#[derive(Clone, Debug, PartialEq, Eq)]
7pub enum MemoryRequest {
8 Read(ObjectPath, Option<ByteRange>),
10 List(ObjectPrefix),
12 Create(ObjectPath),
14 Replace(ObjectPath),
16 Status(ObjectPath),
18 Delete(ObjectPath),
20 Other(&'static str),
22}
23
24impl MemoryStorage {
25 pub fn request_trace(&self) -> Vec<MemoryRequest> {
27 self.provider.request_trace.lock().expect("request trace poisoned").clone()
28 }
29}
30
31impl MemoryStorage {
32 pub async fn hold_next_listing(
35 &self,
36 prefix: ObjectPrefix,
37 listed: tokio::sync::oneshot::Sender<()>,
38 resume: tokio::sync::oneshot::Receiver<()>,
39 ) {
40 let mut state = self.provider.state.lock().await;
41 assert!(state.held_listing.is_none(), "a listing is already held");
42 state.held_listing = Some(HeldRequest { prefix, listed, resume });
43 }
44 pub async fn hold_next_request(
47 &self,
48 started: tokio::sync::oneshot::Sender<()>,
49 resume: tokio::sync::oneshot::Receiver<()>,
50 ) {
51 let mut state = self.provider.state.lock().await;
52 assert!(state.held_request.is_none(), "a request is already held");
53 state.held_request = Some(HeldNext { request: None, started, resume });
54 }
55 pub async fn hold_next_request_of(
58 &self,
59 request: MemoryRequest,
60 started: tokio::sync::oneshot::Sender<()>,
61 resume: tokio::sync::oneshot::Receiver<()>,
62 ) {
63 let mut state = self.provider.state.lock().await;
64 assert!(state.held_request.is_none(), "a request is already held");
65 state.held_request = Some(HeldNext { request: Some(request), started, resume });
66 }
67 pub async fn hold_next_creation(
69 &self,
70 prefix: ObjectPrefix,
71 started: tokio::sync::oneshot::Sender<()>,
72 resume: tokio::sync::oneshot::Receiver<()>,
73 ) {
74 let mut state = self.provider.state.lock().await;
75 assert!(state.held_creation.is_none(), "a creation is already held");
76 state.held_creation = Some(HeldRequest { prefix, listed: started, resume });
77 }
78}
79
80pub(super) struct HeldAccess {
82 account: String,
83 grant: bool,
84 started: tokio::sync::oneshot::Sender<()>,
85 resume: tokio::sync::oneshot::Receiver<()>,
86}
87
88impl MemoryStorage {
89 pub async fn hold_next_access(
91 &self,
92 account: &str,
93 grant: bool,
94 started: tokio::sync::oneshot::Sender<()>,
95 resume: tokio::sync::oneshot::Receiver<()>,
96 ) {
97 let mut state = self.provider.state.lock().await;
98 assert!(state.held_access.is_none(), "an access request is already held");
99 state.held_access = Some(HeldAccess { account: account.into(), grant, started, resume });
100 }
101}
102
103impl MemoryProvider {
104 #[expect(
105 clippy::let_underscore_must_use,
106 reason = "a send fails only when the receiver is gone, which this names"
107 )]
108 pub(super) async fn hold_access(&self, account: &str, grant: bool) {
109 let held = {
110 let mut state = self.state.lock().await;
111 if state.held_access.as_ref().is_some_and(|h| h.account == account && h.grant == grant)
112 {
113 state.held_access.take()
114 } else {
115 None
116 }
117 };
118 if let Some(held) = held {
119 let _ = held.started.send(());
120 held.resume.await.expect("held access request was not released");
121 }
122 }
123}
124
125impl MemoryProvider {
126 pub(super) async fn before_request(&self, request: MemoryRequest) -> Result<(), StorageError> {
127 self.request_going(request, None).await
128 }
129 async fn request_going(
134 &self,
135 request: MemoryRequest,
136 start: Option<MemoryStart<'_>>,
137 ) -> Result<(), StorageError> {
138 let active = self.active_requests.fetch_add(1, std::sync::atomic::Ordering::SeqCst) + 1;
139 let _request = ActiveMemoryRequest(&self.active_requests);
140 self.peak_requests.fetch_max(active, std::sync::atomic::Ordering::SeqCst);
141 self.request_trace.lock().expect("request trace poisoned").push(request.clone());
142 self.requests.send_modify(|count| *count += 1);
143 let held = {
144 let mut state = self.state.lock().await;
145 match &state.held_request {
146 Some(held) if held.request.as_ref().is_none_or(|kind| *kind == request) => {
147 state.held_request.take()
148 }
149 _ => None,
150 }
151 };
152 if let Some(held) = held {
153 held.started
154 .send(())
155 .map_err(|()| StorageFailure::Protocol.with_source("request observer dropped"))?;
156 held.resume.await.map_err(|closed| StorageFailure::Protocol.with_source(closed))?;
157 }
158 if let Some(start) = start {
159 start.go()?;
160 }
161 if !self.online.load(std::sync::atomic::Ordering::SeqCst) {
162 return Err(StorageFailure::Network
163 .with_source(std::io::Error::from(std::io::ErrorKind::NotConnected)));
164 }
165 let (delay, failure, barrier) = {
166 let mut state = self.state.lock().await;
167 if std::mem::replace(&mut state.faults.expire_uploads, false) {
168 state.uploads.clear();
169 }
170 let failure = if state.faults.fail_next > 0 {
171 state.faults.fail_next -= 1;
172 Some((state.faults.failure, state.faults.response, state.faults.retry_after))
173 } else {
174 None
175 };
176 let (barrier, gate) = match &request {
177 MemoryRequest::Create(_) => {
178 (state.creation_barrier.clone(), state.creation_gate.clone())
179 }
180 MemoryRequest::Read(..) => (None, state.read_gate.clone()),
181 _ => (None, None),
182 };
183 (state.faults.delay, failure, (barrier, gate))
184 };
185 let (barrier, gate) = barrier;
186 if let Some(barrier) = barrier {
187 barrier.wait().await;
188 }
189 if let Some(gate) = gate {
190 gate.acquire()
191 .await
192 .map_err(|closed| StorageFailure::Protocol.with_source(closed))?
193 .forget();
194 }
195 if !delay.is_zero() {
196 self.clock.deadline(delay).await;
197 }
198 match failure {
199 Some(failure) => Err(self.injected(failure)),
200 None => self.authorize(request).await,
201 }
202 }
203 pub(super) fn injected(
207 &self,
208 (failure, status, retry_after): (StorageFailure, Option<u16>, Option<u64>),
209 ) -> StorageError {
210 match (status, retry_after) {
211 (None, None) => StorageError::Failure(failure),
212 (status, retry_after) => crate::providers::ProviderResponse::injected(
213 self.config.provider(),
214 failure,
215 status.unwrap_or(429),
216 retry_after,
217 ),
218 }
219 }
220 async fn authorize(&self, request: MemoryRequest) -> Result<(), StorageError> {
223 let Some(held) = self.tokens.lock().await.clone() else {
224 return Ok(());
225 };
226 let rejected = |tokens: &OAuthTokens| {
227 let token = tokens.access_token.as_str().to_owned();
228 async move { self.state.lock().await.rejected_tokens.contains(&token) }
229 };
230 let used = held.current().await;
231 if !rejected(&used).await {
232 return Ok(());
233 }
234 let replacement = held.rejected(&used).await?;
235 self.request_trace.lock().expect("request trace poisoned").push(request);
236 self.requests.send_modify(|count| *count += 1);
237 if rejected(&replacement).await {
238 return Err(StorageFailure::Authentication.into());
239 }
240 Ok(())
241 }
242 pub(super) async fn before(&self, request: MemoryRequest) -> Result<(), StorageError> {
243 self.before_going(request, None).await
244 }
245 pub(super) async fn before_going(
247 &self,
248 request: MemoryRequest,
249 start: Option<MemoryStart<'_>>,
250 ) -> Result<(), StorageError> {
251 self.request_going(request, start).await?;
252 if let Account::Recipient(email) = &self.account {
253 let state = self.state.lock().await;
254 let allowed = match state.accounts.get(email) {
255 Some(AccountAccess::Joined) => true,
256 Some(AccountAccess::Invited) | None => false,
257 };
258 if !allowed {
259 return Err(StorageFailure::PermissionDenied.into());
260 }
261 }
262 Ok(())
263 }
264}
265
266struct ActiveMemoryRequest<'a>(&'a std::sync::atomic::AtomicUsize);
267impl Drop for ActiveMemoryRequest<'_> {
268 fn drop(&mut self) {
269 self.0.fetch_sub(1, std::sync::atomic::Ordering::SeqCst);
270 }
271}