refactor: Use a common code for try_take_leased_lock.

This code is shared by all `MemoryStore` implementations.
This commit is contained in:
Ivan Enderlin
2024-11-06 10:38:38 +01:00
parent 7b3eb0b6f1
commit 94bd421a8d
3 changed files with 70 additions and 111 deletions

View File

@@ -12,15 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::{
collections::{hash_map::Entry, HashMap},
num::NonZeroUsize,
sync::RwLock as StdRwLock,
time::{Duration, Instant},
};
use std::{collections::HashMap, num::NonZeroUsize, sync::RwLock as StdRwLock, time::Instant};
use async_trait::async_trait;
use matrix_sdk_common::ring_buffer::RingBuffer;
use matrix_sdk_common::{
ring_buffer::RingBuffer, store_locks::memory_store_helper::try_take_leased_lock,
};
use ruma::{MxcUri, OwnedMxcUri};
use super::{EventCacheStore, EventCacheStoreError, Result};
@@ -66,44 +63,7 @@ impl EventCacheStore for MemoryStore {
key: &str,
holder: &str,
) -> Result<bool, Self::Error> {
let now = Instant::now();
let expiration = now + Duration::from_millis(lease_duration_ms.into());
match self.leases.write().unwrap().entry(key.to_owned()) {
// There is an existing holder.
Entry::Occupied(mut entry) => {
let (current_holder, current_expiration) = entry.get_mut();
if current_holder == holder {
// We had the lease before, extend it.
*current_expiration = expiration;
Ok(true)
} else {
// We didn't have it.
if *current_expiration < now {
// Steal it!
*current_holder = holder.to_owned();
*current_expiration = expiration;
Ok(true)
} else {
// We tried our best.
Ok(false)
}
}
}
// There is no holder, easy.
Entry::Vacant(entry) => {
entry.insert((
holder.to_owned(),
Instant::now() + Duration::from_millis(lease_duration_ms.into()),
));
Ok(true)
}
}
Ok(try_take_leased_lock(&self.leases, lease_duration_ms, key, holder))
}
async fn add_media_content(&self, request: &MediaRequest, data: Vec<u8>) -> Result<()> {

View File

@@ -338,7 +338,7 @@ pub enum LockStoreError {
mod tests {
use std::{
collections::HashMap,
sync::{atomic, Arc, Mutex},
sync::{atomic, Arc, RwLock},
time::Instant,
};
@@ -350,47 +350,18 @@ mod tests {
};
use super::{
BackingStore, CrossProcessStoreLock, CrossProcessStoreLockGuard, LockStoreError,
EXTEND_LEASE_EVERY_MS,
memory_store_helper::try_take_leased_lock, BackingStore, CrossProcessStoreLock,
CrossProcessStoreLockGuard, LockStoreError, EXTEND_LEASE_EVERY_MS,
};
#[derive(Clone, Default)]
struct TestStore {
leases: Arc<Mutex<HashMap<String, (String, Instant)>>>,
leases: Arc<RwLock<HashMap<String, (String, Instant)>>>,
}
impl TestStore {
fn try_take_leased_lock(&self, lease_duration_ms: u32, key: &str, holder: &str) -> bool {
let now = Instant::now();
let expiration = now + Duration::from_millis(lease_duration_ms.into());
let mut leases = self.leases.lock().unwrap();
if let Some(prev) = leases.get_mut(key) {
if prev.0 == holder {
// We had the lease before, extend it.
prev.1 = expiration;
true
} else {
// We didn't have it.
if prev.1 < now {
// Steal it!
prev.0 = holder.to_owned();
prev.1 = expiration;
true
} else {
// We tried our best.
false
}
}
} else {
leases.insert(
key.to_owned(),
(
holder.to_owned(),
Instant::now() + Duration::from_millis(lease_duration_ms.into()),
),
);
true
}
try_take_leased_lock(&self.leases, lease_duration_ms, key, holder)
}
}
@@ -525,3 +496,59 @@ mod tests {
Ok(())
}
}
/// Some code that is shared by almost all `MemoryStore` implementations out
/// there.
pub mod memory_store_helper {
use std::{
collections::{hash_map::Entry, HashMap},
sync::RwLock,
time::{Duration, Instant},
};
pub fn try_take_leased_lock(
leases: &RwLock<HashMap<String, (String, Instant)>>,
lease_duration_ms: u32,
key: &str,
holder: &str,
) -> bool {
let now = Instant::now();
let expiration = now + Duration::from_millis(lease_duration_ms.into());
match leases.write().unwrap().entry(key.to_owned()) {
// There is an existing holder.
Entry::Occupied(mut entry) => {
let (current_holder, current_expiration) = entry.get_mut();
if current_holder == holder {
// We had the lease before, extend it.
*current_expiration = expiration;
true
} else {
// We didn't have it.
if *current_expiration < now {
// Steal it!
*current_holder = holder.to_owned();
*current_expiration = expiration;
true
} else {
// We tried our best.
false
}
}
}
// There is no holder, easy.
Entry::Vacant(entry) => {
entry.insert((
holder.to_owned(),
Instant::now() + Duration::from_millis(lease_duration_ms.into()),
));
true
}
}
}
}

View File

@@ -13,13 +13,14 @@
// limitations under the License.
use std::{
collections::{hash_map::Entry, BTreeMap, HashMap, HashSet},
collections::{BTreeMap, HashMap, HashSet},
convert::Infallible,
sync::RwLock as StdRwLock,
time::{Duration, Instant},
time::Instant,
};
use async_trait::async_trait;
use matrix_sdk_common::store_locks::memory_store_helper::try_take_leased_lock;
use ruma::{
events::secret::request::SecretName, DeviceId, OwnedDeviceId, OwnedRoomId, OwnedTransactionId,
OwnedUserId, RoomId, TransactionId, UserId,
@@ -631,36 +632,7 @@ impl CryptoStore for MemoryStore {
key: &str,
holder: &str,
) -> Result<bool> {
let now = Instant::now();
let expiration = now + Duration::from_millis(lease_duration_ms.into());
match self.leases.write().unwrap().entry(key.to_owned()) {
Entry::Occupied(mut o) => {
let prev = o.get_mut();
if prev.0 == holder {
// We had the lease before, extend it.
prev.1 = expiration;
Ok(true)
} else {
// We didn't have it.
if prev.1 < now {
// Steal it!
prev.0 = holder.to_owned();
prev.1 = expiration;
Ok(true)
} else {
// We tried our best.
Ok(false)
}
}
}
Entry::Vacant(v) => {
v.insert((
holder.to_owned(),
Instant::now() + Duration::from_millis(lease_duration_ms.into()),
));
Ok(true)
}
}
Ok(try_take_leased_lock(&self.leases, lease_duration_ms, key, holder))
}
}