diff --git a/crates/matrix-sdk-base/src/event_cache_store/mod.rs b/crates/matrix-sdk-base/src/event_cache_store/mod.rs index 6709ec66420..cd57ad7804b 100644 --- a/crates/matrix-sdk-base/src/event_cache_store/mod.rs +++ b/crates/matrix-sdk-base/src/event_cache_store/mod.rs @@ -19,7 +19,7 @@ //! into the event cache for the actual storage. By default this brings an //! in-memory store. -use std::{str::Utf8Error, sync::Arc}; +use std::{fmt, ops::Deref, str::Utf8Error, sync::Arc}; #[cfg(any(test, feature = "testing"))] #[macro_use] @@ -27,7 +27,9 @@ pub mod integration_tests; mod memory_store; mod traits; -use matrix_sdk_common::store_locks::BackingStore; +use matrix_sdk_common::store_locks::{ + BackingStore, CrossProcessStoreLock, CrossProcessStoreLockGuard, LockStoreError, +}; pub use matrix_sdk_store_encryption::Error as StoreEncryptionError; #[cfg(any(test, feature = "testing"))] @@ -37,6 +39,75 @@ pub use self::{ traits::{DynEventCacheStore, EventCacheStore, IntoEventCacheStore}, }; +/// The high-level public type to represent an `EventCacheStore` lock. +pub struct EventCacheStoreLock { + /// The inner cross process lock that is used to lock the `EventCacheStore`. + cross_process_lock: CrossProcessStoreLock, + + /// The store itself. + /// + /// That's the only place where the store exists. + store: Arc, +} + +impl fmt::Debug for EventCacheStoreLock { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.debug_struct("EventCacheStoreLock").finish_non_exhaustive() + } +} + +impl EventCacheStoreLock { + /// Create a new lock around the [`EventCacheStore`]. + pub fn new(store: S, key: String, holder: String) -> Self + where + S: IntoEventCacheStore, + { + let store = store.into_event_cache_store(); + + Self { + cross_process_lock: CrossProcessStoreLock::new( + LockableEventCacheStore(store.clone()), + key, + holder, + ), + store, + } + } + + /// Acquire a spin lock (see [`CrossProcessStoreLock::spin_lock`]). + pub async fn lock(&self) -> Result, LockStoreError> { + let cross_process_lock_guard = self.cross_process_lock.spin_lock(None).await?; + + Ok(EventCacheStoreLockGuard { cross_process_lock_guard, store: self.store.deref() }) + } +} + +/// An RAII implementation of a “scoped lock” of an [`EventCacheStoreLock`]. +/// When this structure is dropped (falls out of scope), the lock will be +/// unlocked. +pub struct EventCacheStoreLockGuard<'a> { + /// The cross process lock guard. + #[allow(unused)] + cross_process_lock_guard: CrossProcessStoreLockGuard, + + /// A reference to the store. + store: &'a DynEventCacheStore, +} + +impl<'a> fmt::Debug for EventCacheStoreLockGuard<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.debug_struct("EventCacheStoreLockGuard").finish_non_exhaustive() + } +} + +impl<'a> Deref for EventCacheStoreLockGuard<'a> { + type Target = DynEventCacheStore; + + fn deref(&self) -> &Self::Target { + self.store + } +} + /// Event cache store specific error type. #[derive(Debug, thiserror::Error)] pub enum EventCacheStoreError {