Crate lockable

source ·
Expand description

The lockable library offers thread-safe HashMap (see LockableHashMap) and LruCache (see LockableLruCache) types where individual keys can be locked/unlocked, even if there is no entry for this key in the map.

This can be very useful for synchronizing access to an underlying key-value store or for building cache data structures on top of such a key-value store.

LRU cache example

This example builds a simple LRU cache and locks some entries.

use lockable::{AsyncLimit, LockableLruCache};

let lockable_cache: LockableLruCache<i64, String> = LockableLruCache::new();

// Insert an entry
lockable_cache.async_lock(4, AsyncLimit::no_limit())
    .await?
    .insert(String::from("Value"));

// Hold a lock on a different entry
let guard = lockable_cache.async_lock(5, AsyncLimit::no_limit())
    .await?;

// This next line would wait until the lock gets released, which in this case would
// cause a deadlock because we're on the same thread.
// let guard2 = lockable_cache.async_lock(5, AsyncLimit::no_limit()).await?;

// After dropping the corresponding guard, we can lock it again
std::mem::drop(guard);
let guard2 = lockable_cache.async_lock(5, AsyncLimit::no_limit()).await?;

Lockpool example

This example builds a simple lock pool using the LockableHashMap data structure. A lock pool is a pool of keyable locks. In this example, the entries don’t have a value assigned to them and the lock pool is only used to synchronize access to some keyed resource.

use lockable::{AsyncLimit, LockableHashMap};

let lockable_cache: LockableHashMap<i64, ()> = LockableHashMap::new();
let entry1 = lockable_cache.async_lock(4, AsyncLimit::no_limit()).await?;
let entry2 = lockable_cache.async_lock(5, AsyncLimit::no_limit()).await?;

// This next line would wait until the lock gets released, which in this case would
// cause a deadlock because we're on the same thread.
// let entry3 = lockable_cache.async_lock(4, AsyncLimit::no_limit()).await?;

// After dropping the corresponding guard, we can lock it again
std::mem::drop(entry1);
let entry3 = lockable_cache.async_lock(4, AsyncLimit::no_limit()).await?;

Structs

A RAII implementation of a scoped lock for locks from a LockableHashMap or LockableLruCache. When this instance is dropped (falls out of scope), the lock will be unlocked.
A threadsafe hash map where individual keys can be locked/unlocked, even if there is no entry for this key in the map. It initially considers all keys as “unlocked”, but they can be locked and if a second thread tries to acquire a lock for the same key, they will have to wait.
A threadsafe LRU cache where individual keys can be locked/unlocked, even if there is no entry for this key in the cache. It initially considers all keys as “unlocked”, but they can be locked and if a second thread tries to acquire a lock for the same key, they will have to wait.

Enums

An instance of this enum defines a limit on the number of entries in a LockableLruCache or a LockableHashMap. It can be used to cause old entries to be evicted if a limit on the number of entries is exceeded in a call to the following functions:
A type that can never be instantiated. This can be used in a Result<T, Never> to indicate that an operation cannot return an error.
An instance of this enum defines a limit on the number of entries in a LockableLruCache or a LockableHashMap. It can be used to cause old entries to be evicted if a limit on the number of entries is exceeded in a call to the following functions:
This error is thrown by Guard::try_insert if the entry already exists

Traits

Extension trait for Result<T, Never> that adds infallible_unwrap(), an infallible version of unwrap().
A common trait for both LockableHashMap and LockableLruCache that offers some common functionalities.