Skip to content

Commit eff9827

Browse files
committed
feat(base): Implement LockableEventCacheStore::is_poisoned.
This patch implements `LockableEventCacheStore:is_poisoned` to know whether the lock has been poisoned or not.
1 parent d4e69a3 commit eff9827

File tree

1 file changed

+54
-5
lines changed
  • crates/matrix-sdk-base/src/event_cache/store

1 file changed

+54
-5
lines changed

crates/matrix-sdk-base/src/event_cache/store/mod.rs

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@
1919
//! into the event cache for the actual storage. By default this brings an
2020
//! in-memory store.
2121
22-
use std::{fmt, ops::Deref, result::Result as StdResult, str::Utf8Error, sync::Arc};
22+
use std::{
23+
fmt,
24+
ops::{Deref, DerefMut},
25+
result::Result as StdResult,
26+
str::Utf8Error,
27+
sync::{Arc, Mutex},
28+
};
2329

2430
#[cfg(any(test, feature = "testing"))]
2531
#[macro_use]
@@ -28,7 +34,8 @@ mod memory_store;
2834
mod traits;
2935

3036
use matrix_sdk_common::store_locks::{
31-
BackingStore, CrossProcessStoreLock, CrossProcessStoreLockGuard, LockStoreError,
37+
BackingStore, CrossProcessStoreLock, CrossProcessStoreLockGuard, LockGeneration,
38+
LockStoreError, FIRST_LOCK_GENERATION,
3239
};
3340
pub use matrix_sdk_store_encryption::Error as StoreEncryptionError;
3441

@@ -71,7 +78,7 @@ impl EventCacheStoreLock {
7178

7279
Self {
7380
cross_process_lock: CrossProcessStoreLock::new(
74-
LockableEventCacheStore(store.clone()),
81+
LockableEventCacheStore::new(store.clone()),
7582
"default".to_owned(),
7683
holder,
7784
),
@@ -168,7 +175,23 @@ pub type Result<T, E = EventCacheStoreError> = StdResult<T, E>;
168175
/// A type that wraps the [`EventCacheStore`] but implements [`BackingStore`] to
169176
/// make it usable inside the cross process lock.
170177
#[derive(Clone, Debug)]
171-
struct LockableEventCacheStore(Arc<DynEventCacheStore>);
178+
struct LockableEventCacheStore {
179+
store: Arc<DynEventCacheStore>,
180+
generation_and_is_poisoned: Arc<Mutex<(LockGeneration, bool)>>,
181+
}
182+
183+
impl LockableEventCacheStore {
184+
fn new(store: Arc<DynEventCacheStore>) -> Self {
185+
Self {
186+
store,
187+
generation_and_is_poisoned: Arc::new(Mutex::new((FIRST_LOCK_GENERATION, false))),
188+
}
189+
}
190+
191+
fn is_poisoned(&self) -> bool {
192+
self.generation_and_is_poisoned.lock().unwrap().1
193+
}
194+
}
172195

173196
#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
174197
#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
@@ -181,6 +204,32 @@ impl BackingStore for LockableEventCacheStore {
181204
key: &str,
182205
holder: &str,
183206
) -> StdResult<bool, Self::LockError> {
184-
Ok(self.0.try_take_leased_lock(lease_duration_ms, key, holder).await?.is_some())
207+
let lock_generation =
208+
self.store.try_take_leased_lock(lease_duration_ms, key, holder).await?;
209+
210+
Ok(match lock_generation {
211+
// Lock hasn't been acquired.
212+
None => false,
213+
214+
// Lock has been acquired, and we have a generation.
215+
Some(generation) => {
216+
let mut guard = self.generation_and_is_poisoned.lock().unwrap();
217+
let (last_generation, is_poisoned) = guard.deref_mut();
218+
219+
// The lock is considered poisoned if it's been acquired
220+
// from another holder. If the lock is acquired from another
221+
// holder, its generation is incremented by one. So, if
222+
// `lock_generation` is different of `last_generation`, it
223+
// means it's been acquired from another holder, and it is
224+
// consequently poisoned; otherwise it is not poisoned.
225+
//
226+
// The initial value for `last_generation` **must be**
227+
// `FIRST_LOCK_GENERATION`.
228+
*is_poisoned = generation != *last_generation;
229+
*last_generation = generation;
230+
231+
true
232+
}
233+
})
185234
}
186235
}

0 commit comments

Comments
 (0)