remove expired client threads
This commit is contained in:
@@ -23,7 +23,6 @@
|
|||||||
#define REPERTORY_INCLUDE_COMM_PACKET_CLIENT_POOL_HPP_
|
#define REPERTORY_INCLUDE_COMM_PACKET_CLIENT_POOL_HPP_
|
||||||
|
|
||||||
#include "comm/packet/packet.hpp"
|
#include "comm/packet/packet.hpp"
|
||||||
#include "types/repertory.hpp"
|
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
class client_pool final {
|
class client_pool final {
|
||||||
@@ -46,25 +45,26 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct work_queue final {
|
struct work_queue final {
|
||||||
work_queue(std::function<void(work_queue &)> &&run)
|
work_queue();
|
||||||
: thread([this, run]() { run(*this); }) {}
|
~work_queue();
|
||||||
|
|
||||||
~work_queue() {
|
|
||||||
if (thread.joinable()) {
|
|
||||||
thread.join();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
work_queue(const work_queue &) = delete;
|
work_queue(const work_queue &) = delete;
|
||||||
work_queue(work_queue &&) = delete;
|
work_queue(work_queue &&) = delete;
|
||||||
|
|
||||||
|
std::deque<std::shared_ptr<work_item>> actions;
|
||||||
|
std::chrono::steady_clock::time_point modified{
|
||||||
|
std::chrono::steady_clock::now(),
|
||||||
|
};
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
std::condition_variable notify;
|
std::condition_variable notify;
|
||||||
std::deque<std::shared_ptr<work_item>> actions;
|
stop_type shutdown{false};
|
||||||
std::thread thread;
|
std::unique_ptr<std::thread> thread;
|
||||||
|
|
||||||
auto operator=(const work_queue &) -> work_queue & = delete;
|
auto operator=(const work_queue &) -> work_queue & = delete;
|
||||||
auto operator=(work_queue &&) -> work_queue & = delete;
|
auto operator=(work_queue &&) -> work_queue & = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void work_thread();
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -81,12 +81,13 @@ private:
|
|||||||
private:
|
private:
|
||||||
std::mutex pool_mtx_;
|
std::mutex pool_mtx_;
|
||||||
std::unordered_map<std::uint64_t, std::shared_ptr<work_queue>> pool_queues_;
|
std::unordered_map<std::uint64_t, std::shared_ptr<work_queue>> pool_queues_;
|
||||||
stop_type shutdown_{false};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void execute(std::uint64_t thread_id, worker_callback worker,
|
void execute(std::uint64_t thread_id, worker_callback worker,
|
||||||
worker_complete_callback worker_complete);
|
worker_complete_callback worker_complete);
|
||||||
|
|
||||||
|
void remove_expired();
|
||||||
|
|
||||||
void shutdown();
|
void shutdown();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -113,6 +114,8 @@ public:
|
|||||||
|
|
||||||
void remove_client(std::string client_id);
|
void remove_client(std::string client_id);
|
||||||
|
|
||||||
|
void remove_expired();
|
||||||
|
|
||||||
void shutdown();
|
void shutdown();
|
||||||
};
|
};
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "types/repertory.hpp"
|
#include "types/repertory.hpp"
|
||||||
#include "utils/base64.hpp"
|
#include "utils/base64.hpp"
|
||||||
#include "utils/path.hpp"
|
#include "utils/path.hpp"
|
||||||
|
#include "utils/polling.hpp"
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
template <typename drive>
|
template <typename drive>
|
||||||
@@ -77,6 +78,13 @@ public:
|
|||||||
method, request, response,
|
method, request, response,
|
||||||
message_complete);
|
message_complete);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
polling::instance().set_callback({
|
||||||
|
"remote_server_expired",
|
||||||
|
polling::frequency::high,
|
||||||
|
[this](auto && /* stop */) { client_pool_.remove_expired(); },
|
||||||
|
});
|
||||||
|
|
||||||
event_system::instance().raise<service_start_end>(function_name,
|
event_system::instance().raise<service_start_end>(function_name,
|
||||||
"remote_server_base");
|
"remote_server_base");
|
||||||
}
|
}
|
||||||
@@ -86,7 +94,10 @@ public:
|
|||||||
|
|
||||||
event_system::instance().raise<service_stop_begin>(function_name,
|
event_system::instance().raise<service_stop_begin>(function_name,
|
||||||
"remote_server_base");
|
"remote_server_base");
|
||||||
|
polling::instance().remove_callback("remote_server_expired");
|
||||||
|
|
||||||
client_pool_.shutdown();
|
client_pool_.shutdown();
|
||||||
|
|
||||||
packet_server_.reset();
|
packet_server_.reset();
|
||||||
event_system::instance().raise<service_stop_end>(function_name,
|
event_system::instance().raise<service_stop_end>(function_name,
|
||||||
"remote_server_base");
|
"remote_server_base");
|
||||||
|
|||||||
@@ -27,31 +27,40 @@
|
|||||||
#include "events/types/service_stop_begin.hpp"
|
#include "events/types/service_stop_begin.hpp"
|
||||||
#include "events/types/service_stop_end.hpp"
|
#include "events/types/service_stop_end.hpp"
|
||||||
#include "utils/error.hpp"
|
#include "utils/error.hpp"
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
void client_pool::pool::execute(std::uint64_t thread_id, worker_callback worker,
|
client_pool::pool::work_queue::work_queue() {
|
||||||
worker_complete_callback worker_complete) {
|
thread = std::make_unique<std::thread>([this]() { work_thread(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
client_pool::pool::work_queue::~work_queue() {
|
||||||
|
if (thread->joinable()) {
|
||||||
|
thread->join();
|
||||||
|
}
|
||||||
|
|
||||||
|
thread.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void client_pool::pool::work_queue::work_thread() {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
unique_mutex_lock pool_lock(pool_mtx_);
|
unique_mutex_lock lock(mutex);
|
||||||
if (pool_queues_[thread_id] == nullptr) {
|
const auto unlock_and_notify = [this, &lock]() {
|
||||||
pool_queues_[thread_id] =
|
notify.notify_all();
|
||||||
std::make_shared<work_queue>([this](work_queue &queue) {
|
|
||||||
unique_mutex_lock lock(queue.mutex);
|
|
||||||
const auto unlock_and_notify = [&lock, &queue]() {
|
|
||||||
queue.notify.notify_all();
|
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
};
|
};
|
||||||
unlock_and_notify();
|
unlock_and_notify();
|
||||||
|
|
||||||
const auto process_next_item = [&unlock_and_notify, &queue]() {
|
const auto process_next_item = [this, &unlock_and_notify]() {
|
||||||
if (queue.actions.empty()) {
|
if (actions.empty()) {
|
||||||
unlock_and_notify();
|
unlock_and_notify();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto item = queue.actions.front();
|
auto item = actions.front();
|
||||||
queue.actions.pop_front();
|
actions.pop_front();
|
||||||
unlock_and_notify();
|
unlock_and_notify();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -63,10 +72,10 @@ void client_pool::pool::execute(std::uint64_t thread_id, worker_callback worker,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
while (not shutdown_) {
|
while (not shutdown) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
if (queue.actions.empty()) {
|
if (actions.empty()) {
|
||||||
queue.notify.wait(lock);
|
notify.wait(lock);
|
||||||
unlock_and_notify();
|
unlock_and_notify();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -74,11 +83,19 @@ void client_pool::pool::execute(std::uint64_t thread_id, worker_callback worker,
|
|||||||
process_next_item();
|
process_next_item();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (not queue.actions.empty()) {
|
while (not actions.empty()) {
|
||||||
lock.lock();
|
lock.lock();
|
||||||
process_next_item();
|
process_next_item();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
void client_pool::pool::execute(std::uint64_t thread_id, worker_callback worker,
|
||||||
|
worker_complete_callback worker_complete) {
|
||||||
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
unique_mutex_lock pool_lock(pool_mtx_);
|
||||||
|
if (pool_queues_[thread_id] == nullptr) {
|
||||||
|
pool_queues_[thread_id] = std::make_shared<work_queue>();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pool_queue = pool_queues_[thread_id];
|
auto pool_queue = pool_queues_[thread_id];
|
||||||
@@ -89,13 +106,41 @@ void client_pool::pool::execute(std::uint64_t thread_id, worker_callback worker,
|
|||||||
|
|
||||||
mutex_lock queue_lock(pool_queue->mutex);
|
mutex_lock queue_lock(pool_queue->mutex);
|
||||||
pool_queue->actions.emplace_back(std::move(job));
|
pool_queue->actions.emplace_back(std::move(job));
|
||||||
|
pool_queue->modified = std::chrono::steady_clock::now();
|
||||||
pool_queue->notify.notify_all();
|
pool_queue->notify.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void client_pool::pool::shutdown() {
|
void client_pool::pool::remove_expired() {
|
||||||
shutdown_ = true;
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
unique_mutex_lock pool_lock(pool_mtx_);
|
||||||
|
auto results = std::accumulate(
|
||||||
|
pool_queues_.begin(), pool_queues_.end(),
|
||||||
|
std::unordered_map<std::uint64_t, std::shared_ptr<work_queue>>(),
|
||||||
|
[&now](auto &&res, auto &&entry) -> auto {
|
||||||
|
auto duration = now - entry.second->modified;
|
||||||
|
if (std::chrono::duration_cast<std::chrono::minutes>(duration) >=
|
||||||
|
std::chrono::minutes(2U)) {
|
||||||
|
res[entry.first] = entry.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
pool_lock.unlock();
|
||||||
|
|
||||||
|
for (const auto &entry : results) {
|
||||||
|
pool_lock.lock();
|
||||||
|
pool_queues_.erase(entry.first);
|
||||||
|
pool_lock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
results.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void client_pool::pool::shutdown() {
|
||||||
for (auto &entry : pool_queues_) {
|
for (auto &entry : pool_queues_) {
|
||||||
|
entry.second->shutdown = true;
|
||||||
|
|
||||||
mutex_lock lock(entry.second->mutex);
|
mutex_lock lock(entry.second->mutex);
|
||||||
entry.second->notify.notify_all();
|
entry.second->notify.notify_all();
|
||||||
}
|
}
|
||||||
@@ -136,6 +181,14 @@ void client_pool::remove_client(std::string client_id) {
|
|||||||
pool_lookup_.erase(client_id);
|
pool_lookup_.erase(client_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void client_pool::remove_expired() {
|
||||||
|
mutex_lock pool_lock(pool_mutex_);
|
||||||
|
|
||||||
|
for (auto &entry : pool_lookup_) {
|
||||||
|
entry.second->remove_expired();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void client_pool::shutdown() {
|
void client_pool::shutdown() {
|
||||||
REPERTORY_USES_FUNCTION_NAME();
|
REPERTORY_USES_FUNCTION_NAME();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user