lockmap
A high-performance, thread-safe HashMap and LRU cache for Rust with fine-grained per-key locking.
Data Structures
| Type | Description |
|---|---|
LockMap |
Thread-safe HashMap with per-key level locking |
LruLockMap |
Thread-safe LRU cache with per-key locking and automatic capacity-based eviction |
LockMap
LockMap is a high-performance, thread-safe HashMap implementation 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.
Features
- 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. - Single Hash Computation: Each key is hashed once; the pre-computed hash is stored alongside the key and reused for shard selection, table probing, and rehashing.
- No Key Duplication: Uses
hashbrown::HashTableso each key is stored only once, inside the entry state. - Entry API: Ergonomic unified RAII guard (
Entry) for managing locks.
Usage
use LockMap;
use BTreeSet;
// Create a new lock map
let map = new;
// 1. Basic Insert
map.insert_by_ref;
// 2. Get a value (Clones the value)
assert_eq!;
// 3. Entry API: Exclusive access (Read/Write)
// This locks ONLY "key", other threads can access "other_key" concurrently.
// Lock is automatically released here
// 4. Remove a value
assert_eq!;
// 5. Batch Locking (Deadlock safe)
// Acquires locks for multiple keys in a deterministic order.
let mut keys = new;
keys.insert;
keys.insert;
// `locked_entries` holds all the locks
let mut locked_entries = map.;
if let Some = locked_entries.get_mut
// All locks released when `locked_entries` is dropped
LruLockMap
LruLockMap extends the per-key locking design with LRU (Least Recently Used) eviction. Each internal shard maintains its own LRU ordering via an intrusive doubly-linked list, ensuring that eviction decisions are local and lock-free from other shards.
Features
- Per-Key Locking: Same fine-grained locking as
LockMap. - Per-Shard LRU Eviction: Each shard independently tracks access order and evicts least recently used entries when capacity is exceeded.
- Non-Blocking Eviction: In-use entries are skipped during eviction; traversal continues to the next candidate, ensuring progress even when the tail is held.
- Intrusive Linked List: LRU bookkeeping uses pointers embedded directly in each entry, avoiding extra allocations.
- No Key Duplication: Uses
hashbrown::HashTableso each key is stored only once, inside the entry state. - Single Hash, Single Probe: One hasher for the whole map; each operation hashes once. Uses
HashTable::entry/find_entryfor single-probe find-or-insert/remove.
Usage
use LruLockMap;
// Create a cache with capacity 1000
let cache = new;
// Insert and retrieve values
cache.insert_by_ref;
assert_eq!;
// Entry API for exclusive access (promotes in LRU list)
// Remove a value
assert_eq!;
// When the cache exceeds capacity, the least recently used
// entries are automatically evicted.
Important Caveats
1. No Lock Poisoning
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.
2. get() Performance
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.
Changelog
0.2.0
This is a major restructuring release. The previous workspace of three crates (lockmap, lockmap-lru, lockmap-core) has been consolidated into a single lockmap crate.
Breaking Changes
- Unified crate:
lockmap-lruandlockmap-coreno longer exist as separate crates. Import bothLockMapandLruLockMapfromlockmap:use ; - Unified
Entrytype: The separateEntryByValandEntryByReftypes inLockMaphave been replaced by a singleEntrytype. The key is now stored inside the entry state and accessed viaentry.key(). parking_lotmutex: The custom futex-based mutex andatomic-waitdependency have been replaced byparking_lot::RawMutex.HashTablestorage forLockMap:LockMapnow useshashbrown::HashTable(likeLruLockMap) with the key and pre-computed hash stored in the entry state. Each operation hashes the key only once.
Migration Guide
| 0.1.x | 0.2.0 |
|---|---|
use lockmap::EntryByVal |
use lockmap::Entry |
use lockmap::EntryByRef |
use lockmap::Entry |
use lockmap_lru::LruLockMap |
use lockmap::LruLockMap |
use lockmap_lru::LruEntry |
use lockmap::LruEntry |