1use core::ops::{Deref, DerefMut};
27pub use parking_lot::{
28 Condvar, Mutex, MutexGuard, Once, RwLock, RwLockReadGuard, RwLockWriteGuard,
29};
30pub use tokio::sync::{
31 Barrier, Mutex as AsyncMutex, MutexGuard as AsyncMutexGuard, Notify, RwLock as AsyncRwLock,
32 RwLockReadGuard as AsyncRwLockReadGuard, RwLockWriteGuard as AsyncRwLockWriteGuard,
33};
34
35pub struct TracedAsyncMutex<T> {
40 name: &'static str,
41 inner: tokio::sync::Mutex<T>,
42}
43
44impl<T> TracedAsyncMutex<T> {
45 pub fn new(name: &'static str, value: T) -> Self {
47 Self {
48 name,
49 inner: tokio::sync::Mutex::new(value),
50 }
51 }
52
53 #[tracing::instrument(name = "utils.mutex.lock", level = "info", skip_all, fields(lock = self.name))]
55 pub async fn lock(&self) -> AsyncMutexGuard<'_, T> {
56 self.inner.lock().await
57 }
58}
59
60pub struct TracedAsyncRwLock<T> {
66 name: &'static str,
67 inner: tokio::sync::RwLock<T>,
68}
69
70impl<T> TracedAsyncRwLock<T> {
71 pub fn new(name: &'static str, value: T) -> Self {
73 Self {
74 name,
75 inner: tokio::sync::RwLock::new(value),
76 }
77 }
78
79 #[tracing::instrument(name = "utils.rwlock.read", level = "info", skip_all, fields(lock = self.name))]
81 pub async fn read(&self) -> AsyncRwLockReadGuard<'_, T> {
82 self.inner.read().await
83 }
84
85 #[tracing::instrument(name = "utils.rwlock.write", level = "info", skip_all, fields(lock = self.name))]
87 pub async fn write(&self) -> AsyncRwLockWriteGuard<'_, T> {
88 self.inner.write().await
89 }
90}
91
92pub struct UpgradableAsyncRwLock<T> {
97 rw: tokio::sync::RwLock<T>,
98 gate: tokio::sync::Mutex<()>,
99}
100
101impl<T> UpgradableAsyncRwLock<T> {
102 pub fn new(value: T) -> Self {
104 Self {
105 rw: tokio::sync::RwLock::new(value),
106 gate: tokio::sync::Mutex::new(()),
107 }
108 }
109
110 pub async fn read(&self) -> tokio::sync::RwLockReadGuard<'_, T> {
112 self.rw.read().await
113 }
114
115 pub async fn write(&self) -> UpgradableAsyncRwLockWriteGuard<'_, T> {
119 let gate_guard = self.gate.lock().await;
120 let guard = self.rw.write().await;
121 UpgradableAsyncRwLockWriteGuard {
122 lock: self,
123 guard,
124 gate_guard,
125 }
126 }
127
128 pub async fn upgradable_read(&self) -> UpgradableAsyncRwLockUpgradableReadGuard<'_, T> {
133 let gate_guard = self.gate.lock().await;
134 let guard = self.rw.read().await;
135 UpgradableAsyncRwLockUpgradableReadGuard {
136 lock: self,
137 guard,
138 gate_guard,
139 }
140 }
141
142 pub fn into_inner(self) -> T {
144 self.rw.into_inner()
145 }
146}
147
148pub struct UpgradableAsyncRwLockWriteGuard<'a, T> {
150 lock: &'a UpgradableAsyncRwLock<T>,
151 guard: tokio::sync::RwLockWriteGuard<'a, T>,
152 gate_guard: tokio::sync::MutexGuard<'a, ()>,
153}
154
155impl<'a, T> UpgradableAsyncRwLockWriteGuard<'a, T> {
156 pub fn downgrade_to_upgradable(self) -> UpgradableAsyncRwLockUpgradableReadGuard<'a, T> {
158 let Self {
159 lock,
160 guard,
161 gate_guard,
162 } = self;
163 let guard = tokio::sync::RwLockWriteGuard::downgrade(guard);
164 UpgradableAsyncRwLockUpgradableReadGuard {
165 lock,
166 guard,
167 gate_guard,
168 }
169 }
170}
171
172impl<T> Deref for UpgradableAsyncRwLockWriteGuard<'_, T> {
173 type Target = T;
174
175 fn deref(&self) -> &Self::Target {
176 &self.guard
177 }
178}
179
180impl<T> DerefMut for UpgradableAsyncRwLockWriteGuard<'_, T> {
181 fn deref_mut(&mut self) -> &mut Self::Target {
182 &mut self.guard
183 }
184}
185
186pub struct UpgradableAsyncRwLockUpgradableReadGuard<'a, T> {
188 lock: &'a UpgradableAsyncRwLock<T>,
189 guard: tokio::sync::RwLockReadGuard<'a, T>,
190 gate_guard: tokio::sync::MutexGuard<'a, ()>,
191}
192
193impl<'a, T> UpgradableAsyncRwLockUpgradableReadGuard<'a, T> {
194 pub async fn upgrade(self) -> UpgradableAsyncRwLockWriteGuard<'a, T> {
196 let Self {
197 lock,
198 guard,
199 gate_guard,
200 } = self;
201 drop(guard);
202 let guard = lock.rw.write().await;
203 UpgradableAsyncRwLockWriteGuard {
204 lock,
205 guard,
206 gate_guard,
207 }
208 }
209}
210
211impl<T> Deref for UpgradableAsyncRwLockUpgradableReadGuard<'_, T> {
212 type Target = T;
213
214 fn deref(&self) -> &Self::Target {
215 &self.guard
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::{AsyncRwLock, TracedAsyncMutex, TracedAsyncRwLock, UpgradableAsyncRwLock};
222 use futures::{pin_mut, FutureExt};
223
224 #[test]
225 fn test_traced_async_mutex() {
226 futures::executor::block_on(async {
227 let lock = TracedAsyncMutex::new("test", 100u64);
228
229 let mut guard = lock.lock().await;
230 *guard += 1;
231 drop(guard);
232
233 assert_eq!(*lock.lock().await, 101);
234 });
235 }
236
237 #[test]
238 fn test_traced_async_rwlock() {
239 futures::executor::block_on(async {
240 let lock = TracedAsyncRwLock::new("test", 100u64);
241
242 let r1 = lock.read().await;
243 let r2 = lock.read().await;
244 assert_eq!(*r1 + *r2, 200);
245
246 drop((r1, r2));
247 let mut writer = lock.write().await;
248 *writer += 1;
249
250 assert_eq!(*writer, 101);
251 });
252 }
253
254 #[test]
255 fn test_async_rwlock() {
256 futures::executor::block_on(async {
257 let lock = AsyncRwLock::new(100u64);
258
259 let r1 = lock.read().await;
260 let r2 = lock.read().await;
261 assert_eq!(*r1 + *r2, 200);
262
263 drop((r1, r2));
264 let mut writer = lock.write().await;
265 *writer += 1;
266
267 assert_eq!(*writer, 101);
268 });
269 }
270
271 #[test]
272 fn test_upgradable_read_blocks_write() {
273 futures::executor::block_on(async {
274 let lock = UpgradableAsyncRwLock::new(1u64);
275 let upgradable = lock.upgradable_read().await;
276
277 let write = lock.write();
278 pin_mut!(write);
279 assert!(write.as_mut().now_or_never().is_none());
280
281 drop(upgradable);
282
283 let mut write = write.await;
284 *write = 2;
285 drop(write);
286
287 assert_eq!(*lock.read().await, 2);
288 });
289 }
290
291 #[test]
292 fn test_read_allowed_during_upgradable_read() {
293 futures::executor::block_on(async {
294 let lock = UpgradableAsyncRwLock::new(5u64);
295 let upgradable = lock.upgradable_read().await;
296 let reader = lock.read().await;
297 assert_eq!(*upgradable, 5);
298 assert_eq!(*reader, 5);
299 });
300 }
301
302 #[test]
303 fn test_upgrade_prevents_writer_interleaving() {
304 futures::executor::block_on(async {
305 let lock = UpgradableAsyncRwLock::new(1u64);
306 let upgradable = lock.upgradable_read().await;
307
308 let writer = async {
309 let mut writer = lock.write().await;
310 let observed = *writer;
311 *writer = 7;
312 observed
313 };
314 pin_mut!(writer);
315 assert!(writer.as_mut().now_or_never().is_none());
316
317 let mut upgraded = upgradable.upgrade().await;
318 *upgraded = 5;
319 drop(upgraded);
320
321 assert_eq!(writer.await, 5);
322 });
323 }
324
325 #[test]
326 fn test_downgrade_to_upgradable() {
327 futures::executor::block_on(async {
328 let lock = UpgradableAsyncRwLock::new(10u64);
329 let mut writer = lock.write().await;
330 *writer = 11;
331
332 let upgradable = writer.downgrade_to_upgradable();
333 let writer = lock.write();
334 pin_mut!(writer);
335 assert!(writer.as_mut().now_or_never().is_none());
336 drop(upgradable);
337
338 let writer = writer.await;
339 assert_eq!(*writer, 11);
340 });
341 }
342}