Add if_contains_unsafe function that does not lock the parallel hash map mutex

Add find_as_pair function, since make_iterator in find was very expensive.  With an equal number of read and write operations in a sample program, more time was being spent in the read then write.
This commit is contained in:
Brian McKinnon
2021-05-07 21:42:03 -05:00
parent f158416ea2
commit 3a0e372bbf
+23 -8
View File
@@ -3376,12 +3376,18 @@ private:
protected:
template <class K = key_type, class L = typename Lockable::SharedLock>
iterator find(const key_arg<K>& key, size_t hashval, L &mutexlock) {
std::pair<Inner*, EmbeddedIterator> find_as_pair(const key_arg<K>& key, size_t hashval, L& mutexlock)
{
Inner& inner = sets_[subidx(hashval)];
auto& set = inner.set_;
auto& set = inner.set_;
mutexlock = std::move(L(inner));
auto it = set.find(key, hashval);
return make_iterator(&inner, it);
return std::make_pair(&inner, set.find(key, hashval));
}
template <class K = key_type, class L = typename Lockable::SharedLock>
iterator find(const key_arg<K>& key, size_t hashval, L& mutexlock) {
auto res = find_as_pair(key, hashval, mutexlock);
return make_iterator(res.first, res.second);
}
template <class K>
@@ -3603,7 +3609,7 @@ public:
template <class K = key_type, class... Args>
iterator try_emplace_with_hash(size_t hashval, const_iterator, const key_arg<K>& k, Args&&... args) {
return try_emplace_with_hash(hashval, k, std::forward<Args>(args)...).first;
}
}
// if map contains key, lambda is called with the mapped value (under read lock protection),
// and if_contains returns true. This is a const API and lambda should not modify the value
@@ -3614,6 +3620,15 @@ public:
modify_if_impl<K, F, typename Lockable::SharedLock>(key, std::forward<F>(f));
}
// if map contains key, lambda is called with the mapped value without read lock protection,
// and if_contains_unsafe returns true. This is a const API and lambda should not modify the value
// -----------------------------------------------------------------------------------------
template <class K = key_type, class F>
bool if_contains_unsafe(const key_arg<K>& key, F&& f) const {
return const_cast<parallel_hash_map*>(this)->template
modify_if_impl<K, F, LockableBaseImpl<phmap::NullMutex>::DoNothing>(key, std::forward<F>(f));
}
// if map contains key, lambda is called with the mapped value (under write lock protection),
// and modify_if returns true. This is a non-const API and lambda is allowed to modify the mapped value
// ----------------------------------------------------------------------------------------------------
@@ -3674,10 +3689,10 @@ private:
static_assert(std::is_invocable<F, mapped_type&>::value);
#endif
L m;
auto it = this->template find<K, L>(key, this->hash(key), m);
if (it == this->end())
auto res = this->template find_as_pair<K, L>(key, this->hash(key), m);
if (res.second == res.first->set_.end())
return false;
std::forward<F>(f)(Policy::value(&*it));
std::forward<F>(f)(Policy::value(&*res.second));
return true;
}