#locks #thread #mutex #key-value-store #data-structures

lockable

This library offers hash map and cache data structures where individual entries can be locked

8 releases

0.0.8 Jan 25, 2024
0.0.7 Dec 15, 2023
0.0.6 Nov 23, 2022
0.0.2 Apr 11, 2022

#75 in Concurrency

Download history 6594/week @ 2023-12-23 7170/week @ 2023-12-30 704/week @ 2024-01-06 2068/week @ 2024-01-13 557/week @ 2024-01-20 3927/week @ 2024-01-27 610/week @ 2024-02-03 3075/week @ 2024-02-10 1640/week @ 2024-02-17 3684/week @ 2024-02-24 851/week @ 2024-03-02 863/week @ 2024-03-09 759/week @ 2024-03-16 26/week @ 2024-03-23 53/week @ 2024-03-30 56/week @ 2024-04-06

1,505 downloads per month

MIT/Apache

325KB
4.5K SLoC

Build Status Latest Version docs.rs License License codecov unsafe forbidden

lockable

The lockable library offers thread-safe HashMap (see LockableHashMap), LruCache (see LockableLruCache) and LockPool (see LockPool) types. In all of these dat atypes, individual keys can be locked/unlocked, even if there is no entry for this key in the map or cache.

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>::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 LockPool data structure. A lock pool is a pool of keyable locks. This can be used if you don't need a cache but just some way to synchronize access to an underlying resource.

use lockable::LockPool;

let lockpool = LockPool::new();
let guard1 = lockpool.async_lock(4).await;
let guard2 = lockpool.async_lock(5).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 guard3 = lockpool.async_lock(4).await;

// After dropping the corresponding guard, we can lock it again
std::mem::drop(guard1);
let guard3 = lockpool.async_lock(4).await;

HashMap example

If you need a lockable key-value store but don't need the LRU ordering, you can use LockableHashMap.

use lockable::{AsyncLimit, LockableHashMap};

let lockable_map = LockableHashMap::<i64, String>::new();

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

// Hold a lock on a different entry
let guard = lockable_map.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_map.async_lock(5, AsyncLimit::no_limit())
//    .await?;

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

Crate Features

License: MIT OR Apache-2.0

Dependencies

~7.5MB
~127K SLoC