Skip to main content

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.

LockMap provides a concurrent hashmap with fine-grained per-key locking. Each key can be independently locked, so operations on different keys can proceed in parallel. The map is internally sharded to reduce contention on the map structure itself.

§Storage Design

The key and its pre-computed hash are stored together in the internal entry state, so each operation hashes the key only once. The full hash is also reused for shard selection and table probing.

§Examples

use lockmap::LockMap;

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

// Basic operations
map.insert("key1".to_string(), 42);
assert_eq!(map.get("key1"), Some(42));

// Entry API for exclusive access
{
    let mut entry = map.entry("key2".to_string());
    entry.insert(123);
}

// Remove a value
assert_eq!(map.remove("key1"), Some(42));
assert_eq!(map.get("key1"), None);

Implementations§

Source§

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

Source

pub fn new() -> Self

Creates a new LockMap with the default number of shards.

Source

pub fn with_capacity(capacity: usize) -> Self

Creates a new LockMap with the specified initial capacity.

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.

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) -> Entry<'_, K, V>

Gets exclusive access to an entry in the map.

The returned Entry 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);
}
Source

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

Gets exclusive access to an entry by reference.

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);
}
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.

§Performance Note

When no other thread holds an entry for this key, the clone() operation is performed while holding the shard lock. If V::clone() is expensive, consider using entry() or entry_by_ref() combined with Entry::get() to avoid blocking other keys in the same shard.

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

§Examples
use lockmap::LockMap;

let map = LockMap::<String, u32>::new();
map.insert("key".to_string(), 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>

Sets a value in the map, returning the previous value if any.

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

§Examples
use lockmap::LockMap;

let map = LockMap::<String, u32>::new();
assert_eq!(map.insert("key".to_string(), 42), None);
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 by reference key.

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));
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.

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.

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

§Examples
use lockmap::LockMap;

let map = LockMap::<String, u32>::new();
map.insert("key".to_string(), 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, Entry<'a, K, V>)>,

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

Takes a BTreeSet of keys, ensuring they are processed and locked in a consistent, sorted order across all threads.

§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);

let mut keys = BTreeSet::new();
keys.insert(3);
keys.insert(1);
keys.insert(2);

let mut locked_entries = map.batch_lock::<std::collections::HashMap<_, _>>(keys);

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));

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>

§

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

§

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.