More efficient insertion.

This commit is contained in:
Acrimon 2019-09-03 16:56:20 +02:00
parent 354eb83e52
commit 730fb5692a
No known key found for this signature in database
GPG Key ID: 5F96EDD054C9729E
6 changed files with 32 additions and 29 deletions

View File

@ -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"

View File

@ -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;

View File

@ -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(),
}
}

View File

@ -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 }
}

View File

@ -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 }
}

View File

@ -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();