2020#pragma once
2121
2222#include " data/BackendInterface.hpp"
23- #include " rpc/Counters.hpp"
2423#include " rpc/Errors.hpp"
2524#include " rpc/RPCHelpers.hpp"
2625#include " rpc/WorkQueue.hpp"
2726#include " rpc/common/HandlerProvider.hpp"
2827#include " rpc/common/Types.hpp"
2928#include " rpc/common/impl/ForwardingProxy.hpp"
29+ #include " util/ResponseExpirationCache.hpp"
3030#include " util/log/Logger.hpp"
3131#include " web/Context.hpp"
3232#include " web/dosguard/DOSGuardInterface.hpp"
3333
3434#include < boost/asio/spawn.hpp>
35+ #include < boost/iterator/transform_iterator.hpp>
3536#include < boost/json.hpp>
3637#include < fmt/core.h>
38+ #include < fmt/format.h>
3739#include < xrpl/protocol/ErrorCodes.h>
3840
3941#include < chrono>
4244#include < memory>
4345#include < optional>
4446#include < string>
47+ #include < unordered_set>
4548#include < utility>
4649
47- // forward declarations
48- namespace etl {
49- class LoadBalancer ;
50- class ETLService ;
51- } // namespace etl
52-
5350/* *
5451 * @brief This namespace contains all the RPC logic and handlers.
5552 */
@@ -58,23 +55,27 @@ namespace rpc {
5855/* *
5956 * @brief The RPC engine that ties all RPC-related functionality together.
6057 */
58+ template <typename LoadBalancerType, typename CountersType>
6159class RPCEngine {
6260 util::Logger perfLog_{" Performance" };
6361 util::Logger log_{" RPC" };
6462
6563 std::shared_ptr<BackendInterface> backend_;
6664 std::reference_wrapper<web::dosguard::DOSGuardInterface const > dosGuard_;
6765 std::reference_wrapper<WorkQueue> workQueue_;
68- std::reference_wrapper<Counters > counters_;
66+ std::reference_wrapper<CountersType > counters_;
6967
7068 std::shared_ptr<HandlerProvider const > handlerProvider_;
7169
72- impl::ForwardingProxy<etl::LoadBalancer, Counters, HandlerProvider> forwardingProxy_;
70+ impl::ForwardingProxy<LoadBalancerType, CountersType, HandlerProvider> forwardingProxy_;
71+
72+ std::optional<util::ResponseExpirationCache> responseCache_;
7373
7474public:
7575 /* *
7676 * @brief Construct a new RPCEngine object
7777 *
78+ * @param config The config to use
7879 * @param backend The backend to use
7980 * @param balancer The load balancer to use
8081 * @param dosGuard The DOS guard to use
@@ -83,11 +84,12 @@ class RPCEngine {
8384 * @param handlerProvider The handler provider to use
8485 */
8586 RPCEngine (
87+ util::Config const & config,
8688 std::shared_ptr<BackendInterface> const & backend,
87- std::shared_ptr<etl::LoadBalancer > const & balancer,
89+ std::shared_ptr<LoadBalancerType > const & balancer,
8890 web::dosguard::DOSGuardInterface const & dosGuard,
8991 WorkQueue& workQueue,
90- Counters & counters,
92+ CountersType & counters,
9193 std::shared_ptr<HandlerProvider const > const & handlerProvider
9294 )
9395 : backend_{backend}
@@ -97,11 +99,22 @@ class RPCEngine {
9799 , handlerProvider_{handlerProvider}
98100 , forwardingProxy_{balancer, counters, handlerProvider}
99101 {
102+ // Let main thread catch the exception if config type is wrong
103+ auto const cacheTimeout = config.valueOr <float >(" rpc.cache_timeout" , 0 .f );
104+
105+ if (cacheTimeout > 0 .f ) {
106+ LOG (log_.info ()) << fmt::format (" Init RPC Cache, timeout: {} seconds" , cacheTimeout);
107+
108+ responseCache_.emplace (
109+ util::Config::toMilliseconds (cacheTimeout), std::unordered_set<std::string>{" server_info" }
110+ );
111+ }
100112 }
101113
102114 /* *
103115 * @brief Factory function to create a new instance of the RPC engine.
104116 *
117+ * @param config The config to use
105118 * @param backend The backend to use
106119 * @param balancer The load balancer to use
107120 * @param dosGuard The DOS guard to use
@@ -112,15 +125,16 @@ class RPCEngine {
112125 */
113126 static std::shared_ptr<RPCEngine>
114127 make_RPCEngine (
128+ util::Config const & config,
115129 std::shared_ptr<BackendInterface> const & backend,
116- std::shared_ptr<etl::LoadBalancer > const & balancer,
130+ std::shared_ptr<LoadBalancerType > const & balancer,
117131 web::dosguard::DOSGuardInterface const & dosGuard,
118132 WorkQueue& workQueue,
119- Counters & counters,
133+ CountersType & counters,
120134 std::shared_ptr<HandlerProvider const > const & handlerProvider
121135 )
122136 {
123- return std::make_shared<RPCEngine>(backend, balancer, dosGuard, workQueue, counters, handlerProvider);
137+ return std::make_shared<RPCEngine>(config, backend, balancer, dosGuard, workQueue, counters, handlerProvider);
124138 }
125139
126140 /* *
@@ -140,6 +154,11 @@ class RPCEngine {
140154 return forwardingProxy_.forward (ctx);
141155 }
142156
157+ if (not ctx.isAdmin and responseCache_) {
158+ if (auto res = responseCache_->get (ctx.method ); res.has_value ())
159+ return Result{std::move (res).value ()};
160+ }
161+
143162 if (backend_->isTooBusy ()) {
144163 LOG (log_.error ()) << " Database is too busy. Rejecting request" ;
145164 notifyTooBusy (); // TODO: should we add ctx.method if we have it?
@@ -160,8 +179,11 @@ class RPCEngine {
160179
161180 LOG (perfLog_.debug ()) << ctx.tag () << " finish executing rpc `" << ctx.method << ' `' ;
162181
163- if (not v)
182+ if (not v) {
164183 notifyErrored (ctx.method );
184+ } else if (not ctx.isAdmin and responseCache_) {
185+ responseCache_->put (ctx.method , v.result ->as_object ());
186+ }
165187
166188 return Result{std::move (v)};
167189 } catch (data::DatabaseTimeout const & t) {
0 commit comments