LockMap is a high-performance, thread-safe HashMap implementation for Rust that provides fine-grained locking at the key level.
Unlike standard concurrent maps that might lock the entire map or large buckets, LockMap allows you to hold an exclusive lock on a specific key (including non-existent ones) for complex atomic operations, minimizing contention across different keys.
- Key-Level Locking: Acquire exclusive locks for specific keys. Operations on different keys run in parallel.
- Sharding Architecture: Internal sharding reduces contention on the map structure itself during insertions and removals.
- Deadlock Prevention: Provides
batch_lockto safely acquire locks on multiple keys simultaneously using a deterministic order. - Efficient Waiting: Uses a hybrid spin-then-park Futex implementation for low-overhead locking.
- Entry API: Ergonomic RAII guards (
EntryByVal,EntryByRef) for managing locks.
Unlike std::sync::Mutex, this library does not implement lock poisoning. If a thread panics while holding an Entry, the lock is released immediately (via Drop) to avoid deadlocks, but the data is not marked as poisoned.
Warning: Users must ensure exception safety. If a panic occurs during a partial update, the data associated with that key may be left in an inconsistent state for subsequent readers.
The map.get(key) method clones the value while holding an internal shard lock.
Note: If your value type
Vis expensive to clone (e.g., deep copy of large structures), or ifclone()acquires other locks, usemap.entry(key).get()instead. This moves the clone operation outside the internal map lock, preventing blocking of other threads accessing the same shard.
use lockmap::LockMap;
use std::collections::BTreeSet;
// Create a new lock map
let map = LockMap::<String, String>::new();
// 1. Basic Insert
map.insert_by_ref("key", "value".into());
// 2. Get a value (Clones the value)
assert_eq!(map.get("key"), Some("value".into()));
// 3. Entry API: Exclusive access (Read/Write)
// This locks ONLY "key", other threads can access "other_key" concurrently.
{
let mut entry = map.entry_by_ref("key");
// Check value
assert_eq!(entry.get().as_deref(), Some("value"));
// Update value atomically
entry.insert("new value".to_string());
} // Lock is automatically released here
// 4. Remove a value
assert_eq!(map.remove("key"), Some("new value".into()));
// 5. Batch Locking (Deadlock safe)
// Acquires locks for multiple keys in a deterministic order.
let mut keys = BTreeSet::new();
keys.insert("key1".to_string());
keys.insert("key2".to_string());
// `locked_entries` holds all the locks
let mut locked_entries = map.batch_lock::<std::collections::HashMap<_, _>>(keys);
if let Some(mut entry) = locked_entries.get_mut("key1") {
entry.insert("updated_in_batch".into());
}
// All locks released when `locked_entries` is dropped