diff --git a/common/expirecontainer.cpp b/common/expirecontainer.cpp index 4e9e3a0b..49cc065f 100644 --- a/common/expirecontainer.cpp +++ b/common/expirecontainer.cpp @@ -108,15 +108,16 @@ auto ObjectCacheBase::ref_acquire(const Item& key_item, } } if (!item->_obj) { - ref_release(item, false); + ref_release(item, false, true); return nullptr; } return item; } -int ObjectCacheBase::ref_release(ItemPtr item, bool recycle) { +void* ObjectCacheBase::ref_release(ItemPtr item, bool recycle, bool destroy) { DEFER(expire()); photon::semaphore sem; + void * ret = nullptr; { SCOPED_LOCK(_lock); if (item->_recycle) recycle = false; @@ -140,15 +141,18 @@ int ObjectCacheBase::ref_release(ItemPtr item, bool recycle) { assert(item->_refcnt == 0); _set.erase(item); } + if (!destroy) { + std::swap(ret, item->_obj); + } delete item; blocker.notify_all(); } - return 0; + return ret; } // the argument `key` plays the roles of (type-erased) key -int ObjectCacheBase::release(const Item& key_item, bool recycle) { +void* ObjectCacheBase::release(const Item& key_item, bool recycle, bool destroy) { auto item = ExpireContainerBase::TypedIterator(Base::find(key_item)); - if (item == end()) return -1; - return ref_release(*item, recycle); + if (item == end()) return nullptr; + return ref_release(*item, recycle, destroy); } diff --git a/common/expirecontainer.h b/common/expirecontainer.h index 6453e3e3..11557378 100644 --- a/common/expirecontainer.h +++ b/common/expirecontainer.h @@ -243,7 +243,7 @@ class ObjectCacheBase : public ExpireContainerBase { Item* ref_acquire(const Item& key_item, Delegate ctor, uint64_t failure_cooldown = 0); - int ref_release(ItemPtr item, bool recycle = false); + void* ref_release(ItemPtr item, bool recycle, bool destroy); void* acquire(const Item& key_item, Delegate ctor, uint64_t failure_cooldown = 0) { @@ -252,7 +252,7 @@ class ObjectCacheBase : public ExpireContainerBase { } // the argument `key` plays the roles of (type-erased) key - int release(const Item& key_item, bool recycle = false); + void* release(const Item& key_item, bool recycle, bool destroy); public: template @@ -324,11 +324,12 @@ class ObjectCacheBase : public ExpireContainerBase { ObjectCache* _oc; Item* _ref; bool _recycle = false; + bool _moveout = false; Borrow(ObjectCache* oc, Item* ref, bool recycle) : _oc(oc), _ref(ref), _recycle(recycle) {} ~Borrow() { - if (_ref) _oc->ref_release(_ref, _recycle); + if (_ref) _oc->ref_release(_ref, _recycle, !_moveout); } Borrow() = delete; @@ -346,6 +347,9 @@ class ObjectCacheBase : public ExpireContainerBase { typename Item::ValPtr operator->() { return _ref->get_ptr(); } typename Item::ValEntity& operator*() { return _ref->get_ref(); } + bool moved() const { return _moveout; } + bool moveout(bool x) { return _moveout = x; } + protected: void move(Borrow&& rhs) { _oc = rhs._oc; @@ -391,14 +395,6 @@ class __ObjectCache : public ObjectCacheBase { return Item::get_content(ref_acquire(key, ctor, failure_cooldown)); } - int ref_release(ItemPtr item, bool recycle = false) { - return Base::ref_release(item, recycle); - } - - int release(const InterfaceKey& key, bool recycle = false) { - return Base::release(Item(key), recycle); - } - using iterator = typename ExpireContainerBase::TypedIterator; iterator begin() { return Base::begin(); } iterator end() { return Base::end(); } @@ -427,9 +423,21 @@ class ObjectCache : public __ObjectCache> { public: - using __ObjectCache< - KeyType, ValPtr, - ObjectCacheBase::PtrItem>::__ObjectCache; + using Base = __ObjectCache>; + using Base::Base; + + ValPtr ref_release(typename Base::ItemPtr item, bool recycle = false, + bool destroy = true) { + return reinterpret_cast( + Base::ref_release(item, recycle, destroy)); + } + + ValPtr release(const typename Base::InterfaceKey& key, bool recycle = false, + bool destroy = true) { + return reinterpret_cast( + Base::release(typename Base::Item(key), recycle, destroy)); + } }; template @@ -438,7 +446,20 @@ class ObjectCache> KeyType, intrusive_list, ObjectCacheBase::ListItem>> { public: - using __ObjectCache, - ObjectCacheBase::ListItem< - KeyType, intrusive_list>>::__ObjectCache; + using Base = __ObjectCache< + KeyType, intrusive_list, + ObjectCacheBase::ListItem>>; + using Base::Base; + + NodeType* ref_release(typename Base::ItemPtr item, bool recycle = false, + bool destroy = true) { + return reinterpret_cast( + Base::ref_release(item, recycle, destroy)); + } + + NodeType* release(const typename Base::InterfaceKey& key, + bool recycle = false, bool destroy = true) { + return reinterpret_cast( + Base::release(typename Base::Item(key), recycle, destroy)); + } }; diff --git a/common/test/test_objcache.cpp b/common/test/test_objcache.cpp index 16e206a0..15919264 100644 --- a/common/test/test_objcache.cpp +++ b/common/test/test_objcache.cpp @@ -25,6 +25,7 @@ limitations under the License. #include #include #include +#include #include #include "../../test/ci-tools.h" @@ -491,6 +492,51 @@ TEST(ObjCache, with_list) { } } +TEST(ObjectCache, no_destroy) { + ObjectCache oc(1000UL * 1000); + int* ptr = nullptr; + auto th1 = photon::thread_enable_join(photon::thread_create11([&oc, &ptr] { + auto a = oc.acquire(0, [] { return new int(1); }); + ptr = a; + photon::thread_yield(); + auto x = oc.release(0, true, false); + EXPECT_EQ(x, a); + })); + auto th2 = photon::thread_enable_join(photon::thread_create11([&oc, &ptr] { + auto a = oc.acquire(0, [] { return new int(2); }); + EXPECT_EQ(a, ptr); + photon::thread_yield(); + auto x = oc.release(0); + EXPECT_EQ(nullptr, x); + })); + photon::thread_join(th1); + photon::thread_join(th2); + auto x = oc.acquire(0, [] { return new int(3);}); + EXPECT_EQ(3, *x); + oc.release(0); +} +TEST(ObjectCache, movedout) { + ObjectCache oc(1000UL * 1000); + int* ptr = nullptr; + auto th1 = photon::thread_enable_join(photon::thread_create11([&oc, &ptr] { + auto a = oc.borrow(0, [] { return new int(1); }); + ptr = &*a; + photon::thread_yield(); + a.recycle(true); + a.moveout(true); + EXPECT_TRUE(a.moved()); + })); + auto th2 = photon::thread_enable_join(photon::thread_create11([&oc, &ptr] { + auto a = oc.borrow(0, [] { return new int(2); }); + EXPECT_EQ(ptr, &*a); + photon::thread_yield(); + })); + photon::thread_join(th1); + photon::thread_join(th2); + auto x = oc.borrow(0, [] { return new int(3);}); + EXPECT_EQ(3, *x); +} + int main(int argc, char** argv) { if (!photon::is_using_default_engine()) return 0; photon::vcpu_init(); diff --git a/rpc/rpc.cpp b/rpc/rpc.cpp index 01c6b88d..dbfecb10 100644 --- a/rpc/rpc.cpp +++ b/rpc/rpc.cpp @@ -447,7 +447,8 @@ namespace rpc { } int put_stub(const net::EndPoint& endpoint, bool immediately) override { - return m_pool->release(endpoint, immediately); + m_pool->release(endpoint, immediately); + return 0; } Stub* acquire(const net::EndPoint& endpoint) override {