mirror of https://github.com/xacrimon/dashmap
Revert "Fix double hash issue"
This commit is contained in:
parent
5d2e015572
commit
3bb9f93d92
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
89
src/lib.rs
89
src/lib.rs
|
@ -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 {
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue