Skip to content

Commit c14049b

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 64a3487 commit c14049b

File tree

1 file changed

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

1 file changed

+56
-5
lines changed

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

Lines changed: 56 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,
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,25 @@ 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+
last_generation: Arc<Mutex<LockGeneration>>,
181+
is_poisoned: Arc<Mutex<bool>>,
182+
}
183+
184+
impl LockableEventCacheStore {
185+
fn new(store: Arc<DynEventCacheStore>) -> Self {
186+
Self {
187+
store,
188+
last_generation: Arc::new(Mutex::new(FIRST_LOCK_GENERATION)),
189+
is_poisoned: Arc::new(Mutex::new(false)),
190+
}
191+
}
192+
193+
fn is_poisoned(&self) -> bool {
194+
*self.is_poisoned.lock().unwrap()
195+
}
196+
}
172197

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

0 commit comments

Comments
 (0)