Revert "Fix double hash issue"

This commit is contained in:
Acrimon 2020-02-06 09:45:03 +01:00 committed by GitHub
parent 5d2e015572
commit 3bb9f93d92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 179 deletions

View File

@ -1,75 +0,0 @@
use std::hash::{BuildHasher, Hash, Hasher};
use std::marker::PhantomData;
#[derive(Clone, Default)]
pub struct ShardBuildHasher<S>(PhantomData<S>);
#[derive(Clone, Default, Debug)]
pub struct ShardHasher {
hash: u64,
}
#[derive(Eq, Clone)]
pub struct ShardKey<K> {
key: Option<K>,
hash: u64,
}
impl<S> BuildHasher for ShardBuildHasher<S> {
type Hasher = ShardHasher;
fn build_hasher(&self) -> Self::Hasher {
ShardHasher { hash: 0 }
}
}
impl<S> ShardBuildHasher<S> {
pub fn new() -> Self {
Self(PhantomData)
}
}
impl Hasher for ShardHasher {
fn finish(&self) -> u64 {
self.hash
}
fn write(&mut self, _: &[u8]) {}
fn write_u64(&mut self, i: u64) {
self.hash = i;
}
}
impl<K> Hash for ShardKey<K> {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(self.hash)
}
}
impl<K> PartialEq for ShardKey<K> {
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}
impl<K> ShardKey<K> {
pub fn new(key: K, hash: u64) -> Self {
Self {
key: Some(key),
hash,
}
}
pub fn new_hash(hash: u64) -> Self {
Self { key: None, hash }
}
pub fn into_inner(self) -> K {
self.key.unwrap()
}
pub fn get(&self) -> &K {
self.key.as_ref().unwrap()
}
}

View File

@ -1,4 +1,3 @@
use super::hasher::ShardKey;
use super::mapref::multiple::{RefMulti, RefMutMulti};
use super::util;
use crate::t::Map;
@ -11,11 +10,11 @@ use std::sync::Arc;
type GuardIter<'a, K, V, S> = (
Arc<RwLockReadGuard<'a, HashMap<K, V, S>>>,
hash_map::Iter<'a, ShardKey<K>, SharedValue<V>>,
hash_map::Iter<'a, K, SharedValue<V>>,
);
type GuardIterMut<'a, K, V, S> = (
Arc<RwLockWriteGuard<'a, HashMap<K, V, S>>>,
hash_map::IterMut<'a, ShardKey<K>, SharedValue<V>>,
hash_map::IterMut<'a, K, SharedValue<V>>,
);
/// Iterator over a DashMap yielding immutable references.
@ -64,7 +63,7 @@ impl<'a, K: Eq + Hash, V, S: 'a + BuildHasher, M: Map<'a, K, V, S>> Iterator
if let Some(current) = self.current.as_mut() {
if let Some((k, v)) = current.1.next() {
let guard = current.0.clone();
return Some(RefMulti::new(guard, k.get(), v.get()));
return Some(RefMulti::new(guard, k, v.get()));
}
}
@ -132,7 +131,7 @@ impl<'a, K: Eq + Hash, V, S: 'a + BuildHasher, M: Map<'a, K, V, S>> Iterator
unsafe {
let k = util::change_lifetime_const(k);
let v = &mut *v.as_ptr();
return Some(RefMutMulti::new(guard, k.get(), v));
return Some(RefMutMulti::new(guard, k, v));
}
}
}

View File

@ -2,7 +2,6 @@
extern crate qadapt_spin as parking_lot;
mod hasher;
pub mod iter;
pub mod mapref;
mod t;
@ -13,7 +12,6 @@ mod serde;
use ahash::RandomState;
use cfg_if::cfg_if;
use hasher::{ShardBuildHasher, ShardKey};
use iter::{Iter, IterMut};
use mapref::entry::{Entry, OccupiedEntry, VacantEntry};
use mapref::multiple::RefMulti;
@ -35,7 +33,7 @@ cfg_if! {
}
}
type HashMap<K, V, S> = std::collections::HashMap<ShardKey<K>, SharedValue<V>, ShardBuildHasher<S>>;
type HashMap<K, V, S> = std::collections::HashMap<K, SharedValue<V>, S>;
#[inline]
fn shard_amount() -> usize {
@ -52,7 +50,7 @@ fn ncb(shard_amount: usize) -> usize {
/// DashMap tries to implement an easy to use API similar to `std::collections::HashMap`
/// with some slight changes to handle concurrency.
///
/// DashMap tries to be very simple to use and to be a direct replacement for `RwLock<HashMap<K, V, S>>`.
/// DashMap tries to be very simple to use and to be a direct replacement for `RwLock<HashMap<K, V>>`.
/// To accomplish these all methods take `&self` instead modifying methods taking `&mut self`.
/// This allows you to put a DashMap in an `Arc<T>` and share it between threads while being able to modify it.
pub struct DashMap<K, V, S = RandomState> {
@ -137,7 +135,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
let shard_amount = shard_amount();
let shift = util::ptr_size_bits() - ncb(shard_amount);
let shards = (0..shard_amount)
.map(|_| RwLock::new(HashMap::with_hasher(ShardBuildHasher::new())))
.map(|_| RwLock::new(HashMap::with_hasher(hasher.clone())))
.collect();
Self {
@ -166,12 +164,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
let shift = util::ptr_size_bits() - ncb(shard_amount);
let cps = capacity / shard_amount;
let shards = (0..shard_amount)
.map(|_| {
RwLock::new(HashMap::with_capacity_and_hasher(
cps,
ShardBuildHasher::new(),
))
})
.map(|_| RwLock::new(HashMap::with_capacity_and_hasher(cps, hasher.clone())))
.collect();
Self {
@ -243,34 +236,17 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: BuildHasher + Clone> DashMap<K, V, S> {
{
let hash = self.hash_usize(&key);
(hash >> self.shift)
}
}
}
cfg_if! {
if #[cfg(feature = "raw-api")] {
/// Finds which shard a certain hash is stored in.
///
/// Requires the `raw-api` feature to be enabled.
///
/// # Examples
///
/// ```
/// use dashmap::DashMap;
///
/// let map = DashMap::new();
/// let key = "key";
/// let hash = map.hash_usize(&key);
/// println!("hash is stored in shard: {}", map.determine_shard(hash));
/// ```
#[inline]
pub fn determine_shard(&self, hash: usize) -> usize {
(hash >> self.shift)
}
} else {
#[inline]
fn determine_shard(&self, hash: usize) -> usize {
fn determine_map<Q>(&self, key: &Q) -> usize
where
K: Borrow<Q>,
Q: Hash + Eq + ?Sized,
{
let hash = self.hash_usize(&key);
(hash >> self.shift)
}
}
@ -566,11 +542,10 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
#[inline]
fn _insert(&self, key: K, value: V) -> Option<V> {
let hash = self.hash_usize(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_map(&key);
let mut shard = unsafe { self._yield_write_shard(idx) };
shard
.insert(ShardKey::new(key, hash as u64), SharedValue::new(value))
.insert(key, SharedValue::new(value))
.map(SharedValue::into_inner)
}
@ -580,13 +555,9 @@ 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 idx = self.determine_shard(hash);
let idx = self.determine_map(&key);
let mut shard = unsafe { self._yield_write_shard(idx) };
let shard_key = ShardKey::new_hash(hash as u64);
shard
.remove_entry(&shard_key)
.map(|(k, v)| (k.into_inner(), v.into_inner()))
shard.remove_entry(key).map(|(k, v)| (k, v.into_inner()))
}
#[inline]
@ -605,15 +576,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 idx = self.determine_shard(hash);
let idx = self.determine_map(&key);
let shard = unsafe { self._yield_read_shard(idx) };
let shard_key = ShardKey::new_hash(hash as u64);
if let Some((kptr, vptr)) = shard.get_key_value(&shard_key) {
if let Some((kptr, vptr)) = shard.get_key_value(key) {
unsafe {
let kptr = util::change_lifetime_const(kptr);
let vptr = util::change_lifetime_const(vptr);
Some(Ref::new(shard, kptr.get(), vptr.get()))
Some(Ref::new(shard, kptr, vptr.get()))
}
} else {
None
@ -626,15 +595,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 idx = self.determine_shard(hash);
let idx = self.determine_map(&key);
let shard = unsafe { self._yield_write_shard(idx) };
let shard_key = ShardKey::new_hash(hash as u64);
if let Some((kptr, vptr)) = shard.get_key_value(&shard_key) {
if let Some((kptr, vptr)) = shard.get_key_value(key) {
unsafe {
let kptr = util::change_lifetime_const(kptr);
let vptr = &mut *vptr.as_ptr();
Some(RefMut::new(shard, kptr.get(), vptr))
Some(RefMut::new(shard, kptr, vptr))
}
} else {
None
@ -650,7 +617,7 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
fn _retain(&self, mut f: impl FnMut(&K, &mut V) -> bool) {
self.shards
.iter()
.for_each(|s| s.write().retain(|k, v| f(k.get(), v.get_mut())));
.for_each(|s| s.write().retain(|k, v| f(k, v.get_mut())));
}
#[inline]
@ -679,21 +646,19 @@ impl<'a, K: 'a + Eq + Hash, V: 'a, S: 'a + BuildHasher + Clone> Map<'a, K, V, S>
self.shards.iter().for_each(|s| {
s.write()
.iter_mut()
.for_each(|(k, v)| util::map_in_place_2((k.get(), v.get_mut()), &mut f));
.for_each(|(k, v)| util::map_in_place_2((k, v.get_mut()), &mut f));
});
}
#[inline]
fn _entry(&'a self, key: K) -> Entry<'a, K, V, S> {
let hash = self.hash_usize(&key);
let idx = self.determine_shard(hash);
let idx = self.determine_map(&key);
let shard = unsafe { self._yield_write_shard(idx) };
let shard_key = ShardKey::new_hash(hash as u64);
if let Some((kptr, vptr)) = shard.get_key_value(&shard_key) {
if let Some((kptr, vptr)) = shard.get_key_value(&key) {
unsafe {
let kptr = util::change_lifetime_const(kptr);
let vptr = &mut *vptr.as_ptr();
Entry::Occupied(OccupiedEntry::new(shard, Some(key), (kptr.get(), vptr)))
Entry::Occupied(OccupiedEntry::new(shard, Some(key), (kptr, vptr)))
}
} else {
Entry::Vacant(VacantEntry::new(shard, key))
@ -841,7 +806,7 @@ mod tests {
s: String,
u: u8,
}
let dm = DashMap::new();
let dm = DashMap::default();
let range = 0..10;
for i in range {
let t = T0 {

View File

@ -1,11 +1,10 @@
use super::one::RefMut;
use crate::hasher::ShardKey;
use crate::util;
use crate::util::SharedValue;
use crate::HashMap;
use ahash::RandomState;
use parking_lot::RwLockWriteGuard;
use std::hash::{BuildHasher, Hash, Hasher};
use std::hash::{BuildHasher, Hash};
use std::mem;
use std::ptr;
@ -88,26 +87,15 @@ impl<'a, K: Eq + Hash, V, S: BuildHasher> VacantEntry<'a, K, V, S> {
Self { shard, key }
}
#[inline]
fn hash_u64<T: Hash>(&self, item: &T) -> u64 {
let mut hasher = self.shard.hasher().build_hasher();
item.hash(&mut hasher);
hasher.finish()
}
#[inline]
pub fn insert(mut self, value: V) -> RefMut<'a, K, V, S> {
unsafe {
let c: K = ptr::read(&self.key);
let hash_c = self.hash_u64(&c);
let hash = self.hash_u64(&self.key);
self.shard
.insert(ShardKey::new(self.key, hash), SharedValue::new(value));
let shard_key_c = ShardKey::new_hash(hash_c);
let (k, v) = self.shard.get_key_value(&shard_key_c).unwrap();
self.shard.insert(self.key, SharedValue::new(value));
let (k, v) = self.shard.get_key_value(&c).unwrap();
let k = util::change_lifetime_const(k);
let v = &mut *v.as_ptr();
let r = RefMut::new(self.shard, k.get(), v);
let r = RefMut::new(self.shard, k, v);
mem::forget(c);
r
}
@ -171,38 +159,23 @@ impl<'a, K: Eq + Hash, V, S: BuildHasher> OccupiedEntry<'a, K, V, S> {
self.elem.0
}
#[inline]
fn hash_u64<T: Hash>(&self, item: &T) -> u64 {
let mut hasher = self.shard.hasher().build_hasher();
item.hash(&mut hasher);
hasher.finish()
}
#[inline]
pub fn remove(mut self) -> V {
let hash = self.hash_u64(&self.elem.0);
let shard_key = ShardKey::new_hash(hash);
self.shard.remove(&shard_key).unwrap().into_inner()
self.shard.remove(self.elem.0).unwrap().into_inner()
}
#[inline]
pub fn remove_entry(mut self) -> (K, V) {
let hash = self.hash_u64(&self.elem.0);
let shard_key = ShardKey::new_hash(hash);
let (k, v) = self.shard.remove_entry(&shard_key).unwrap();
let (k, v) = self.shard.remove_entry(self.elem.0).unwrap();
(k.into_inner(), v.into_inner())
(k, v.into_inner())
}
#[inline]
pub fn replace_entry(mut self, value: V) -> (K, V) {
let hash = self.hash_u64(&self.elem.0);
let hash_nk = self.hash_u64(self.key.as_ref().unwrap());
let nk = self.key.unwrap();
let shard_key = ShardKey::new_hash(hash);
let (k, v) = self.shard.remove_entry(&shard_key).unwrap();
self.shard
.insert(ShardKey::new(nk, hash_nk), SharedValue::new(value));
(k.into_inner(), v.into_inner())
let (k, v) = self.shard.remove_entry(self.elem.0).unwrap();
self.shard.insert(nk, SharedValue::new(value));
(k, v.into_inner())
}
}