mirror of https://github.com/xacrimon/dashmap
More efficient insertion.
This commit is contained in:
parent
354eb83e52
commit
730fb5692a
|
@ -19,7 +19,7 @@ async = ["futures"]
|
|||
nightly = ["parking_lot/nightly", "hashbrown/nightly"]
|
||||
|
||||
[dependencies]
|
||||
hashbrown = "0.6.0"
|
||||
hashbrown = { path = "hashbrown", features = ["raw"] }
|
||||
parking_lot = "0.9.0"
|
||||
num_cpus = "1.10.1"
|
||||
ahash = "0.2.12"
|
||||
fxhash = "0.2.1"
|
||||
|
|
|
@ -3,6 +3,7 @@ use super::DashMap;
|
|||
use hashbrown::HashMap;
|
||||
use std::sync::Arc;
|
||||
use super::util;
|
||||
use fxhash::FxBuildHasher;
|
||||
|
||||
use parking_lot::{RwLockReadGuard, RwLockWriteGuard};
|
||||
use std::hash::Hash;
|
||||
|
@ -10,11 +11,11 @@ use std::hash::Hash;
|
|||
use hashbrown::hash_map;
|
||||
|
||||
type GuardIter<'a, K, V> = (
|
||||
Arc<RwLockReadGuard<'a, HashMap<K, V>>>,
|
||||
Arc<RwLockReadGuard<'a, HashMap<K, V, FxBuildHasher>>>,
|
||||
hash_map::Iter<'a, K, V>,
|
||||
);
|
||||
type GuardIterMut<'a, K, V> = (
|
||||
Arc<RwLockWriteGuard<'a, HashMap<K, V>>>,
|
||||
Arc<RwLockWriteGuard<'a, HashMap<K, V, FxBuildHasher>>>,
|
||||
hash_map::IterMut<'a, K, V>,
|
||||
);
|
||||
|
||||
|
@ -51,7 +52,7 @@ impl<'a, K: Eq + Hash, V> Iterator for Iter<'a, K, V> {
|
|||
|
||||
let shards = self.map.shards();
|
||||
let guard = shards[self.shard_i].read();
|
||||
let sref: &HashMap<K, V> = unsafe { util::change_lifetime_const(&*guard) };
|
||||
let sref: &HashMap<K, V, FxBuildHasher> = unsafe { util::change_lifetime_const(&*guard) };
|
||||
let iter = sref.iter();
|
||||
self.current = Some((Arc::new(guard), iter));
|
||||
self.shard_i += 1;
|
||||
|
@ -95,7 +96,7 @@ impl<'a, K: Eq + Hash, V> Iterator for IterMut<'a, K, V> {
|
|||
|
||||
let shards = self.map.shards();
|
||||
let mut guard = shards[self.shard_i].write();
|
||||
let sref: &mut HashMap<K, V> = unsafe { util::change_lifetime_mut(&mut *guard) };
|
||||
let sref: &mut HashMap<K, V, FxBuildHasher> = unsafe { util::change_lifetime_mut(&mut *guard) };
|
||||
let iter = sref.iter_mut();
|
||||
self.current = Some((Arc::new(guard), iter));
|
||||
self.shard_i += 1;
|
||||
|
|
19
src/lib.rs
19
src/lib.rs
|
@ -1,9 +1,8 @@
|
|||
// TO-DO: entry api
|
||||
// TO-DO: entry api && contains
|
||||
// api results instead
|
||||
// coarse transactions
|
||||
// shortcuts api
|
||||
// fix deadlock
|
||||
// optimizations
|
||||
// fine grained transactions
|
||||
// optimizations
|
||||
// useful traits
|
||||
|
@ -19,7 +18,7 @@ mod util;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use ahash::ABuildHasher;
|
||||
use fxhash::FxBuildHasher;
|
||||
use hashbrown::HashMap;
|
||||
use parking_lot::RwLock;
|
||||
pub use query::ExecutableQuery;
|
||||
|
@ -32,16 +31,16 @@ where
|
|||
K: Eq + Hash,
|
||||
{
|
||||
ncb: usize,
|
||||
shards: Box<[RwLock<HashMap<K, V>>]>,
|
||||
hash_builder: ABuildHasher,
|
||||
shards: Box<[RwLock<HashMap<K, V, FxBuildHasher>>]>,
|
||||
hash_builder: FxBuildHasher,
|
||||
}
|
||||
|
||||
impl<'a, K: 'a + Eq + Hash, V: 'a> DashMap<K, V> {
|
||||
pub(crate) fn shards(&'a self) -> &'a Box<[RwLock<HashMap<K, V>>]> {
|
||||
pub(crate) fn shards(&'a self) -> &'a Box<[RwLock<HashMap<K, V, FxBuildHasher>>]> {
|
||||
&self.shards
|
||||
}
|
||||
|
||||
pub(crate) fn determine_map<Q>(&self, key: &Q) -> usize
|
||||
pub(crate) fn determine_map<Q>(&self, key: &Q) -> (usize, u64)
|
||||
where
|
||||
K: Borrow<Q>,
|
||||
Q: Hash + Eq + ?Sized,
|
||||
|
@ -52,21 +51,21 @@ impl<'a, K: 'a + Eq + Hash, V: 'a> DashMap<K, V> {
|
|||
let hash = hash_state.finish();
|
||||
let shift = util::ptr_size_bits() - self.ncb;
|
||||
|
||||
(hash >> shift) as usize
|
||||
((hash >> shift) as usize, hash)
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
let shard_amount = (num_cpus::get() * 16).next_power_of_two();
|
||||
let shift = (shard_amount as f32).log2() as usize;
|
||||
let shards = (0..shard_amount)
|
||||
.map(|_| RwLock::new(HashMap::new()))
|
||||
.map(|_| RwLock::new(HashMap::with_hasher(FxBuildHasher::default())))
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
|
||||
Self {
|
||||
ncb: shift,
|
||||
shards,
|
||||
hash_builder: ABuildHasher::new(),
|
||||
hash_builder: FxBuildHasher::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,17 +3,18 @@ use std::sync::Arc;
|
|||
use parking_lot::{RwLockReadGuard, RwLockWriteGuard};
|
||||
use std::hash::Hash;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use fxhash::FxBuildHasher;
|
||||
|
||||
// -- Shared
|
||||
|
||||
pub struct DashMapRefMulti<'a, K: Eq + Hash, V> {
|
||||
_guard: Arc<RwLockReadGuard<'a, HashMap<K, V>>>,
|
||||
_guard: Arc<RwLockReadGuard<'a, HashMap<K, V, FxBuildHasher>>>,
|
||||
k: &'a K,
|
||||
v: &'a V,
|
||||
}
|
||||
|
||||
impl<'a, K: Eq + Hash, V> DashMapRefMulti<'a, K, V> {
|
||||
pub(crate) fn new(guard: Arc<RwLockReadGuard<'a, HashMap<K, V>>>, k: &'a K, v: &'a V) -> Self {
|
||||
pub(crate) fn new(guard: Arc<RwLockReadGuard<'a, HashMap<K, V, FxBuildHasher>>>, k: &'a K, v: &'a V) -> Self {
|
||||
Self { _guard: guard, k, v }
|
||||
}
|
||||
|
||||
|
@ -43,13 +44,13 @@ impl<'a, K: Eq + Hash, V> Deref for DashMapRefMulti<'a, K, V> {
|
|||
// -- Unique
|
||||
|
||||
pub struct DashMapRefMutMulti<'a, K: Eq + Hash, V> {
|
||||
_guard: Arc<RwLockWriteGuard<'a, HashMap<K, V>>>,
|
||||
_guard: Arc<RwLockWriteGuard<'a, HashMap<K, V, FxBuildHasher>>>,
|
||||
k: &'a K,
|
||||
v: &'a mut V,
|
||||
}
|
||||
|
||||
impl<'a, K: Eq + Hash, V> DashMapRefMutMulti<'a, K, V> {
|
||||
pub(crate) fn new(guard: Arc<RwLockWriteGuard<'a, HashMap<K, V>>>, k: &'a K, v: &'a mut V) -> Self {
|
||||
pub(crate) fn new(guard: Arc<RwLockWriteGuard<'a, HashMap<K, V, FxBuildHasher>>>, k: &'a K, v: &'a mut V) -> Self {
|
||||
Self { _guard: guard, k, v }
|
||||
}
|
||||
|
||||
|
|
|
@ -2,17 +2,18 @@ use hashbrown::HashMap;
|
|||
use parking_lot::{RwLockReadGuard, RwLockWriteGuard};
|
||||
use std::hash::Hash;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use fxhash::FxBuildHasher;
|
||||
|
||||
// -- Shared
|
||||
|
||||
pub struct DashMapRef<'a, K: Eq + Hash, V> {
|
||||
_guard: RwLockReadGuard<'a, HashMap<K, V>>,
|
||||
_guard: RwLockReadGuard<'a, HashMap<K, V, FxBuildHasher>>,
|
||||
k: &'a K,
|
||||
v: &'a V,
|
||||
}
|
||||
|
||||
impl<'a, K: Eq + Hash, V> DashMapRef<'a, K, V> {
|
||||
pub(crate) fn new(guard: RwLockReadGuard<'a, HashMap<K, V>>, k: &'a K, v: &'a V) -> Self {
|
||||
pub(crate) fn new(guard: RwLockReadGuard<'a, HashMap<K, V, FxBuildHasher>>, k: &'a K, v: &'a V) -> Self {
|
||||
Self { _guard: guard, k, v }
|
||||
}
|
||||
|
||||
|
@ -42,13 +43,13 @@ impl<'a, K: Eq + Hash, V> Deref for DashMapRef<'a, K, V> {
|
|||
// -- Unique
|
||||
|
||||
pub struct DashMapRefMut<'a, K: Eq + Hash, V> {
|
||||
_guard: RwLockWriteGuard<'a, HashMap<K, V>>,
|
||||
_guard: RwLockWriteGuard<'a, HashMap<K, V, FxBuildHasher>>,
|
||||
k: &'a K,
|
||||
v: &'a mut V,
|
||||
}
|
||||
|
||||
impl<'a, K: Eq + Hash, V> DashMapRefMut<'a, K, V> {
|
||||
pub(crate) fn new(guard: RwLockWriteGuard<'a, HashMap<K, V>>, k: &'a K, v: &'a mut V) -> Self {
|
||||
pub(crate) fn new(guard: RwLockWriteGuard<'a, HashMap<K, V, FxBuildHasher>>, k: &'a K, v: &'a mut V) -> Self {
|
||||
Self { _guard: guard, k, v }
|
||||
}
|
||||
|
||||
|
|
11
src/query.rs
11
src/query.rs
|
@ -494,7 +494,7 @@ impl<'a, 'k, Q: Eq + Hash, K: Eq + Hash + Borrow<Q>, V> ExecutableQuery
|
|||
type Output = Option<(K, V)>;
|
||||
|
||||
fn exec(self) -> Self::Output {
|
||||
let shard_id = self.inner.inner.map.determine_map(&self.inner.key);
|
||||
let shard_id = self.inner.inner.map.determine_map(&self.inner.key).0;
|
||||
let shards = self.inner.inner.map.shards();
|
||||
let mut shard = shards[shard_id].write();
|
||||
shard.remove_entry(&self.inner.key)
|
||||
|
@ -539,10 +539,11 @@ impl<'a, K: Eq + Hash, V> ExecutableQuery for QueryInsertSync<'a, K, V> {
|
|||
type Output = Option<V>;
|
||||
|
||||
fn exec(self) -> Self::Output {
|
||||
let shard_id = self.inner.inner.map.determine_map(&self.inner.key);
|
||||
let (shard_id, hash) = self.inner.inner.map.determine_map(&self.inner.key);
|
||||
let shards = self.inner.inner.map.shards();
|
||||
let mut shard = shards[shard_id].write();
|
||||
shard.insert(self.inner.key, self.inner.value)
|
||||
|
||||
shard.insert_with_hash_nocheck(self.inner.key, self.inner.value, hash)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -607,7 +608,7 @@ impl<'a, 'k, Q: Eq + Hash, K: Eq + Hash + Borrow<Q>, V> ExecutableQuery
|
|||
type Output = Option<DashMapRef<'a, K, V>>;
|
||||
|
||||
fn exec(self) -> Self::Output {
|
||||
let shard_id = self.inner.inner.map.determine_map(&self.inner.key);
|
||||
let shard_id = self.inner.inner.map.determine_map(&self.inner.key).0;
|
||||
let shards = self.inner.inner.map.shards();
|
||||
let shard = shards[shard_id].read();
|
||||
if let Some((k, v)) = shard.get_key_value(&self.inner.key) {
|
||||
|
@ -647,7 +648,7 @@ impl<'a, 'k, Q: Eq + Hash, K: Eq + Hash + Borrow<Q>, V> ExecutableQuery
|
|||
.inner
|
||||
.inner
|
||||
.map
|
||||
.determine_map(&self.inner.inner.key);
|
||||
.determine_map(&self.inner.inner.key).0;
|
||||
let shards = self.inner.inner.inner.map.shards();
|
||||
let shard = shards[shard_id].write();
|
||||
|
||||
|
|
Loading…
Reference in New Issue