Struct scc::hash_index::HashIndex

source ·
pub struct HashIndex<K, V, H = RandomState>
where H: BuildHasher,
{ /* private fields */ }
Expand description

Scalable concurrent hash index.

HashIndex is a concurrent and asynchronous hash map data structure that is optimized for parallel read operations. The key characteristics of HashIndex are similar to that of HashMap except that its read operations are lock-free.

§The key differences between HashIndex and HashMap.

  • Lock-free-read: read and scan operations do not modify shared data and are never blocked.
  • Immutability: the data in the container is immutable until it becomes unreachable.
  • Linearizability: HashIndex read operations are not linearizable.

§The key statistics for HashIndex

  • The expected size of metadata for a single key-value pair: 2-byte.
  • The expected number of atomic write operations required for an operation on a single key: 2.
  • The expected number of atomic variables accessed during a single key operation: 2.
  • The number of entries managed by a single bucket without a linked list: 32.
  • The expected maximum linked list length when resize is triggered: log(capacity) / 8.

§Unwind safety

HashIndex is impervious to out-of-memory errors and panics in user specified code on one condition; H::Hasher::hash, K::drop and V::drop must not panic.

Implementations§

source§

impl<K, V, H> HashIndex<K, V, H>
where H: BuildHasher,

source

pub fn with_hasher(build_hasher: H) -> Self

Creates an empty HashIndex with the given BuildHasher.

§Examples
use scc::HashIndex;
use std::collections::hash_map::RandomState;

let hashindex: HashIndex<u64, u32, RandomState> =
    HashIndex::with_hasher(RandomState::new());
source

pub fn with_capacity_and_hasher(capacity: usize, build_hasher: H) -> Self

Creates an empty HashIndex with the specified capacity and BuildHasher.

The actual capacity is equal to or greater than the specified capacity.

§Examples
use scc::HashIndex;
use std::collections::hash_map::RandomState;

let hashindex: HashIndex<u64, u32, RandomState> =
    HashIndex::with_capacity_and_hasher(1000, RandomState::new());

let result = hashindex.capacity();
assert_eq!(result, 1024);
source§

impl<K, V, H> HashIndex<K, V, H>
where K: 'static + Clone + Eq + Hash, V: 'static + Clone, H: BuildHasher,

source

pub fn reserve( &self, additional_capacity: usize ) -> Option<Reserve<'_, K, V, H>>

Temporarily increases the minimum capacity of the HashIndex.

A Reserve is returned if the HashIndex could increase the minimum capacity while the increased capacity is not exclusively owned by the returned Reserve, allowing others to benefit from it. The memory for the additional space may not be immediately allocated if the HashIndex is empty or currently being resized, however once the memory is reserved eventually, the capacity will not shrink below the additional capacity until the returned Reserve is dropped.

§Errors

Returns None if a too large number is given.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<usize, usize> = HashIndex::with_capacity(1000);
assert_eq!(hashindex.capacity(), 1024);

let reserved = hashindex.reserve(10000);
assert!(reserved.is_some());
assert_eq!(hashindex.capacity(), 16384);

assert!(hashindex.reserve(usize::MAX).is_none());
assert_eq!(hashindex.capacity(), 16384);

for i in 0..16 {
    assert!(hashindex.insert(i, i).is_ok());
}
drop(reserved);

assert_eq!(hashindex.capacity(), 1024);
source

pub fn entry(&self, key: K) -> Entry<'_, K, V, H>

Gets the entry associated with the given key in the map for in-place manipulation.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<char, u32> = HashIndex::default();

for ch in "a short treatise on fungi".chars() {
    unsafe {
        hashindex.entry(ch).and_modify(|counter| *counter += 1).or_insert(1);
    }
}

assert_eq!(hashindex.peek_with(&'s', |_, v| *v), Some(2));
assert_eq!(hashindex.peek_with(&'t', |_, v| *v), Some(3));
assert!(hashindex.peek_with(&'y', |_, v| *v).is_none());
source

pub async fn entry_async(&self, key: K) -> Entry<'_, K, V, H>

Gets the entry associated with the given key in the map for in-place manipulation.

It is an asynchronous method returning an impl Future for the caller to await.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<char, u32> = HashIndex::default();

let future_entry = hashindex.entry_async('b');
source

pub fn first_entry(&self) -> Option<OccupiedEntry<'_, K, V, H>>

Gets the first occupied entry for in-place manipulation.

The returned OccupiedEntry in combination with OccupiedEntry::next or OccupiedEntry::next_async can act as a mutable iterator over entries.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.insert(1, 0).is_ok());

let mut first_entry = hashindex.first_entry().unwrap();
unsafe {
    *first_entry.get_mut() = 2;
}

assert!(first_entry.next().is_none());
assert_eq!(hashindex.peek_with(&1, |_, v| *v), Some(2));
source

pub async fn first_entry_async(&self) -> Option<OccupiedEntry<'_, K, V, H>>

Gets the first occupied entry for in-place manipulation.

The returned OccupiedEntry in combination with OccupiedEntry::next or OccupiedEntry::next_async can act as a mutable iterator over entries.

It is an asynchronous method returning an impl Future for the caller to await.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<char, u32> = HashIndex::default();

let future_entry = hashindex.first_entry_async();
source

pub fn insert(&self, key: K, val: V) -> Result<(), (K, V)>

Inserts a key-value pair into the HashIndex.

§Errors

Returns an error along with the supplied key-value pair if the key exists.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.insert(1, 0).is_ok());
assert_eq!(hashindex.insert(1, 1).unwrap_err(), (1, 1));
source

pub async fn insert_async(&self, key: K, val: V) -> Result<(), (K, V)>

Inserts a key-value pair into the HashIndex.

It is an asynchronous method returning an impl Future for the caller to await.

§Errors

Returns an error along with the supplied key-value pair if the key exists.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();
let future_insert = hashindex.insert_async(11, 17);
source

pub fn remove<Q>(&self, key: &Q) -> bool
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Removes a key-value pair if the key exists.

Returns false if the key does not exist.

Returns true if the key existed and the condition was met after marking the entry unreachable; the memory will be reclaimed later.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(!hashindex.remove(&1));
assert!(hashindex.insert(1, 0).is_ok());
assert!(hashindex.remove(&1));
assert_eq!(hashindex.capacity(), 0);
source

pub async fn remove_async<Q>(&self, key: &Q) -> bool
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Removes a key-value pair if the key exists.

Returns false if the key does not exist. It is an asynchronous method returning an impl Future for the caller to await.

Returns true if the key existed and the condition was met after marking the entry unreachable; the memory will be reclaimed later.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();
let future_insert = hashindex.insert_async(11, 17);
let future_remove = hashindex.remove_async(&11);
source

pub fn remove_if<Q, F: FnOnce(&V) -> bool>(&self, key: &Q, condition: F) -> bool
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Removes a key-value pair if the key exists and the given condition is met.

Returns false if the key does not exist or the condition was not met.

Returns true if the key existed and the condition was met after marking the entry unreachable; the memory will be reclaimed later.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.insert(1, 0).is_ok());
assert!(!hashindex.remove_if(&1, |v| *v == 1));
assert!(hashindex.remove_if(&1, |v| *v == 0));
assert_eq!(hashindex.capacity(), 0);
source

pub async fn remove_if_async<Q, F: FnOnce(&V) -> bool>( &self, key: &Q, condition: F ) -> bool
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Removes a key-value pair if the key exists and the given condition is met.

Returns false if the key does not exist or the condition was not met. It is an asynchronous method returning an impl Future for the caller to await.

Returns true if the key existed and the condition was met after marking the entry unreachable; the memory will be reclaimed later.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();
let future_insert = hashindex.insert_async(11, 17);
let future_remove = hashindex.remove_if_async(&11, |_| true);
source

pub fn get<Q>(&self, key: &Q) -> Option<OccupiedEntry<'_, K, V, H>>
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Gets an occupied entry corresponding to the key.

Returns None if the key does not exist.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.get(&1).is_none());
assert!(hashindex.insert(1, 10).is_ok());
assert_eq!(*hashindex.get(&1).unwrap().get(), 10);
source

pub async fn get_async<Q>(&self, key: &Q) -> Option<OccupiedEntry<'_, K, V, H>>
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Gets an occupied entry corresponding to the key.

Returns None if the key does not exist. It is an asynchronous method returning an impl Future for the caller to await.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();
let future_insert = hashindex.insert_async(11, 17);
let future_get = hashindex.get_async(&11);
source

pub fn peek<'g, Q>(&self, key: &Q, guard: &'g Guard) -> Option<&'g V>
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Returns a guarded reference to the value for the specified key without acquiring locks.

Returns None if the key does not exist. The returned reference can survive as long as the associated Guard is alive.

This method is not linearizable since the entry can be removed while being read.

§Examples
use scc::ebr::Guard;
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.insert(1, 10).is_ok());

let guard = Guard::new();
let value_ref = hashindex.peek(&1, &guard).unwrap();
assert_eq!(*value_ref, 10);
source

pub fn peek_with<Q, R, F: FnOnce(&K, &V) -> R>( &self, key: &Q, reader: F ) -> Option<R>
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Peeks a key-value pair without acquiring locks.

Returns None if the key does not exist.

This method is not linearizable since the entry can be removed while being read.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.peek_with(&1, |_, v| *v).is_none());
assert!(hashindex.insert(1, 10).is_ok());
assert_eq!(hashindex.peek_with(&1, |_, v| *v).unwrap(), 10);
source

pub fn contains<Q>(&self, key: &Q) -> bool
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Returns true if the HashIndex contains a value for the specified key.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(!hashindex.contains(&1));
assert!(hashindex.insert(1, 0).is_ok());
assert!(hashindex.contains(&1));
source

pub fn retain<F: FnMut(&K, &V) -> bool>(&self, pred: F)

Retains the entries specified by the predicate.

Entries that have existed since the invocation of the method are guaranteed to be visited if they are not removed, however the same entry can be visited more than once if the HashIndex gets resized by another thread.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.insert(1, 0).is_ok());
assert!(hashindex.insert(2, 1).is_ok());
assert!(hashindex.insert(3, 2).is_ok());

hashindex.retain(|k, v| *k == 1 && *v == 0);

assert!(hashindex.contains(&1));
assert!(!hashindex.contains(&2));
assert!(!hashindex.contains(&3));
source

pub async fn retain_async<F: FnMut(&K, &V) -> bool>(&self, pred: F)

Retains the entries specified by the predicate.

Entries that have existed since the invocation of the method are guaranteed to be visited if they are not removed, however the same entry can be visited more than once if the HashIndex gets resized by another thread.

It is an asynchronous method returning an impl Future for the caller to await.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

let future_insert = hashindex.insert_async(1, 0);
let future_retain = hashindex.retain_async(|k, v| *k == 1);
source

pub fn clear(&self)

Clears the HashIndex by removing all key-value pairs.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.insert(1, 0).is_ok());
hashindex.clear();

assert!(!hashindex.contains(&1));
source

pub async fn clear_async(&self)

Clears the HashIndex by removing all key-value pairs.

It is an asynchronous method returning an impl Future for the caller to await.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

let future_insert = hashindex.insert_async(1, 0);
let future_retain = hashindex.clear_async();
source

pub fn len(&self) -> usize

Returns the number of entries in the HashIndex.

It reads the entire metadata area of the bucket array to calculate the number of valid entries, making its time complexity O(N). Furthermore, it may overcount entries if an old bucket array has yet to be dropped.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.insert(1, 0).is_ok());
assert_eq!(hashindex.len(), 1);
source

pub fn is_empty(&self) -> bool

Returns true if the HashIndex is empty.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.is_empty());
assert!(hashindex.insert(1, 0).is_ok());
assert!(!hashindex.is_empty());
source

pub fn capacity(&self) -> usize

Returns the capacity of the HashIndex.

§Examples
use scc::HashIndex;

let hashindex_default: HashIndex<u64, u32> = HashIndex::default();
assert_eq!(hashindex_default.capacity(), 0);

assert!(hashindex_default.insert(1, 0).is_ok());
assert_eq!(hashindex_default.capacity(), 64);

let hashindex: HashIndex<u64, u32> = HashIndex::with_capacity(1000000);
assert_eq!(hashindex.capacity(), 1048576);
source

pub fn capacity_range(&self) -> RangeInclusive<usize>

Returns the current capacity range of the HashIndex.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert_eq!(hashindex.capacity_range(), 0..=(1_usize << (usize::BITS - 1)));

let reserved = hashindex.reserve(1000);
assert_eq!(hashindex.capacity_range(), 1000..=(1_usize << (usize::BITS - 1)));
source

pub fn bucket_index<Q>(&self, key: &Q) -> usize
where K: Borrow<Q>, Q: Eq + Hash + ?Sized,

Returns the index of the bucket that may contain the key.

The method returns the index of the bucket associated with the key. The number of buckets can be calculated by dividing 32 into the capacity.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::with_capacity(1024);

let bucket_index = hashindex.bucket_index(&11);
assert!(bucket_index < hashindex.capacity() / 32);
source

pub fn iter<'h, 'g>(&'h self, guard: &'g Guard) -> Iter<'h, 'g, K, V, H>

Returns an Iter.

It is guaranteed to go through all the key-value pairs pertaining in the HashIndex at the moment, however the same key-value pair can be visited more than once if the HashIndex is being resized.

It requires the user to supply a reference to a Guard.

§Examples
use scc::ebr::Guard;
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

assert!(hashindex.insert(1, 0).is_ok());

let guard = Guard::new();

let mut iter = hashindex.iter(&guard);
let entry_ref = iter.next().unwrap();
assert_eq!(iter.next(), None);

for iter in hashindex.iter(&guard) {
    assert_eq!(iter, (&1, &0));
}

drop(hashindex);

assert_eq!(entry_ref, (&1, &0));
source§

impl<K, V> HashIndex<K, V, RandomState>
where K: 'static + Clone + Eq + Hash, V: 'static + Clone,

source

pub fn new() -> Self

Creates an empty default HashIndex.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::new();

let result = hashindex.capacity();
assert_eq!(result, 0);
source

pub fn with_capacity(capacity: usize) -> Self

Creates an empty HashIndex with the specified capacity.

The actual capacity is equal to or greater than the specified capacity.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::with_capacity(1000);

let result = hashindex.capacity();
assert_eq!(result, 1024);

Trait Implementations§

source§

impl<'h, K, V, H> AsRef<HashIndex<K, V, H>> for Reserve<'h, K, V, H>
where K: 'static + Clone + Eq + Hash, V: 'static + Clone, H: BuildHasher,

source§

fn as_ref(&self) -> &HashIndex<K, V, H>

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl<K, V, H> Clone for HashIndex<K, V, H>
where K: 'static + Clone + Eq + Hash, V: 'static + Clone, H: BuildHasher + Clone,

source§

fn clone(&self) -> Self

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<K, V, H> Debug for HashIndex<K, V, H>
where K: 'static + Clone + Debug + Eq + Hash, V: 'static + Clone + Debug, H: BuildHasher,

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<K, V, H> Default for HashIndex<K, V, H>
where K: 'static, V: 'static, H: BuildHasher + Default,

source§

fn default() -> Self

Creates an empty default HashIndex.

The default capacity is 64.

§Examples
use scc::HashIndex;

let hashindex: HashIndex<u64, u32> = HashIndex::default();

let result = hashindex.capacity();
assert_eq!(result, 0);
source§

impl<K, V, H> PartialEq for HashIndex<K, V, H>
where K: 'static + Clone + Eq + Hash, V: 'static + Clone + PartialEq, H: BuildHasher,

source§

fn eq(&self, other: &Self) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.

Auto Trait Implementations§

§

impl<K, V, H = RandomState> !Freeze for HashIndex<K, V, H>

§

impl<K, V, H> RefUnwindSafe for HashIndex<K, V, H>
where H: RefUnwindSafe,

§

impl<K, V, H> Send for HashIndex<K, V, H>
where H: Send, K: Send, V: Send,

§

impl<K, V, H> Sync for HashIndex<K, V, H>
where H: Sync, K: Sync, V: Sync,

§

impl<K, V, H> Unpin for HashIndex<K, V, H>
where H: Unpin,

§

impl<K, V, H> UnwindSafe for HashIndex<K, V, H>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.