diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2019-01-14 18:05:26 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2019-01-14 18:07:15 +0100 |
commit | cf0c67b62c2037dc9e70ea84ffee3b205a9b1bef (patch) | |
tree | 1a8c9ed60f360f883a71d0d6db166b79304e10e7 /src/rpc | |
parent | 035f349371a5b67922ce92c11ad9aa7178fa04f7 (diff) | |
parent | a0ac15459a0df598e1ee1fd36a3899a129cecaeb (diff) |
Merge #14982: rpc: Add getrpcinfo command
a0ac15459a0df598e1ee1fd36a3899a129cecaeb doc: Add getrpcinfo release notes (João Barbosa)
251a91c1bf245b3674c2612149382a0f1e18dc98 qa: Add tests for getrpcinfo (João Barbosa)
d0730f5ce475e5a84da7c61fe79bcd6ed24d693e rpc: Add getrpcinfo command (João Barbosa)
068a8fc05f8dbec198bdc3fe46f955d8a5255303 rpc: Track active commands (João Barbosa)
bf4383277d6761cc5b7a91975752c08df829af72 rpc: Remove unused PreCommand signal (João Barbosa)
Pull request description:
The new `getrpcinfo` command exposes details of the RPC interface. The details can be configuration properties or runtime values/stats.
This can be particular useful to coordinate concurrent functional tests (see #14958 from where this was extracted).
Tree-SHA512: 7292cb6087f4c429973d991aa2b53ffa1327d5a213df7d6ba5fc69b01b2e1a411f6d1609fed9234896293317dab05f65064da48b8f2b4a998eba532591d31882
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/server.cpp | 59 |
1 files changed, 56 insertions, 3 deletions
diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index e7e047334e..edaf64f3e1 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -31,11 +31,39 @@ static RPCTimerInterface* timerInterface = nullptr; /* Map of name to timer. */ static std::map<std::string, std::unique_ptr<RPCTimerBase> > deadlineTimers; +struct RPCCommandExecutionInfo +{ + std::string method; + int64_t start; +}; + +struct RPCServerInfo +{ + Mutex mutex; + std::list<RPCCommandExecutionInfo> active_commands GUARDED_BY(mutex); +}; + +static RPCServerInfo g_rpc_server_info; + +struct RPCCommandExecution +{ + std::list<RPCCommandExecutionInfo>::iterator it; + explicit RPCCommandExecution(const std::string& method) + { + LOCK(g_rpc_server_info.mutex); + it = g_rpc_server_info.active_commands.insert(g_rpc_server_info.active_commands.cend(), {method, GetTimeMicros()}); + } + ~RPCCommandExecution() + { + LOCK(g_rpc_server_info.mutex); + g_rpc_server_info.active_commands.erase(it); + } +}; + static struct CRPCSignals { boost::signals2::signal<void ()> Started; boost::signals2::signal<void ()> Stopped; - boost::signals2::signal<void (const CRPCCommand&)> PreCommand; } g_rpcSignals; void RPCServer::OnStarted(std::function<void ()> slot) @@ -254,11 +282,37 @@ static UniValue uptime(const JSONRPCRequest& jsonRequest) return GetTime() - GetStartupTime(); } +static UniValue getrpcinfo(const JSONRPCRequest& request) +{ + if (request.fHelp || request.params.size() > 0) { + throw std::runtime_error( + RPCHelpMan{"getrpcinfo", + "\nReturns details of the RPC server.\n", {}} + .ToString() + ); + } + + LOCK(g_rpc_server_info.mutex); + UniValue active_commands(UniValue::VARR); + for (const RPCCommandExecutionInfo& info : g_rpc_server_info.active_commands) { + UniValue entry(UniValue::VOBJ); + entry.pushKV("method", info.method); + entry.pushKV("duration", GetTimeMicros() - info.start); + active_commands.push_back(entry); + } + + UniValue result(UniValue::VOBJ); + result.pushKV("active_commands", active_commands); + + return result; +} + // clang-format off static const CRPCCommand vRPCCommands[] = { // category name actor (function) argNames // --------------------- ------------------------ ----------------------- ---------- /* Overall control/query calls */ + { "control", "getrpcinfo", &getrpcinfo, {} }, { "control", "help", &help, {"command"} }, { "control", "stop", &stop, {"wait"} }, { "control", "uptime", &uptime, {} }, @@ -483,10 +537,9 @@ UniValue CRPCTable::execute(const JSONRPCRequest &request) const if (!pcmd) throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found"); - g_rpcSignals.PreCommand(*pcmd); - try { + RPCCommandExecution execution(request.strMethod); // Execute, convert arguments to array if necessary if (request.params.isObject()) { return pcmd->actor(transformNamedArguments(request, pcmd->argNames)); |