mirror of
https://github.com/XRPLF/clio.git
synced 2026-06-07 18:56:41 +00:00
fix: Faster implementation of work queue (#2887)
This commit is contained in:
@@ -25,15 +25,12 @@
|
||||
#include "util/prometheus/Counter.hpp"
|
||||
#include "util/prometheus/Gauge.hpp"
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/spawn.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/asio/strand.hpp>
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <boost/json.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
@@ -64,7 +61,13 @@ struct Reportable {
|
||||
*/
|
||||
class WorkQueue : public Reportable {
|
||||
using TaskType = std::function<void(boost::asio::yield_context)>;
|
||||
using QueueType = std::queue<TaskType>;
|
||||
|
||||
struct TaskWithTimestamp {
|
||||
TaskType task;
|
||||
std::chrono::system_clock::time_point queuedAt;
|
||||
};
|
||||
|
||||
using QueueType = std::queue<TaskWithTimestamp>;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -76,22 +79,21 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
struct DispatcherState {
|
||||
struct QueueState {
|
||||
QueueType high;
|
||||
QueueType normal;
|
||||
|
||||
bool isIdle = false;
|
||||
size_t highPriorityCounter = 0;
|
||||
|
||||
void
|
||||
push(Priority priority, auto&& task)
|
||||
push(Priority priority, TaskType&& task)
|
||||
{
|
||||
auto& queue = [this, priority] -> QueueType& {
|
||||
if (priority == Priority::High)
|
||||
return high;
|
||||
return normal;
|
||||
}();
|
||||
queue.push(std::forward<decltype(task)>(task));
|
||||
queue.push(TaskWithTimestamp{.task = std::move(task), .queuedAt = std::chrono::system_clock::now()});
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
@@ -100,21 +102,21 @@ private:
|
||||
return high.empty() and normal.empty();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<TaskType>
|
||||
[[nodiscard]] std::optional<TaskWithTimestamp>
|
||||
popNext()
|
||||
{
|
||||
if (not high.empty() and (highPriorityCounter < kTAKE_HIGH_PRIO or normal.empty())) {
|
||||
auto task = std::move(high.front());
|
||||
auto taskWithTimestamp = std::move(high.front());
|
||||
high.pop();
|
||||
++highPriorityCounter;
|
||||
return task;
|
||||
return taskWithTimestamp;
|
||||
}
|
||||
|
||||
if (not normal.empty()) {
|
||||
auto task = std::move(normal.front());
|
||||
auto taskWithTimestamp = std::move(normal.front());
|
||||
normal.pop();
|
||||
highPriorityCounter = 0;
|
||||
return task;
|
||||
return taskWithTimestamp;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
@@ -133,14 +135,26 @@ private:
|
||||
|
||||
util::Logger log_{"RPC"};
|
||||
boost::asio::thread_pool ioc_;
|
||||
boost::asio::strand<boost::asio::thread_pool::executor_type> strand_;
|
||||
bool hasDispatcher_ = false;
|
||||
|
||||
std::atomic_bool stopping_;
|
||||
std::atomic_bool processingStarted_{false};
|
||||
|
||||
util::Mutex<std::function<void()>> onQueueEmpty_;
|
||||
util::Mutex<DispatcherState> dispatcherState_;
|
||||
boost::asio::steady_timer waitTimer_;
|
||||
class OneTimeCallable {
|
||||
std::function<void()> func_;
|
||||
bool called_{false};
|
||||
|
||||
public:
|
||||
void
|
||||
setCallable(std::function<void()> func);
|
||||
|
||||
void
|
||||
operator()();
|
||||
|
||||
explicit
|
||||
operator bool() const;
|
||||
};
|
||||
util::Mutex<OneTimeCallable> onQueueEmpty_;
|
||||
util::Mutex<QueueState> queueState_;
|
||||
|
||||
public:
|
||||
struct DontStartProcessingTag {};
|
||||
@@ -234,7 +248,7 @@ public:
|
||||
|
||||
private:
|
||||
void
|
||||
dispatcherLoop(boost::asio::yield_context yield);
|
||||
executeTask(boost::asio::yield_context yield);
|
||||
};
|
||||
|
||||
} // namespace rpc
|
||||
|
||||
Reference in New Issue
Block a user