From c5893f882c8ec8e0632346f7d2bf0d9c42587f7c Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 11 Nov 2025 17:33:00 +0100 Subject: [PATCH] feat(common): Add `CrossProcessLockGuard::is_dirty` and `::clear_dirty`. This patch replicates the `is_dirty` and `clear_dirty` methods from `CrossProcessLock` to `CrossProcessLockGuard`. It allows to get an access to this API from a guard when one doesn't have the cross-process lock at hand. --- crates/matrix-sdk-base/src/media/store/mod.rs | 2 +- .../src/cross_process_lock.rs | 31 ++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/crates/matrix-sdk-base/src/media/store/mod.rs b/crates/matrix-sdk-base/src/media/store/mod.rs index 5fd1642be..b7f6b4ba0 100644 --- a/crates/matrix-sdk-base/src/media/store/mod.rs +++ b/crates/matrix-sdk-base/src/media/store/mod.rs @@ -142,7 +142,7 @@ impl MediaStoreLock { // the time of writing (2025-11-11). There is nothing that can be out-of-sync: all the // state is in the database, nothing in memory. CrossProcessLockState::Dirty(guard) => { - self.cross_process_lock.clear_dirty(); + guard.clear_dirty(); guard } diff --git a/crates/matrix-sdk-common/src/cross_process_lock.rs b/crates/matrix-sdk-common/src/cross_process_lock.rs index 7f834c303..48a873bbd 100644 --- a/crates/matrix-sdk-common/src/cross_process_lock.rs +++ b/crates/matrix-sdk-common/src/cross_process_lock.rs @@ -110,12 +110,35 @@ enum WaitingTime { #[derive(Debug)] #[must_use = "If unused, the `CrossProcessLock` will unlock at the end of the lease"] pub struct CrossProcessLockGuard { + /// A clone of [`CrossProcessLock::num_holders`]. num_holders: Arc, + + /// A clone of [`CrossProcessLock::is_dirty`]. + is_dirty: Arc, } impl CrossProcessLockGuard { - fn new(num_holders: Arc) -> Self { - Self { num_holders } + fn new(num_holders: Arc, is_dirty: Arc) -> Self { + Self { num_holders, is_dirty } + } + + /// Determine whether the cross-process lock associated to this guard is + /// dirty. + /// + /// See [`CrossProcessLockState::Dirty`] to learn more about the semantics + /// of _dirty_. + pub fn is_dirty(&self) -> bool { + self.is_dirty.load(Ordering::SeqCst) + } + + /// Clear the dirty state from the cross-process lock associated to this + /// guard. + /// + /// If the cross-process lock is dirtied, it will remain dirtied until + /// this method is called. This allows recovering from a dirty state and + /// marking that it has recovered. + pub fn clear_dirty(&self) { + self.is_dirty.store(false, Ordering::SeqCst); } } @@ -245,7 +268,6 @@ where /// marking that it has recovered. pub fn clear_dirty(&self) { self.is_dirty.store(false, Ordering::SeqCst); - self.generation.store(NO_CROSS_PROCESS_LOCK_GENERATION, Ordering::SeqCst); } /// Try to lock once, returns whether the lock was obtained or not. @@ -273,6 +295,7 @@ where return Ok(Ok(CrossProcessLockState::Clean(CrossProcessLockGuard::new( self.num_holders.clone(), + self.is_dirty.clone(), )))); } @@ -397,7 +420,7 @@ where self.num_holders.fetch_add(1, Ordering::SeqCst); - let guard = CrossProcessLockGuard::new(self.num_holders.clone()); + let guard = CrossProcessLockGuard::new(self.num_holders.clone(), self.is_dirty.clone()); Ok(Ok(if self.is_dirty() { CrossProcessLockState::Dirty(guard)