diff options
author | David Sherret <dsherret@users.noreply.github.com> | 2024-06-05 15:17:35 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-06-05 15:17:35 -0400 |
commit | 1b355d8a87a3ad43bf240aa66b88eb98c1cd777f (patch) | |
tree | 0422d22a6a0e40873eea4c1ef3eff9d6648f1c51 /cli/util/sync/sync_read_async_write_lock.rs | |
parent | 7ed90a20d04982ae15a52ae2378cbffd4b6839df (diff) |
refactor(npm): improve locking around updating npm resolution (#24104)
Introduces a `SyncReadAsyncWriteLock` to make it harder to write to the
npm resolution without first waiting async in a queue. For the npm
resolution, reading synchronously is fine, but when updating, someone
should wait async, clone the data, then write the data at the end back.
Diffstat (limited to 'cli/util/sync/sync_read_async_write_lock.rs')
-rw-r--r-- | cli/util/sync/sync_read_async_write_lock.rs | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/cli/util/sync/sync_read_async_write_lock.rs b/cli/util/sync/sync_read_async_write_lock.rs new file mode 100644 index 000000000..8bd211aa7 --- /dev/null +++ b/cli/util/sync/sync_read_async_write_lock.rs @@ -0,0 +1,62 @@ +// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. + +use deno_core::parking_lot::RwLock; +use deno_core::parking_lot::RwLockReadGuard; +use deno_core::parking_lot::RwLockWriteGuard; + +use super::TaskQueue; +use super::TaskQueuePermit; + +/// A lock that can be read synchronously at any time (including when +/// being written to), but must write asynchronously. +pub struct SyncReadAsyncWriteLockWriteGuard<'a, T: Send + Sync> { + _update_permit: TaskQueuePermit<'a>, + data: &'a RwLock<T>, +} + +impl<'a, T: Send + Sync> SyncReadAsyncWriteLockWriteGuard<'a, T> { + pub fn read(&self) -> RwLockReadGuard<'_, T> { + self.data.read() + } + + /// Warning: Only `write()` with data you created within this + /// write this `SyncReadAsyncWriteLockWriteGuard`. + /// + /// ```rs + /// let mut data = lock.write().await; + /// + /// let mut data = data.read().clone(); + /// data.value = 2; + /// *data.write() = data; + /// ``` + pub fn write(&self) -> RwLockWriteGuard<'_, T> { + self.data.write() + } +} + +/// A lock that can only be +pub struct SyncReadAsyncWriteLock<T: Send + Sync> { + data: RwLock<T>, + update_queue: TaskQueue, +} + +impl<T: Send + Sync> SyncReadAsyncWriteLock<T> { + pub fn new(data: T) -> Self { + Self { + data: RwLock::new(data), + update_queue: TaskQueue::default(), + } + } + + pub fn read(&self) -> RwLockReadGuard<'_, T> { + self.data.read() + } + + pub async fn acquire(&self) -> SyncReadAsyncWriteLockWriteGuard<'_, T> { + let update_permit = self.update_queue.acquire().await; + SyncReadAsyncWriteLockWriteGuard { + _update_permit: update_permit, + data: &self.data, + } + } +} |