mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
try to adjust recycling strategy for large message cache
This commit is contained in:
parent
2179ce2a19
commit
7dd9937670
68
src/ipc.cpp
68
src/ipc.cpp
@ -92,6 +92,14 @@ auto cc_acc() {
|
|||||||
return static_cast<acc_t*>(acc_h.get());
|
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 {
|
struct chunk_info_t {
|
||||||
ipc::id_pool<> pool_;
|
ipc::id_pool<> pool_;
|
||||||
ipc::spin_lock lock_;
|
ipc::spin_lock lock_;
|
||||||
@ -100,9 +108,13 @@ struct chunk_info_t {
|
|||||||
return ipc::id_pool<>::max_count * chunk_size;
|
return ipc::id_pool<>::max_count * chunk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ipc::byte_t *at(std::size_t chunk_size, ipc::storage_id_t id) noexcept {
|
ipc::byte_t* chunks_mem() noexcept {
|
||||||
if (id < 0) return nullptr;
|
return reinterpret_cast<ipc::byte_t*>(this + 1);
|
||||||
return reinterpret_cast<ipc::byte_t *>(this + 1) + (chunk_size * id);
|
}
|
||||||
|
|
||||||
|
ipc::byte_t* at(std::size_t chunk_size, ipc::storage_id_t id) noexcept {
|
||||||
|
assert(id >= 0);
|
||||||
|
return chunks_mem() + (chunk_size * id);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -130,16 +142,11 @@ auto& chunk_storages() {
|
|||||||
return chunk_s;
|
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) {
|
chunk_info_t *chunk_storage_info(std::size_t chunk_size) {
|
||||||
return chunk_storages()[chunk_size].get_info(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);
|
std::size_t chunk_size = calc_chunk_size(size);
|
||||||
auto info = chunk_storage_info(chunk_size);
|
auto info = chunk_storage_info(chunk_size);
|
||||||
if (info == nullptr) return {};
|
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) {
|
void release_storage(ipc::storage_id_t id, std::size_t size) {
|
||||||
if (id < 0) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t chunk_size = calc_chunk_size(size);
|
std::size_t chunk_size = calc_chunk_size(size);
|
||||||
auto info = chunk_storage_info(chunk_size);
|
auto info = chunk_storage_info(chunk_size);
|
||||||
if (info == nullptr) return;
|
if (info == nullptr) return;
|
||||||
|
|
||||||
info->lock_.lock();
|
info->lock_.lock();
|
||||||
info->pool_.release(id);
|
info->pool_.release(id);
|
||||||
info->lock_.unlock();
|
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 msg_id = acc->fetch_add(1, std::memory_order_relaxed);
|
||||||
auto try_push = std::forward<F>(gen_push)(info_of(h), que, msg_id);
|
auto try_push = std::forward<F>(gen_push)(info_of(h), que, msg_id);
|
||||||
if (size > ipc::large_msg_limit) {
|
if (size > ipc::large_msg_limit) {
|
||||||
auto dat = apply_storage(size);
|
auto dat = acquire_storage(size);
|
||||||
void * buf = dat.second;
|
void * buf = dat.second;
|
||||||
if (buf != nullptr) {
|
if (buf != nullptr) {
|
||||||
std::memcpy(buf, data, size);
|
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) {
|
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
|
||||||
if (!wait_for(info->wt_waiter_, [&] {
|
if (!wait_for(info->wt_waiter_, [&] {
|
||||||
return !que->push(
|
return !que->push(
|
||||||
recycle_message<typename queue_t::value_t>,
|
[](void*) { return true; },
|
||||||
info->cc_id_, msg_id, remain, data, size);
|
info->cc_id_, msg_id, remain, data, size);
|
||||||
}, tm)) {
|
}, tm)) {
|
||||||
ipc::log("force_push: msg_id = %zd, remain = %d, size = %zd\n", msg_id, remain, size);
|
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) {
|
return [tm, info, que, msg_id](std::int32_t remain, void const * data, std::size_t size) {
|
||||||
if (!wait_for(info->wt_waiter_, [&] {
|
if (!wait_for(info->wt_waiter_, [&] {
|
||||||
return !que->push(
|
return !que->push(
|
||||||
recycle_message<typename queue_t::value_t>,
|
[](void*) { return true; },
|
||||||
info->cc_id_, msg_id, remain, data, size);
|
info->cc_id_, msg_id, remain, data, size);
|
||||||
}, tm)) {
|
}, tm)) {
|
||||||
return false;
|
return false;
|
||||||
@ -475,7 +480,10 @@ static ipc::buff_t recv(ipc::handle_t h, std::size_t tm) {
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
// pop a new message
|
// pop a new message
|
||||||
typename queue_t::value_t msg;
|
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.
|
// pop failed, just return.
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -490,23 +498,29 @@ static ipc::buff_t recv(ipc::handle_t h, std::size_t tm) {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
std::size_t msg_size = static_cast<std::size_t>(r_size);
|
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_
|
// find cache with msg.id_
|
||||||
auto cac_it = rc.find(msg.id_);
|
auto cac_it = rc.find(msg.id_);
|
||||||
if (cac_it == rc.end()) {
|
if (cac_it == rc.end()) {
|
||||||
if (msg_size <= ipc::data_length) {
|
if (msg_size <= ipc::data_length) {
|
||||||
return make_cache(msg.data_, msg_size);
|
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
|
// gc
|
||||||
if (rc.size() > 1024) {
|
if (rc.size() > 1024) {
|
||||||
std::vector<msg_id_t> need_del;
|
std::vector<msg_id_t> need_del;
|
||||||
|
|||||||
@ -130,10 +130,10 @@ public:
|
|||||||
return head_.force_push(que, std::forward<F>(f), block_);
|
return head_.force_push(que, std::forward<F>(f), block_);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Q, typename F>
|
template <typename Q, typename F, typename R>
|
||||||
bool pop(Q* que, cursor_t* cur, F&& f) {
|
bool pop(Q* que, cursor_t* cur, F&& f, R&& out) {
|
||||||
if (cur == nullptr) return false;
|
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_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -58,13 +58,14 @@ struct prod_cons_impl<wr<relat::single, relat::single, trans::unicast>> {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename W, typename F, typename E>
|
template <typename W, typename F, typename R, typename E>
|
||||||
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, E* elems) {
|
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));
|
auto cur_rd = circ::index_of(rd_.load(std::memory_order_relaxed));
|
||||||
if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
|
if (cur_rd == circ::index_of(wt_.load(std::memory_order_acquire))) {
|
||||||
return false; // empty
|
return false; // empty
|
||||||
}
|
}
|
||||||
std::forward<F>(f)(&(elems[cur_rd].data_));
|
std::forward<F>(f)(&(elems[cur_rd].data_));
|
||||||
|
std::forward<R>(out)(true);
|
||||||
rd_.fetch_add(1, std::memory_order_release);
|
rd_.fetch_add(1, std::memory_order_release);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -80,8 +81,9 @@ struct prod_cons_impl<wr<relat::single, relat::multi , trans::unicast>>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename W, typename F, template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
|
template <typename W, typename F, typename R,
|
||||||
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, E<DS, AS>* elems) {
|
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];
|
byte_t buff[DS];
|
||||||
for (unsigned k = 0;;) {
|
for (unsigned k = 0;;) {
|
||||||
auto cur_rd = rd_.load(std::memory_order_relaxed);
|
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));
|
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)) {
|
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
|
||||||
std::forward<F>(f)(buff);
|
std::forward<F>(f)(buff);
|
||||||
|
std::forward<R>(out)(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ipc::yield(k);
|
ipc::yield(k);
|
||||||
@ -156,8 +159,9 @@ struct prod_cons_impl<wr<relat::multi , relat::multi, trans::unicast>>
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename W, typename F, template <std::size_t, std::size_t> class E, std::size_t DS, std::size_t AS>
|
template <typename W, typename F, typename R,
|
||||||
bool pop(W* /*wrapper*/, circ::u2_t& /*cur*/, F&& f, E<DS, AS>* elems) {
|
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];
|
byte_t buff[DS];
|
||||||
for (unsigned k = 0;;) {
|
for (unsigned k = 0;;) {
|
||||||
auto cur_rd = rd_.load(std::memory_order_relaxed);
|
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));
|
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)) {
|
if (rd_.compare_exchange_weak(cur_rd, cur_rd + 1, std::memory_order_release)) {
|
||||||
std::forward<F>(f)(buff);
|
std::forward<F>(f)(buff);
|
||||||
|
std::forward<R>(out)(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ipc::yield(k);
|
ipc::yield(k);
|
||||||
@ -263,20 +268,20 @@ struct prod_cons_impl<wr<relat::single, relat::multi, trans::broadcast>> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename W, typename F, typename E>
|
template <typename W, typename F, typename R, typename E>
|
||||||
bool pop(W* wrapper, circ::u2_t& cur, F&& f, E* elems) {
|
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E* elems) {
|
||||||
if (cur == cursor()) return false; // acquire
|
if (cur == cursor()) return false; // acquire
|
||||||
auto* el = elems + circ::index_of(cur++);
|
auto* el = elems + circ::index_of(cur++);
|
||||||
std::forward<F>(f)(&(el->data_));
|
std::forward<F>(f)(&(el->data_));
|
||||||
for (unsigned k = 0;;) {
|
for (unsigned k = 0;;) {
|
||||||
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
||||||
circ::cc_t rem_cc = cur_rc & ep_mask;
|
if ((cur_rc & ep_mask) == 0) {
|
||||||
if (rem_cc == 0) {
|
std::forward<R>(out)(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (el->rc_.compare_exchange_weak(cur_rc,
|
auto nxt_rc = cur_rc & ~static_cast<rc_t>(wrapper->connected_id());
|
||||||
cur_rc & ~static_cast<rc_t>(wrapper->connected_id()),
|
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
|
||||||
std::memory_order_release)) {
|
std::forward<R>(out)((nxt_rc & ep_mask) == 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ipc::yield(k);
|
ipc::yield(k);
|
||||||
@ -395,8 +400,8 @@ struct prod_cons_impl<wr<relat::multi, relat::multi, trans::broadcast>> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename W, typename F, typename E, std::size_t N>
|
template <typename W, typename F, typename R, typename E, std::size_t N>
|
||||||
bool pop(W* wrapper, circ::u2_t& cur, F&& f, E(& elems)[N]) {
|
bool pop(W* wrapper, circ::u2_t& cur, F&& f, R&& out, E(& elems)[N]) {
|
||||||
auto* el = elems + circ::index_of(cur);
|
auto* el = elems + circ::index_of(cur);
|
||||||
auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
|
auto cur_fl = el->f_ct_.load(std::memory_order_acquire);
|
||||||
if (cur_fl != ~static_cast<flag_t>(cur)) {
|
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_));
|
std::forward<F>(f)(&(el->data_));
|
||||||
for (unsigned k = 0;;) {
|
for (unsigned k = 0;;) {
|
||||||
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
auto cur_rc = el->rc_.load(std::memory_order_acquire);
|
||||||
circ::cc_t rem_cc = cur_rc & rc_mask;
|
if ((cur_rc & rc_mask) == 0) {
|
||||||
if (rem_cc == 0) {
|
std::forward<R>(out)(true);
|
||||||
el->f_ct_.store(cur + N - 1, std::memory_order_release);
|
el->f_ct_.store(cur + N - 1, std::memory_order_release);
|
||||||
return true;
|
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);
|
el->f_ct_.store(cur + N - 1, std::memory_order_release);
|
||||||
}
|
}
|
||||||
if (el->rc_.compare_exchange_weak(cur_rc,
|
if (el->rc_.compare_exchange_weak(cur_rc, nxt_rc, std::memory_order_release)) {
|
||||||
inc_rc(cur_rc) & ~static_cast<rc_t>(wrapper->connected_id()),
|
std::forward<R>(out)(last_one);
|
||||||
std::memory_order_release)) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
ipc::yield(k);
|
ipc::yield(k);
|
||||||
|
|||||||
@ -171,14 +171,14 @@ public:
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T, typename F>
|
||||||
bool pop(T& item) {
|
bool pop(T& item, F&& out) {
|
||||||
if (elems_ == nullptr) {
|
if (elems_ == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return elems_->pop(this, &(this->cursor_), [&item](void* p) {
|
return elems_->pop(this, &(this->cursor_), [&item](void* p) {
|
||||||
::new (&item) T(std::move(*static_cast<T*>(p)));
|
::new (&item) T(std::move(*static_cast<T*>(p)));
|
||||||
});
|
}, std::forward<F>(out));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -204,7 +204,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool pop(T& item) {
|
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));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user