pub struct MbarcMap<T: Hash + Eq, U> { /* private fields */ }
Expand description
The heart of this crate, a map which is safe to use in threading contexts without wrapping in a Mutex.
This map does not hold any locks beyond the duration of its member functions, it is completely safe to hold the results of get indefinitely, regardless of what happens in other threads, and this map will not cause deadlocks This means it is safe to:
- Hold multiple DataReferences to the same value across multiple threads
- Remove elements while a DataReference to that value is held elsewhere
- Drop the Map itself while DataReferences exist elsewhere
- Iterate over elements in one thread without taking a lock to the map (iterators hold a reference to each element at time of creation)
Additionally:
- Values are stored in mostly-continuous blocks of memory, and they remain in a fixed address until dropped, making it safe to take references/pointers.
- Values are implicitly wrapped in their own Mutex, requiring only that locks are taken on a per-element basis for data access
- Values are only dropped when all DataReferences to them have been dropped
This map is not quite a true HashMap, implementing many non-constant (though still sub-linear) operations for managing metadata. The theory behind this approach, however, is that by keeping mutex lock duration to a minimum and everything else “fast enough”, any potential performance losses elsewhere should be more than made up accounted for in practice by allowing more saturated thread usage.
Implementations§
Source§impl<T: Hash + Eq, U> MbarcMap<T, U>
impl<T: Hash + Eq, U> MbarcMap<T, U>
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new, empty MbarcMap
§Example
use std::sync::Arc;
use mbarc_map::MbarcMap;
let concurrent_map = Arc::new(MbarcMap::<u64,String>::new());
Sourcepub fn insert(&self, key: T, value: U) -> Option<DataReference<U>>
pub fn insert(&self, key: T, value: U) -> Option<DataReference<U>>
Inserts a key-value pair into the map.
The return of this function is identical to the insert function of the underlying map type used internally to store references. Currently, this is std::collections::HashMap
Sourcepub fn contains(&self, key: &T) -> bool
pub fn contains(&self, key: &T) -> bool
Returns true
if the map contains a value for the specified key.
Note that, in threaded contexts, this is only correct at the moment this function is called. It is possible that another thread could add or remove the requested key before you are able to use the return value.
If you intend to use the pattern “if contains then get”, then using get alone is sufficient
Sourcepub fn get(&self, key: &T) -> Option<DataReference<U>>
pub fn get(&self, key: &T) -> Option<DataReference<U>>
Returns a DataReference to the value corresponding to the key. If the key is not present, None will be returned
Note that, in threaded contexts, it is possible for another thread to potentially remove the value you get before you can use it. In cases like this, the value referenced by the returned DataReference will not be dropped until all remaining DataReference have been dropped
Sourcepub fn remove(&self, key: &T) -> Option<DataReference<U>>
pub fn remove(&self, key: &T) -> Option<DataReference<U>>
Returns a DataReference to the value corresponding to the key and removes the key/value from this map. If the key is not present, None will be returned
The value referenced by the returned DataReference will not be dropped until all remaining DataReference have been dropped
Sourcepub fn iter(&self) -> Iter<DataReference<U>> ⓘ
pub fn iter(&self) -> Iter<DataReference<U>> ⓘ
An iterator visiting all values in arbitrary order
Important concurrency note: This iterator will represent the state of the map at creation time. Adding or removing elements during iteration (in this thread or others) will not have any impact on iteration order, and creation of this iterator has a cost.
Sourcepub fn iter_exclusive(&self) -> LockedContainer<'_, T, U>
pub fn iter_exclusive(&self) -> LockedContainer<'_, T, U>
Exclusive lock on the map for iteration. This does not clone any elements, therefore requiring a lock is taken on the map. This returns a LockedContainer, which only provides an iter() function, returning the iterator you want.
Usage: given some my_hash: MbarcMap<T,U>
, lock and iterate over it via
for (k,v) in my_hash.iter_exclusive().iter()
Source§impl<T: Hash + Eq + Clone, U> MbarcMap<T, U>
impl<T: Hash + Eq + Clone, U> MbarcMap<T, U>
Sourcepub fn iter_cloned_keys(&self) -> Iter<(T, DataReference<U>)> ⓘ
pub fn iter_cloned_keys(&self) -> Iter<(T, DataReference<U>)> ⓘ
An iterator visiting all key-value pairs in arbitrary order, only for keys which implement Clone
Comments regarding concurrency and performance are the same as in MbarcMap::iter
Source§impl<T: Hash + Eq + Copy, U> MbarcMap<T, U>
impl<T: Hash + Eq + Copy, U> MbarcMap<T, U>
Sourcepub fn iter_copied_keys(&self) -> Iter<(T, DataReference<U>)> ⓘ
pub fn iter_copied_keys(&self) -> Iter<(T, DataReference<U>)> ⓘ
An iterator visiting all key-value pairs in arbitrary order, only for keys which implement Copy
Comments regarding concurrency and performance are the same as in MbarcMap::iter