LockMap

Struct LockMap 

Source
pub struct LockMap<K, V> { /* private fields */ }
Expand description

A thread-safe hashmap that supports locking entries at the key level.

Implementations§

Source§

impl<K: Eq + Hash, V> LockMap<K, V>

The main thread-safe map type providing per-key level locking.

Source

pub fn new() -> Self

Creates a new LockMap with the default number of shards.

§Returns

A new LockMap instance.

Source

pub fn with_capacity(capacity: usize) -> Self

Creates a new LockMap with the specified initial capacity and the default number of shards.

§Arguments
  • capacity - The initial capacity of the hashmap.
§Returns

A new LockMap instance.

Source

pub fn with_capacity_and_shard_amount( capacity: usize, shard_amount: usize, ) -> Self

Creates a new LockMap with the specified initial capacity and number of shards.

§Arguments
  • capacity - The initial capacity of the hashmap.
  • shard_amount - The number of shards to create.
§Returns

A new LockMap instance.

Source

pub fn len(&self) -> usize

Returns the number of elements in the map.

Source

pub fn is_empty(&self) -> bool

Returns true if the map contains no elements.

Source

pub fn entry(&self, key: K) -> EntryByVal<'_, K, V>
where K: Clone,

Gets exclusive access to an entry in the map.

The returned EntryByVal provides exclusive access to the key and its associated value until it is dropped.

Locking behaviour: Deadlock if called when holding the same entry.

§Examples
let map = LockMap::<String, u32>::new();
{
    let mut entry = map.entry("key".to_string());
    entry.insert(42);
    // let _ = map.get("key".to_string()); // DEADLOCK!
    // map.insert("key".to_string(), 21); // DEADLOCK!
    // map.remove("key".to_string()); // DEADLOCK!
    // let mut entry2 = map.entry("key".to_string()); // DEADLOCK!
}
Source

pub fn entry_by_ref<'a, 'b, Q>( &'a self, key: &'b Q, ) -> EntryByRef<'a, 'b, K, Q, V>
where K: Borrow<Q> + for<'c> From<&'c Q>, Q: Eq + Hash + ?Sized,

Gets exclusive access to an entry in the map.

The returned EntryByVal provides exclusive access to the key and its associated value until it is dropped.

Locking behaviour: Deadlock if called when holding the same entry.

§Examples
let map = LockMap::<String, u32>::new();
{
    let mut entry = map.entry_by_ref("key");
    entry.insert(42);
    // let _ = map.get("key"); // DEADLOCK!
    // map.insert_by_ref("key", 21); // DEADLOCK!
    // map.remove("key"); // DEADLOCK!
    // let mut entry2 = map.entry_by_ref("key"); // DEADLOCK!
}
Source

pub fn get<Q>(&self, key: &Q) -> Option<V>
where K: Borrow<Q>, V: Clone, Q: Eq + Hash + ?Sized,

Gets the value associated with the given key.

If other threads are currently accessing the key, this will wait until exclusive access is available before returning.

§Arguments
  • key - The key to look up
§Returns
  • Some(V) if the key exists
  • None if the key doesn’t exist

Locking behaviour: Deadlock if called when holding the same entry.

§Examples
use lockmap::LockMap;

let map = LockMap::<String, u32>::new();
map.insert_by_ref("key", 42);
assert_eq!(map.get("key"), Some(42));
assert_eq!(map.get("missing"), None);
Source

pub fn insert(&self, key: K, value: V) -> Option<V>
where K: Clone,

Sets a value in the map.

If other threads are currently accessing the key, this will wait until exclusive access is available before updating.

§Arguments
  • key - The key to update
  • value - The value to set

Locking behaviour: Deadlock if called when holding the same entry.

§Examples
use lockmap::LockMap;

let map = LockMap::<String, u32>::new();

// Set a value
assert_eq!(map.insert("key".to_string(), 42), None);

// Update existing value
assert_eq!(map.insert("key".to_string(), 123), Some(42));
Source

pub fn insert_by_ref<Q>(&self, key: &Q, value: V) -> Option<V>
where K: Borrow<Q> + for<'c> From<&'c Q>, Q: Eq + Hash + ?Sized,

Sets a value in the map.

If other threads are currently accessing the key, this will wait until exclusive access is available before updating.

§Arguments
  • key - The key to update
  • value - The value to set

Locking behaviour: Deadlock if called when holding the same entry.

§Examples
use lockmap::LockMap;

let map = LockMap::<String, u32>::new();

// Set a value
map.insert_by_ref("key", 42);

// Update existing value
map.insert_by_ref("key", 123);
Source

pub fn contains_key<Q>(&self, key: &Q) -> bool
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Checks if the map contains a key.

If other threads are currently accessing the key, this will wait until exclusive access is available before checking.

§Arguments
  • key - The key to check
§Returns
  • true if the key exists
  • false if the key doesn’t exist

Locking behaviour: Deadlock if called when holding the same entry.

§Examples
use lockmap::LockMap;

let map = LockMap::new();
map.insert("key", 42);
assert!(map.contains_key("key"));
assert!(!map.contains_key("non_existent_key"));
Source

pub fn remove<Q>(&self, key: &Q) -> Option<V>
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Removes a key from the map.

If other threads are currently accessing the key, this will wait until exclusive access is available before removing.

§Arguments
  • key - The key to remove
§Returns
  • Some(V) if the key exists
  • None if the key doesn’t exist

Locking behaviour: Deadlock if called when holding the same entry.

§Examples
use lockmap::LockMap;

let map = LockMap::<String, u32>::new();
map.insert_by_ref("key", 42);
assert_eq!(map.remove("key"), Some(42));
assert_eq!(map.get("key"), None);
Source

pub fn batch_lock<'a, M>(&'a self, keys: BTreeSet<K>) -> M
where K: Clone, M: FromIterator<(K, EntryByVal<'a, K, V>)>,

Acquires exclusive locks for a batch of keys in a deadlock-safe manner.

This function is designed to prevent deadlocks that can occur when multiple threads try to acquire locks on the same set of keys in different orders. It achieves this by taking a BTreeSet of keys, which ensures the keys are processed and locked in a consistent, sorted order across all threads.

The function iterates through the sorted keys, acquiring an exclusive lock for each key and its associated value. The returned Vec contains RAII guards, which automatically release the locks when they are dropped.

§Arguments
  • keys - The BTreeSet of keys to lock. The use of BTreeSet is crucial as it enforces a global, canonical locking order, thus preventing deadlocks.
§Returns

A Vec<EntryByVal<K, V>> containing the RAII guards for each locked key.

Locking behaviour: Deadlock if called when holding the same entry.

§Examples
use lockmap::LockMap;
use std::collections::BTreeSet;

let map = LockMap::<u32, u32>::new();
map.insert(1, 100);
map.insert(2, 200);
map.insert(3, 300);

// Create a set of keys to lock. Note that the order in the set doesn't matter
// since BTreeSet will sort them.
let mut keys = BTreeSet::new();
keys.insert(3);
keys.insert(1);
keys.insert(2);

// Acquire locks for all keys in a deadlock-safe manner
let mut locked_entries = map.batch_lock::<std::collections::HashMap<_, _>>(keys);

// The locks are held as long as `locked_entries` is in scope
locked_entries.get_mut(&1).and_then(|entry| entry.insert(101));
locked_entries.get_mut(&2).and_then(|entry| entry.insert(201));
locked_entries.get_mut(&3).and_then(|entry| entry.insert(301));

// When `locked_entries` is dropped, all locks are released
drop(locked_entries);

assert_eq!(map.get(&1), Some(101));
assert_eq!(map.get(&2), Some(201));
assert_eq!(map.get(&3), Some(301));

Trait Implementations§

Source§

impl<K, V> Debug for LockMap<K, V>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<K: Eq + Hash, V> Default for LockMap<K, V>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<K, V> Freeze for LockMap<K, V>

§

impl<K, V> RefUnwindSafe for LockMap<K, V>

§

impl<K, V> Send for LockMap<K, V>
where K: Send, V: Send,

§

impl<K, V> Sync for LockMap<K, V>
where K: Send, V: Send,

§

impl<K, V> Unpin for LockMap<K, V>
where K: Unpin,

§

impl<K, V> UnwindSafe for LockMap<K, V>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.