try to adjust recycling strategy for large message cache

This commit is contained in:
mutouyun 2021-06-27 18:03:17 +08:00
parent 2179ce2a19
commit 7dd9937670
4 changed files with 82 additions and 57 deletions

View File

@ -92,6 +92,14 @@ auto cc_acc() {
return static_cast<acc_t*>(acc_h.get());
}
IPC_CONSTEXPR_ std::size_t align_chunk_size(std::size_t size) noexcept {
return (((size - 1) / ipc::large_msg_align) + 1) * ipc::large_msg_align;
}
IPC_CONSTEXPR_ std::size_t calc_chunk_size(std::size_t size) noexcept {
return ipc::make_align(alignof(std::max_align_t), align_chunk_size(size));
}
struct chunk_info_t {
ipc::id_pool<> pool_;
ipc::spin_lock lock_;
@ -100,9 +108,13 @@ struct chunk_info_t {
return ipc::id_pool<>::max_count * chunk_size;
}
ipc::byte_t* chunks_mem() noexcept {
return reinterpret_cast<ipc::byte_t*>(this + 1);
}
ipc::byte_t* at(std::size_t chunk_size, ipc::storage_id_t id) noexcept {
if (id < 0) return nullptr;
return reinterpret_cast<ipc::byte_t *>(this + 1) + (chunk_size * id);
assert(id >= 0);
return chunks_mem() + (chunk_size * id);
}
};
@ -130,16 +142,11 @@ auto& chunk_storages() {
return chunk_s;
}
IPC_CONSTEXPR_ std::size_t calc_chunk_size(std::size_t size) noexcept {
return ipc::make_align(alignof(std::max_align_t),
(((size - 1) / ipc::large_msg_align) + 1) * ipc::large_msg_align);
}
chunk_info_t *chunk_storage_info(std::size_t chunk_size) {
return chunk_storages()[chunk_size].get_info(chunk_size);
}
std::pair<ipc::storage_id_t, void*> apply_storage(std::size_t size) {
std::pair<ipc::storage_id_t, void*> acquire_storage(std::size_t size) {
std::size_t chunk_size = calc_chunk_size(size);
auto info = chunk_storage_info(chunk_size);
if (info == nullptr) return {};
@ -166,14 +173,12 @@ void *find_storage(ipc::storage_id_t id, std::size_t size) {
void release_storage(ipc::storage_id_t id, std::size_t size) {
if (id < 0) {
ipc::error("[clear_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
ipc::error("[release_storage] id is invalid: id = %ld, size = %zd\n", (long)id, size);
return;
}
std::size_t chunk_size = calc_chunk_size(size);
auto info = chunk_storage_info(chunk_size);
if (info == nullptr) return;
info->lock_.lock();
info->pool_.release(id);
info->lock_.unlock();
@ -394,7 +399,7 @@ static bool send(F&& gen_push, ipc::handle_t h, void const * data, std::size_t s
auto msg_id = acc->fetch_add(1, std::memory_order_relaxed);
auto try_push = std::forward<F>(gen_push)(info_of(h), que, msg_id);
if (size > ipc::large_msg_limit) {
auto dat = apply_storage(size);
auto dat = acquire_storage(size);
void * buf = dat.second;
if (buf != nullptr) {
std::memcpy(buf, data, size);
@ -429,7 +434,7 @@ static bool send(ipc::handle_t h, void const * data, std::size_t size, std::size
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
if (!wait_for(info->wt_waiter_, [&] {
return !que->push(
recycle_message<typename queue_t::value_t>,
[](void*) { return true; },
info->cc_id_, msg_id, remain, data, size);
}, tm)) {
ipc::log("force_push: msg_id = %zd, remain = %d, size = %zd\n", msg_id, remain, size);
@ -450,7 +455,7 @@ static bool try_send(ipc::handle_t h, void const * data, std::size_t size, std::
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
if (!wait_for(info->wt_waiter_, [&] {
return !que->push(
recycle_message<typename queue_t::value_t>,
[](void*) { return true; },
info->cc_id_, msg_id, remain, data, size);
}, tm)) {
return false;
@ -475,7 +480,10 @@ static ipc::buff_t recv(ipc::handle_t h, std::size_t tm) {
for (;;) {
// pop a new message
typename queue_t::value_t msg;
if (!wait_for(info_of(h)->rd_waiter_, [que, &msg] { return !que->pop(msg); }, tm)) {
bool recycled = false;
if (!wait_for(info_of(h)->rd_waiter_, [que, &msg, &recycled] {
return !que->pop(msg, [&recycled](bool r) { recycled = r; });
}, tm)) {
// pop failed, just return.
return {};
}
@ -490,23 +498,29 @@ static ipc::buff_t recv(ipc::handle_t h, std::size_t tm) {
return {};
}
std::size_t msg_size = static_cast<std::size_t>(r_size);
// large message
if (msg.storage_) {
ipc::storage_id_t buf_id = *reinterpret_cast<ipc::storage_id_t*>(&msg.data_);
void* buf = find_storage(buf_id, msg_size);
if (buf != nullptr) {
if (recycled) {
return ipc::buff_t{buf, msg_size, [](void* pmid, std::size_t size) {
release_storage(reinterpret_cast<ipc::storage_id_t>(pmid) - 1, size);
}, reinterpret_cast<void*>(buf_id + 1)};
} else {
return ipc::buff_t{buf, msg_size}; // no recycle
}
} else {
ipc::log("fail: shm::handle for large message. msg_id: %zd, buf_id: %zd, size: %zd\n", msg.id_, buf_id, msg_size);
continue;
}
}
// find cache with msg.id_
auto cac_it = rc.find(msg.id_);
if (cac_it == rc.end()) {
if (msg_size <= ipc::data_length) {
return make_cache(msg.data_, msg_size);
}
if (msg.storage_) {
std::size_t buf_id = *reinterpret_cast<std::size_t*>(&msg.data_);
void * buf = find_storage(buf_id, msg_size);
if (buf != nullptr) {
return ipc::buff_t{buf, msg_size};
}
else {
ipc::log("fail: shm::handle for big message. msg_id: %zd, buf_id: %zd, size: %zd\n", msg.id_, buf_id, msg_size);
continue;
}
}
// gc
if (rc.size() > 1024) {
std::vector<msg_id_t> need_del;

View File

@ -130,10 +130,10 @@ public:
return head_.force_push(que, std::forward<F>(f), block_);
}
template <typename Q, typename F>
bool pop(Q* que, cursor_t* cur, F&& f) {
template <typename Q, typename F, typename R>
bool pop(Q* que, cursor_t* cur, F&& f, R&& out) {
if (cur == nullptr) return false;
return head_.pop(que, *cur, std::forward<F>(f), block_);
return head_.pop(que, *cur, std::forward<F>(f), std::forward<R>(out), block_);
}
};

View File

@ -58,13 +58,14 @@ struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
return false;
}
template <typename W, typename F, typename E>
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, E* elems) {
template <typename W, typename F, typename R, typename E>
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E* elems) {
auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
return false; // empty
}
std::forward<F>(f)(&(elems[cur_rd].data_));
std::forward<R>(out)(true);
rd_.fetch_add(1, std::memory_order_release);
return true;
}
@ -80,8 +81,9 @@ struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
return false;
}
template <typename W, typename F, template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, E<DS, AS>* elems) {
template <typename W, typename F, typename R,
template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
byte_t buff[DS];
for (unsigned k = 0;;) {
auto cur_rd = rd_.load(std::memory_order_relaxed);
@ -92,6 +94,7 @@ struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
std::forward<F>(f)(buff);
std::forward<R>(out)(true);
return true;
}
ipc::yield(k);
@ -156,8 +159,9 @@ struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
return false;
}
template <typename W, typename F, template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, E<DS, AS>* elems) {
template <typename W, typename F, typename R,
template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, R&& out, E<DS, AS>* elems) {
byte_t buff[DS];
for (unsigned k = 0;;) {
auto cur_rd = rd_.load(std::memory_order_relaxed);
@ -179,6 +183,7 @@ struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
std::memcpy(buff, &(elems[circ::index_of(cur_rd)].data_), sizeof(buff));
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
std::forward<F>(f)(buff);
std::forward<R>(out)(true);
return true;
}
ipc::yield(k);
@ -263,20 +268,20 @@ struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
return true;
}
template <typename W, typename F, typename E>
bool pop(W* wrapper, circ::u2_t& cur, F&& f, E* elems) {
template <typename W, typename F, typename R, typename E>
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
if (cur == cursor()) return false; // acquire
auto* el = elems + circ::index_of(cur++);
std::forward<F>(f)(&(el->data_));
for (unsigned k = 0;;) {
auto cur_rc = el->rc_.load(std::memory_order_acquire);
circ::cc_t rem_cc = cur_rc & ep_mask;
if (rem_cc == 0) {
if ((cur_rc & ep_mask) == 0) {
std::forward<R>(out)(true);
return true;
}
if (el->rc_.compare_exchange_weak(cur_rc,
cur_rc & ~static_cast<rc_t>(wrapper->connected_id()),
std::memory_order_release)) {
auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
std::forward<R>(out)((nxt_rc & ep_mask) == 0);
return true;
}
ipc::yield(k);
@ -395,8 +400,8 @@ struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
return true;
}
template <typename W, typename F, typename E, std::size_t N>
bool pop(W* wrapper, circ::u2_t& cur, F&& f, E(& elems)[N]) {
template <typename W, typename F, typename R, typename E, std::size_t N>
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
auto* el = elems + circ::index_of(cur);
auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
if (cur_fl != ~static_cast<flag_t>(cur)) {
@ -406,17 +411,18 @@ struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
std::forward<F>(f)(&(el->data_));
for (unsigned k = 0;;) {
auto cur_rc = el->rc_.load(std::memory_order_acquire);
circ::cc_t rem_cc = cur_rc & rc_mask;
if (rem_cc == 0) {
if ((cur_rc & rc_mask) == 0) {
std::forward<R>(out)(true);
el->f_ct_.store(cur + N - 1, std::memory_order_release);
return true;
}
if ((rem_cc & ~wrapper->connected_id()) == 0) {
auto nxt_rc = inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id());
bool last_one = false;
if ((last_one = (nxt_rc & rc_mask) == 0)) {
el->f_ct_.store(cur + N - 1, std::memory_order_release);
}
if (el->rc_.compare_exchange_weak(cur_rc,
inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id()),
std::memory_order_release)) {
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
std::forward<R>(out)(last_one);
return true;
}
ipc::yield(k);

View File

@ -171,14 +171,14 @@ public:
});
}
template <typename T>
bool pop(T& item) {
template <typename T, typename F>
bool pop(T& item, F&& out) {
if (elems_ == nullptr) {
return false;
}
return elems_->pop(this, &(this->cursor_), [&item](void* p) {
::new (&item) T(std::move(*static_cast<T*>(p)));
});
}, std::forward<F>(out));
}
};
@ -204,7 +204,12 @@ public:
}
bool pop(T& item) {
return base_t::pop(item);
return base_t::pop(item, [](bool) {});
}
template <typename F>
bool pop(T& item, F&& out) {
return base_t::pop(item, std::forward<F>(out));
}
};