Hash keys once (#194)

This commit is contained in:
Stepan Koltsov 2022-04-27 13:15:16 +01:00 committed by GitHub
parent 0516c3cc65
commit 3d315aa7a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 66 deletions

View File

@ -20,6 +20,7 @@ send_guard = ["parking_lot/send_guard"]
[dependencies]
num_cpus = "1.13.1"
parking_lot = "0.12.0"
hashbrown = "0.11.2"
serde = { version = "1.0.136", optional = true, features = ["derive"] }
cfg-if = "1.0.0"
rayon = { version = "1.5.1", optional = true }

View File

@ -6,7 +6,6 @@ use crate::{DashMap, HashMap};
use core::hash::{BuildHasher, Hash};
use core::mem;
use parking_lot::{RwLockReadGuard, RwLockWriteGuard};
use std::collections::hash_map;
use std::collections::hash_map::RandomState;
use std::sync::Arc;
@ -39,7 +38,7 @@ impl<K: Eq + Hash, V, S: BuildHasher + Clone> OwningIter<K, V, S> {
}
}
type GuardOwningIter<K, V> = hash_map::IntoIter<K, SharedValue<V>>;
type GuardOwningIter<K, V> = hashbrown::hash_map::IntoIter<K, SharedValue<V>>;
impl<K: Eq + Hash, V, S: BuildHasher + Clone> Iterator for OwningIter<K, V, S> {
type Item = (K, V);
@ -93,12 +92,12 @@ where
type GuardIter<'a, K, V, S> = (
Arc<RwLockReadGuard<'a, HashMap<K, V, S>>>,
hash_map::Iter<'a, K, SharedValue<V>>,
hashbrown::hash_map::Iter<'a, K, SharedValue<V>>,
);
type GuardIterMut<'a, K, V, S> = (
Arc<RwLockWriteGuard<'a, HashMap<K, V, S>>>,
hash_map::IterMut<'a, K, SharedValue<V>>,
hashbrown::hash_map::IterMut<'a, K, SharedValue<V>>,
);
/// Iterator over a DashMap yielding immutable references.

View File

@ -43,7 +43,7 @@ cfg_if! {
}
}
pub(crate) type HashMap<K, V, S> = std::collections::HashMap<K, SharedValue<V>, S>;
pub(crate) type HashMap<K, V, S> = hashbrown::HashMap<K, SharedValue<V>, S>;
fn default_shard_amount() -> usize {
(num_cpus::get() * 4).next_power_of_two()
@ -271,14 +271,18 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
}
}
/// Hash a given item to produce a usize.
/// Uses the provided or default HashBuilder.
pub fn hash_usize<T: Hash>(&self, item: &T) -> usize {
fn hash_u64<T: Hash>(&self, item: &T) -> u64 {
let mut hasher = self.hasher.build_hasher();
item.hash(&mut hasher);
hasher.finish() as usize
hasher.finish()
}
/// Hash a given item to produce a usize.
/// Uses the provided or default HashBuilder.
pub fn hash_usize<T: Hash>(&self, item: &T) -> usize {
self.hash_u64(item) as usize
}
cfg_if! {
@ -329,8 +333,8 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
self.determine_shard(hash)
let hash = self.hash_u64(&key);
self.determine_shard(hash as usize)
}
}
}
@ -837,15 +841,21 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
}
fn _insert(&self, key: K, value: V) -> Option<V> {
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let mut shard = unsafe { self._yield_write_shard(idx) };
shard
.insert(key, SharedValue::new(value))
.map(|v| v.into_inner())
match shard.raw_entry_mut().from_key_hashed_nocheck(hash, &key) {
hashbrown::hash_map::RawEntryMut::Occupied(mut occupied) => {
Some(occupied.insert(SharedValue::new(value)).into_inner())
}
hashbrown::hash_map::RawEntryMut::Vacant(vacant) => {
vacant.insert(key, SharedValue::new(value));
None
}
}
}
fn _remove<Q>(&self, key: &Q) -> Option<(K, V)>
@ -853,13 +863,19 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let mut shard = unsafe { self._yield_write_shard(idx) };
shard.remove_entry(key).map(|(k, v)| (k, v.into_inner()))
match shard.raw_entry_mut().from_key_hashed_nocheck(hash, key) {
hashbrown::hash_map::RawEntryMut::Occupied(entry) => {
let (k, v) = entry.remove_entry();
Some((k, v.into_inner()))
}
hashbrown::hash_map::RawEntryMut::Vacant(_) => None,
}
}
fn _remove_if<Q>(&self, key: &Q, f: impl FnOnce(&K, &V) -> bool) -> Option<(K, V)>
@ -867,20 +883,22 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let mut shard = unsafe { self._yield_write_shard(idx) };
if let Some((k, v)) = shard.get_key_value(key) {
if f(k, v.get()) {
shard.remove_entry(key).map(|(k, v)| (k, v.into_inner()))
} else {
None
match shard.raw_entry_mut().from_key_hashed_nocheck(hash, key) {
hashbrown::hash_map::RawEntryMut::Occupied(occupied) => {
if f(&occupied.key(), &occupied.get().get()) {
let (k, v) = occupied.remove_entry();
Some((k, v.into_inner()))
} else {
None
}
}
} else {
None
hashbrown::hash_map::RawEntryMut::Vacant(_) => None,
}
}
@ -889,25 +907,23 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let mut shard = unsafe { self._yield_write_shard(idx) };
if let Some((kptr, vptr)) = shard.get_key_value(&key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();
if f(&*kptr, &mut *vptr) {
shard.remove_entry(key).map(|(k, v)| (k, v.into_inner()))
match shard.raw_entry_mut().from_key_hashed_nocheck(hash, key) {
hashbrown::hash_map::RawEntryMut::Occupied(mut occupied) => {
let (k, v) = occupied.get_key_value_mut();
if f(k, v.get_mut()) {
let (k, v) = occupied.remove_entry();
Some((k, v.into_inner()))
} else {
None
}
}
} else {
None
hashbrown::hash_map::RawEntryMut::Vacant(_) => None,
}
}
@ -924,13 +940,13 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let shard = unsafe { self._yield_read_shard(idx) };
if let Some((kptr, vptr)) = shard.get_key_value(key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *const V = vptr.get();
@ -946,13 +962,13 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let shard = unsafe { self._yield_write_shard(idx) };
if let Some((kptr, vptr)) = shard.get_key_value(key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();
@ -968,16 +984,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let shard = match unsafe { self._try_yield_read_shard(idx) } {
Some(shard) => shard,
None => return TryResult::Locked,
};
if let Some((kptr, vptr)) = shard.get_key_value(key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *const V = vptr.get();
@ -993,16 +1009,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let shard = match unsafe { self._try_yield_write_shard(idx) } {
Some(shard) => shard,
None => return TryResult::Locked,
};
if let Some((kptr, vptr)) = shard.get_key_value(key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();
@ -1061,13 +1077,13 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
}
fn _entry(&'a self, key: K) -> Entry<'a, K, V, S> {
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let shard = unsafe { self._yield_write_shard(idx) };
if let Some((kptr, vptr)) = shard.get_key_value(&key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, &key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();
@ -1079,16 +1095,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
}
fn _try_entry(&'a self, key: K) -> Option<Entry<'a, K, V, S>> {
let hash = self.hash_usize(&key);
let hash = self.hash_u64(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_shard(hash as usize);
let shard = match unsafe { self._try_yield_write_shard(idx) } {
Some(shard) => shard,
None => return None,
};
if let Some((kptr, vptr)) = shard.get_key_value(&key) {
if let Some((kptr, vptr)) = shard.raw_entry().from_key_hashed_nocheck(hash, &key) {
unsafe {
let kptr: *const K = kptr;
let vptr: *mut V = vptr.as_ptr();

View File

@ -59,13 +59,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.map.hash_usize(&key);
let hash = self.map.hash_u64(&key);
let idx = self.map.determine_shard(hash);
let idx = self.map.determine_shard(hash as usize);
let shard = unsafe { self.map._get_read_shard(idx) };
shard.contains_key(key)
shard
.raw_entry()
.from_key_hashed_nocheck(hash, key)
.is_some()
}
/// Returns a reference to the value corresponding to the key.
@ -74,13 +77,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.map.hash_usize(&key);
let hash = self.map.hash_u64(&key);
let idx = self.map.determine_shard(hash);
let idx = self.map.determine_shard(hash as usize);
let shard = unsafe { self.map._get_read_shard(idx) };
shard.get(key).map(|v| v.get())
shard
.raw_entry()
.from_key_hashed_nocheck(hash, key)
.map(|(_k, v)| v.get())
}
/// Returns the key-value pair corresponding to the supplied key.
@ -89,13 +95,16 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> ReadOnlyView<K, V, S>
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.map.hash_usize(&key);
let hash = self.map.hash_u64(&key);
let idx = self.map.determine_shard(hash);
let idx = self.map.determine_shard(hash as usize);
let shard = unsafe { self.map._get_read_shard(idx) };
shard.get_key_value(key).map(|(k, v)| (k, v.get()))
shard
.raw_entry()
.from_key_hashed_nocheck(hash, key)
.map(|(k, v)| (k, v.get()))
}
fn shard_read_iter(&'a self) -> impl Iterator<Item = &'a HashMap<K, V, S>> + 'a {