Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some modify and fix in ObjectCacheV2 #531

Merged
merged 4 commits into from
Aug 8, 2024
Merged

Conversation

Coldwings
Copy link
Collaborator

Some fixes.

@Coldwings Coldwings requested a review from lihuiba August 5, 2024 07:48
photon::thread* reclaimer = nullptr;
photon::common::RingChannel<LockfreeMPMCRingQueue<std::shared_ptr<V>, 4096>>
reclaim_queue;
photon::spinlock maplock;
std::unordered_set<Box, ItemHash, ItemEqual> map;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use box/Box instead of item/Item

return *item;
}

uint64_t __expire() {
intrusive_list<Box> delete_list;
uint64_t now = photon::now;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's simpler to use now - lifespan

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if lifespan has been set a extra-big number (like UINT64_MAX, present object in objcache never reclaim

sat_add is necessary.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sat_sub(now, lifespan)

auto x = lru_list.front();
while (x && (photon::sat_add(x->timestamp, lifespan) < now)) {
lru_list.pop(x);
__update(*x, nullptr);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's more performant to realize x->reset(), which simply invokes shared_ptr::reset().

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In new implementation still use exchange/swap like stuff instead of reset().

swapped out object still have at lease one reference if result is assigned to another variable, so it could able to control when to perform object destruction.

_reader(std::move(reader)),
_recycle(false) {}
Borrow(ObjectCacheV2* oc, Box* item, const std::shared_ptr<V>& reader)
: _oc(oc), _item(item), _reader(reader), _recycle(false) {}

Borrow(Borrow&& rhs) : _reader(nullptr) { *this = std::move(rhs); }

Borrow& operator=(Borrow&& rhs) {
Copy link
Collaborator

@lihuiba lihuiba Aug 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of swap/exchange, it's more semantically right to:

assert(_oc == rhs._oc);
std::atomic_exchange(&_reader, rhs._reader);
_item = rhs._item;
_recycle = rhs._recycle;
rhs._reader.reset();
rhs._item = nullptr;
rhs._recycle = false;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

according to cppreference https://en.cppreference.com/w/cpp/memory/shared_ptr

If multiple threads of execution access the same shared_ptr object without synchronization and any of those accesses uses a non-const member function of shared_ptr then a data race will occur

Since atomic<shared_ptr> is not supported by c++11/14/17, an new implementation using photon::mutex helps keep shared_ptr update in critical zone.

return *item;
}

uint64_t __expire() {
intrusive_list<Box> delete_list;
uint64_t now = photon::now;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sat_sub(now, lifespan)

reclaim_queue.template send<PhotonPause>(nullptr);
photon::thread_join((photon::join_handle*)reclaimer);
reclaimer = nullptr;
}
SCOPED_LOCK(maplock);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use maplock only to protect a single assignment?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

code here want to access intrusive_list only for preventing hit assert of list.

Technically in dtor, other threads should not have any other accesses to the whole object cache, the lock here could be ignored.

I will remove the lock acquiring here

photon::now) {
r = __update(item, ctor());
auto r = std::shared_ptr<V>(ctor());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ctor() may return a shared_ptr?

Box& __find_or_create_box(KeyType&& key) {
Box keybox(key);
Box* box = nullptr;
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why this scope?

std::swap(r, ref);
return r;
}
std::shared_ptr<V> clear(uint64_t ts = 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"reset" seems better

// make vector holds those shared_ptr
// prevent object destroy in critical zone
to_release.push_back(x->clear());
map.erase(*x);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use map.extract().value() obtain the Box element, so as to use the intrusive_list for to_release.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems add macro to check c++ version to show different implementation for those above C++17 is a good idea.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seem that C++17 node_handle owns the element Box, can not get out the pointer to Box without hacking.

@lihuiba lihuiba merged commit 33e3251 into alibaba:main Aug 8, 2024
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants