Skip to content

Commit

Permalink
Add moveout feature for ObjectCache
Browse files Browse the repository at this point in the history
  • Loading branch information
Coldwings committed Dec 2, 2024
1 parent 9712349 commit e5f7284
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 24 deletions.
16 changes: 10 additions & 6 deletions common/expirecontainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<Item>(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);
}
55 changes: 38 additions & 17 deletions common/expirecontainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ class ObjectCacheBase : public ExpireContainerBase {
Item* ref_acquire(const Item& key_item, Delegate<void, void*> 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<void, void*> ctor,
uint64_t failure_cooldown = 0) {
Expand All @@ -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 <typename KeyType, typename ValType>
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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<Item>;
iterator begin() { return Base::begin(); }
iterator end() { return Base::end(); }
Expand Down Expand Up @@ -427,9 +423,21 @@ class ObjectCache
: public __ObjectCache<KeyType, ValPtr,
ObjectCacheBase::PtrItem<KeyType, ValPtr>> {
public:
using __ObjectCache<
KeyType, ValPtr,
ObjectCacheBase::PtrItem<KeyType, ValPtr>>::__ObjectCache;
using Base = __ObjectCache<KeyType, ValPtr,
ObjectCacheBase::PtrItem<KeyType, ValPtr>>;
using Base::Base;

ValPtr ref_release(typename Base::ItemPtr item, bool recycle = false,
bool destroy = true) {
return reinterpret_cast<ValPtr>(
Base::ref_release(item, recycle, destroy));
}

ValPtr release(const typename Base::InterfaceKey& key, bool recycle = false,
bool destroy = true) {
return reinterpret_cast<ValPtr>(
Base::release(typename Base::Item(key), recycle, destroy));
}
};

template <typename KeyType, typename NodeType>
Expand All @@ -438,7 +446,20 @@ class ObjectCache<KeyType, intrusive_list<NodeType>>
KeyType, intrusive_list<NodeType>,
ObjectCacheBase::ListItem<KeyType, intrusive_list<NodeType>>> {
public:
using __ObjectCache<KeyType, intrusive_list<NodeType>,
ObjectCacheBase::ListItem<
KeyType, intrusive_list<NodeType>>>::__ObjectCache;
using Base = __ObjectCache<
KeyType, intrusive_list<NodeType>,
ObjectCacheBase::ListItem<KeyType, intrusive_list<NodeType>>>;
using Base::Base;

NodeType* ref_release(typename Base::ItemPtr item, bool recycle = false,
bool destroy = true) {
return reinterpret_cast<NodeType*>(
Base::ref_release(item, recycle, destroy));
}

NodeType* release(const typename Base::InterfaceKey& key,
bool recycle = false, bool destroy = true) {
return reinterpret_cast<NodeType*>(
Base::release(typename Base::Item(key), recycle, destroy));
}
};
46 changes: 46 additions & 0 deletions common/test/test_objcache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ limitations under the License.
#include <thread>
#include <gtest/gtest.h>
#include <photon/thread/thread.h>
#include <photon/thread/thread11.h>
#include <photon/common/alog.h>
#include "../../test/ci-tools.h"

Expand Down Expand Up @@ -491,6 +492,51 @@ TEST(ObjCache, with_list) {
}
}

TEST(ObjectCache, no_destroy) {
ObjectCache<int, int*> 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<int, int*> 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();
Expand Down
3 changes: 2 additions & 1 deletion rpc/rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down

0 comments on commit e5f7284

Please sign in to comment.