From ab2fb882bf7e97a3650e0eaf618219cc29eb9cc0 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Wed, 27 Jun 2018 15:41:29 +0800 Subject: [PATCH] common/shared_cache: add lockless SharedLRU Signed-off-by: Kefu Chai --- src/common/lock_cond.h | 41 ++++++++++++++++++++++++ src/common/lock_mutex.h | 3 ++ src/common/lock_shared_ptr.h | 23 +++++++++++++ src/common/shared_cache.hpp | 48 +++++++++++++++------------- src/test/common/test_shared_cache.cc | 4 +-- 5 files changed, 95 insertions(+), 24 deletions(-) create mode 100644 src/common/lock_cond.h create mode 100644 src/common/lock_shared_ptr.h diff --git a/src/common/lock_cond.h b/src/common/lock_cond.h new file mode 100644 index 0000000000000..0cab3fa21ee8b --- /dev/null +++ b/src/common/lock_cond.h @@ -0,0 +1,41 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- + +#pragma once + +#include "lock_policy.h" +#include "Cond.h" + +class SharedLRUTest; + +namespace ceph::internal { + +// empty helper class except when the template argument is LockPolicy::MUTEX +template +class LockCond { +public: + int Wait(LockMutex&) { + return 0; + } + int Signal() { + return 0; + } +}; + +template<> +class LockCond { +public: + int Wait(LockMutex& mutex) { + return cond.Wait(mutex.get()); + } + int Signal() { + return cond.Signal(); + } +private: + Cond& get() { + return cond; + } + Cond cond; + friend class ::SharedLRUTest; +}; + +} // namespace ceph::internal diff --git a/src/common/lock_mutex.h b/src/common/lock_mutex.h index 40ffa51490f2b..ea69d319fabe5 100644 --- a/src/common/lock_mutex.h +++ b/src/common/lock_mutex.h @@ -5,6 +5,8 @@ #include "lock_policy.h" #include "Mutex.h" +class SharedLRUTest; + namespace ceph::internal { template class LockCond; @@ -43,6 +45,7 @@ private: } mutable Mutex mutex; friend class LockCond; + friend class ::SharedLRUTest; }; } // namespace ceph::internal diff --git a/src/common/lock_shared_ptr.h b/src/common/lock_shared_ptr.h new file mode 100644 index 0000000000000..0e2f6e8cf2e34 --- /dev/null +++ b/src/common/lock_shared_ptr.h @@ -0,0 +1,23 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- + +#pragma once + +#include "lock_policy.h" +#include +#include + +namespace ceph::internal { + +template +struct SharedPtrTrait { + template using shared_ptr = boost::local_shared_ptr; + template using weak_ptr = boost::weak_ptr; +}; + +template<> +struct SharedPtrTrait { + template using shared_ptr = std::shared_ptr; + template using weak_ptr = std::weak_ptr; +}; + +} diff --git a/src/common/shared_cache.hpp b/src/common/shared_cache.hpp index 266a3b9def381..526de44f88756 100644 --- a/src/common/shared_cache.hpp +++ b/src/common/shared_cache.hpp @@ -17,21 +17,25 @@ #include #include -#include "common/Mutex.h" -#include "common/Cond.h" +#include "common/lock_cond.h" +#include "common/lock_mutex.h" +#include "common/lock_policy.h" +#include "common/lock_shared_ptr.h" #include "include/unordered_map.h" // re-include our assert to clobber the system one; fix dout: #include "include/assert.h" -template +template class SharedLRU { CephContext *cct; - typedef std::shared_ptr VPtr; - typedef std::weak_ptr WeakVPtr; - Mutex lock; + using shared_ptr_trait_t = ceph::internal::SharedPtrTrait; + using VPtr = typename shared_ptr_trait_t::template shared_ptr; + using WeakVPtr = typename shared_ptr_trait_t::template weak_ptr; + ceph::internal::LockMutex lock; size_t max_size; - Cond cond; + ceph::internal::LockCond cond; unsigned size; public: int waiting; @@ -74,7 +78,7 @@ private: } void remove(const K& key, V *valptr) { - Mutex::Locker l(lock); + auto locker = lock(); typename map, C>::iterator i = weak_refs.find(key); if (i != weak_refs.end() && i->second.second == valptr) { weak_refs.erase(i); @@ -84,9 +88,9 @@ private: class Cleanup { public: - SharedLRU *cache; + SharedLRU *cache; K key; - Cleanup(SharedLRU *cache, K key) : cache(cache), key(key) {} + Cleanup(SharedLRU *cache, K key) : cache(cache), key(key) {} void operator()(V *ptr) { cache->remove(key, ptr); delete ptr; @@ -119,7 +123,7 @@ public: // reorder. map, C> temp; - Mutex::Locker l(lock); + auto locker = lock(); temp.swap(weak_refs); // reconstruct with new comparator @@ -156,7 +160,7 @@ public: void clear() { while (true) { VPtr val; // release any ref we have after we drop the lock - Mutex::Locker l(lock); + auto locker = lock(); if (size == 0) break; @@ -168,7 +172,7 @@ public: void clear(const K& key) { VPtr val; // release any ref we have after we drop the lock { - Mutex::Locker l(lock); + auto locker = lock(); typename map, C>::iterator i = weak_refs.find(key); if (i != weak_refs.end()) { val = i->second.first.lock(); @@ -180,7 +184,7 @@ public: void purge(const K &key) { VPtr val; // release any ref we have after we drop the lock { - Mutex::Locker l(lock); + auto locker = lock(); typename map, C>::iterator i = weak_refs.find(key); if (i != weak_refs.end()) { val = i->second.first.lock(); @@ -193,7 +197,7 @@ public: void set_size(size_t new_size) { list to_release; { - Mutex::Locker l(lock); + auto locker = lock(); max_size = new_size; trim_cache(&to_release); } @@ -201,7 +205,7 @@ public: // Returns K key s.t. key <= k for all currently cached k,v K cached_key_lower_bound() { - Mutex::Locker l(lock); + auto locker = lock(); return weak_refs.begin()->first; } @@ -209,7 +213,7 @@ public: VPtr val; list to_release; { - Mutex::Locker l(lock); + auto locker = lock(); ++waiting; bool retry = false; do { @@ -236,7 +240,7 @@ public: bool get_next(const K &key, pair *next) { pair r; { - Mutex::Locker l(lock); + auto locker = lock(); VPtr next_val; typename map, C>::iterator i = weak_refs.upper_bound(key); @@ -269,7 +273,7 @@ public: VPtr val; list to_release; { - Mutex::Locker l(lock); + auto locker = lock(); ++waiting; bool retry = false; do { @@ -294,7 +298,7 @@ public: VPtr val; list to_release; { - Mutex::Locker l(lock); + auto locker = lock(); bool retry = false; do { retry = false; @@ -327,7 +331,7 @@ public: * in the cache. */ bool empty() { - Mutex::Locker l(lock); + auto locker = lock(); return weak_refs.empty(); } @@ -347,7 +351,7 @@ public: VPtr val; list to_release; { - Mutex::Locker l(lock); + auto locker = lock(); typename map, C>::iterator actual = weak_refs.lower_bound(key); if (actual != weak_refs.end() && actual->first == key) { diff --git a/src/test/common/test_shared_cache.cc b/src/test/common/test_shared_cache.cc index 026c99fe70b3b..ea0ba288e42b0 100644 --- a/src/test/common/test_shared_cache.cc +++ b/src/test/common/test_shared_cache.cc @@ -28,8 +28,8 @@ class SharedLRUTest : public SharedLRU { public: - Mutex &get_lock() { return lock; } - Cond &get_cond() { return cond; } + Mutex &get_lock() { return lock.get(); } + Cond &get_cond() { return cond.get(); } map, int* > > &get_weak_refs() { return weak_refs; } -- 2.39.5