From 993a64f11ed80a3ebaeebd49e52795d0198c0a38 Mon Sep 17 00:00:00 2001 From: intelliot Date: Tue, 24 Oct 2023 23:01:45 +0000 Subject: [PATCH] deploy: 1eac4d2c07eaac04178ff53c7288bc46c6ce7da0 --- AMMExtended__test_8cpp_source.html | 4 +- AMM__test_8cpp_source.html | 2 +- Connect_8cpp_source.html | 2 +- DownloadShard_8cpp_source.html | 2 +- Escrow__test_8cpp_source.html | 8 +- GRPCServer_8cpp_source.html | 6 +- GRPCServer_8h_source.html | 2 +- Handler_8cpp_source.html | 565 +-- Handler_8h_source.html | 283 +- Handler__test_8cpp_source.html | 246 ++ LedgerCleanerHandler_8cpp_source.html | 2 +- LedgerHandler_8cpp_source.html | 12 +- LedgerHandler_8h_source.html | 193 +- LedgerHeader__test_8cpp_source.html | 180 + LogRotate_8cpp_source.html | 2 +- P2pProxy_8cpp_source.html | 6 +- P2pProxy_8h_source.html | 6 +- Path__test_8cpp_source.html | 4 +- PerfLogImp_8cpp_source.html | 37 +- PerfLogImp_8h_source.html | 219 +- PerfLog__test_8cpp_source.html | 2122 +++++----- RPCHandler_8cpp_source.html | 10 +- RPCHelpers_8h_source.html | 97 +- Stop_8cpp_source.html | 2 +- TestHelpers_8cpp_source.html | 4 +- TestHelpers_8h_source.html | 807 ++-- TransactionHistory__test_8cpp_source.html | 209 +- Version_8h_source.html | 62 +- annotated.html | 1190 +++--- classes.html | 1865 ++++----- ...sripple_1_1LedgerHeader__test-members.html | 87 + classripple_1_1LedgerHeader__test.html | 229 ++ ...ple_1_1LedgerHeader__test__coll__graph.map | 4 + ...ple_1_1LedgerHeader__test__coll__graph.md5 | 1 + ...ple_1_1LedgerHeader__test__coll__graph.png | Bin 0 -> 2938 bytes ..._1_1LedgerHeader__test__inherit__graph.map | 4 + ..._1_1LedgerHeader__test__inherit__graph.md5 | 1 + ..._1_1LedgerHeader__test__inherit__graph.png | Bin 0 -> 2938 bytes classripple_1_1PerfLog__test.html | 26 +- ...ipple_1_1RPC_1_1LedgerHandler-members.html | 8 +- classripple_1_1RPC_1_1LedgerHandler.html | 123 +- ...pple_1_1RPC_1_1VersionHandler-members.html | 8 +- classripple_1_1RPC_1_1VersionHandler.html | 227 +- ...e_1_1TransactionHistory__test-members.html | 3 +- classripple_1_1TransactionHistory__test.html | 33 +- classripple_1_1perf_1_1PerfLogImp.html | 38 +- ...pple_1_1test_1_1Handler__test-members.html | 86 + classripple_1_1test_1_1Handler__test.html | 218 + ..._1_1test_1_1Handler__test__coll__graph.map | 4 + ..._1_1test_1_1Handler__test__coll__graph.md5 | 1 + ..._1_1test_1_1Handler__test__coll__graph.png | Bin 0 -> 2763 bytes ...1test_1_1Handler__test__inherit__graph.map | 4 + ...1test_1_1Handler__test__inherit__graph.md5 | 1 + ...1test_1_1Handler__test__inherit__graph.png | Bin 0 -> 2763 bytes dir_9e5c3433ad783ee5f9e7b66541a4db0e.html | 4 + functions_c.html | 18 +- functions_func_c.html | 30 +- functions_func_n.html | 12 +- functions_func_p.html | 4 +- functions_func_r.html | 19 +- functions_func_s.html | 12 +- functions_func_t.html | 49 +- functions_func_v.html | 4 +- functions_m.html | 18 +- functions_n.html | 4 +- functions_p.html | 18 +- functions_r.html | 21 +- functions_s.html | 24 +- functions_t.html | 71 +- functions_v.html | 6 +- functions_vars_c.html | 4 + functions_vars_m.html | 14 + functions_vars_n.html | 2 + functions_vars_r.html | 2 + functions_w.html | 4 +- hierarchy.html | 554 +-- inherit_graph_14.md5 | 2 +- inherit_graph_15.md5 | 2 +- inherit_graph_161.md5 | 2 +- inherit_graph_252.md5 | 2 +- inherit_graph_262.md5 | 2 +- inherit_graph_264.md5 | 2 +- inherit_graph_273.md5 | 2 +- inherit_graph_277.md5 | 2 +- inherit_graph_284.md5 | 2 +- inherit_graph_291.md5 | 2 +- inherit_graph_312.md5 | 2 +- inherit_graph_313.md5 | 2 +- inherit_graph_34.md5 | 2 +- inherit_graph_36.md5 | 2 +- inherit_graph_368.md5 | 2 +- inherit_graph_434.md5 | 2 +- inherit_graph_495.md5 | 2 +- inherit_graph_514.md5 | 2 +- inherit_graph_525.md5 | 2 +- inherit_graph_535.md5 | 2 +- inherit_graph_546.md5 | 2 +- inherit_graph_602.md5 | 2 +- inherit_graph_618.md5 | 2 +- inherit_graph_65.md5 | 2 +- inherit_graph_711.md5 | 2 +- inherit_graph_828.map | 426 +- inherit_graph_828.md5 | 2 +- inherit_graph_828.png | Bin 1997655 -> 2220078 bytes inherit_graph_835.md5 | 2 +- inherit_graph_850.md5 | 2 +- inherit_graph_874.md5 | 2 +- inherit_graph_892.md5 | 2 +- inherit_graph_936.md5 | 2 +- inherit_graph_953.md5 | 2 +- inherit_graph_958.md5 | 2 +- inherit_graph_959.md5 | 2 +- inherit_graph_964.md5 | 2 +- inherit_graph_966.md5 | 2 +- inherits.html | 374 +- namespacemembers.html | 5 +- namespacemembers_b.html | 12 +- namespacemembers_func_b.html | 6 +- namespacemembers_func_g.html | 8 +- namespacemembers_func_o.html | 17 +- namespacemembers_g.html | 6 +- namespacemembers_o.html | 21 +- namespacemembers_vars.html | 3 + namespacemembers_vars_g.html | 3 + namespaceripple.html | 170 +- namespaceripple_1_1RPC.html | 50 +- namespaceripple_1_1test.html | 86 +- namespaceripple_1_1test_1_1jtx.html | 88 +- namespaceripple_1_1test_1_1jtx_1_1check.html | 4 +- search/all_1.js | 601 +-- search/all_10.js | 1252 +++--- search/all_11.js | 94 +- search/all_12.js | 1375 +++---- search/all_13.js | 3082 +++++++------- search/all_14.js | 3651 +++++++++-------- search/all_15.js | 714 ++-- search/all_16.js | 524 +-- search/all_17.js | 486 +-- search/all_18.js | 206 +- search/all_19.js | 16 +- search/all_1a.js | 18 +- search/all_1b.js | 724 ++-- search/all_2.js | 682 +-- search/all_3.js | 1718 ++++---- search/all_4.js | 1182 +++--- search/all_5.js | 610 +-- search/all_6.js | 1006 ++--- search/all_7.js | 1358 +++--- search/all_8.js | 401 +- search/all_9.js | 1644 ++++---- search/all_a.js | 240 +- search/all_b.js | 114 +- search/all_c.js | 983 ++--- search/all_d.js | 2030 ++++----- search/all_e.js | 676 +-- search/all_f.js | 712 ++-- search/classes_0.js | 4 +- search/classes_1.js | 452 +- search/classes_10.js | 268 +- search/classes_11.js | 22 +- search/classes_12.js | 258 +- search/classes_13.js | 690 ++-- search/classes_14.js | 302 +- search/classes_15.js | 408 +- search/classes_16.js | 260 +- search/classes_17.js | 144 +- search/classes_18.js | 72 +- search/classes_19.js | 4 +- search/classes_1a.js | 10 +- search/classes_2.js | 236 +- search/classes_3.js | 442 +- search/classes_4.js | 208 +- search/classes_5.js | 178 +- search/classes_6.js | 156 +- search/classes_7.js | 56 +- search/classes_8.js | 81 +- search/classes_9.js | 412 +- search/classes_a.js | 50 +- search/classes_b.js | 32 +- search/classes_c.js | 223 +- search/classes_d.js | 286 +- search/classes_e.js | 188 +- search/classes_f.js | 202 +- search/enums_0.js | 16 +- search/enums_1.js | 22 +- search/enums_10.js | 36 +- search/enums_11.js | 34 +- search/enums_12.js | 10 +- search/enums_13.js | 10 +- search/enums_14.js | 6 +- search/enums_2.js | 8 +- search/enums_3.js | 10 +- search/enums_4.js | 8 +- search/enums_5.js | 4 +- search/enums_6.js | 4 +- search/enums_7.js | 4 +- search/enums_8.js | 4 +- search/enums_9.js | 14 +- search/enums_a.js | 4 +- search/enums_b.js | 6 +- search/enums_c.js | 8 +- search/enums_d.js | 18 +- search/enums_e.js | 2 +- search/enums_f.js | 10 +- search/enumvalues_0.js | 50 +- search/enumvalues_1.js | 48 +- search/enumvalues_10.js | 4 +- search/enumvalues_11.js | 178 +- search/enumvalues_12.js | 144 +- search/enumvalues_13.js | 562 +-- search/enumvalues_14.js | 28 +- search/enumvalues_15.js | 12 +- search/enumvalues_16.js | 20 +- search/enumvalues_17.js | 24 +- search/enumvalues_18.js | 2 +- search/enumvalues_2.js | 52 +- search/enumvalues_3.js | 58 +- search/enumvalues_4.js | 26 +- search/enumvalues_5.js | 36 +- search/enumvalues_6.js | 44 +- search/enumvalues_7.js | 24 +- search/enumvalues_8.js | 36 +- search/enumvalues_9.js | 96 +- search/enumvalues_a.js | 28 +- search/enumvalues_b.js | 180 +- search/enumvalues_c.js | 50 +- search/enumvalues_d.js | 68 +- search/enumvalues_e.js | 38 +- search/enumvalues_f.js | 42 +- search/files_0.js | 8 +- search/files_1.js | 4 +- search/files_10.js | 8 +- search/files_2.js | 68 +- search/files_3.js | 2 +- search/files_4.js | 4 +- search/files_5.js | 10 +- search/files_6.js | 14 +- search/files_7.js | 6 +- search/files_8.js | 8 +- search/files_9.js | 4 +- search/files_a.js | 4 +- search/files_b.js | 2 +- search/files_c.js | 8 +- search/files_d.js | 26 +- search/files_e.js | 10 +- search/files_f.js | 6 +- search/functions_0.js | 2 +- search/functions_1.js | 826 ++-- search/functions_10.js | 748 ++-- search/functions_11.js | 46 +- search/functions_12.js | 618 +-- search/functions_13.js | 1440 +++---- search/functions_14.js | 2445 +++++------ search/functions_15.js | 242 +- search/functions_16.js | 178 +- search/functions_17.js | 304 +- search/functions_18.js | 118 +- search/functions_19.js | 2 +- search/functions_1a.js | 10 +- search/functions_1b.js | 724 ++-- search/functions_2.js | 320 +- search/functions_3.js | 984 ++--- search/functions_4.js | 766 ++-- search/functions_5.js | 332 +- search/functions_6.js | 544 +-- search/functions_7.js | 1242 +++--- search/functions_8.js | 194 +- search/functions_9.js | 882 ++-- search/functions_a.js | 54 +- search/functions_b.js | 34 +- search/functions_c.js | 374 +- search/functions_d.js | 630 +-- search/functions_e.js | 322 +- search/functions_f.js | 436 +- search/groups_0.js | 2 +- search/namespaces_0.js | 24 +- search/namespaces_1.js | 4 +- search/namespaces_2.js | 2 +- search/namespaces_3.js | 86 +- search/namespaces_4.js | 24 +- search/pages_0.js | 2 +- search/pages_1.js | 4 +- search/pages_10.js | 2 +- search/pages_2.js | 10 +- search/pages_3.js | 6 +- search/pages_4.js | 2 +- search/pages_5.js | 4 +- search/pages_6.js | 6 +- search/pages_7.js | 2 +- search/pages_8.js | 4 +- search/pages_9.js | 4 +- search/pages_a.js | 2 +- search/pages_b.js | 4 +- search/pages_c.js | 6 +- search/pages_d.js | 16 +- search/pages_e.js | 8 +- search/pages_f.js | 2 +- search/related_0.js | 8 +- search/related_1.js | 16 +- search/related_2.js | 4 +- search/related_3.js | 6 +- search/related_4.js | 2 +- search/related_5.js | 6 +- search/related_6.js | 18 +- search/related_7.js | 18 +- search/related_8.js | 34 +- search/related_9.js | 6 +- search/related_a.js | 12 +- search/related_b.js | 12 +- search/related_c.js | 4 +- search/related_d.js | 6 +- search/typedefs_0.js | 54 +- search/typedefs_1.js | 32 +- search/typedefs_10.js | 2 +- search/typedefs_11.js | 54 +- search/typedefs_12.js | 164 +- search/typedefs_13.js | 88 +- search/typedefs_14.js | 16 +- search/typedefs_15.js | 14 +- search/typedefs_16.js | 10 +- search/typedefs_17.js | 2 +- search/typedefs_18.js | 2 +- search/typedefs_2.js | 72 +- search/typedefs_3.js | 28 +- search/typedefs_4.js | 40 +- search/typedefs_5.js | 20 +- search/typedefs_6.js | 2 +- search/typedefs_7.js | 38 +- search/typedefs_8.js | 52 +- search/typedefs_9.js | 8 +- search/typedefs_a.js | 14 +- search/typedefs_b.js | 54 +- search/typedefs_c.js | 60 +- search/typedefs_d.js | 22 +- search/typedefs_e.js | 20 +- search/typedefs_f.js | 56 +- search/variables_0.js | 395 +- search/variables_1.js | 166 +- search/variables_10.js | 42 +- search/variables_11.js | 340 +- search/variables_12.js | 1052 ++--- search/variables_13.js | 440 +- search/variables_14.js | 78 +- search/variables_15.js | 136 +- search/variables_16.js | 100 +- search/variables_17.js | 28 +- search/variables_18.js | 6 +- search/variables_19.js | 4 +- search/variables_2.js | 363 +- search/variables_3.js | 246 +- search/variables_4.js | 126 +- search/variables_5.js | 384 +- search/variables_6.js | 59 +- search/variables_7.js | 106 +- search/variables_8.js | 408 +- search/variables_9.js | 56 +- search/variables_a.js | 28 +- search/variables_b.js | 298 +- search/variables_c.js | 1174 +++--- search/variables_d.js | 200 +- search/variables_e.js | 98 +- search/variables_f.js | 320 +- structripple_1_1PerfLog__test_1_1Cur.html | 8 +- structripple_1_1PerfLog__test_1_1Fixture.html | 24 +- structripple_1_1RPC_1_1Handler-members.html | 4 +- structripple_1_1RPC_1_1Handler.html | 48 +- ...erf_1_1PerfLogImp_1_1Counters-members.html | 2 +- ...ple_1_1perf_1_1PerfLogImp_1_1Counters.html | 10 +- ...ripple_1_1test_1_1jtx_1_1cancel__time.html | 8 +- structripple_1_1test_1_1jtx_1_1condition.html | 10 +- ...ripple_1_1test_1_1jtx_1_1finish__time.html | 8 +- ...tripple_1_1test_1_1jtx_1_1fulfillment.html | 10 +- 372 files changed, 34989 insertions(+), 33438 deletions(-) create mode 100644 Handler__test_8cpp_source.html create mode 100644 LedgerHeader__test_8cpp_source.html create mode 100644 classripple_1_1LedgerHeader__test-members.html create mode 100644 classripple_1_1LedgerHeader__test.html create mode 100644 classripple_1_1LedgerHeader__test__coll__graph.map create mode 100644 classripple_1_1LedgerHeader__test__coll__graph.md5 create mode 100644 classripple_1_1LedgerHeader__test__coll__graph.png create mode 100644 classripple_1_1LedgerHeader__test__inherit__graph.map create mode 100644 classripple_1_1LedgerHeader__test__inherit__graph.md5 create mode 100644 classripple_1_1LedgerHeader__test__inherit__graph.png create mode 100644 classripple_1_1test_1_1Handler__test-members.html create mode 100644 classripple_1_1test_1_1Handler__test.html create mode 100644 classripple_1_1test_1_1Handler__test__coll__graph.map create mode 100644 classripple_1_1test_1_1Handler__test__coll__graph.md5 create mode 100644 classripple_1_1test_1_1Handler__test__coll__graph.png create mode 100644 classripple_1_1test_1_1Handler__test__inherit__graph.map create mode 100644 classripple_1_1test_1_1Handler__test__inherit__graph.md5 create mode 100644 classripple_1_1test_1_1Handler__test__inherit__graph.png diff --git a/AMMExtended__test_8cpp_source.html b/AMMExtended__test_8cpp_source.html index dca8ea6914..f155f79ac6 100644 --- a/AMMExtended__test_8cpp_source.html +++ b/AMMExtended__test_8cpp_source.html @@ -3995,7 +3995,7 @@ $(function() {
void testMultisign()
void receive_max()
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Definition: amount.h:241
-
bool same(STPathSet const &st1, Args const &... args)
Definition: TestHelpers.h:133
+
bool same(STPathSet const &st1, Args const &... args)
Definition: TestHelpers.h:142
AccountID const & ammAccount() const
Definition: AMM.h:255
void testPayStrand()
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
@@ -4070,7 +4070,7 @@ $(function() {
Sets the SendMax on a JTx.
Definition: sendmax.h:31
XRPAmount reserve(jtx::Env &env, std::uint32_t count) const
Definition: AMMTest.cpp:147
void testToStrand(FeatureBitset features)
-
STPath stpath(Args const &... args)
Definition: TestHelpers.h:124
+
STPath stpath(Args const &... args)
Definition: TestHelpers.h:133
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
bool expectOffers(Env &env, AccountID const &account, std::uint16_t size, std::vector< Amounts > const &toMatch)
Set the flags on a JTx.
Definition: txflags.h:30
diff --git a/AMM__test_8cpp_source.html b/AMM__test_8cpp_source.html index 135e67cbdd..15b6b2566b 100644 --- a/AMM__test_8cpp_source.html +++ b/AMM__test_8cpp_source.html @@ -4912,7 +4912,7 @@ $(function() {
void testBid()
Definition: AMM_test.cpp:2519
void testAmendment()
Definition: AMM_test.cpp:3681
-
bool same(STPathSet const &st1, Args const &... args)
Definition: TestHelpers.h:133
+
bool same(STPathSet const &st1, Args const &... args)
Definition: TestHelpers.h:142
@ temBAD_CURRENCY
Definition: TER.h:89
AccountID const & ammAccount() const
Definition: AMM.h:255
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
diff --git a/Connect_8cpp_source.html b/Connect_8cpp_source.html index f84ad6563c..97e3453357 100644 --- a/Connect_8cpp_source.html +++ b/Connect_8cpp_source.html @@ -160,7 +160,7 @@ $(function() {
@ intValue
signed integer value
Definition: json_value.h:37
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:49
virtual Overlay & overlay()=0
-
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:63
+
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:67
Int asInt() const
Definition: json_value.cpp:503
Json::Value doConnect(RPC::JsonContext &context)
Definition: Connect.cpp:38
Json::Value params
Definition: Context.h:64
diff --git a/DownloadShard_8cpp_source.html b/DownloadShard_8cpp_source.html index df5d4da6c4..1f55b19a1a 100644 --- a/DownloadShard_8cpp_source.html +++ b/DownloadShard_8cpp_source.html @@ -266,7 +266,7 @@ $(function() {
@ rpcNO_PERMISSION
Definition: ErrorCodes.h:53
Handles the download and import of one or more shard archives.
T empty(T... args)
-
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:63
+
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:67
std::string scheme
T make_pair(T... args)
std::string domain
diff --git a/Escrow__test_8cpp_source.html b/Escrow__test_8cpp_source.html index af0da9b154..2414195927 100644 --- a/Escrow__test_8cpp_source.html +++ b/Escrow__test_8cpp_source.html @@ -1617,7 +1617,7 @@ $(function() {
Json::Value finish(AccountID const &account, AccountID const &from, std::uint32_t seq)
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
void require(Args const &... args)
Check a set of requirements.
Definition: Env.h:479
-
Set the "FinishAfter" time tag on a JTx.
Definition: TestHelpers.h:244
+
Set the "FinishAfter" time tag on a JTx.
Definition: TestHelpers.h:253
An immutable linear range of bytes.
Definition: Slice.h:44
void testEscrowWithTickets()
A balance matches.
Definition: balance.h:38
@@ -1645,11 +1645,11 @@ $(function() {
std::shared_ptr< STObject const > meta()
Return metadata for the last JTx.
Definition: Env.cpp:374
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Definition: Indexes.cpp:327
void testTiming()
-
Definition: TestHelpers.h:302
+
Definition: TestHelpers.h:311
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition: flags.cpp:28
@ tecUNFUNDED
Definition: TER.h:276
-
Set the "CancelAfter" time tag on a JTx.
Definition: TestHelpers.h:262
+
Set the "CancelAfter" time tag on a JTx.
Definition: TestHelpers.h:271
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
void run() override
@ temBAD_AMOUNT
Definition: TER.h:88
@@ -1663,7 +1663,7 @@ $(function() {
const SF_UINT8 sfTransactionResult
NetClock::time_point now()
Returns the current network time.
Definition: Env.h:265
void test1571()
-
Definition: TestHelpers.h:279
+
Definition: TestHelpers.h:288
const std::array< std::uint8_t, 4 > fb1
Definition: Escrow_test.cpp:37
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition: Env.cpp:228
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:216
diff --git a/GRPCServer_8cpp_source.html b/GRPCServer_8cpp_source.html index c54a1bc4aa..9f7cfad0aa 100644 --- a/GRPCServer_8cpp_source.html +++ b/GRPCServer_8cpp_source.html @@ -845,13 +845,13 @@ $(function() {
std::unique_ptr< org::xrpl::rpc::v1::XRPLedgerAPIService::Stub > getP2pForwardingStub(RPC::Context &context)
Get stub used to forward gRPC requests to a p2p node.
Definition: P2pProxy.cpp:35
T find_last_of(T... args)
virtual JobQueue & getJobQueue()=0
-
@ NO_CONDITION
Definition: Handler.h:40
+
@ NO_CONDITION
Definition: Handler.h:41
@ PROXY
Stream error() const
Definition: Journal.h:332
Stream info() const
Definition: Journal.h:320
GRPCServerImpl(Application &app)
Definition: GRPCServer.cpp:426
Endpoint from_asio(boost::asio::ip::address const &address)
Convert to Endpoint.
-
Condition
Definition: Handler.h:39
+
Condition
Definition: Handler.h:40
Maps an rpc error code to its token, default message, and HTTP status.
Definition: ErrorCodes.h:169
Resource::Charge getLoadType()
Definition: GRPCServer.cpp:280
T pop_back(T... args)
@@ -875,7 +875,7 @@ $(function() {
grpc::ServerContext ctx_
Definition: GRPCServer.h:162
Definition: LedgerMaster.h:56
bool shouldForwardToP2p(RPC::JsonContext &context)
Whether a request should be forwarded, based on request parameters.
Definition: P2pProxy.cpp:45
-
error_code_i conditionMet(Condition condition_required, T &context)
Definition: Handler.h:78
+
error_code_i conditionMet(Condition condition_required, T &context)
Definition: Handler.h:82
T begin(T... args)
T getline(T... args)
STL namespace.
diff --git a/GRPCServer_8h_source.html b/GRPCServer_8h_source.html index 18a9af19ae..2debd03c5d 100644 --- a/GRPCServer_8h_source.html +++ b/GRPCServer_8h_source.html @@ -435,7 +435,7 @@ $(function() {
GRPCServerImpl & operator=(const GRPCServerImpl &)=delete
GRPCServerImpl(Application &app)
Definition: GRPCServer.cpp:426
A generic endpoint for log messages.
Definition: Journal.h:58
-
Condition
Definition: Handler.h:39
+
Condition
Definition: Handler.h:40
Resource::Charge getLoadType()
Definition: GRPCServer.cpp:280
std::optional< boost::asio::ip::tcp::endpoint > getProxiedClientEndpoint()
Definition: GRPCServer.cpp:352
diff --git a/Handler_8cpp_source.html b/Handler_8cpp_source.html index af0bca0da5..18ef11ac39 100644 --- a/Handler_8cpp_source.html +++ b/Handler_8cpp_source.html @@ -88,246 +88,305 @@ $(function() {
17 */
18 //==============================================================================
19 
-
20 #include <ripple/rpc/handlers/Handlers.h>
-
21 #include <ripple/rpc/handlers/Version.h>
-
22 #include <ripple/rpc/impl/Handler.h>
-
23 #include <ripple/rpc/impl/RPCHelpers.h>
-
24 
-
25 namespace ripple {
-
26 namespace RPC {
-
27 namespace {
-
28 
-
30 template <typename Function>
-
31 Handler::Method<Json::Value>
-
32 byRef(Function const& f)
-
33 {
-
34  return [f](JsonContext& context, Json::Value& result) {
-
35  result = f(context);
-
36  if (result.type() != Json::objectValue)
-
37  {
-
38  assert(false);
-
39  result = RPC::makeObjectValue(result);
-
40  }
-
41 
-
42  return Status();
-
43  };
-
44 }
-
45 
-
46 template <class Object, class HandlerImpl>
-
47 Status
-
48 handle(JsonContext& context, Object& object)
-
49 {
-
50  HandlerImpl handler(context);
-
51 
-
52  auto status = handler.check();
-
53  if (status)
-
54  status.inject(object);
-
55  else
-
56  handler.writeResult(object);
-
57  return status;
-
58 };
-
59 
-
60 Handler const handlerArray[]{
-
61  // Some handlers not specified here are added to the table via addHandler()
-
62  // Request-response methods
-
63  {"account_info", byRef(&doAccountInfo), Role::USER, NO_CONDITION},
-
64  {"account_currencies",
-
65  byRef(&doAccountCurrencies),
-
66  Role::USER,
-
67  NO_CONDITION},
-
68  {"account_lines", byRef(&doAccountLines), Role::USER, NO_CONDITION},
-
69  {"account_channels", byRef(&doAccountChannels), Role::USER, NO_CONDITION},
-
70  {"account_nfts", byRef(&doAccountNFTs), Role::USER, NO_CONDITION},
-
71  {"account_objects", byRef(&doAccountObjects), Role::USER, NO_CONDITION},
-
72  {"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
-
73  {"account_tx", byRef(&doAccountTxJson), Role::USER, NO_CONDITION},
-
74  {"amm_info", byRef(&doAMMInfo), Role::USER, NO_CONDITION},
-
75  {"blacklist", byRef(&doBlackList), Role::ADMIN, NO_CONDITION},
-
76  {"book_changes", byRef(&doBookChanges), Role::USER, NO_CONDITION},
-
77  {"book_offers", byRef(&doBookOffers), Role::USER, NO_CONDITION},
-
78  {"can_delete", byRef(&doCanDelete), Role::ADMIN, NO_CONDITION},
-
79  {"channel_authorize", byRef(&doChannelAuthorize), Role::USER, NO_CONDITION},
-
80  {"channel_verify", byRef(&doChannelVerify), Role::USER, NO_CONDITION},
-
81  {"connect", byRef(&doConnect), Role::ADMIN, NO_CONDITION},
-
82  {"consensus_info", byRef(&doConsensusInfo), Role::ADMIN, NO_CONDITION},
-
83  {"crawl_shards", byRef(&doCrawlShards), Role::ADMIN, NO_CONDITION},
-
84  {"deposit_authorized",
-
85  byRef(&doDepositAuthorized),
-
86  Role::USER,
-
87  NO_CONDITION},
-
88  {"download_shard", byRef(&doDownloadShard), Role::ADMIN, NO_CONDITION},
-
89 #ifdef RIPPLED_REPORTING
-
90  {"gateway_balances", byRef(&doGatewayBalances), Role::ADMIN, NO_CONDITION},
-
91 #else
-
92  {"gateway_balances", byRef(&doGatewayBalances), Role::USER, NO_CONDITION},
-
93 #endif
-
94  {"get_counts", byRef(&doGetCounts), Role::ADMIN, NO_CONDITION},
-
95  {"feature", byRef(&doFeature), Role::ADMIN, NO_CONDITION},
-
96  {"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER},
-
97  {"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION},
-
98  {"ledger_accept",
-
99  byRef(&doLedgerAccept),
-
100  Role::ADMIN,
-
101  NEEDS_CURRENT_LEDGER},
-
102  {"ledger_cleaner",
-
103  byRef(&doLedgerCleaner),
-
104  Role::ADMIN,
-
105  NEEDS_NETWORK_CONNECTION},
-
106  {"ledger_closed", byRef(&doLedgerClosed), Role::USER, NEEDS_CLOSED_LEDGER},
-
107  {"ledger_current",
-
108  byRef(&doLedgerCurrent),
-
109  Role::USER,
-
110  NEEDS_CURRENT_LEDGER},
-
111  {"ledger_data", byRef(&doLedgerData), Role::USER, NO_CONDITION},
-
112  {"ledger_entry", byRef(&doLedgerEntry), Role::USER, NO_CONDITION},
-
113  {"ledger_header", byRef(&doLedgerHeader), Role::USER, NO_CONDITION},
-
114  {"ledger_request", byRef(&doLedgerRequest), Role::ADMIN, NO_CONDITION},
-
115  {"log_level", byRef(&doLogLevel), Role::ADMIN, NO_CONDITION},
-
116  {"logrotate", byRef(&doLogRotate), Role::ADMIN, NO_CONDITION},
-
117  {"manifest", byRef(&doManifest), Role::USER, NO_CONDITION},
-
118  {"nft_buy_offers", byRef(&doNFTBuyOffers), Role::USER, NO_CONDITION},
-
119  {"nft_sell_offers", byRef(&doNFTSellOffers), Role::USER, NO_CONDITION},
-
120  {"node_to_shard", byRef(&doNodeToShard), Role::ADMIN, NO_CONDITION},
-
121  {"noripple_check", byRef(&doNoRippleCheck), Role::USER, NO_CONDITION},
-
122  {"owner_info", byRef(&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER},
-
123  {"peers", byRef(&doPeers), Role::ADMIN, NO_CONDITION},
-
124  {"path_find", byRef(&doPathFind), Role::USER, NEEDS_CURRENT_LEDGER},
-
125  {"ping", byRef(&doPing), Role::USER, NO_CONDITION},
-
126  {"print", byRef(&doPrint), Role::ADMIN, NO_CONDITION},
-
127  // { "profile", byRef (&doProfile), Role::USER,
-
128  // NEEDS_CURRENT_LEDGER },
-
129  {"random", byRef(&doRandom), Role::USER, NO_CONDITION},
-
130  {"peer_reservations_add",
-
131  byRef(&doPeerReservationsAdd),
-
132  Role::ADMIN,
-
133  NO_CONDITION},
-
134  {"peer_reservations_del",
-
135  byRef(&doPeerReservationsDel),
-
136  Role::ADMIN,
-
137  NO_CONDITION},
-
138  {"peer_reservations_list",
-
139  byRef(&doPeerReservationsList),
-
140  Role::ADMIN,
-
141  NO_CONDITION},
-
142  {"ripple_path_find", byRef(&doRipplePathFind), Role::USER, NO_CONDITION},
-
143  {"server_definitions",
-
144  byRef(&doServerDefinitions),
-
145  Role::USER,
-
146  NO_CONDITION},
-
147  {"server_info", byRef(&doServerInfo), Role::USER, NO_CONDITION},
-
148  {"server_state", byRef(&doServerState), Role::USER, NO_CONDITION},
-
149  {"sign", byRef(&doSign), Role::USER, NO_CONDITION},
-
150  {"sign_for", byRef(&doSignFor), Role::USER, NO_CONDITION},
-
151  {"stop", byRef(&doStop), Role::ADMIN, NO_CONDITION},
-
152  {"submit", byRef(&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER},
-
153  {"submit_multisigned",
-
154  byRef(&doSubmitMultiSigned),
-
155  Role::USER,
-
156  NEEDS_CURRENT_LEDGER},
-
157  {"transaction_entry", byRef(&doTransactionEntry), Role::USER, NO_CONDITION},
-
158  {"tx", byRef(&doTxJson), Role::USER, NEEDS_NETWORK_CONNECTION},
-
159  {"tx_history", byRef(&doTxHistory), Role::USER, NO_CONDITION},
-
160  {"tx_reduce_relay", byRef(&doTxReduceRelay), Role::USER, NO_CONDITION},
-
161  {"unl_list", byRef(&doUnlList), Role::ADMIN, NO_CONDITION},
-
162  {"validation_create",
-
163  byRef(&doValidationCreate),
-
164  Role::ADMIN,
+
20 #include <ripple/basics/contract.h>
+
21 #include <ripple/rpc/handlers/Handlers.h>
+
22 #include <ripple/rpc/handlers/Version.h>
+
23 #include <ripple/rpc/impl/Handler.h>
+
24 #include <ripple/rpc/impl/RPCHelpers.h>
+
25 
+
26 #include <map>
+
27 
+
28 namespace ripple {
+
29 namespace RPC {
+
30 namespace {
+
31 
+
33 template <typename Function>
+
34 Handler::Method<Json::Value>
+
35 byRef(Function const& f)
+
36 {
+
37  return [f](JsonContext& context, Json::Value& result) {
+
38  result = f(context);
+
39  if (result.type() != Json::objectValue)
+
40  {
+
41  assert(false);
+
42  result = RPC::makeObjectValue(result);
+
43  }
+
44 
+
45  return Status();
+
46  };
+
47 }
+
48 
+
49 template <class Object, class HandlerImpl>
+
50 Status
+
51 handle(JsonContext& context, Object& object)
+
52 {
+
53  assert(
+
54  context.apiVersion >= HandlerImpl::minApiVer &&
+
55  context.apiVersion <= HandlerImpl::maxApiVer);
+
56  HandlerImpl handler(context);
+
57 
+
58  auto status = handler.check();
+
59  if (status)
+
60  status.inject(object);
+
61  else
+
62  handler.writeResult(object);
+
63  return status;
+
64 }
+
65 
+
66 template <typename HandlerImpl>
+
67 Handler
+
68 handlerFrom()
+
69 {
+
70  return {
+
71  HandlerImpl::name,
+
72  &handle<Json::Value, HandlerImpl>,
+
73  HandlerImpl::role,
+
74  HandlerImpl::condition,
+
75  HandlerImpl::minApiVer,
+
76  HandlerImpl::maxApiVer};
+
77 }
+
78 
+
79 Handler const handlerArray[]{
+
80  // Some handlers not specified here are added to the table via addHandler()
+
81  // Request-response methods
+
82  {"account_info", byRef(&doAccountInfo), Role::USER, NO_CONDITION},
+
83  {"account_currencies",
+
84  byRef(&doAccountCurrencies),
+
85  Role::USER,
+
86  NO_CONDITION},
+
87  {"account_lines", byRef(&doAccountLines), Role::USER, NO_CONDITION},
+
88  {"account_channels", byRef(&doAccountChannels), Role::USER, NO_CONDITION},
+
89  {"account_nfts", byRef(&doAccountNFTs), Role::USER, NO_CONDITION},
+
90  {"account_objects", byRef(&doAccountObjects), Role::USER, NO_CONDITION},
+
91  {"account_offers", byRef(&doAccountOffers), Role::USER, NO_CONDITION},
+
92  {"account_tx", byRef(&doAccountTxJson), Role::USER, NO_CONDITION},
+
93  {"amm_info", byRef(&doAMMInfo), Role::USER, NO_CONDITION},
+
94  {"blacklist", byRef(&doBlackList), Role::ADMIN, NO_CONDITION},
+
95  {"book_changes", byRef(&doBookChanges), Role::USER, NO_CONDITION},
+
96  {"book_offers", byRef(&doBookOffers), Role::USER, NO_CONDITION},
+
97  {"can_delete", byRef(&doCanDelete), Role::ADMIN, NO_CONDITION},
+
98  {"channel_authorize", byRef(&doChannelAuthorize), Role::USER, NO_CONDITION},
+
99  {"channel_verify", byRef(&doChannelVerify), Role::USER, NO_CONDITION},
+
100  {"connect", byRef(&doConnect), Role::ADMIN, NO_CONDITION},
+
101  {"consensus_info", byRef(&doConsensusInfo), Role::ADMIN, NO_CONDITION},
+
102  {"crawl_shards", byRef(&doCrawlShards), Role::ADMIN, NO_CONDITION},
+
103  {"deposit_authorized",
+
104  byRef(&doDepositAuthorized),
+
105  Role::USER,
+
106  NO_CONDITION},
+
107  {"download_shard", byRef(&doDownloadShard), Role::ADMIN, NO_CONDITION},
+
108 #ifdef RIPPLED_REPORTING
+
109  {"gateway_balances", byRef(&doGatewayBalances), Role::ADMIN, NO_CONDITION},
+
110 #else
+
111  {"gateway_balances", byRef(&doGatewayBalances), Role::USER, NO_CONDITION},
+
112 #endif
+
113  {"get_counts", byRef(&doGetCounts), Role::ADMIN, NO_CONDITION},
+
114  {"feature", byRef(&doFeature), Role::ADMIN, NO_CONDITION},
+
115  {"fee", byRef(&doFee), Role::USER, NEEDS_CURRENT_LEDGER},
+
116  {"fetch_info", byRef(&doFetchInfo), Role::ADMIN, NO_CONDITION},
+
117  {"ledger_accept",
+
118  byRef(&doLedgerAccept),
+
119  Role::ADMIN,
+
120  NEEDS_CURRENT_LEDGER},
+
121  {"ledger_cleaner",
+
122  byRef(&doLedgerCleaner),
+
123  Role::ADMIN,
+
124  NEEDS_NETWORK_CONNECTION},
+
125  {"ledger_closed", byRef(&doLedgerClosed), Role::USER, NEEDS_CLOSED_LEDGER},
+
126  {"ledger_current",
+
127  byRef(&doLedgerCurrent),
+
128  Role::USER,
+
129  NEEDS_CURRENT_LEDGER},
+
130  {"ledger_data", byRef(&doLedgerData), Role::USER, NO_CONDITION},
+
131  {"ledger_entry", byRef(&doLedgerEntry), Role::USER, NO_CONDITION},
+
132  {"ledger_header", byRef(&doLedgerHeader), Role::USER, NO_CONDITION, 1, 1},
+
133  {"ledger_request", byRef(&doLedgerRequest), Role::ADMIN, NO_CONDITION},
+
134  {"log_level", byRef(&doLogLevel), Role::ADMIN, NO_CONDITION},
+
135  {"logrotate", byRef(&doLogRotate), Role::ADMIN, NO_CONDITION},
+
136  {"manifest", byRef(&doManifest), Role::USER, NO_CONDITION},
+
137  {"nft_buy_offers", byRef(&doNFTBuyOffers), Role::USER, NO_CONDITION},
+
138  {"nft_sell_offers", byRef(&doNFTSellOffers), Role::USER, NO_CONDITION},
+
139  {"node_to_shard", byRef(&doNodeToShard), Role::ADMIN, NO_CONDITION},
+
140  {"noripple_check", byRef(&doNoRippleCheck), Role::USER, NO_CONDITION},
+
141  {"owner_info", byRef(&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER},
+
142  {"peers", byRef(&doPeers), Role::ADMIN, NO_CONDITION},
+
143  {"path_find", byRef(&doPathFind), Role::USER, NEEDS_CURRENT_LEDGER},
+
144  {"ping", byRef(&doPing), Role::USER, NO_CONDITION},
+
145  {"print", byRef(&doPrint), Role::ADMIN, NO_CONDITION},
+
146  // { "profile", byRef (&doProfile), Role::USER,
+
147  // NEEDS_CURRENT_LEDGER },
+
148  {"random", byRef(&doRandom), Role::USER, NO_CONDITION},
+
149  {"peer_reservations_add",
+
150  byRef(&doPeerReservationsAdd),
+
151  Role::ADMIN,
+
152  NO_CONDITION},
+
153  {"peer_reservations_del",
+
154  byRef(&doPeerReservationsDel),
+
155  Role::ADMIN,
+
156  NO_CONDITION},
+
157  {"peer_reservations_list",
+
158  byRef(&doPeerReservationsList),
+
159  Role::ADMIN,
+
160  NO_CONDITION},
+
161  {"ripple_path_find", byRef(&doRipplePathFind), Role::USER, NO_CONDITION},
+
162  {"server_definitions",
+
163  byRef(&doServerDefinitions),
+
164  Role::USER,
165  NO_CONDITION},
-
166  {"validators", byRef(&doValidators), Role::ADMIN, NO_CONDITION},
-
167  {"validator_list_sites",
-
168  byRef(&doValidatorListSites),
-
169  Role::ADMIN,
-
170  NO_CONDITION},
-
171  {"validator_info", byRef(&doValidatorInfo), Role::ADMIN, NO_CONDITION},
-
172  {"wallet_propose", byRef(&doWalletPropose), Role::ADMIN, NO_CONDITION},
-
173  // Evented methods
-
174  {"subscribe", byRef(&doSubscribe), Role::USER, NO_CONDITION},
-
175  {"unsubscribe", byRef(&doUnsubscribe), Role::USER, NO_CONDITION},
-
176 };
-
177 
-
178 class HandlerTable
-
179 {
-
180 private:
-
181  template <std::size_t N>
-
182  explicit HandlerTable(const Handler (&entries)[N])
-
183  {
-
184  for (std::size_t i = 0; i < N; ++i)
-
185  {
-
186  auto const& entry = entries[i];
-
187  assert(table_.find(entry.name_) == table_.end());
-
188  table_[entry.name_] = entry;
-
189  }
-
190 
-
191  // This is where the new-style handlers are added.
-
192  addHandler<LedgerHandler>();
-
193  addHandler<VersionHandler>();
-
194  }
-
195 
-
196 public:
-
197  static HandlerTable const&
-
198  instance()
-
199  {
-
200  static HandlerTable const handlerTable(handlerArray);
-
201  return handlerTable;
-
202  }
-
203 
-
204  Handler const*
-
205  getHandler(unsigned version, bool betaEnabled, std::string const& name)
-
206  const
-
207  {
-
208  if (version < RPC::apiMinimumSupportedVersion ||
-
209  version > (betaEnabled ? RPC::apiBetaVersion
-
210  : RPC::apiMaximumSupportedVersion))
-
211  return nullptr;
-
212  auto i = table_.find(name);
-
213  return i == table_.end() ? nullptr : &i->second;
-
214  }
-
215 
-
216  std::vector<char const*>
-
217  getHandlerNames() const
-
218  {
-
219  std::vector<char const*> ret;
-
220  ret.reserve(table_.size());
-
221  for (auto const& i : table_)
-
222  ret.push_back(i.second.name_);
-
223  return ret;
-
224  }
-
225 
-
226 private:
-
227  std::map<std::string, Handler> table_;
-
228 
-
229  template <class HandlerImpl>
-
230  void
-
231  addHandler()
-
232  {
-
233  assert(table_.find(HandlerImpl::name()) == table_.end());
+
166  {"server_info", byRef(&doServerInfo), Role::USER, NO_CONDITION},
+
167  {"server_state", byRef(&doServerState), Role::USER, NO_CONDITION},
+
168  {"sign", byRef(&doSign), Role::USER, NO_CONDITION},
+
169  {"sign_for", byRef(&doSignFor), Role::USER, NO_CONDITION},
+
170  {"stop", byRef(&doStop), Role::ADMIN, NO_CONDITION},
+
171  {"submit", byRef(&doSubmit), Role::USER, NEEDS_CURRENT_LEDGER},
+
172  {"submit_multisigned",
+
173  byRef(&doSubmitMultiSigned),
+
174  Role::USER,
+
175  NEEDS_CURRENT_LEDGER},
+
176  {"transaction_entry", byRef(&doTransactionEntry), Role::USER, NO_CONDITION},
+
177  {"tx", byRef(&doTxJson), Role::USER, NEEDS_NETWORK_CONNECTION},
+
178  {"tx_history", byRef(&doTxHistory), Role::USER, NO_CONDITION, 1, 1},
+
179  {"tx_reduce_relay", byRef(&doTxReduceRelay), Role::USER, NO_CONDITION},
+
180  {"unl_list", byRef(&doUnlList), Role::ADMIN, NO_CONDITION},
+
181  {"validation_create",
+
182  byRef(&doValidationCreate),
+
183  Role::ADMIN,
+
184  NO_CONDITION},
+
185  {"validators", byRef(&doValidators), Role::ADMIN, NO_CONDITION},
+
186  {"validator_list_sites",
+
187  byRef(&doValidatorListSites),
+
188  Role::ADMIN,
+
189  NO_CONDITION},
+
190  {"validator_info", byRef(&doValidatorInfo), Role::ADMIN, NO_CONDITION},
+
191  {"wallet_propose", byRef(&doWalletPropose), Role::ADMIN, NO_CONDITION},
+
192  // Evented methods
+
193  {"subscribe", byRef(&doSubscribe), Role::USER, NO_CONDITION},
+
194  {"unsubscribe", byRef(&doUnsubscribe), Role::USER, NO_CONDITION},
+
195 };
+
196 
+
197 class HandlerTable
+
198 {
+
199 private:
+
200  using handler_table_t = std::multimap<std::string, Handler>;
+
201 
+
202  // Use with equal_range to enforce that API range of a newly added handler
+
203  // does not overlap with API range of an existing handler with same name
+
204  [[nodiscard]] bool
+
205  overlappingApiVersion(
+
206  std::pair<handler_table_t::iterator, handler_table_t::iterator> range,
+
207  unsigned minVer,
+
208  unsigned maxVer)
+
209  {
+
210  assert(minVer <= maxVer);
+
211  assert(maxVer <= RPC::apiMaximumValidVersion);
+
212 
+
213  return std::any_of(
+
214  range.first,
+
215  range.second, //
+
216  [minVer, maxVer](auto const& item) {
+
217  return item.second.minApiVer_ <= maxVer &&
+
218  item.second.maxApiVer_ >= minVer;
+
219  });
+
220  }
+
221 
+
222  template <std::size_t N>
+
223  explicit HandlerTable(const Handler (&entries)[N])
+
224  {
+
225  for (auto const& entry : entries)
+
226  {
+
227  if (overlappingApiVersion(
+
228  table_.equal_range(entry.name_),
+
229  entry.minApiVer_,
+
230  entry.maxApiVer_))
+
231  LogicError(
+
232  std::string("Handler for ") + entry.name_ +
+
233  " overlaps with an existing handler");
234 
-
235  Handler h;
-
236  h.name_ = HandlerImpl::name();
-
237  h.valueMethod_ = &handle<Json::Value, HandlerImpl>;
-
238  h.role_ = HandlerImpl::role();
-
239  h.condition_ = HandlerImpl::condition();
-
240 
-
241  table_[HandlerImpl::name()] = h;
-
242  }
-
243 };
-
244 
-
245 } // namespace
-
246 
-
247 Handler const*
-
248 getHandler(unsigned version, bool betaEnabled, std::string const& name)
-
249 {
-
250  return HandlerTable::instance().getHandler(version, betaEnabled, name);
-
251 }
-
252 
-
253 std::vector<char const*>
-
254 getHandlerNames()
-
255 {
-
256  return HandlerTable::instance().getHandlerNames();
-
257 };
-
258 
-
259 } // namespace RPC
-
260 } // namespace ripple
+
235  table_.insert({entry.name_, entry});
+
236  }
+
237 
+
238  // This is where the new-style handlers are added.
+
239  addHandler<LedgerHandler>();
+
240  addHandler<VersionHandler>();
+
241  }
+
242 
+
243 public:
+
244  static HandlerTable const&
+
245  instance()
+
246  {
+
247  static HandlerTable const handlerTable(handlerArray);
+
248  return handlerTable;
+
249  }
+
250 
+
251  [[nodiscard]] Handler const*
+
252  getHandler(unsigned version, bool betaEnabled, std::string const& name)
+
253  const
+
254  {
+
255  if (version < RPC::apiMinimumSupportedVersion ||
+
256  version > (betaEnabled ? RPC::apiBetaVersion
+
257  : RPC::apiMaximumSupportedVersion))
+
258  return nullptr;
+
259 
+
260  auto const range = table_.equal_range(name);
+
261  auto const i = std::find_if(
+
262  range.first, range.second, [version](auto const& entry) {
+
263  return entry.second.minApiVer_ <= version &&
+
264  version <= entry.second.maxApiVer_;
+
265  });
+
266 
+
267  return i == range.second ? nullptr : &i->second;
+
268  }
+
269 
+
270  [[nodiscard]] std::set<char const*>
+
271  getHandlerNames() const
+
272  {
+
273  std::set<char const*> ret;
+
274  for (auto const& i : table_)
+
275  ret.insert(i.second.name_);
+
276 
+
277  return ret;
+
278  }
+
279 
+
280 private:
+
281  handler_table_t table_;
+
282 
+
283  template <class HandlerImpl>
+
284  void
+
285  addHandler()
+
286  {
+
287  static_assert(HandlerImpl::minApiVer <= HandlerImpl::maxApiVer);
+
288  static_assert(HandlerImpl::maxApiVer <= RPC::apiMaximumValidVersion);
+
289  static_assert(
+
290  RPC::apiMinimumSupportedVersion <= HandlerImpl::minApiVer);
+
291 
+
292  if (overlappingApiVersion(
+
293  table_.equal_range(HandlerImpl::name),
+
294  HandlerImpl::minApiVer,
+
295  HandlerImpl::maxApiVer))
+
296  LogicError(
+
297  std::string("Handler for ") + HandlerImpl::name +
+
298  " overlaps with an existing handler");
+
299 
+
300  table_.insert({HandlerImpl::name, handlerFrom<HandlerImpl>()});
+
301  }
+
302 };
+
303 
+
304 } // namespace
+
305 
+
306 Handler const*
+
307 getHandler(unsigned version, bool betaEnabled, std::string const& name)
+
308 {
+
309  return HandlerTable::instance().getHandler(version, betaEnabled, name);
+
310 }
+
311 
+
312 std::set<char const*>
+
313 getHandlerNames()
+
314 {
+
315  return HandlerTable::instance().getHandlerNames();
+
316 }
+
317 
+
318 } // namespace RPC
+
319 } // namespace ripple
Json::Value doAccountNFTs(RPC::JsonContext &context)
General RPC command that can retrieve objects in the account root.
Json::Value doFeature(RPC::JsonContext &context)
Definition: Feature1.cpp:35
@@ -345,23 +404,24 @@ $(function() {
Json::Value doAccountInfo(RPC::JsonContext &context)
Definition: AccountInfo.cpp:50
Json::Value doRipplePathFind(RPC::JsonContext &)
Json::Value doSignFor(RPC::JsonContext &)
Definition: SignFor.cpp:35
-
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:248
+
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:307
+
std::set< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:313
+
Json::Value doAccountObjects(RPC::JsonContext &context)
-
T reserve(T... args)
-
STL class.
+
T find_if(T... args)
Json::Value doServerDefinitions(RPC::JsonContext &)
Definition: ServerInfo.cpp:299
Json::Value doValidators(RPC::JsonContext &)
Definition: Validators.cpp:29
Json::Value doValidatorListSites(RPC::JsonContext &)
Json::Value doTxReduceRelay(RPC::JsonContext &)
+
T any_of(T... args)
Json::Value doChannelVerify(RPC::JsonContext &)
-
@ NEEDS_NETWORK_CONNECTION
Definition: Handler.h:41
+
@ NEEDS_NETWORK_CONNECTION
Definition: Handler.h:42
Json::Value doPrint(RPC::JsonContext &)
Definition: Print.cpp:29
Json::Value doGatewayBalances(RPC::JsonContext &context)
Json::Value doManifest(RPC::JsonContext &)
Json::Value doPeers(RPC::JsonContext &)
Definition: Peers.cpp:32
Json::Value doSubmitMultiSigned(RPC::JsonContext &)
constexpr unsigned int apiBetaVersion
Definition: RPCHelpers.h:244
-
T push_back(T... args)
Json::Value doNFTBuyOffers(RPC::JsonContext &)
Definition: NFTOffers.cpp:165
Json::Value doCrawlShards(RPC::JsonContext &context)
RPC command that reports stored shards by nodes.
Definition: CrawlShards.cpp:44
Json::Value doTxHistory(RPC::JsonContext &)
Definition: TxHistory.cpp:43
@@ -374,39 +434,44 @@ $(function() {
Json::Value doNFTSellOffers(RPC::JsonContext &)
Definition: NFTOffers.cpp:151
@ USER
Json::Value doChannelAuthorize(RPC::JsonContext &)
-
@ NEEDS_CURRENT_LEDGER
Definition: Handler.h:42
+
@ NEEDS_CURRENT_LEDGER
Definition: Handler.h:43
Json::Value doRandom(RPC::JsonContext &)
Definition: Random.cpp:39
Json::Value doValidatorInfo(RPC::JsonContext &)
Json::Value doStop(RPC::JsonContext &)
Definition: Stop.cpp:33
Json::Value doWalletPropose(RPC::JsonContext &)
-
@ NO_CONDITION
Definition: Handler.h:40
+
@ NO_CONDITION
Definition: Handler.h:41
Json::Value doCanDelete(RPC::JsonContext &context)
Definition: CanDelete.cpp:35
Json::Value doConsensusInfo(RPC::JsonContext &context)
Json::Value doLedgerData(RPC::JsonContext &)
Definition: LedgerData.cpp:45
Json::Value doAccountOffers(RPC::JsonContext &context)
Json::Value doLogRotate(RPC::JsonContext &)
Definition: LogRotate.cpp:28
Json::Value doNoRippleCheck(RPC::JsonContext &)
-
@ NEEDS_CLOSED_LEDGER
Definition: Handler.h:43
-
STL class.
+
@ NEEDS_CLOSED_LEDGER
Definition: Handler.h:44
+
Json::Value doLedgerClosed(RPC::JsonContext &)
+
ClosedInterval< T > range(T low, T high)
Create a closed range interval.
Definition: RangeSet.h:54
Json::Value doBookOffers(RPC::JsonContext &context)
Definition: BookOffers.cpp:36
T status(T... args)
Json::Value doPeerReservationsList(RPC::JsonContext &)
Json::Value doAMMInfo(RPC::JsonContext &context)
Definition: AMMInfo.cpp:73
Status
Return codes from Backend operations.
Json::Value doTransactionEntry(RPC::JsonContext &)
+
T equal_range(T... args)
Json::Value doUnsubscribe(RPC::JsonContext &)
Definition: Unsubscribe.cpp:32
constexpr unsigned int apiMinimumSupportedVersion
Definition: RPCHelpers.h:242
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
+
constexpr unsigned int apiMaximumValidVersion
Definition: RPCHelpers.h:245
Json::Value doBlackList(RPC::JsonContext &context)
Definition: BlackList.cpp:28
+
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
Definition: contract.cpp:48
Json::Value doAccountTxJson(RPC::JsonContext &context)
Definition: AccountTx.cpp:386
+
T insert(T... args)
Json::Value doSign(RPC::JsonContext &)
Definition: SignHandler.cpp:33
Json::Value doPeerReservationsDel(RPC::JsonContext &)
Json::Value doTxJson(RPC::JsonContext &)
Definition: Tx.cpp:347
constexpr unsigned int apiMaximumSupportedVersion
Definition: RPCHelpers.h:243
Json::Value doNodeToShard(RPC::JsonContext &)
Definition: NodeToShard.cpp:33
-
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:63
-
+
STL class.
+
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:67
Json::Value doAccountChannels(RPC::JsonContext &context)
Json::Value doServerInfo(RPC::JsonContext &)
Definition: ServerInfo.cpp:322
Json::Value doLedgerHeader(RPC::JsonContext &)
@@ -414,8 +479,8 @@ $(function() {
Json::Value doServerState(RPC::JsonContext &)
Definition: ServerState.cpp:31
Json::Value doConnect(RPC::JsonContext &context)
Definition: Connect.cpp:38
Json::Value doLedgerCleaner(RPC::JsonContext &)
-
std::vector< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:254
Json::Value doDepositAuthorized(RPC::JsonContext &context)
+
STL class.
Json::Value doPeerReservationsAdd(RPC::JsonContext &)
Json::Value doBookChanges(RPC::JsonContext &context)
Definition: BookOffers.cpp:205
Json::Value doAccountLines(RPC::JsonContext &context)
diff --git a/Handler_8h_source.html b/Handler_8h_source.html index d31a066846..acd4bb1b1e 100644 --- a/Handler_8h_source.html +++ b/Handler_8h_source.html @@ -96,166 +96,175 @@ $(function() {
25 #include <ripple/core/Config.h>
26 #include <ripple/rpc/RPCHandler.h>
27 #include <ripple/rpc/Status.h>
-
28 #include <ripple/rpc/impl/Tuning.h>
-
29 #include <vector>
-
30 
-
31 namespace Json {
-
32 class Object;
-
33 }
-
34 
-
35 namespace ripple {
-
36 namespace RPC {
-
37 
-
38 // Under what condition can we call this RPC?
-
39 enum Condition {
-
40  NO_CONDITION = 0,
-
41  NEEDS_NETWORK_CONNECTION = 1,
-
42  NEEDS_CURRENT_LEDGER = 1 << 1,
-
43  NEEDS_CLOSED_LEDGER = 1 << 2,
-
44 };
-
45 
-
46 struct Handler
-
47 {
-
48  template <class JsonValue>
-
49  using Method = std::function<Status(JsonContext&, JsonValue&)>;
-
50 
-
51  const char* name_;
-
52  Method<Json::Value> valueMethod_;
-
53  Role role_;
-
54  RPC::Condition condition_;
-
55 };
+
28 #include <ripple/rpc/impl/RPCHelpers.h>
+
29 #include <ripple/rpc/impl/Tuning.h>
+
30 #include <vector>
+
31 
+
32 namespace Json {
+
33 class Object;
+
34 }
+
35 
+
36 namespace ripple {
+
37 namespace RPC {
+
38 
+
39 // Under what condition can we call this RPC?
+
40 enum Condition {
+
41  NO_CONDITION = 0,
+
42  NEEDS_NETWORK_CONNECTION = 1,
+
43  NEEDS_CURRENT_LEDGER = 1 << 1,
+
44  NEEDS_CLOSED_LEDGER = 1 << 2,
+
45 };
+
46 
+
47 struct Handler
+
48 {
+
49  template <class JsonValue>
+
50  using Method = std::function<Status(JsonContext&, JsonValue&)>;
+
51 
+
52  const char* name_;
+
53  Method<Json::Value> valueMethod_;
+
54  Role role_;
+
55  RPC::Condition condition_;
56 
-
57 Handler const*
-
58 getHandler(unsigned int version, bool betaEnabled, std::string const&);
-
59 
-
61 template <class Value>
-
62 Json::Value
-
63 makeObjectValue(
-
64  Value const& value,
-
65  Json::StaticString const& field = jss::message)
-
66 {
-
67  Json::Value result(Json::objectValue);
-
68  result[field] = value;
-
69  return result;
-
70 }
-
71 
-
73 std::vector<char const*>
-
74 getHandlerNames();
+
57  unsigned minApiVer_ = apiMinimumSupportedVersion;
+
58  unsigned maxApiVer_ = apiMaximumValidVersion;
+
59 };
+
60 
+
61 Handler const*
+
62 getHandler(unsigned int version, bool betaEnabled, std::string const&);
+
63 
+
65 template <class Value>
+
66 Json::Value
+
67 makeObjectValue(
+
68  Value const& value,
+
69  Json::StaticString const& field = jss::message)
+
70 {
+
71  Json::Value result(Json::objectValue);
+
72  result[field] = value;
+
73  return result;
+
74 }
75 
-
76 template <class T>
-
77 error_code_i
-
78 conditionMet(Condition condition_required, T& context)
-
79 {
-
80  if (context.app.config().reporting())
-
81  {
-
82  if (condition_required == NEEDS_CURRENT_LEDGER)
-
83  {
-
84  return rpcNO_CURRENT;
-
85  }
-
86  else if (condition_required == NEEDS_CLOSED_LEDGER)
+
77 std::set<char const*>
+
78 getHandlerNames();
+
79 
+
80 template <class T>
+
81 error_code_i
+
82 conditionMet(Condition condition_required, T& context)
+
83 {
+
84  if (context.app.config().reporting())
+
85  {
+
86  if (condition_required == NEEDS_CURRENT_LEDGER)
87  {
-
88  return rpcNO_CLOSED;
+
88  return rpcNO_CURRENT;
89  }
-
90  else
+
90  else if (condition_required == NEEDS_CLOSED_LEDGER)
91  {
-
92  return rpcSUCCESS;
+
92  return rpcNO_CLOSED;
93  }
-
94  }
-
95 
-
96  if (context.app.getOPs().isAmendmentBlocked() &&
-
97  (condition_required != NO_CONDITION))
-
98  {
-
99  return rpcAMENDMENT_BLOCKED;
-
100  }
-
101 
-
102  if (context.app.getOPs().isUNLBlocked() &&
-
103  (condition_required != NO_CONDITION))
-
104  {
-
105  return rpcEXPIRED_VALIDATOR_LIST;
-
106  }
-
107 
-
108  if ((condition_required != NO_CONDITION) &&
-
109  (context.netOps.getOperatingMode() < OperatingMode::SYNCING))
-
110  {
-
111  JLOG(context.j.info()) << "Insufficient network mode for RPC: "
-
112  << context.netOps.strOperatingMode();
-
113 
-
114  if (context.apiVersion == 1)
-
115  return rpcNO_NETWORK;
-
116  return rpcNOT_SYNCED;
-
117  }
-
118 
-
119  if (!context.app.config().standalone() &&
-
120  condition_required != NO_CONDITION)
-
121  {
-
122  if (context.ledgerMaster.getValidatedLedgerAge() >
-
123  Tuning::maxValidatedLedgerAge)
-
124  {
-
125  if (context.apiVersion == 1)
-
126  return rpcNO_CURRENT;
-
127  return rpcNOT_SYNCED;
-
128  }
-
129 
-
130  auto const cID = context.ledgerMaster.getCurrentLedgerIndex();
-
131  auto const vID = context.ledgerMaster.getValidLedgerIndex();
-
132 
-
133  if (cID + 10 < vID)
-
134  {
-
135  JLOG(context.j.debug())
-
136  << "Current ledger ID(" << cID
-
137  << ") is less than validated ledger ID(" << vID << ")";
-
138  if (context.apiVersion == 1)
-
139  return rpcNO_CURRENT;
-
140  return rpcNOT_SYNCED;
-
141  }
-
142  }
-
143 
-
144  if ((condition_required != NO_CONDITION) &&
-
145  !context.ledgerMaster.getClosedLedger())
-
146  {
-
147  if (context.apiVersion == 1)
-
148  return rpcNO_CLOSED;
-
149  return rpcNOT_SYNCED;
-
150  }
-
151 
-
152  return rpcSUCCESS;
-
153 }
-
154 
-
155 } // namespace RPC
-
156 } // namespace ripple
-
157 
-
158 #endif
+
94  else
+
95  {
+
96  return rpcSUCCESS;
+
97  }
+
98  }
+
99 
+
100  if (context.app.getOPs().isAmendmentBlocked() &&
+
101  (condition_required != NO_CONDITION))
+
102  {
+
103  return rpcAMENDMENT_BLOCKED;
+
104  }
+
105 
+
106  if (context.app.getOPs().isUNLBlocked() &&
+
107  (condition_required != NO_CONDITION))
+
108  {
+
109  return rpcEXPIRED_VALIDATOR_LIST;
+
110  }
+
111 
+
112  if ((condition_required != NO_CONDITION) &&
+
113  (context.netOps.getOperatingMode() < OperatingMode::SYNCING))
+
114  {
+
115  JLOG(context.j.info()) << "Insufficient network mode for RPC: "
+
116  << context.netOps.strOperatingMode();
+
117 
+
118  if (context.apiVersion == 1)
+
119  return rpcNO_NETWORK;
+
120  return rpcNOT_SYNCED;
+
121  }
+
122 
+
123  if (!context.app.config().standalone() &&
+
124  condition_required != NO_CONDITION)
+
125  {
+
126  if (context.ledgerMaster.getValidatedLedgerAge() >
+
127  Tuning::maxValidatedLedgerAge)
+
128  {
+
129  if (context.apiVersion == 1)
+
130  return rpcNO_CURRENT;
+
131  return rpcNOT_SYNCED;
+
132  }
+
133 
+
134  auto const cID = context.ledgerMaster.getCurrentLedgerIndex();
+
135  auto const vID = context.ledgerMaster.getValidLedgerIndex();
+
136 
+
137  if (cID + 10 < vID)
+
138  {
+
139  JLOG(context.j.debug())
+
140  << "Current ledger ID(" << cID
+
141  << ") is less than validated ledger ID(" << vID << ")";
+
142  if (context.apiVersion == 1)
+
143  return rpcNO_CURRENT;
+
144  return rpcNOT_SYNCED;
+
145  }
+
146  }
+
147 
+
148  if ((condition_required != NO_CONDITION) &&
+
149  !context.ledgerMaster.getClosedLedger())
+
150  {
+
151  if (context.apiVersion == 1)
+
152  return rpcNO_CLOSED;
+
153  return rpcNOT_SYNCED;
+
154  }
+
155 
+
156  return rpcSUCCESS;
+
157 }
+
158 
+
159 } // namespace RPC
+
160 } // namespace ripple
+
161 
+
162 #endif
@ rpcNO_NETWORK
Definition: ErrorCodes.h:66
Definition: Context.h:53
STL class.
-
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:248
-
Role role_
Definition: Handler.h:53
+
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:307
+
std::set< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:313
+
Role role_
Definition: Handler.h:54
-
const char * name_
Definition: Handler.h:51
-
@ NEEDS_NETWORK_CONNECTION
Definition: Handler.h:41
+
unsigned maxApiVer_
Definition: Handler.h:58
+
const char * name_
Definition: Handler.h:52
+
@ NEEDS_NETWORK_CONNECTION
Definition: Handler.h:42
error_code_i
Definition: ErrorCodes.h:40
@ SYNCING
fallen slightly behind
@ rpcAMENDMENT_BLOCKED
Definition: ErrorCodes.h:61
JSON (JavaScript Object Notation).
Definition: DeliverMax.h:28
@ rpcSUCCESS
Definition: ErrorCodes.h:44
-
Definition: Handler.h:46
+
Definition: Handler.h:47
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
-
@ NEEDS_CURRENT_LEDGER
Definition: Handler.h:42
-
RPC::Condition condition_
Definition: Handler.h:54
-
@ NO_CONDITION
Definition: Handler.h:40
+
@ NEEDS_CURRENT_LEDGER
Definition: Handler.h:43
+
RPC::Condition condition_
Definition: Handler.h:55
+
@ NO_CONDITION
Definition: Handler.h:41
@ rpcNO_CURRENT
Definition: ErrorCodes.h:65
-
@ NEEDS_CLOSED_LEDGER
Definition: Handler.h:43
-
Condition
Definition: Handler.h:39
+
@ NEEDS_CLOSED_LEDGER
Definition: Handler.h:44
+
Condition
Definition: Handler.h:40
Status represents the results of an operation that might fail.
Definition: Status.h:39
+
constexpr unsigned int apiMinimumSupportedVersion
Definition: RPCHelpers.h:242
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
-
Method< Json::Value > valueMethod_
Definition: Handler.h:52
-
error_code_i conditionMet(Condition condition_required, T &context)
Definition: Handler.h:78
+
Method< Json::Value > valueMethod_
Definition: Handler.h:53
+
constexpr unsigned int apiMaximumValidVersion
Definition: RPCHelpers.h:245
+
error_code_i conditionMet(Condition condition_required, T &context)
Definition: Handler.h:82
Lightweight wrapper to tag static string.
Definition: json_value.h:60
-
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:63
+
unsigned minApiVer_
Definition: Handler.h:57
+
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:67
@ rpcNO_CLOSED
Definition: ErrorCodes.h:64
-
std::vector< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:254
+
STL class.
Role
Indicates the level of administrative permission to grant.
Definition: Role.h:43
constexpr auto maxValidatedLedgerAge
@ rpcNOT_SYNCED
Definition: ErrorCodes.h:67
diff --git a/Handler__test_8cpp_source.html b/Handler__test_8cpp_source.html new file mode 100644 index 0000000000..e4bb4a03e2 --- /dev/null +++ b/Handler__test_8cpp_source.html @@ -0,0 +1,246 @@ + + + + + + + +rippled: Handler_test.cpp Source File + + + + + + + + + +
+
+ + + + + + +
+
rippled +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
Handler_test.cpp
+
+
+
1 //------------------------------------------------------------------------------
+
2 /*
+
3  This file is part of rippled: https://github.com/ripple/rippled
+
4  Copyright (c) 2023 Ripple Labs Inc.
+
5 
+
6  Permission to use, copy, modify, and/or distribute this software for any
+
7  purpose with or without fee is hereby granted, provided that the above
+
8  copyright notice and this permission notice appear in all copies.
+
9 
+
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
17 */
+
18 //==============================================================================
+
19 
+
20 #include <ripple/beast/unit_test.h>
+
21 #include <ripple/rpc/impl/Handler.h>
+
22 #include <test/jtx.h>
+
23 
+
24 #include <chrono>
+
25 #include <iostream>
+
26 #include <limits>
+
27 #include <numeric>
+
28 #include <random>
+
29 
+
30 namespace ripple::test {
+
31 
+
32 // NOTE: there should be no need for this function;
+
33 // `std::cout << some_duration` should just work if built with a compliant
+
34 // C++20 compiler. Sadly, we are not using one, as of today
+
35 // TODO: remove this operator<< overload when we bump compiler version
+ + +
38 {
+
39  return (os << ns.count() << "ns");
+
40 }
+
41 
+
42 // NOTE This is a rather naive effort at a microbenchmark. Ideally we want
+
43 // Google Benchmark, or something similar. Also, this actually does not belong
+
44 // to unit tests, as it makes little sense to run it in conditions very
+
45 // dissimilar to how rippled will normally work.
+
46 // TODO as https://github.com/XRPLF/rippled/issues/4765
+
47 
+
48 class Handler_test : public beast::unit_test::suite
+
49 {
+
50  auto
+
51  time(std::size_t n, auto f, auto prng) -> auto
+
52  {
+
53  using clock = std::chrono::steady_clock;
+
54  assert(n > 0);
+
55  double sum = 0;
+
56  double sum_squared = 0;
+
57  std::size_t j = 0;
+
58  while (j < n)
+
59  {
+
60  // Generate 100 inputs upfront, separated from the inner loop
+
61  std::array<decltype(prng()), 100> inputs = {};
+
62  for (auto& i : inputs)
+
63  {
+
64  i = prng();
+
65  }
+
66 
+
67  // Take 100 samples, then sort and throw away 35 from each end,
+
68  // using only middle 30. This helps to reduce measurement noise.
+
69  std::array<long, 100> samples = {};
+
70  for (std::size_t k = 0; k < 100; ++k)
+
71  {
+
72  auto start = std::chrono::steady_clock::now();
+
73  f(inputs[k]);
+
74  samples[k] = (std::chrono::steady_clock::now() - start).count();
+
75  }
+
76 
+
77  std::sort(samples.begin(), samples.end());
+
78  for (std::size_t k = 35; k < 65; ++k)
+
79  {
+
80  j += 1;
+
81  sum += samples[k];
+
82  sum_squared += (samples[k] * samples[k]);
+
83  }
+
84  }
+
85 
+
86  const double mean_squared = (sum * sum) / (j * j);
+
87  return std::make_tuple(
+
88  clock::duration{static_cast<long>(sum / j)},
+
89  clock::duration{
+
90  static_cast<long>(std::sqrt((sum_squared / j) - mean_squared))},
+
91  j);
+
92  }
+
93 
+
94  void
+ +
96  {
+
97  testcase("Handler lookup performance");
+
98 
+ +
100  std::ranlux48 prng(dev());
+
101 
+ +
103  test::jtx::make_vector(ripple::RPC::getHandlerNames());
+
104 
+
105  std::uniform_int_distribution<std::size_t> distr{0, names.size() - 1};
+
106 
+
107  std::size_t dummy = 0;
+
108  auto const [mean, stdev, n] = time(
+
109  1'000'000,
+
110  [&](std::size_t i) {
+
111  auto const d = RPC::getHandler(1, false, names[i]);
+
112  dummy = dummy + i + (int)d->role_;
+
113  },
+
114  [&]() -> std::size_t { return distr(prng); });
+
115 
+
116  std::cout << "mean=" << mean << " stdev=" << stdev << " N=" << n
+
117  << '\n';
+
118 
+
119  BEAST_EXPECT(dummy != 0);
+
120  }
+
121 
+
122 public:
+
123  void
+
124  run() override
+
125  {
+ +
127  }
+
128 };
+
129 
+
130 BEAST_DEFINE_TESTSUITE_MANUAL(Handler, test, ripple);
+
131 
+
132 } // namespace ripple::test
+
+
+
T make_tuple(T... args)
+
void run() override
+
+
+
void reportLookupPerformance()
+
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:307
+
std::set< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:313
+
STL class.
+
T size(T... args)
+
+
+
+
T sort(T... args)
+
T sqrt(T... args)
+
+
+
STL class.
+
+
STL class.
+
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
+
+
auto time(std::size_t n, auto f, auto prng) -> auto
+
+
T begin(T... args)
+
T count(T... args)
+
std::ostream & operator<<(std::ostream &os, std::chrono::nanoseconds ns)
+
+
T end(T... args)
+
BEAST_DEFINE_TESTSUITE_MANUAL(AMMCalc, app, ripple)
+
+
static auto sum(TCollection const &col)
Definition: BookStep.cpp:884
+
+
T now(T... args)
+ + + + diff --git a/LedgerCleanerHandler_8cpp_source.html b/LedgerCleanerHandler_8cpp_source.html index 8da0453ba7..e44eb0715a 100644 --- a/LedgerCleanerHandler_8cpp_source.html +++ b/LedgerCleanerHandler_8cpp_source.html @@ -110,7 +110,7 @@ $(function() {
virtual void clean(Json::Value const &parameters)=0
Start a long running task to clean the ledger.
virtual LedgerCleaner & getLedgerCleaner()=0
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
-
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:63
+
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:67
Json::Value doLedgerCleaner(RPC::JsonContext &)
Json::Value params
Definition: Context.h:64
Represents a JSON value.
Definition: json_value.h:145
diff --git a/LedgerHandler_8cpp_source.html b/LedgerHandler_8cpp_source.html index ef1618610c..729ab85687 100644 --- a/LedgerHandler_8cpp_source.html +++ b/LedgerHandler_8cpp_source.html @@ -396,7 +396,7 @@ $(function() {
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
@ dumpTxrp
Definition: LedgerToJson.h:47
Definition: Context.h:53
-
JsonContext & context_
Definition: LedgerHandler.h:80
+
JsonContext & context_
Definition: LedgerHandler.h:73
STL class.
@ rpcINVALID_PARAMS
Definition: ErrorCodes.h:84
STL class.
@@ -405,7 +405,7 @@ $(function() {
const SF_ACCOUNT sfOwner
Resource::Charge & loadType
Definition: Context.h:43
std::vector< TxDetails > getTxs() const
Returns information about all transactions currently in the queue.
Definition: TxQ.cpp:1815
-
std::shared_ptr< ReadView const > ledger_
Definition: LedgerHandler.h:81
+
std::shared_ptr< ReadView const > ledger_
Definition: LedgerHandler.h:74
@ dumpQueue
Definition: LedgerToJson.h:53
LedgerMaster & ledgerMaster
Definition: Context.h:45
std::pair< org::xrpl::rpc::v1::GetLedgerResponse, grpc::Status > doLedgerGrpc(RPC::GRPCContext< org::xrpl::rpc::v1::GetLedgerRequest > &context)
@@ -451,13 +451,13 @@ $(function() {
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:986
@ rpcNO_PERMISSION
Definition: ErrorCodes.h:53
const_iterator end() const
Definition: SHAMap.h:752
-
LedgerEntryType type_
Definition: LedgerHandler.h:85
+
LedgerEntryType type_
Definition: LedgerHandler.h:78
Blob const & peekData() const
Definition: Serializer.h:169
Status check()
bool compare(SHAMap const &otherMap, Delta &differences, int maxCount) const
Keylet quality(Keylet const &k, std::uint64_t q) noexcept
The initial directory page for a specific quality.
Definition: Indexes.cpp:237
-
int options_
Definition: LedgerHandler.h:84
-
std::vector< TxQ::TxDetails > queueTxs_
Definition: LedgerHandler.h:82
+
int options_
Definition: LedgerHandler.h:77
+
std::vector< TxQ::TxDetails > queueTxs_
Definition: LedgerHandler.h:75
const_iterator lower_bound(uint256 const &id) const
Find the object with the greatest object id smaller than the input id.
Definition: SHAMap.cpp:652
@ dumpState
Definition: LedgerToJson.h:48
T max(T... args)
@@ -466,7 +466,7 @@ $(function() {
T data(T... args)
Status ledgerFromRequest(T &ledger, GRPCContext< R > &context)
Definition: RPCHelpers.cpp:395
const Charge feeHighBurdenRPC
-
Json::Value result_
Definition: LedgerHandler.h:83
+
Json::Value result_
Definition: LedgerHandler.h:76
txs_type txs
Definition: ReadView.h:252
T now(T... args)
diff --git a/LedgerHandler_8h_source.html b/LedgerHandler_8h_source.html index 755ab9b767..88e0947b74 100644 --- a/LedgerHandler_8h_source.html +++ b/LedgerHandler_8h_source.html @@ -101,120 +101,117 @@ $(function() {
30 #include <ripple/rpc/Role.h>
31 #include <ripple/rpc/Status.h>
32 #include <ripple/rpc/impl/Handler.h>
-
33 
-
34 namespace Json {
-
35 class Object;
-
36 }
-
37 
-
38 namespace ripple {
-
39 namespace RPC {
-
40 
-
41 struct JsonContext;
-
42 
-
43 // ledger [id|index|current|closed] [full]
-
44 // {
-
45 // ledger: 'current' | 'closed' | <uint256> | <number>, // optional
-
46 // full: true | false // optional, defaults to false.
-
47 // }
-
48 
-
49 class LedgerHandler
-
50 {
-
51 public:
-
52  explicit LedgerHandler(JsonContext&);
-
53 
-
54  Status
-
55  check();
-
56 
-
57  template <class Object>
-
58  void
-
59  writeResult(Object&);
-
60 
-
61  static char const*
-
62  name()
-
63  {
-
64  return "ledger";
-
65  }
-
66 
-
67  static Role
-
68  role()
-
69  {
-
70  return Role::USER;
-
71  }
-
72 
-
73  static Condition
-
74  condition()
-
75  {
-
76  return NO_CONDITION;
-
77  }
-
78 
-
79 private:
-
80  JsonContext& context_;
-
81  std::shared_ptr<ReadView const> ledger_;
-
82  std::vector<TxQ::TxDetails> queueTxs_;
-
83  Json::Value result_;
-
84  int options_ = 0;
-
85  LedgerEntryType type_;
-
86 };
-
87 
-
90 //
-
91 // Implementation.
-
92 
-
93 template <class Object>
-
94 void
-
95 LedgerHandler::writeResult(Object& value)
-
96 {
-
97  if (ledger_)
-
98  {
-
99  Json::copyFrom(value, result_);
-
100  addJson(value, {*ledger_, &context_, options_, queueTxs_, type_});
-
101  }
-
102  else
-
103  {
-
104  auto& master = context_.app.getLedgerMaster();
-
105  {
-
106  auto&& closed = Json::addObject(value, jss::closed);
-
107  addJson(closed, {*master.getClosedLedger(), &context_, 0});
-
108  }
-
109  {
-
110  auto&& open = Json::addObject(value, jss::open);
-
111  addJson(open, {*master.getCurrentLedger(), &context_, 0});
-
112  }
-
113  }
-
114 }
-
115 
-
116 } // namespace RPC
-
117 } // namespace ripple
-
118 
-
119 #endif
+
33 #include <ripple/rpc/impl/RPCHelpers.h>
+
34 
+
35 namespace Json {
+
36 class Object;
+
37 }
+
38 
+
39 namespace ripple {
+
40 namespace RPC {
+
41 
+
42 struct JsonContext;
+
43 
+
44 // ledger [id|index|current|closed] [full]
+
45 // {
+
46 // ledger: 'current' | 'closed' | <uint256> | <number>, // optional
+
47 // full: true | false // optional, defaults to false.
+
48 // }
+
49 
+
50 class LedgerHandler
+
51 {
+
52 public:
+
53  explicit LedgerHandler(JsonContext&);
+
54 
+
55  Status
+
56  check();
+
57 
+
58  template <class Object>
+
59  void
+
60  writeResult(Object&);
+
61 
+
62  static constexpr char name[] = "ledger";
+
63 
+
64  static constexpr unsigned minApiVer = RPC::apiMinimumSupportedVersion;
+
65 
+
66  static constexpr unsigned maxApiVer = RPC::apiMaximumValidVersion;
+
67 
+
68  static constexpr Role role = Role::USER;
+
69 
+
70  static constexpr Condition condition = NO_CONDITION;
+
71 
+
72 private:
+
73  JsonContext& context_;
+
74  std::shared_ptr<ReadView const> ledger_;
+
75  std::vector<TxQ::TxDetails> queueTxs_;
+
76  Json::Value result_;
+
77  int options_ = 0;
+
78  LedgerEntryType type_;
+
79 };
+
80 
+
83 //
+
84 // Implementation.
+
85 
+
86 template <class Object>
+
87 void
+
88 LedgerHandler::writeResult(Object& value)
+
89 {
+
90  if (ledger_)
+
91  {
+
92  Json::copyFrom(value, result_);
+
93  addJson(value, {*ledger_, &context_, options_, queueTxs_, type_});
+
94  }
+
95  else
+
96  {
+
97  auto& master = context_.app.getLedgerMaster();
+
98  {
+
99  auto&& closed = Json::addObject(value, jss::closed);
+
100  addJson(closed, {*master.getClosedLedger(), &context_, 0});
+
101  }
+
102  {
+
103  auto&& open = Json::addObject(value, jss::open);
+
104  addJson(open, {*master.getCurrentLedger(), &context_, 0});
+
105  }
+
106  }
+
107 }
+
108 
+
109 } // namespace RPC
+
110 } // namespace ripple
+
111 
+
112 #endif
-
Definition: LedgerHandler.h:49
+
static constexpr unsigned minApiVer
Definition: LedgerHandler.h:64
+
Definition: LedgerHandler.h:50
Definition: Context.h:53
-
JsonContext & context_
Definition: LedgerHandler.h:80
+
JsonContext & context_
Definition: LedgerHandler.h:73
STL class.
+
static constexpr unsigned maxApiVer
Definition: LedgerHandler.h:66
STL class.
-
std::shared_ptr< ReadView const > ledger_
Definition: LedgerHandler.h:81
+
std::shared_ptr< ReadView const > ledger_
Definition: LedgerHandler.h:74
void copyFrom(Json::Value &to, Json::Value const &from)
Copy all the keys and values from one object into another.
Definition: Object.cpp:226
-
static Role role()
Definition: LedgerHandler.h:68
-
static Condition condition()
Definition: LedgerHandler.h:74
JSON (JavaScript Object Notation).
Definition: DeliverMax.h:28
virtual LedgerMaster & getLedgerMaster()=0
@ USER
-
@ NO_CONDITION
Definition: Handler.h:40
-
static char const * name()
Definition: LedgerHandler.h:62
+
@ NO_CONDITION
Definition: Handler.h:41
Application & app
Definition: Context.h:42
-
Condition
Definition: Handler.h:39
+
Condition
Definition: Handler.h:40
+
static constexpr Condition condition
Definition: LedgerHandler.h:70
Status represents the results of an operation that might fail.
Definition: Status.h:39
+
constexpr unsigned int apiMinimumSupportedVersion
Definition: RPCHelpers.h:242
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
LedgerHandler(JsonContext &)
-
void writeResult(Object &)
Definition: LedgerHandler.h:95
+
void writeResult(Object &)
Definition: LedgerHandler.h:88
LedgerEntryType
Identifiers for on-ledger objects.
Definition: LedgerFormats.h:53
+
constexpr unsigned int apiMaximumValidVersion
Definition: RPCHelpers.h:245
Json::Value & addObject(Json::Value &, Json::StaticString const &key)
Add a new subobject at a named key in a Json object.
Definition: Object.h:426
-
LedgerEntryType type_
Definition: LedgerHandler.h:85
+
LedgerEntryType type_
Definition: LedgerHandler.h:78
Status check()
void addJson(Json::Value &json, LedgerFill const &fill)
Given a Ledger and options, fill a Json::Object or Json::Value with a description of the ledger.
-
int options_
Definition: LedgerHandler.h:84
-
std::vector< TxQ::TxDetails > queueTxs_
Definition: LedgerHandler.h:82
-
Json::Value result_
Definition: LedgerHandler.h:83
+
static constexpr char name[]
Definition: LedgerHandler.h:62
+
int options_
Definition: LedgerHandler.h:77
+
std::vector< TxQ::TxDetails > queueTxs_
Definition: LedgerHandler.h:75
+
static constexpr Role role
Definition: LedgerHandler.h:68
+
Json::Value result_
Definition: LedgerHandler.h:76
Role
Indicates the level of administrative permission to grant.
Definition: Role.h:43
Represents a JSON value.
Definition: json_value.h:145
void open(soci::session &s, BasicConfig const &config, std::string const &dbName)
Open a soci session.
Definition: SociDB.cpp:98
diff --git a/LedgerHeader__test_8cpp_source.html b/LedgerHeader__test_8cpp_source.html new file mode 100644 index 0000000000..bc7a19e8fb --- /dev/null +++ b/LedgerHeader__test_8cpp_source.html @@ -0,0 +1,180 @@ + + + + + + + +rippled: LedgerHeader_test.cpp Source File + + + + + + + + + +
+
+ + + + + + +
+
rippled +
+
+
+ + + + + + + + +
+
+ + +
+ +
+ + +
+
+
+
LedgerHeader_test.cpp
+
+
+
1 //------------------------------------------------------------------------------
+
2 /*
+
3  This file is part of rippled: https://github.com/ripple/rippled
+
4  Copyright (c) 2023 Ripple Labs Inc.
+
5 
+
6  Permission to use, copy, modify, and/or distribute this software for any
+
7  purpose with or without fee is hereby granted, provided that the above
+
8  copyright notice and this permission notice appear in all copies.
+
9 
+
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
17 */
+
18 //==============================================================================
+
19 
+
20 #include <ripple/protocol/jss.h>
+
21 #include <test/jtx/Env.h>
+
22 #include <test/jtx/envconfig.h>
+
23 
+
24 namespace ripple {
+
25 
+
26 class LedgerHeader_test : public beast::unit_test::suite
+
27 {
+
28  void
+ +
30  {
+
31  testcase("Current ledger");
+
32  using namespace test::jtx;
+
33  Env env{*this, envconfig(no_admin)};
+
34 
+ +
36  params[jss::api_version] = 1;
+
37  params[jss::ledger_index] = "current";
+
38  auto const result =
+
39  env.client().invoke("ledger_header", params)[jss::result];
+
40  BEAST_EXPECT(result[jss::status] == "success");
+
41  BEAST_EXPECT(result.isMember("ledger"));
+
42  BEAST_EXPECT(result[jss::ledger][jss::closed] == false);
+
43  BEAST_EXPECT(result[jss::validated] == false);
+
44  }
+
45 
+
46  void
+ +
48  {
+
49  testcase("Validated ledger");
+
50  using namespace test::jtx;
+
51  Env env{*this, envconfig(no_admin)};
+
52 
+ +
54  params[jss::api_version] = 1;
+
55  params[jss::ledger_index] = "validated";
+
56  auto const result =
+
57  env.client().invoke("ledger_header", params)[jss::result];
+
58  BEAST_EXPECT(result[jss::status] == "success");
+
59  BEAST_EXPECT(result.isMember("ledger"));
+
60  BEAST_EXPECT(result[jss::ledger][jss::closed] == true);
+
61  BEAST_EXPECT(result[jss::validated] == true);
+
62  }
+
63 
+
64  void
+ +
66  {
+
67  testcase("Command retired from API v2");
+
68  using namespace test::jtx;
+
69  Env env{*this, envconfig(no_admin)};
+
70 
+ +
72  params[jss::api_version] = 2;
+
73  auto const result =
+
74  env.client().invoke("ledger_header", params)[jss::result];
+
75  BEAST_EXPECT(result[jss::error] == "unknownCmd");
+
76  BEAST_EXPECT(result[jss::status] == "error");
+
77  }
+
78 
+
79 public:
+
80  void
+
81  run() override
+
82  {
+ + + +
86  }
+
87 };
+
88 
+
89 BEAST_DEFINE_TESTSUITE(LedgerHeader, rpc, ripple);
+
90 
+
91 } // namespace ripple
+
+
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
+
void testSimpleCurrent()
+
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
+
+
void run() override
+
void testSimpleValidated()
+
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
+
Represents a JSON value.
Definition: json_value.h:145
+
void testCommandRetired()
+ + + + diff --git a/LogRotate_8cpp_source.html b/LogRotate_8cpp_source.html index ab15161267..eb3d024568 100644 --- a/LogRotate_8cpp_source.html +++ b/LogRotate_8cpp_source.html @@ -111,7 +111,7 @@ $(function() {
Json::Value doLogRotate(RPC::JsonContext &)
Definition: LogRotate.cpp:28
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
virtual void rotate()=0
Rotate perf log file.
-
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:63
+
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:67
virtual perf::PerfLog & getPerfLog()=0
Represents a JSON value.
Definition: json_value.h:145
diff --git a/P2pProxy_8cpp_source.html b/P2pProxy_8cpp_source.html index e309bc6d48..ed3917c18b 100644 --- a/P2pProxy_8cpp_source.html +++ b/P2pProxy_8cpp_source.html @@ -158,12 +158,12 @@ $(function() {
STL class.
Stream trace() const
Severity stream access functions.
Definition: Journal.h:308
Json::Value forwardToP2p(RPC::JsonContext &context) const
Forward a JSON RPC request to a randomly selected p2p node.
Definition: ETLSource.cpp:755
-
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:248
+
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:307
std::unique_ptr< org::xrpl::rpc::v1::XRPLedgerAPIService::Stub > getP2pForwardingStub() const
Randomly select a p2p node to forward a gRPC request to.
Definition: ETLSource.cpp:733
const beast::Journal j
Definition: Context.h:41
bool reporting() const
Definition: Config.h:351
virtual ReportingETL & getReportingETL()=0
-
@ NEEDS_CURRENT_LEDGER
Definition: Handler.h:42
+
@ NEEDS_CURRENT_LEDGER
Definition: Handler.h:43
virtual Config & config()=0
ETLLoadBalancer & getETLLoadBalancer()
Definition: ReportingETL.h:356
std::unique_ptr< org::xrpl::rpc::v1::XRPLedgerAPIService::Stub > getP2pForwardingStub(RPC::Context &context)
Get stub used to forward gRPC requests to a p2p node.
Definition: P2pProxy.cpp:35
@@ -171,7 +171,7 @@ $(function() {
Stream error() const
Definition: Journal.h:332
bool BETA_RPC_API
Definition: Config.h:299
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
-
@ NEEDS_CLOSED_LEDGER
Definition: Handler.h:43
+
@ NEEDS_CLOSED_LEDGER
Definition: Handler.h:44
Json::Value forwardToP2p(RPC::JsonContext &context)
Forward a JSON request to a p2p node and return the response.
Definition: P2pProxy.cpp:28
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool shouldForwardToP2p(RPC::JsonContext &context)
Whether a request should be forwarded, based on request parameters.
Definition: P2pProxy.cpp:45
diff --git a/P2pProxy_8h_source.html b/P2pProxy_8h_source.html index 62ff79bc9c..57f9a470e2 100644 --- a/P2pProxy_8h_source.html +++ b/P2pProxy_8h_source.html @@ -173,13 +173,13 @@ $(function() {
bool needCurrentOrClosed(Request &request)
Definition: P2pProxy.h:46
bool reporting() const
Definition: Config.h:351
-
@ NEEDS_CURRENT_LEDGER
Definition: Handler.h:42
+
@ NEEDS_CURRENT_LEDGER
Definition: Handler.h:43
virtual Config & config()=0
Definition: Context.h:70
std::unique_ptr< org::xrpl::rpc::v1::XRPLedgerAPIService::Stub > getP2pForwardingStub(RPC::Context &context)
Get stub used to forward gRPC requests to a p2p node.
Definition: P2pProxy.cpp:35
Application & app
Definition: Context.h:42
-
@ NEEDS_CLOSED_LEDGER
Definition: Handler.h:43
-
Condition
Definition: Handler.h:39
+
@ NEEDS_CLOSED_LEDGER
Definition: Handler.h:44
+
Condition
Definition: Handler.h:40
Json::Value forwardToP2p(RPC::JsonContext &context)
Forward a JSON request to a p2p node and return the response.
Definition: P2pProxy.cpp:28
RequestType params
Definition: Context.h:72
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
diff --git a/Path__test_8cpp_source.html b/Path__test_8cpp_source.html index 02ef1d9977..54884a680a 100644 --- a/Path__test_8cpp_source.html +++ b/Path__test_8cpp_source.html @@ -1472,7 +1472,7 @@ $(function() {
Definition: Path_test.cpp:95
STL class.
@ jtCLIENT
Definition: Job.h:45
-
bool same(STPathSet const &st1, Args const &... args)
Definition: TestHelpers.h:133
+
bool same(STPathSet const &st1, Args const &... args)
Definition: TestHelpers.h:142
const SField sfGeneric(access, 0)
Definition: SField.h:356
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition: ter.h:33
bool signaled_
Definition: Path_test.cpp:100
@@ -1533,7 +1533,7 @@ $(function() {
Sets the SendMax on a JTx.
Definition: sendmax.h:31
void path_find_06()
Definition: Path_test.cpp:1118
STL class.
-
STPath stpath(Args const &... args)
Definition: TestHelpers.h:124
+
STPath stpath(Args const &... args)
Definition: TestHelpers.h:133
T to_string(T... args)
Set Paths, SendMax on a JTx.
Definition: paths.h:32
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition: Env.cpp:121
diff --git a/PerfLogImp_8cpp_source.html b/PerfLogImp_8cpp_source.html index a45567036d..69eb3dc7af 100644 --- a/PerfLogImp_8cpp_source.html +++ b/PerfLogImp_8cpp_source.html @@ -113,13 +113,13 @@ $(function() {
42 namespace ripple {
43 namespace perf {
44 
-
45 PerfLogImp::Counters::Counters(
-
46  std::vector<char const*> const& labels,
+
45 PerfLogImp::Counters::Counters(
+
46  std::set<char const*> const& labels,
47  JobTypes const& jobTypes)
48 {
49  {
50  // populateRpc
-
51  rpc_.reserve(labels.size());
+
51  rpc_.reserve(labels.size());
52  for (std::string const label : labels)
53  {
54  auto const inserted = rpc_.emplace(label, Rpc()).second;
@@ -591,7 +591,7 @@ $(function() {
std::uint64_t started
Definition: PerfLogImp.h:85
STL class.
std::uint64_t finished
Definition: PerfLogImp.h:101
-
system_time_point lastLog_
Definition: PerfLogImp.h:134
+
system_time_point lastLog_
Definition: PerfLogImp.h:132
Definition: JobTypes.h:32
std::uint64_t queued
Definition: PerfLogImp.h:99
@@ -604,12 +604,12 @@ $(function() {
Decorator for streaming out compact json.
Definition: json_writer.h:316
std::mutex methodsMutex_
Definition: PerfLogImp.h:114
STL class.
-
T size(T... args)
+
T size(T... args)
void jobFinish(JobType const type, microseconds dur, int instance) override
Log job finishing.
Definition: PerfLogImp.cpp:418
-
const beast::Journal j_
Definition: PerfLogImp.h:127
+
const beast::Journal j_
Definition: PerfLogImp.h:125
void rotate() override
Rotate perf log file.
Definition: PerfLogImp.cpp:445
-
std::condition_variable cond_
Definition: PerfLogImp.h:133
+
std::condition_variable cond_
Definition: PerfLogImp.h:131
std::uint64_t finished
Definition: PerfLogImp.h:86
std::unique_ptr< PerfLog > make_PerfLog(PerfLog::Setup const &setup, Application &app, beast::Journal journal, std::function< void()> &&signalStop)
Definition: PerfLogImp.cpp:501
@@ -621,22 +621,23 @@ $(function() {
std::uint64_t errored
Definition: PerfLogImp.h:87
virtual void stateAccounting(Json::Value &obj)=0
-
const std::string hostname_
Definition: PerfLogImp.h:135
+
const std::string hostname_
Definition: PerfLogImp.h:133
virtual NetworkOPs & getOPs()=0
Configuration from [perf] section of rippled.cfg.
Definition: PerfLog.h:62
void jobStart(JobType const type, microseconds dur, steady_time_point startTime, int instance) override
Log job executing.
Definition: PerfLogImp.cpp:395
bool get_if_exists(Section const &section, std::string const &name, T &v)
Definition: BasicConfig.h:384
T push_back(T... args)
-
bool rotate_
Definition: PerfLogImp.h:137
+
bool rotate_
Definition: PerfLogImp.h:135
T joinable(T... args)
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
STL class.
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
-
std::mutex mutex_
Definition: PerfLogImp.h:132
+
std::mutex mutex_
Definition: PerfLogImp.h:130
std::vector< std::pair< JobType, steady_time_point > > jobs_
Definition: PerfLogImp.h:111
std::unordered_map< JobType, Locked< Jq > > jq_
Definition: PerfLogImp.h:110
STL class.
+
Counters(std::set< char const * > const &labels, JobTypes const &jobTypes)
Definition: PerfLogImp.cpp:45
T to_string(T... args)
@ jtINVALID
Definition: Job.h:37
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:313
@@ -644,13 +645,13 @@ $(function() {
T close(T... args)
-
std::thread thread_
Definition: PerfLogImp.h:131
+
std::thread thread_
Definition: PerfLogImp.h:129
@ current
This was a new validation and was added.
T open(T... args)
A generic endpoint for log messages.
Definition: Journal.h:58
-
const std::function< void()> signalStop_
Definition: PerfLogImp.h:128
+
const std::function< void()> signalStop_
Definition: PerfLogImp.h:126
std::unordered_map< std::string, Locked< Rpc > > rpc_
Definition: PerfLogImp.h:109
Job Queue task performance counters.
Definition: PerfLogImp.h:95
~PerfLogImp() override
Definition: PerfLogImp.cpp:322
@@ -663,7 +664,7 @@ $(function() {
virtual NodeStore::Database & getNodeStore()=0
T endl(T... args)
-
bool stop_
Definition: PerfLogImp.h:136
+
bool stop_
Definition: PerfLogImp.h:134
RPC performance counters.
Definition: PerfLogImp.h:81
T wait_until(T... args)
STL namespace.
@@ -677,12 +678,11 @@ $(function() {
JobType
Definition: Job.h:35
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
-
const Setup setup_
Definition: PerfLogImp.h:125
+
const Setup setup_
Definition: PerfLogImp.h:123
void stop() override
Definition: PerfLogImp.cpp:463
-
Application & app_
Definition: PerfLogImp.h:126
-
Counters(std::vector< char const * > const &labels, JobTypes const &jobTypes)
Definition: PerfLogImp.cpp:45
-
std::ofstream logFile_
Definition: PerfLogImp.h:130
-
Counters counters_
Definition: PerfLogImp.h:129
+
Application & app_
Definition: PerfLogImp.h:124
+
std::ofstream logFile_
Definition: PerfLogImp.h:128
+
Counters counters_
Definition: PerfLogImp.h:127
STL class.
microseconds duration
Definition: PerfLogImp.h:89
void jobQueue(JobType const type) override
Log queued job.
Definition: PerfLogImp.cpp:382
@@ -691,6 +691,7 @@ $(function() {
void start() override
Definition: PerfLogImp.cpp:456
Map::size_type size() const
Definition: JobTypes.h:156
T is_open(T... args)
+
STL class.
void resizeJobs(int const resize) override
Ensure enough room to store each currently executing job.
Definition: PerfLogImp.cpp:437
Json::Value countersJson() const
Definition: PerfLogImp.cpp:78
void report()
Definition: PerfLogImp.cpp:281
diff --git a/PerfLogImp_8h_source.html b/PerfLogImp_8h_source.html index 35f3234747..b84d86826c 100644 --- a/PerfLogImp_8h_source.html +++ b/PerfLogImp_8h_source.html @@ -171,104 +171,102 @@ $(function() {
113  std::unordered_map<std::uint64_t, MethodStart> methods_;
114  mutable std::mutex methodsMutex_;
115 
-
116  Counters(
-
117  std::vector<char const*> const& labels,
-
118  JobTypes const& jobTypes);
+
116  Counters(std::set<char const*> const& labels, JobTypes const& jobTypes);
+
117  Json::Value
+
118  countersJson() const;
119  Json::Value
-
120  countersJson() const;
-
121  Json::Value
-
122  currentJson() const;
-
123  };
-
124 
-
125  Setup const setup_;
-
126  Application& app_;
-
127  beast::Journal const j_;
-
128  std::function<void()> const signalStop_;
-
129  Counters counters_{ripple::RPC::getHandlerNames(), JobTypes::instance()};
-
130  std::ofstream logFile_;
-
131  std::thread thread_;
-
132  std::mutex mutex_;
-
133  std::condition_variable cond_;
-
134  system_time_point lastLog_;
-
135  std::string const hostname_{boost::asio::ip::host_name()};
-
136  bool stop_{false};
-
137  bool rotate_{false};
-
138 
+
120  currentJson() const;
+
121  };
+
122 
+
123  Setup const setup_;
+
124  Application& app_;
+
125  beast::Journal const j_;
+
126  std::function<void()> const signalStop_;
+
127  Counters counters_{ripple::RPC::getHandlerNames(), JobTypes::instance()};
+
128  std::ofstream logFile_;
+
129  std::thread thread_;
+
130  std::mutex mutex_;
+
131  std::condition_variable cond_;
+
132  system_time_point lastLog_;
+
133  std::string const hostname_{boost::asio::ip::host_name()};
+
134  bool stop_{false};
+
135  bool rotate_{false};
+
136 
+
137  void
+
138  openLog();
139  void
-
140  openLog();
+
140  run();
141  void
-
142  run();
+
142  report();
143  void
-
144  report();
-
145  void
-
146  rpcEnd(
-
147  std::string const& method,
-
148  std::uint64_t const requestId,
-
149  bool finish);
-
150 
-
151 public:
-
152  PerfLogImp(
-
153  Setup const& setup,
-
154  Application& app,
-
155  beast::Journal journal,
-
156  std::function<void()>&& signalStop);
+
144  rpcEnd(
+
145  std::string const& method,
+
146  std::uint64_t const requestId,
+
147  bool finish);
+
148 
+
149 public:
+
150  PerfLogImp(
+
151  Setup const& setup,
+
152  Application& app,
+
153  beast::Journal journal,
+
154  std::function<void()>&& signalStop);
+
155 
+
156  ~PerfLogImp() override;
157 
-
158  ~PerfLogImp() override;
-
159 
-
160  void
-
161  rpcStart(std::string const& method, std::uint64_t const requestId) override;
-
162 
-
163  void
-
164  rpcFinish(std::string const& method, std::uint64_t const requestId) override
-
165  {
-
166  rpcEnd(method, requestId, true);
-
167  }
-
168 
-
169  void
-
170  rpcError(std::string const& method, std::uint64_t const requestId) override
-
171  {
-
172  rpcEnd(method, requestId, false);
-
173  }
-
174 
+
158  void
+
159  rpcStart(std::string const& method, std::uint64_t const requestId) override;
+
160 
+
161  void
+
162  rpcFinish(std::string const& method, std::uint64_t const requestId) override
+
163  {
+
164  rpcEnd(method, requestId, true);
+
165  }
+
166 
+
167  void
+
168  rpcError(std::string const& method, std::uint64_t const requestId) override
+
169  {
+
170  rpcEnd(method, requestId, false);
+
171  }
+
172 
+
173  void
+
174  jobQueue(JobType const type) override;
175  void
-
176  jobQueue(JobType const type) override;
-
177  void
-
178  jobStart(
-
179  JobType const type,
-
180  microseconds dur,
-
181  steady_time_point startTime,
-
182  int instance) override;
-
183  void
-
184  jobFinish(JobType const type, microseconds dur, int instance) override;
-
185 
-
186  Json::Value
-
187  countersJson() const override
-
188  {
-
189  return counters_.countersJson();
-
190  }
-
191 
-
192  Json::Value
-
193  currentJson() const override
-
194  {
-
195  return counters_.currentJson();
-
196  }
-
197 
+
176  jobStart(
+
177  JobType const type,
+
178  microseconds dur,
+
179  steady_time_point startTime,
+
180  int instance) override;
+
181  void
+
182  jobFinish(JobType const type, microseconds dur, int instance) override;
+
183 
+
184  Json::Value
+
185  countersJson() const override
+
186  {
+
187  return counters_.countersJson();
+
188  }
+
189 
+
190  Json::Value
+
191  currentJson() const override
+
192  {
+
193  return counters_.currentJson();
+
194  }
+
195 
+
196  void
+
197  resizeJobs(int const resize) override;
198  void
-
199  resizeJobs(int const resize) override;
-
200  void
-
201  rotate() override;
-
202 
-
203  void
-
204  start() override;
-
205 
-
206  void
-
207  stop() override;
-
208 };
-
209 
-
210 } // namespace perf
-
211 } // namespace ripple
-
212 
-
213 #endif // RIPPLE_BASICS_PERFLOGIMP_H
+
199  rotate() override;
+
200 
+
201  void
+
202  start() override;
+
203 
+
204  void
+
205  stop() override;
+
206 };
+
207 
+
208 } // namespace perf
+
209 } // namespace ripple
+
210 
+
211 #endif // RIPPLE_BASICS_PERFLOGIMP_H
std::chrono::microseconds microseconds
Definition: PerfLog.h:57
Definition: Application.h:116
@@ -277,21 +275,22 @@ $(function() {
STL class.
std::uint64_t finished
Definition: PerfLogImp.h:101
-
system_time_point lastLog_
Definition: PerfLogImp.h:134
+
system_time_point lastLog_
Definition: PerfLogImp.h:132
Definition: JobTypes.h:32
std::uint64_t queued
Definition: PerfLogImp.h:99
void openLog()
Definition: PerfLogImp.cpp:222
+
std::set< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:313
std::mutex jobsMutex_
Definition: PerfLogImp.h:112
-
Json::Value countersJson() const override
Render performance counters in Json.
Definition: PerfLogImp.h:187
+
Json::Value countersJson() const override
Render performance counters in Json.
Definition: PerfLogImp.h:185
PerfLogImp(Setup const &setup, Application &app, beast::Journal journal, std::function< void()> &&signalStop)
Definition: PerfLogImp.cpp:312
std::mutex methodsMutex_
Definition: PerfLogImp.h:114
void jobFinish(JobType const type, microseconds dur, int instance) override
Log job finishing.
Definition: PerfLogImp.cpp:418
-
const beast::Journal j_
Definition: PerfLogImp.h:127
+
const beast::Journal j_
Definition: PerfLogImp.h:125
void rotate() override
Rotate perf log file.
Definition: PerfLogImp.cpp:445
-
std::condition_variable cond_
Definition: PerfLogImp.h:133
+
std::condition_variable cond_
Definition: PerfLogImp.h:131
std::uint64_t finished
Definition: PerfLogImp.h:86
std::uint64_t started
Definition: PerfLogImp.h:100
Singleton class that maintains performance counters and optionally writes Json-formatted data to a di...
Definition: PerfLog.h:48
@@ -299,26 +298,27 @@ $(function() {
std::unordered_map< std::uint64_t, MethodStart > methods_
Definition: PerfLogImp.h:113
std::uint64_t errored
Definition: PerfLogImp.h:87
-
const std::string hostname_
Definition: PerfLogImp.h:135
+
const std::string hostname_
Definition: PerfLogImp.h:133
Configuration from [perf] section of rippled.cfg.
Definition: PerfLog.h:62
Locked(T const &value)
Definition: PerfLogImp.h:52
void jobStart(JobType const type, microseconds dur, steady_time_point startTime, int instance) override
Log job executing.
Definition: PerfLogImp.cpp:395
-
bool rotate_
Definition: PerfLogImp.h:137
-
Json::Value currentJson() const override
Render currently executing jobs and RPC calls and durations in Json.
Definition: PerfLogImp.h:193
+
bool rotate_
Definition: PerfLogImp.h:135
+
Json::Value currentJson() const override
Render currently executing jobs and RPC calls and durations in Json.
Definition: PerfLogImp.h:191
Locked(T &&value)
Definition: PerfLogImp.h:55
A box coupling data with a mutex for locking access to it.
Definition: PerfLogImp.h:46
-
std::mutex mutex_
Definition: PerfLogImp.h:132
+
std::mutex mutex_
Definition: PerfLogImp.h:130
STL class.
std::vector< std::pair< JobType, steady_time_point > > jobs_
Definition: PerfLogImp.h:111
std::unordered_map< JobType, Locked< Jq > > jq_
Definition: PerfLogImp.h:110
+
Counters(std::set< char const * > const &labels, JobTypes const &jobTypes)
Definition: PerfLogImp.cpp:45
static JobTypes const & instance()
Definition: JobTypes.h:125
T value
Definition: PerfLogImp.h:48
-
std::thread thread_
Definition: PerfLogImp.h:131
+
std::thread thread_
Definition: PerfLogImp.h:129
A generic endpoint for log messages.
Definition: Journal.h:58
-
const std::function< void()> signalStop_
Definition: PerfLogImp.h:128
+
const std::function< void()> signalStop_
Definition: PerfLogImp.h:126
std::unordered_map< std::string, Locked< Rpc > > rpc_
Definition: PerfLogImp.h:109
Job Queue task performance counters.
Definition: PerfLogImp.h:95
@@ -327,7 +327,7 @@ $(function() {
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Locked(Locked &&rhs)
Definition: PerfLogImp.h:61
std::chrono::time_point< steady_clock > steady_time_point
Definition: PerfLog.h:53
-
bool stop_
Definition: PerfLogImp.h:136
+
bool stop_
Definition: PerfLogImp.h:134
RPC performance counters.
Definition: PerfLogImp.h:81
STL namespace.
void rpcEnd(std::string const &method, std::uint64_t const requestId, bool finish)
Definition: PerfLogImp.cpp:347
@@ -341,23 +341,22 @@ $(function() {
JobType
Definition: Job.h:35
Locked(Locked const &rhs)
Definition: PerfLogImp.h:58
-
const Setup setup_
Definition: PerfLogImp.h:125
-
void rpcFinish(std::string const &method, std::uint64_t const requestId) override
Log successful finish of RPC call.
Definition: PerfLogImp.h:164
+
const Setup setup_
Definition: PerfLogImp.h:123
+
void rpcFinish(std::string const &method, std::uint64_t const requestId) override
Log successful finish of RPC call.
Definition: PerfLogImp.h:162
void stop() override
Definition: PerfLogImp.cpp:463
-
Application & app_
Definition: PerfLogImp.h:126
-
Counters(std::vector< char const * > const &labels, JobTypes const &jobTypes)
Definition: PerfLogImp.cpp:45
-
std::ofstream logFile_
Definition: PerfLogImp.h:130
-
Counters counters_
Definition: PerfLogImp.h:129
-
std::vector< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:254
+
Application & app_
Definition: PerfLogImp.h:124
+
std::ofstream logFile_
Definition: PerfLogImp.h:128
+
Counters counters_
Definition: PerfLogImp.h:127
microseconds duration
Definition: PerfLogImp.h:89
void jobQueue(JobType const type) override
Log queued job.
Definition: PerfLogImp.cpp:382
void start() override
Definition: PerfLogImp.cpp:456
+
STL class.
void resizeJobs(int const resize) override
Ensure enough room to store each currently executing job.
Definition: PerfLogImp.cpp:437
Json::Value countersJson() const
Definition: PerfLogImp.cpp:78
void report()
Definition: PerfLogImp.cpp:281
-
void rpcError(std::string const &method, std::uint64_t const requestId) override
Log errored RPC call.
Definition: PerfLogImp.h:170
+
void rpcError(std::string const &method, std::uint64_t const requestId) override
Log errored RPC call.
Definition: PerfLogImp.h:168
Represents a JSON value.
Definition: json_value.h:145
Locked()=default
diff --git a/PerfLog__test_8cpp_source.html b/PerfLog__test_8cpp_source.html index e71f57dbe1..b2a8b79574 100644 --- a/PerfLog__test_8cpp_source.html +++ b/PerfLog__test_8cpp_source.html @@ -96,1091 +96,1094 @@ $(function() {
25 #include <ripple/protocol/jss.h>
26 #include <ripple/rpc/impl/Handler.h>
27 #include <test/jtx/Env.h>
-
28 
-
29 #include <atomic>
-
30 #include <chrono>
-
31 #include <cmath>
-
32 #include <random>
-
33 #include <string>
-
34 #include <thread>
-
35 
-
36 //------------------------------------------------------------------------------
-
37 
-
38 namespace ripple {
-
39 
-
40 class PerfLog_test : public beast::unit_test::suite
-
41 {
-
42  enum class WithFile : bool { no = false, yes = true };
-
43 
-
44  using path = boost::filesystem::path;
-
45 
-
46  // We're only using Env for its Journal. That Journal gives better
-
47  // coverage in unit tests.
-
48  test::jtx::Env env_{
-
49  *this,
-
50  test::jtx::envconfig(),
-
51  nullptr,
-
52  beast::severities::kDisabled};
-
53  beast::Journal j_{env_.app().journal("PerfLog_test")};
-
54 
-
55  struct Fixture
-
56  {
-
57  Application& app_;
-
58  beast::Journal j_;
-
59  bool stopSignaled{false};
-
60 
-
61  explicit Fixture(Application& app, beast::Journal j) : app_(app), j_(j)
-
62  {
-
63  }
-
64 
-
65  ~Fixture()
-
66  {
-
67  using namespace boost::filesystem;
-
68 
-
69  auto const dir{logDir()};
-
70  auto const file{logFile()};
-
71  if (exists(file))
-
72  remove(file);
-
73 
-
74  if (!exists(dir) || !is_directory(dir) || !is_empty(dir))
-
75  {
-
76  return;
-
77  }
-
78  remove(dir);
-
79  }
-
80 
-
81  void
-
82  signalStop()
-
83  {
-
84  stopSignaled = true;
-
85  }
-
86 
-
87  path
-
88  logDir() const
-
89  {
-
90  using namespace boost::filesystem;
-
91  return temp_directory_path() / "perf_log_test_dir";
-
92  }
-
93 
-
94  path
-
95  logFile() const
-
96  {
-
97  return logDir() / "perf_log.txt";
-
98  }
-
99 
-
100  std::chrono::milliseconds
-
101  logInterval() const
-
102  {
-
103  return std::chrono::milliseconds{10};
-
104  }
-
105 
-
106  std::unique_ptr<perf::PerfLog>
-
107  perfLog(WithFile withFile)
-
108  {
-
109  perf::PerfLog::Setup const setup{
-
110  withFile == WithFile::no ? "" : logFile(), logInterval()};
-
111  return perf::make_PerfLog(
-
112  setup, app_, j_, [this]() { return signalStop(); });
-
113  }
-
114 
-
115  // Block until the log file has grown in size, indicating that the
-
116  // PerfLog has written new values to the file and _should_ have the
-
117  // latest update.
-
118  void
-
119  wait() const
-
120  {
-
121  using namespace boost::filesystem;
-
122 
-
123  auto const path = logFile();
-
124  if (!exists(path))
-
125  return;
-
126 
-
127  // We wait for the file to change size twice. The first file size
-
128  // change may have been in process while we arrived.
-
129  std::uintmax_t const firstSize{file_size(path)};
-
130  std::uintmax_t secondSize{firstSize};
-
131  do
-
132  {
-
133  std::this_thread::sleep_for(logInterval());
-
134  secondSize = file_size(path);
-
135  } while (firstSize >= secondSize);
-
136 
-
137  do
-
138  {
-
139  std::this_thread::sleep_for(logInterval());
-
140  } while (secondSize >= file_size(path));
-
141  }
-
142  };
-
143 
-
144  // Return a uint64 from a JSON string.
-
145  static std::uint64_t
-
146  jsonToUint64(Json::Value const& jsonUintAsString)
-
147  {
-
148  return std::stoull(jsonUintAsString.asString());
-
149  }
-
150 
-
151  // The PerfLog's current state is easier to sort by duration if the
-
152  // duration is converted from string to integer. The following struct
-
153  // is a way to think about the converted entry.
-
154  struct Cur
-
155  {
-
156  std::uint64_t dur;
-
157  std::string name;
-
158 
-
159  Cur(std::uint64_t d, std::string n) : dur(d), name(std::move(n))
-
160  {
-
161  }
-
162  };
-
163 
-
164  // A convenience function to convert JSON to Cur and sort. The sort
-
165  // goes from longest to shortest duration. That way stuff that was started
-
166  // earlier goes to the front.
-
167  static std::vector<Cur>
-
168  getSortedCurrent(Json::Value const& currentJson)
-
169  {
-
170  std::vector<Cur> currents;
-
171  currents.reserve(currentJson.size());
-
172  for (Json::Value const& cur : currentJson)
-
173  {
-
174  currents.emplace_back(
-
175  jsonToUint64(cur[jss::duration_us]),
-
176  cur.isMember(jss::job) ? cur[jss::job].asString()
-
177  : cur[jss::method].asString());
-
178  }
-
179 
-
180  // Note that the longest durations should be at the front of the
-
181  // vector since they were started first.
-
182  std::sort(
-
183  currents.begin(),
-
184  currents.end(),
-
185  [](Cur const& lhs, Cur const& rhs) {
-
186  if (lhs.dur != rhs.dur)
-
187  return (rhs.dur < lhs.dur);
-
188  return (lhs.name < rhs.name);
-
189  });
-
190  return currents;
-
191  }
-
192 
-
193 public:
-
194  void
-
195  testFileCreation()
-
196  {
-
197  using namespace boost::filesystem;
-
198 
-
199  {
-
200  // Verify a PerfLog creates its file when constructed.
-
201  Fixture fixture{env_.app(), j_};
-
202  BEAST_EXPECT(!exists(fixture.logFile()));
-
203 
-
204  auto perfLog{fixture.perfLog(WithFile::yes)};
-
205 
-
206  BEAST_EXPECT(fixture.stopSignaled == false);
-
207  BEAST_EXPECT(exists(fixture.logFile()));
-
208  }
-
209  {
-
210  // Create a file where PerfLog wants to put its directory.
-
211  // Make sure that PerfLog tries to shutdown the server since it
-
212  // can't open its file.
-
213  Fixture fixture{env_.app(), j_};
-
214  if (!BEAST_EXPECT(!exists(fixture.logDir())))
-
215  return;
-
216 
-
217  {
-
218  // Make a file that prevents PerfLog from creating its file.
-
219  std::ofstream nastyFile;
-
220  nastyFile.open(
-
221  fixture.logDir().c_str(), std::ios::out | std::ios::app);
-
222  if (!BEAST_EXPECT(nastyFile))
-
223  return;
-
224  nastyFile.close();
-
225  }
-
226 
-
227  // Now construct a PerfLog. The PerfLog should attempt to shut
-
228  // down the server because it can't open its file.
-
229  BEAST_EXPECT(fixture.stopSignaled == false);
-
230  auto perfLog{fixture.perfLog(WithFile::yes)};
-
231  BEAST_EXPECT(fixture.stopSignaled == true);
-
232 
-
233  // Start PerfLog and wait long enough for PerfLog::report()
-
234  // to not be able to write to its file. That should cause no
-
235  // problems.
-
236  perfLog->start();
-
237  std::this_thread::sleep_for(fixture.logInterval() * 10);
-
238  perfLog->stop();
-
239 
-
240  // Remove the file.
-
241  remove(fixture.logDir());
-
242  }
-
243  {
-
244  // Put a write protected file where PerfLog wants to write its
-
245  // file. Make sure that PerfLog tries to shutdown the server
-
246  // since it can't open its file.
-
247  Fixture fixture{env_.app(), j_};
-
248  if (!BEAST_EXPECT(!exists(fixture.logDir())))
-
249  return;
-
250 
-
251  // Construct and write protect a file to prevent PerfLog
-
252  // from creating its file.
-
253  boost::system::error_code ec;
-
254  boost::filesystem::create_directories(fixture.logDir(), ec);
-
255  if (!BEAST_EXPECT(!ec))
-
256  return;
-
257 
-
258  auto fileWriteable = [](boost::filesystem::path const& p) -> bool {
-
259  return std::ofstream{p.c_str(), std::ios::out | std::ios::app}
-
260  .is_open();
-
261  };
-
262 
-
263  if (!BEAST_EXPECT(fileWriteable(fixture.logFile())))
-
264  return;
-
265 
-
266  boost::filesystem::permissions(
-
267  fixture.logFile(),
-
268  perms::remove_perms | perms::owner_write | perms::others_write |
-
269  perms::group_write);
-
270 
-
271  // If the test is running as root, then the write protect may have
-
272  // no effect. Make sure write protect worked before proceeding.
-
273  if (fileWriteable(fixture.logFile()))
-
274  {
-
275  log << "Unable to write protect file. Test skipped."
-
276  << std::endl;
-
277  return;
-
278  }
-
279 
-
280  // Now construct a PerfLog. The PerfLog should attempt to shut
-
281  // down the server because it can't open its file.
-
282  BEAST_EXPECT(fixture.stopSignaled == false);
-
283  auto perfLog{fixture.perfLog(WithFile::yes)};
-
284  BEAST_EXPECT(fixture.stopSignaled == true);
-
285 
-
286  // Start PerfLog and wait long enough for PerfLog::report()
-
287  // to not be able to write to its file. That should cause no
-
288  // problems.
-
289  perfLog->start();
-
290  std::this_thread::sleep_for(fixture.logInterval() * 10);
-
291  perfLog->stop();
-
292 
-
293  // Fix file permissions so the file can be cleaned up.
-
294  boost::filesystem::permissions(
-
295  fixture.logFile(),
-
296  perms::add_perms | perms::owner_write | perms::others_write |
-
297  perms::group_write);
-
298  }
-
299  }
-
300 
-
301  void
-
302  testRPC(WithFile withFile)
-
303  {
-
304  // Exercise the rpc interfaces of PerfLog.
-
305  // Start up the PerfLog that we'll use for testing.
-
306  Fixture fixture{env_.app(), j_};
-
307  auto perfLog{fixture.perfLog(withFile)};
-
308  perfLog->start();
-
309 
-
310  // Get the all the labels we can use for RPC interfaces without
-
311  // causing an assert.
-
312  std::vector<char const*> labels{ripple::RPC::getHandlerNames()};
-
313  std::shuffle(labels.begin(), labels.end(), default_prng());
-
314 
-
315  // Get two IDs to associate with each label. Errors tend to happen at
-
316  // boundaries, so we pick IDs starting from zero and ending at
-
317  // std::uint64_t>::max().
-
318  std::vector<std::uint64_t> ids;
-
319  ids.reserve(labels.size() * 2);
-
320  std::generate_n(
-
321  std::back_inserter(ids),
-
322  labels.size(),
-
323  [i = std::numeric_limits<std::uint64_t>::min()]() mutable {
-
324  return i++;
-
325  });
-
326  std::generate_n(
-
327  std::back_inserter(ids),
-
328  labels.size(),
-
329  [i = std::numeric_limits<std::uint64_t>::max()]() mutable {
-
330  return i--;
-
331  });
-
332  std::shuffle(ids.begin(), ids.end(), default_prng());
-
333 
-
334  // Start all of the RPC commands twice to show they can all be tracked
-
335  // simultaneously.
-
336  for (int labelIndex = 0; labelIndex < labels.size(); ++labelIndex)
-
337  {
-
338  for (int idIndex = 0; idIndex < 2; ++idIndex)
-
339  {
-
340  std::this_thread::sleep_for(std::chrono::microseconds(10));
-
341  perfLog->rpcStart(
-
342  labels[labelIndex], ids[(labelIndex * 2) + idIndex]);
-
343  }
-
344  }
-
345  {
-
346  // Examine current PerfLog::counterJson() values.
-
347  Json::Value const countersJson{perfLog->countersJson()[jss::rpc]};
-
348  BEAST_EXPECT(countersJson.size() == labels.size() + 1);
-
349  for (auto& label : labels)
-
350  {
-
351  // Expect every label in labels to have the same contents.
-
352  Json::Value const& counter{countersJson[label]};
-
353  BEAST_EXPECT(counter[jss::duration_us] == "0");
-
354  BEAST_EXPECT(counter[jss::errored] == "0");
-
355  BEAST_EXPECT(counter[jss::finished] == "0");
-
356  BEAST_EXPECT(counter[jss::started] == "2");
-
357  }
-
358  // Expect "total" to have a lot of "started"
-
359  Json::Value const& total{countersJson[jss::total]};
-
360  BEAST_EXPECT(total[jss::duration_us] == "0");
-
361  BEAST_EXPECT(total[jss::errored] == "0");
-
362  BEAST_EXPECT(total[jss::finished] == "0");
-
363  BEAST_EXPECT(jsonToUint64(total[jss::started]) == ids.size());
-
364  }
-
365  {
-
366  // Verify that every entry in labels appears twice in currents.
-
367  // If we sort by duration_us they should be in the order the
-
368  // rpcStart() call was made.
-
369  std::vector<Cur> const currents{
-
370  getSortedCurrent(perfLog->currentJson()[jss::methods])};
-
371  BEAST_EXPECT(currents.size() == labels.size() * 2);
-
372 
-
373  std::uint64_t prevDur = std::numeric_limits<std::uint64_t>::max();
-
374  for (int i = 0; i < currents.size(); ++i)
-
375  {
-
376  BEAST_EXPECT(currents[i].name == labels[i / 2]);
-
377  BEAST_EXPECT(prevDur > currents[i].dur);
-
378  prevDur = currents[i].dur;
-
379  }
-
380  }
-
381 
-
382  // Finish all but the first RPC command in reverse order to show that
-
383  // the start and finish of the commands can interleave. Half of the
-
384  // commands finish correctly, the other half with errors.
-
385  for (int labelIndex = labels.size() - 1; labelIndex > 0; --labelIndex)
-
386  {
-
387  std::this_thread::sleep_for(std::chrono::microseconds(10));
-
388  perfLog->rpcFinish(labels[labelIndex], ids[(labelIndex * 2) + 1]);
+
28 #include <test/jtx/TestHelpers.h>
+
29 
+
30 #include <atomic>
+
31 #include <chrono>
+
32 #include <cmath>
+
33 #include <random>
+
34 #include <string>
+
35 #include <thread>
+
36 
+
37 //------------------------------------------------------------------------------
+
38 
+
39 namespace ripple {
+
40 
+
41 class PerfLog_test : public beast::unit_test::suite
+
42 {
+
43  enum class WithFile : bool { no = false, yes = true };
+
44 
+
45  using path = boost::filesystem::path;
+
46 
+
47  // We're only using Env for its Journal. That Journal gives better
+
48  // coverage in unit tests.
+
49  test::jtx::Env env_{
+
50  *this,
+
51  test::jtx::envconfig(),
+
52  nullptr,
+
53  beast::severities::kDisabled};
+
54  beast::Journal j_{env_.app().journal("PerfLog_test")};
+
55 
+
56  struct Fixture
+
57  {
+
58  Application& app_;
+
59  beast::Journal j_;
+
60  bool stopSignaled{false};
+
61 
+
62  explicit Fixture(Application& app, beast::Journal j) : app_(app), j_(j)
+
63  {
+
64  }
+
65 
+
66  ~Fixture()
+
67  {
+
68  using namespace boost::filesystem;
+
69 
+
70  auto const dir{logDir()};
+
71  auto const file{logFile()};
+
72  if (exists(file))
+
73  remove(file);
+
74 
+
75  if (!exists(dir) || !is_directory(dir) || !is_empty(dir))
+
76  {
+
77  return;
+
78  }
+
79  remove(dir);
+
80  }
+
81 
+
82  void
+
83  signalStop()
+
84  {
+
85  stopSignaled = true;
+
86  }
+
87 
+
88  path
+
89  logDir() const
+
90  {
+
91  using namespace boost::filesystem;
+
92  return temp_directory_path() / "perf_log_test_dir";
+
93  }
+
94 
+
95  path
+
96  logFile() const
+
97  {
+
98  return logDir() / "perf_log.txt";
+
99  }
+
100 
+
101  std::chrono::milliseconds
+
102  logInterval() const
+
103  {
+
104  return std::chrono::milliseconds{10};
+
105  }
+
106 
+
107  std::unique_ptr<perf::PerfLog>
+
108  perfLog(WithFile withFile)
+
109  {
+
110  perf::PerfLog::Setup const setup{
+
111  withFile == WithFile::no ? "" : logFile(), logInterval()};
+
112  return perf::make_PerfLog(
+
113  setup, app_, j_, [this]() { return signalStop(); });
+
114  }
+
115 
+
116  // Block until the log file has grown in size, indicating that the
+
117  // PerfLog has written new values to the file and _should_ have the
+
118  // latest update.
+
119  void
+
120  wait() const
+
121  {
+
122  using namespace boost::filesystem;
+
123 
+
124  auto const path = logFile();
+
125  if (!exists(path))
+
126  return;
+
127 
+
128  // We wait for the file to change size twice. The first file size
+
129  // change may have been in process while we arrived.
+
130  std::uintmax_t const firstSize{file_size(path)};
+
131  std::uintmax_t secondSize{firstSize};
+
132  do
+
133  {
+
134  std::this_thread::sleep_for(logInterval());
+
135  secondSize = file_size(path);
+
136  } while (firstSize >= secondSize);
+
137 
+
138  do
+
139  {
+
140  std::this_thread::sleep_for(logInterval());
+
141  } while (secondSize >= file_size(path));
+
142  }
+
143  };
+
144 
+
145  // Return a uint64 from a JSON string.
+
146  static std::uint64_t
+
147  jsonToUint64(Json::Value const& jsonUintAsString)
+
148  {
+
149  return std::stoull(jsonUintAsString.asString());
+
150  }
+
151 
+
152  // The PerfLog's current state is easier to sort by duration if the
+
153  // duration is converted from string to integer. The following struct
+
154  // is a way to think about the converted entry.
+
155  struct Cur
+
156  {
+
157  std::uint64_t dur;
+
158  std::string name;
+
159 
+
160  Cur(std::uint64_t d, std::string n) : dur(d), name(std::move(n))
+
161  {
+
162  }
+
163  };
+
164 
+
165  // A convenience function to convert JSON to Cur and sort. The sort
+
166  // goes from longest to shortest duration. That way stuff that was started
+
167  // earlier goes to the front.
+
168  static std::vector<Cur>
+
169  getSortedCurrent(Json::Value const& currentJson)
+
170  {
+
171  std::vector<Cur> currents;
+
172  currents.reserve(currentJson.size());
+
173  for (Json::Value const& cur : currentJson)
+
174  {
+
175  currents.emplace_back(
+
176  jsonToUint64(cur[jss::duration_us]),
+
177  cur.isMember(jss::job) ? cur[jss::job].asString()
+
178  : cur[jss::method].asString());
+
179  }
+
180 
+
181  // Note that the longest durations should be at the front of the
+
182  // vector since they were started first.
+
183  std::sort(
+
184  currents.begin(),
+
185  currents.end(),
+
186  [](Cur const& lhs, Cur const& rhs) {
+
187  if (lhs.dur != rhs.dur)
+
188  return (rhs.dur < lhs.dur);
+
189  return (lhs.name < rhs.name);
+
190  });
+
191  return currents;
+
192  }
+
193 
+
194 public:
+
195  void
+
196  testFileCreation()
+
197  {
+
198  using namespace boost::filesystem;
+
199 
+
200  {
+
201  // Verify a PerfLog creates its file when constructed.
+
202  Fixture fixture{env_.app(), j_};
+
203  BEAST_EXPECT(!exists(fixture.logFile()));
+
204 
+
205  auto perfLog{fixture.perfLog(WithFile::yes)};
+
206 
+
207  BEAST_EXPECT(fixture.stopSignaled == false);
+
208  BEAST_EXPECT(exists(fixture.logFile()));
+
209  }
+
210  {
+
211  // Create a file where PerfLog wants to put its directory.
+
212  // Make sure that PerfLog tries to shutdown the server since it
+
213  // can't open its file.
+
214  Fixture fixture{env_.app(), j_};
+
215  if (!BEAST_EXPECT(!exists(fixture.logDir())))
+
216  return;
+
217 
+
218  {
+
219  // Make a file that prevents PerfLog from creating its file.
+
220  std::ofstream nastyFile;
+
221  nastyFile.open(
+
222  fixture.logDir().c_str(), std::ios::out | std::ios::app);
+
223  if (!BEAST_EXPECT(nastyFile))
+
224  return;
+
225  nastyFile.close();
+
226  }
+
227 
+
228  // Now construct a PerfLog. The PerfLog should attempt to shut
+
229  // down the server because it can't open its file.
+
230  BEAST_EXPECT(fixture.stopSignaled == false);
+
231  auto perfLog{fixture.perfLog(WithFile::yes)};
+
232  BEAST_EXPECT(fixture.stopSignaled == true);
+
233 
+
234  // Start PerfLog and wait long enough for PerfLog::report()
+
235  // to not be able to write to its file. That should cause no
+
236  // problems.
+
237  perfLog->start();
+
238  std::this_thread::sleep_for(fixture.logInterval() * 10);
+
239  perfLog->stop();
+
240 
+
241  // Remove the file.
+
242  remove(fixture.logDir());
+
243  }
+
244  {
+
245  // Put a write protected file where PerfLog wants to write its
+
246  // file. Make sure that PerfLog tries to shutdown the server
+
247  // since it can't open its file.
+
248  Fixture fixture{env_.app(), j_};
+
249  if (!BEAST_EXPECT(!exists(fixture.logDir())))
+
250  return;
+
251 
+
252  // Construct and write protect a file to prevent PerfLog
+
253  // from creating its file.
+
254  boost::system::error_code ec;
+
255  boost::filesystem::create_directories(fixture.logDir(), ec);
+
256  if (!BEAST_EXPECT(!ec))
+
257  return;
+
258 
+
259  auto fileWriteable = [](boost::filesystem::path const& p) -> bool {
+
260  return std::ofstream{p.c_str(), std::ios::out | std::ios::app}
+
261  .is_open();
+
262  };
+
263 
+
264  if (!BEAST_EXPECT(fileWriteable(fixture.logFile())))
+
265  return;
+
266 
+
267  boost::filesystem::permissions(
+
268  fixture.logFile(),
+
269  perms::remove_perms | perms::owner_write | perms::others_write |
+
270  perms::group_write);
+
271 
+
272  // If the test is running as root, then the write protect may have
+
273  // no effect. Make sure write protect worked before proceeding.
+
274  if (fileWriteable(fixture.logFile()))
+
275  {
+
276  log << "Unable to write protect file. Test skipped."
+
277  << std::endl;
+
278  return;
+
279  }
+
280 
+
281  // Now construct a PerfLog. The PerfLog should attempt to shut
+
282  // down the server because it can't open its file.
+
283  BEAST_EXPECT(fixture.stopSignaled == false);
+
284  auto perfLog{fixture.perfLog(WithFile::yes)};
+
285  BEAST_EXPECT(fixture.stopSignaled == true);
+
286 
+
287  // Start PerfLog and wait long enough for PerfLog::report()
+
288  // to not be able to write to its file. That should cause no
+
289  // problems.
+
290  perfLog->start();
+
291  std::this_thread::sleep_for(fixture.logInterval() * 10);
+
292  perfLog->stop();
+
293 
+
294  // Fix file permissions so the file can be cleaned up.
+
295  boost::filesystem::permissions(
+
296  fixture.logFile(),
+
297  perms::add_perms | perms::owner_write | perms::others_write |
+
298  perms::group_write);
+
299  }
+
300  }
+
301 
+
302  void
+
303  testRPC(WithFile withFile)
+
304  {
+
305  // Exercise the rpc interfaces of PerfLog.
+
306  // Start up the PerfLog that we'll use for testing.
+
307  Fixture fixture{env_.app(), j_};
+
308  auto perfLog{fixture.perfLog(withFile)};
+
309  perfLog->start();
+
310 
+
311  // Get the all the labels we can use for RPC interfaces without
+
312  // causing an assert.
+
313  std::vector<char const*> labels =
+
314  test::jtx::make_vector(ripple::RPC::getHandlerNames());
+
315  std::shuffle(labels.begin(), labels.end(), default_prng());
+
316 
+
317  // Get two IDs to associate with each label. Errors tend to happen at
+
318  // boundaries, so we pick IDs starting from zero and ending at
+
319  // std::uint64_t>::max().
+
320  std::vector<std::uint64_t> ids;
+
321  ids.reserve(labels.size() * 2);
+
322  std::generate_n(
+
323  std::back_inserter(ids),
+
324  labels.size(),
+
325  [i = std::numeric_limits<std::uint64_t>::min()]() mutable {
+
326  return i++;
+
327  });
+
328  std::generate_n(
+
329  std::back_inserter(ids),
+
330  labels.size(),
+
331  [i = std::numeric_limits<std::uint64_t>::max()]() mutable {
+
332  return i--;
+
333  });
+
334  std::shuffle(ids.begin(), ids.end(), default_prng());
+
335 
+
336  // Start all of the RPC commands twice to show they can all be tracked
+
337  // simultaneously.
+
338  for (int labelIndex = 0; labelIndex < labels.size(); ++labelIndex)
+
339  {
+
340  for (int idIndex = 0; idIndex < 2; ++idIndex)
+
341  {
+
342  std::this_thread::sleep_for(std::chrono::microseconds(10));
+
343  perfLog->rpcStart(
+
344  labels[labelIndex], ids[(labelIndex * 2) + idIndex]);
+
345  }
+
346  }
+
347  {
+
348  // Examine current PerfLog::counterJson() values.
+
349  Json::Value const countersJson{perfLog->countersJson()[jss::rpc]};
+
350  BEAST_EXPECT(countersJson.size() == labels.size() + 1);
+
351  for (auto& label : labels)
+
352  {
+
353  // Expect every label in labels to have the same contents.
+
354  Json::Value const& counter{countersJson[label]};
+
355  BEAST_EXPECT(counter[jss::duration_us] == "0");
+
356  BEAST_EXPECT(counter[jss::errored] == "0");
+
357  BEAST_EXPECT(counter[jss::finished] == "0");
+
358  BEAST_EXPECT(counter[jss::started] == "2");
+
359  }
+
360  // Expect "total" to have a lot of "started"
+
361  Json::Value const& total{countersJson[jss::total]};
+
362  BEAST_EXPECT(total[jss::duration_us] == "0");
+
363  BEAST_EXPECT(total[jss::errored] == "0");
+
364  BEAST_EXPECT(total[jss::finished] == "0");
+
365  BEAST_EXPECT(jsonToUint64(total[jss::started]) == ids.size());
+
366  }
+
367  {
+
368  // Verify that every entry in labels appears twice in currents.
+
369  // If we sort by duration_us they should be in the order the
+
370  // rpcStart() call was made.
+
371  std::vector<Cur> const currents{
+
372  getSortedCurrent(perfLog->currentJson()[jss::methods])};
+
373  BEAST_EXPECT(currents.size() == labels.size() * 2);
+
374 
+
375  std::uint64_t prevDur = std::numeric_limits<std::uint64_t>::max();
+
376  for (int i = 0; i < currents.size(); ++i)
+
377  {
+
378  BEAST_EXPECT(currents[i].name == labels[i / 2]);
+
379  BEAST_EXPECT(prevDur > currents[i].dur);
+
380  prevDur = currents[i].dur;
+
381  }
+
382  }
+
383 
+
384  // Finish all but the first RPC command in reverse order to show that
+
385  // the start and finish of the commands can interleave. Half of the
+
386  // commands finish correctly, the other half with errors.
+
387  for (int labelIndex = labels.size() - 1; labelIndex > 0; --labelIndex)
+
388  {
389  std::this_thread::sleep_for(std::chrono::microseconds(10));
-
390  perfLog->rpcError(labels[labelIndex], ids[(labelIndex * 2) + 0]);
-
391  }
-
392  perfLog->rpcFinish(labels[0], ids[0 + 1]);
-
393  // Note that label[0] id[0] is intentionally left unfinished.
-
394 
-
395  auto validateFinalCounters = [this, &labels](
-
396  Json::Value const& countersJson) {
-
397  {
-
398  Json::Value const& jobQueue = countersJson[jss::job_queue];
-
399  BEAST_EXPECT(jobQueue.isObject());
-
400  BEAST_EXPECT(jobQueue.size() == 0);
-
401  }
-
402 
-
403  Json::Value const& rpc = countersJson[jss::rpc];
-
404  BEAST_EXPECT(rpc.size() == labels.size() + 1);
-
405 
-
406  // Verify that every entry in labels appears in rpc.
-
407  // If we access the entries by label we should be able to correlate
-
408  // their durations with the appropriate labels.
-
409  {
-
410  // The first label is special. It should have "errored" : "0".
-
411  Json::Value const& first = rpc[labels[0]];
-
412  BEAST_EXPECT(first[jss::duration_us] != "0");
-
413  BEAST_EXPECT(first[jss::errored] == "0");
-
414  BEAST_EXPECT(first[jss::finished] == "1");
-
415  BEAST_EXPECT(first[jss::started] == "2");
-
416  }
-
417 
-
418  // Check the rest of the labels.
-
419  std::uint64_t prevDur = std::numeric_limits<std::uint64_t>::max();
-
420  for (int i = 1; i < labels.size(); ++i)
-
421  {
-
422  Json::Value const& counter{rpc[labels[i]]};
-
423  std::uint64_t const dur{
-
424  jsonToUint64(counter[jss::duration_us])};
-
425  BEAST_EXPECT(dur != 0 && dur < prevDur);
-
426  prevDur = dur;
-
427  BEAST_EXPECT(counter[jss::errored] == "1");
-
428  BEAST_EXPECT(counter[jss::finished] == "1");
-
429  BEAST_EXPECT(counter[jss::started] == "2");
-
430  }
-
431 
-
432  // Check "total"
-
433  Json::Value const& total{rpc[jss::total]};
-
434  BEAST_EXPECT(total[jss::duration_us] != "0");
-
435  BEAST_EXPECT(
-
436  jsonToUint64(total[jss::errored]) == labels.size() - 1);
-
437  BEAST_EXPECT(jsonToUint64(total[jss::finished]) == labels.size());
-
438  BEAST_EXPECT(
-
439  jsonToUint64(total[jss::started]) == labels.size() * 2);
-
440  };
-
441 
-
442  auto validateFinalCurrent = [this,
-
443  &labels](Json::Value const& currentJson) {
-
444  {
-
445  Json::Value const& job_queue = currentJson[jss::jobs];
-
446  BEAST_EXPECT(job_queue.isArray());
-
447  BEAST_EXPECT(job_queue.size() == 0);
-
448  }
-
449 
-
450  Json::Value const& methods = currentJson[jss::methods];
-
451  BEAST_EXPECT(methods.size() == 1);
-
452  BEAST_EXPECT(methods.isArray());
-
453 
-
454  Json::Value const& only = methods[0u];
-
455  BEAST_EXPECT(only.size() == 2);
-
456  BEAST_EXPECT(only.isObject());
-
457  BEAST_EXPECT(only[jss::duration_us] != "0");
-
458  BEAST_EXPECT(only[jss::method] == labels[0]);
-
459  };
-
460 
-
461  // Validate the final state of the PerfLog.
-
462  validateFinalCounters(perfLog->countersJson());
-
463  validateFinalCurrent(perfLog->currentJson());
-
464 
-
465  // Give the PerfLog enough time to flush it's state to the file.
-
466  fixture.wait();
-
467 
-
468  // Politely stop the PerfLog.
-
469  perfLog->stop();
-
470 
-
471  auto const fullPath = fixture.logFile();
+
390  perfLog->rpcFinish(labels[labelIndex], ids[(labelIndex * 2) + 1]);
+
391  std::this_thread::sleep_for(std::chrono::microseconds(10));
+
392  perfLog->rpcError(labels[labelIndex], ids[(labelIndex * 2) + 0]);
+
393  }
+
394  perfLog->rpcFinish(labels[0], ids[0 + 1]);
+
395  // Note that label[0] id[0] is intentionally left unfinished.
+
396 
+
397  auto validateFinalCounters = [this, &labels](
+
398  Json::Value const& countersJson) {
+
399  {
+
400  Json::Value const& jobQueue = countersJson[jss::job_queue];
+
401  BEAST_EXPECT(jobQueue.isObject());
+
402  BEAST_EXPECT(jobQueue.size() == 0);
+
403  }
+
404 
+
405  Json::Value const& rpc = countersJson[jss::rpc];
+
406  BEAST_EXPECT(rpc.size() == labels.size() + 1);
+
407 
+
408  // Verify that every entry in labels appears in rpc.
+
409  // If we access the entries by label we should be able to correlate
+
410  // their durations with the appropriate labels.
+
411  {
+
412  // The first label is special. It should have "errored" : "0".
+
413  Json::Value const& first = rpc[labels[0]];
+
414  BEAST_EXPECT(first[jss::duration_us] != "0");
+
415  BEAST_EXPECT(first[jss::errored] == "0");
+
416  BEAST_EXPECT(first[jss::finished] == "1");
+
417  BEAST_EXPECT(first[jss::started] == "2");
+
418  }
+
419 
+
420  // Check the rest of the labels.
+
421  std::uint64_t prevDur = std::numeric_limits<std::uint64_t>::max();
+
422  for (int i = 1; i < labels.size(); ++i)
+
423  {
+
424  Json::Value const& counter{rpc[labels[i]]};
+
425  std::uint64_t const dur{
+
426  jsonToUint64(counter[jss::duration_us])};
+
427  BEAST_EXPECT(dur != 0 && dur < prevDur);
+
428  prevDur = dur;
+
429  BEAST_EXPECT(counter[jss::errored] == "1");
+
430  BEAST_EXPECT(counter[jss::finished] == "1");
+
431  BEAST_EXPECT(counter[jss::started] == "2");
+
432  }
+
433 
+
434  // Check "total"
+
435  Json::Value const& total{rpc[jss::total]};
+
436  BEAST_EXPECT(total[jss::duration_us] != "0");
+
437  BEAST_EXPECT(
+
438  jsonToUint64(total[jss::errored]) == labels.size() - 1);
+
439  BEAST_EXPECT(jsonToUint64(total[jss::finished]) == labels.size());
+
440  BEAST_EXPECT(
+
441  jsonToUint64(total[jss::started]) == labels.size() * 2);
+
442  };
+
443 
+
444  auto validateFinalCurrent = [this,
+
445  &labels](Json::Value const& currentJson) {
+
446  {
+
447  Json::Value const& job_queue = currentJson[jss::jobs];
+
448  BEAST_EXPECT(job_queue.isArray());
+
449  BEAST_EXPECT(job_queue.size() == 0);
+
450  }
+
451 
+
452  Json::Value const& methods = currentJson[jss::methods];
+
453  BEAST_EXPECT(methods.size() == 1);
+
454  BEAST_EXPECT(methods.isArray());
+
455 
+
456  Json::Value const& only = methods[0u];
+
457  BEAST_EXPECT(only.size() == 2);
+
458  BEAST_EXPECT(only.isObject());
+
459  BEAST_EXPECT(only[jss::duration_us] != "0");
+
460  BEAST_EXPECT(only[jss::method] == labels[0]);
+
461  };
+
462 
+
463  // Validate the final state of the PerfLog.
+
464  validateFinalCounters(perfLog->countersJson());
+
465  validateFinalCurrent(perfLog->currentJson());
+
466 
+
467  // Give the PerfLog enough time to flush it's state to the file.
+
468  fixture.wait();
+
469 
+
470  // Politely stop the PerfLog.
+
471  perfLog->stop();
472 
-
473  if (withFile == WithFile::no)
-
474  {
-
475  BEAST_EXPECT(!exists(fullPath));
-
476  }
-
477  else
-
478  {
-
479  // The last line in the log file should contain the same
-
480  // information that countersJson() and currentJson() returned.
-
481  // Verify that.
-
482 
-
483  // Get the last line of the log.
-
484  std::ifstream logStream(fullPath.c_str());
-
485  std::string lastLine;
-
486  for (std::string line; std::getline(logStream, line);)
-
487  {
-
488  if (!line.empty())
-
489  lastLine = std::move(line);
-
490  }
-
491 
-
492  Json::Value parsedLastLine;
-
493  Json::Reader().parse(lastLine, parsedLastLine);
-
494  if (!BEAST_EXPECT(!RPC::contains_error(parsedLastLine)))
-
495  // Avoid cascade of failures
-
496  return;
-
497 
-
498  // Validate the contents of the last line of the log.
-
499  validateFinalCounters(parsedLastLine[jss::counters]);
-
500  validateFinalCurrent(parsedLastLine[jss::current_activities]);
-
501  }
-
502  }
-
503 
-
504  void
-
505  testJobs(WithFile withFile)
-
506  {
-
507  using namespace std::chrono;
-
508 
-
509  // Exercise the jobs interfaces of PerfLog.
-
510  // Start up the PerfLog that we'll use for testing.
-
511  Fixture fixture{env_.app(), j_};
-
512  auto perfLog{fixture.perfLog(withFile)};
-
513  perfLog->start();
-
514 
-
515  // Get the all the JobTypes we can use to call the jobs interfaces
-
516  // without causing an assert.
-
517  struct JobName
-
518  {
-
519  JobType type;
-
520  std::string typeName;
-
521 
-
522  JobName(JobType t, std::string name)
-
523  : type(t), typeName(std::move(name))
-
524  {
-
525  }
-
526  };
-
527 
-
528  std::vector<JobName> jobs;
-
529  {
-
530  auto const& jobTypes = JobTypes::instance();
-
531  jobs.reserve(jobTypes.size());
-
532  for (auto const& job : jobTypes)
-
533  {
-
534  jobs.emplace_back(job.first, job.second.name());
-
535  }
-
536  }
-
537  std::shuffle(jobs.begin(), jobs.end(), default_prng());
-
538 
-
539  // Walk through all of the jobs, enqueuing every job once. Check
-
540  // the jobs data with every addition.
-
541  for (int i = 0; i < jobs.size(); ++i)
-
542  {
-
543  perfLog->jobQueue(jobs[i].type);
-
544  Json::Value const jq_counters{
-
545  perfLog->countersJson()[jss::job_queue]};
-
546 
-
547  BEAST_EXPECT(jq_counters.size() == i + 2);
-
548  for (int j = 0; j <= i; ++j)
-
549  {
-
550  // Verify all expected counters are present and contain
-
551  // expected values.
-
552  Json::Value const& counter{jq_counters[jobs[j].typeName]};
-
553  BEAST_EXPECT(counter.size() == 5);
-
554  BEAST_EXPECT(counter[jss::queued] == "1");
-
555  BEAST_EXPECT(counter[jss::started] == "0");
-
556  BEAST_EXPECT(counter[jss::finished] == "0");
-
557  BEAST_EXPECT(counter[jss::queued_duration_us] == "0");
-
558  BEAST_EXPECT(counter[jss::running_duration_us] == "0");
-
559  }
-
560 
-
561  // Verify jss::total is present and has expected values.
-
562  Json::Value const& total{jq_counters[jss::total]};
-
563  BEAST_EXPECT(total.size() == 5);
-
564  BEAST_EXPECT(jsonToUint64(total[jss::queued]) == i + 1);
-
565  BEAST_EXPECT(total[jss::started] == "0");
-
566  BEAST_EXPECT(total[jss::finished] == "0");
-
567  BEAST_EXPECT(total[jss::queued_duration_us] == "0");
-
568  BEAST_EXPECT(total[jss::running_duration_us] == "0");
-
569  }
-
570 
-
571  // Even with jobs queued, the perfLog should report nothing current.
-
572  {
-
573  Json::Value current{perfLog->currentJson()};
-
574  BEAST_EXPECT(current.size() == 2);
-
575  BEAST_EXPECT(current.isMember(jss::jobs));
-
576  BEAST_EXPECT(current[jss::jobs].size() == 0);
-
577  BEAST_EXPECT(current.isMember(jss::methods));
-
578  BEAST_EXPECT(current[jss::methods].size() == 0);
-
579  }
-
580 
-
581  // Current jobs are tracked by Worker ID. Even though it's not
-
582  // realistic, crank up the number of workers so we can have many
-
583  // jobs in process simultaneously without problems.
-
584  perfLog->resizeJobs(jobs.size() * 2);
-
585 
-
586  // Start two instances of every job to show that the same job can run
-
587  // simultaneously (on different Worker threads). Admittedly, this
-
588  // will make the jss::queued count look a bit goofy since there will
-
589  // be half as many queued as started...
-
590  for (int i = 0; i < jobs.size(); ++i)
-
591  {
-
592  perfLog->jobStart(
-
593  jobs[i].type, microseconds{i + 1}, steady_clock::now(), i * 2);
-
594  std::this_thread::sleep_for(microseconds(10));
-
595 
-
596  // Check each jobType counter entry.
-
597  Json::Value const jq_counters{
-
598  perfLog->countersJson()[jss::job_queue]};
-
599  for (int j = 0; j < jobs.size(); ++j)
-
600  {
-
601  Json::Value const& counter{jq_counters[jobs[j].typeName]};
-
602  std::uint64_t const queued_dur_us{
-
603  jsonToUint64(counter[jss::queued_duration_us])};
-
604  if (j < i)
-
605  {
-
606  BEAST_EXPECT(counter[jss::started] == "2");
-
607  BEAST_EXPECT(queued_dur_us == j + 1);
-
608  }
-
609  else if (j == i)
-
610  {
-
611  BEAST_EXPECT(counter[jss::started] == "1");
-
612  BEAST_EXPECT(queued_dur_us == j + 1);
-
613  }
-
614  else
-
615  {
-
616  BEAST_EXPECT(counter[jss::started] == "0");
-
617  BEAST_EXPECT(queued_dur_us == 0);
-
618  }
-
619 
-
620  BEAST_EXPECT(counter[jss::queued] == "1");
-
621  BEAST_EXPECT(counter[jss::finished] == "0");
-
622  BEAST_EXPECT(counter[jss::running_duration_us] == "0");
-
623  }
-
624  {
-
625  // Verify values in jss::total are what we expect.
-
626  Json::Value const& total{jq_counters[jss::total]};
-
627  BEAST_EXPECT(jsonToUint64(total[jss::queued]) == jobs.size());
-
628  BEAST_EXPECT(jsonToUint64(total[jss::started]) == (i * 2) + 1);
-
629  BEAST_EXPECT(total[jss::finished] == "0");
-
630 
-
631  // Total queued duration is triangle number of (i + 1).
-
632  BEAST_EXPECT(
-
633  jsonToUint64(total[jss::queued_duration_us]) ==
-
634  (((i * i) + 3 * i + 2) / 2));
-
635  BEAST_EXPECT(total[jss::running_duration_us] == "0");
-
636  }
-
637 
-
638  perfLog->jobStart(
-
639  jobs[i].type,
-
640  microseconds{0},
-
641  steady_clock::now(),
-
642  (i * 2) + 1);
-
643  std::this_thread::sleep_for(microseconds{10});
-
644 
-
645  // Verify that every entry in jobs appears twice in currents.
-
646  // If we sort by duration_us they should be in the order the
-
647  // rpcStart() call was made.
-
648  std::vector<Cur> const currents{
-
649  getSortedCurrent(perfLog->currentJson()[jss::jobs])};
-
650  BEAST_EXPECT(currents.size() == (i + 1) * 2);
-
651 
-
652  std::uint64_t prevDur = std::numeric_limits<std::uint64_t>::max();
-
653  for (int j = 0; j <= i; ++j)
-
654  {
-
655  BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
-
656  BEAST_EXPECT(prevDur > currents[j * 2].dur);
-
657  prevDur = currents[j * 2].dur;
-
658 
-
659  BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
-
660  BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
-
661  prevDur = currents[(j * 2) + 1].dur;
-
662  }
-
663  }
-
664 
-
665  // Finish every job we started. Finish them in reverse.
-
666  for (int i = jobs.size() - 1; i >= 0; --i)
-
667  {
-
668  // A number of the computations in this loop care about the
-
669  // number of jobs that have finished. Make that available.
-
670  int const finished = ((jobs.size() - i) * 2) - 1;
-
671  perfLog->jobFinish(
-
672  jobs[i].type, microseconds(finished), (i * 2) + 1);
-
673  std::this_thread::sleep_for(microseconds(10));
-
674 
-
675  Json::Value const jq_counters{
-
676  perfLog->countersJson()[jss::job_queue]};
-
677  for (int j = 0; j < jobs.size(); ++j)
-
678  {
-
679  Json::Value const& counter{jq_counters[jobs[j].typeName]};
-
680  std::uint64_t const running_dur_us{
-
681  jsonToUint64(counter[jss::running_duration_us])};
-
682  if (j < i)
-
683  {
-
684  BEAST_EXPECT(counter[jss::finished] == "0");
-
685  BEAST_EXPECT(running_dur_us == 0);
-
686  }
-
687  else if (j == i)
-
688  {
-
689  BEAST_EXPECT(counter[jss::finished] == "1");
-
690  BEAST_EXPECT(running_dur_us == ((jobs.size() - j) * 2) - 1);
-
691  }
-
692  else
-
693  {
-
694  BEAST_EXPECT(counter[jss::finished] == "2");
-
695  BEAST_EXPECT(running_dur_us == ((jobs.size() - j) * 4) - 1);
-
696  }
-
697 
-
698  std::uint64_t const queued_dur_us{
-
699  jsonToUint64(counter[jss::queued_duration_us])};
-
700  BEAST_EXPECT(queued_dur_us == j + 1);
-
701  BEAST_EXPECT(counter[jss::queued] == "1");
-
702  BEAST_EXPECT(counter[jss::started] == "2");
-
703  }
-
704  {
-
705  // Verify values in jss::total are what we expect.
-
706  Json::Value const& total{jq_counters[jss::total]};
-
707  BEAST_EXPECT(jsonToUint64(total[jss::queued]) == jobs.size());
-
708  BEAST_EXPECT(
-
709  jsonToUint64(total[jss::started]) == jobs.size() * 2);
-
710  BEAST_EXPECT(jsonToUint64(total[jss::finished]) == finished);
-
711 
-
712  // Total queued duration should be triangle number of
-
713  // jobs.size().
-
714  int const queuedDur = ((jobs.size() * (jobs.size() + 1)) / 2);
-
715  BEAST_EXPECT(
-
716  jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
-
717 
-
718  // Total running duration should be triangle number of finished.
-
719  int const runningDur = ((finished * (finished + 1)) / 2);
-
720  BEAST_EXPECT(
-
721  jsonToUint64(total[jss::running_duration_us]) ==
-
722  runningDur);
-
723  }
-
724 
-
725  perfLog->jobFinish(
-
726  jobs[i].type, microseconds(finished + 1), (i * 2));
-
727  std::this_thread::sleep_for(microseconds(10));
-
728 
-
729  // Verify that the two jobs we just finished no longer appear in
-
730  // currents.
-
731  std::vector<Cur> const currents{
-
732  getSortedCurrent(perfLog->currentJson()[jss::jobs])};
-
733  BEAST_EXPECT(currents.size() == i * 2);
-
734 
-
735  std::uint64_t prevDur = std::numeric_limits<std::uint64_t>::max();
-
736  for (int j = 0; j < i; ++j)
-
737  {
-
738  BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
-
739  BEAST_EXPECT(prevDur > currents[j * 2].dur);
-
740  prevDur = currents[j * 2].dur;
-
741 
-
742  BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
-
743  BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
-
744  prevDur = currents[(j * 2) + 1].dur;
-
745  }
-
746  }
-
747 
-
748  // Validate the final results.
-
749  auto validateFinalCounters = [this,
-
750  &jobs](Json::Value const& countersJson) {
-
751  {
-
752  Json::Value const& rpc = countersJson[jss::rpc];
-
753  BEAST_EXPECT(rpc.isObject());
-
754  BEAST_EXPECT(rpc.size() == 0);
-
755  }
-
756 
-
757  Json::Value const& jobQueue = countersJson[jss::job_queue];
-
758  for (int i = jobs.size() - 1; i >= 0; --i)
-
759  {
-
760  Json::Value const& counter{jobQueue[jobs[i].typeName]};
-
761  std::uint64_t const running_dur_us{
-
762  jsonToUint64(counter[jss::running_duration_us])};
-
763  BEAST_EXPECT(running_dur_us == ((jobs.size() - i) * 4) - 1);
-
764 
-
765  std::uint64_t const queued_dur_us{
-
766  jsonToUint64(counter[jss::queued_duration_us])};
-
767  BEAST_EXPECT(queued_dur_us == i + 1);
-
768 
-
769  BEAST_EXPECT(counter[jss::queued] == "1");
-
770  BEAST_EXPECT(counter[jss::started] == "2");
-
771  BEAST_EXPECT(counter[jss::finished] == "2");
-
772  }
-
773 
-
774  // Verify values in jss::total are what we expect.
-
775  Json::Value const& total{jobQueue[jss::total]};
-
776  const int finished = jobs.size() * 2;
-
777  BEAST_EXPECT(jsonToUint64(total[jss::queued]) == jobs.size());
-
778  BEAST_EXPECT(jsonToUint64(total[jss::started]) == finished);
-
779  BEAST_EXPECT(jsonToUint64(total[jss::finished]) == finished);
-
780 
-
781  // Total queued duration should be triangle number of
-
782  // jobs.size().
-
783  int const queuedDur = ((jobs.size() * (jobs.size() + 1)) / 2);
-
784  BEAST_EXPECT(
-
785  jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
-
786 
-
787  // Total running duration should be triangle number of finished.
-
788  int const runningDur = ((finished * (finished + 1)) / 2);
-
789  BEAST_EXPECT(
-
790  jsonToUint64(total[jss::running_duration_us]) == runningDur);
-
791  };
-
792 
-
793  auto validateFinalCurrent = [this](Json::Value const& currentJson) {
-
794  {
-
795  Json::Value const& j = currentJson[jss::jobs];
-
796  BEAST_EXPECT(j.isArray());
-
797  BEAST_EXPECT(j.size() == 0);
-
798  }
-
799 
-
800  Json::Value const& methods = currentJson[jss::methods];
-
801  BEAST_EXPECT(methods.size() == 0);
-
802  BEAST_EXPECT(methods.isArray());
-
803  };
-
804 
-
805  // Validate the final state of the PerfLog.
-
806  validateFinalCounters(perfLog->countersJson());
-
807  validateFinalCurrent(perfLog->currentJson());
-
808 
-
809  // Give the PerfLog enough time to flush it's state to the file.
-
810  fixture.wait();
-
811 
-
812  // Politely stop the PerfLog.
-
813  perfLog->stop();
-
814 
-
815  // Check file contents if that is appropriate.
-
816  auto const fullPath = fixture.logFile();
-
817 
-
818  if (withFile == WithFile::no)
-
819  {
-
820  BEAST_EXPECT(!exists(fullPath));
-
821  }
-
822  else
-
823  {
-
824  // The last line in the log file should contain the same
-
825  // information that countersJson() and currentJson() returned.
-
826  // Verify that.
-
827 
-
828  // Get the last line of the log.
-
829  std::ifstream logStream(fullPath.c_str());
-
830  std::string lastLine;
-
831  for (std::string line; std::getline(logStream, line);)
-
832  {
-
833  if (!line.empty())
-
834  lastLine = std::move(line);
-
835  }
-
836 
-
837  Json::Value parsedLastLine;
-
838  Json::Reader().parse(lastLine, parsedLastLine);
-
839  if (!BEAST_EXPECT(!RPC::contains_error(parsedLastLine)))
-
840  // Avoid cascade of failures
-
841  return;
-
842 
-
843  // Validate the contents of the last line of the log.
-
844  validateFinalCounters(parsedLastLine[jss::counters]);
-
845  validateFinalCurrent(parsedLastLine[jss::current_activities]);
-
846  }
-
847  }
-
848 
-
849  void
-
850  testInvalidID(WithFile withFile)
-
851  {
-
852  using namespace std::chrono;
-
853 
-
854  // The Worker ID is used to identify jobs in progress. Show that
-
855  // the PerLog behaves as well as possible if an invalid ID is passed.
-
856 
-
857  // Start up the PerfLog that we'll use for testing.
-
858  Fixture fixture{env_.app(), j_};
-
859  auto perfLog{fixture.perfLog(withFile)};
-
860  perfLog->start();
-
861 
-
862  // Randomly select a job type and its name.
-
863  JobType jobType;
-
864  std::string jobTypeName;
-
865  {
-
866  auto const& jobTypes = JobTypes::instance();
-
867 
-
868  std::uniform_int_distribution<> dis(0, jobTypes.size() - 1);
-
869  auto iter{jobTypes.begin()};
-
870  std::advance(iter, dis(default_prng()));
-
871 
-
872  jobType = iter->second.type();
-
873  jobTypeName = iter->second.name();
-
874  }
-
875 
-
876  // Say there's one worker thread.
-
877  perfLog->resizeJobs(1);
-
878 
-
879  // Lambda to validate countersJson for this test.
-
880  auto verifyCounters = [this, jobTypeName](
-
881  Json::Value const& countersJson,
-
882  int started,
-
883  int finished,
-
884  int queued_us,
-
885  int running_us) {
-
886  BEAST_EXPECT(countersJson.isObject());
-
887  BEAST_EXPECT(countersJson.size() == 2);
-
888 
-
889  BEAST_EXPECT(countersJson.isMember(jss::rpc));
-
890  BEAST_EXPECT(countersJson[jss::rpc].isObject());
-
891  BEAST_EXPECT(countersJson[jss::rpc].size() == 0);
-
892 
-
893  BEAST_EXPECT(countersJson.isMember(jss::job_queue));
-
894  BEAST_EXPECT(countersJson[jss::job_queue].isObject());
-
895  BEAST_EXPECT(countersJson[jss::job_queue].size() == 1);
-
896  {
-
897  Json::Value const& job{
-
898  countersJson[jss::job_queue][jobTypeName]};
-
899 
-
900  BEAST_EXPECT(job.isObject());
-
901  BEAST_EXPECT(jsonToUint64(job[jss::queued]) == 0);
-
902  BEAST_EXPECT(jsonToUint64(job[jss::started]) == started);
-
903  BEAST_EXPECT(jsonToUint64(job[jss::finished]) == finished);
-
904 
-
905  BEAST_EXPECT(
-
906  jsonToUint64(job[jss::queued_duration_us]) == queued_us);
+
473  auto const fullPath = fixture.logFile();
+
474 
+
475  if (withFile == WithFile::no)
+
476  {
+
477  BEAST_EXPECT(!exists(fullPath));
+
478  }
+
479  else
+
480  {
+
481  // The last line in the log file should contain the same
+
482  // information that countersJson() and currentJson() returned.
+
483  // Verify that.
+
484 
+
485  // Get the last line of the log.
+
486  std::ifstream logStream(fullPath.c_str());
+
487  std::string lastLine;
+
488  for (std::string line; std::getline(logStream, line);)
+
489  {
+
490  if (!line.empty())
+
491  lastLine = std::move(line);
+
492  }
+
493 
+
494  Json::Value parsedLastLine;
+
495  Json::Reader().parse(lastLine, parsedLastLine);
+
496  if (!BEAST_EXPECT(!RPC::contains_error(parsedLastLine)))
+
497  // Avoid cascade of failures
+
498  return;
+
499 
+
500  // Validate the contents of the last line of the log.
+
501  validateFinalCounters(parsedLastLine[jss::counters]);
+
502  validateFinalCurrent(parsedLastLine[jss::current_activities]);
+
503  }
+
504  }
+
505 
+
506  void
+
507  testJobs(WithFile withFile)
+
508  {
+
509  using namespace std::chrono;
+
510 
+
511  // Exercise the jobs interfaces of PerfLog.
+
512  // Start up the PerfLog that we'll use for testing.
+
513  Fixture fixture{env_.app(), j_};
+
514  auto perfLog{fixture.perfLog(withFile)};
+
515  perfLog->start();
+
516 
+
517  // Get the all the JobTypes we can use to call the jobs interfaces
+
518  // without causing an assert.
+
519  struct JobName
+
520  {
+
521  JobType type;
+
522  std::string typeName;
+
523 
+
524  JobName(JobType t, std::string name)
+
525  : type(t), typeName(std::move(name))
+
526  {
+
527  }
+
528  };
+
529 
+
530  std::vector<JobName> jobs;
+
531  {
+
532  auto const& jobTypes = JobTypes::instance();
+
533  jobs.reserve(jobTypes.size());
+
534  for (auto const& job : jobTypes)
+
535  {
+
536  jobs.emplace_back(job.first, job.second.name());
+
537  }
+
538  }
+
539  std::shuffle(jobs.begin(), jobs.end(), default_prng());
+
540 
+
541  // Walk through all of the jobs, enqueuing every job once. Check
+
542  // the jobs data with every addition.
+
543  for (int i = 0; i < jobs.size(); ++i)
+
544  {
+
545  perfLog->jobQueue(jobs[i].type);
+
546  Json::Value const jq_counters{
+
547  perfLog->countersJson()[jss::job_queue]};
+
548 
+
549  BEAST_EXPECT(jq_counters.size() == i + 2);
+
550  for (int j = 0; j <= i; ++j)
+
551  {
+
552  // Verify all expected counters are present and contain
+
553  // expected values.
+
554  Json::Value const& counter{jq_counters[jobs[j].typeName]};
+
555  BEAST_EXPECT(counter.size() == 5);
+
556  BEAST_EXPECT(counter[jss::queued] == "1");
+
557  BEAST_EXPECT(counter[jss::started] == "0");
+
558  BEAST_EXPECT(counter[jss::finished] == "0");
+
559  BEAST_EXPECT(counter[jss::queued_duration_us] == "0");
+
560  BEAST_EXPECT(counter[jss::running_duration_us] == "0");
+
561  }
+
562 
+
563  // Verify jss::total is present and has expected values.
+
564  Json::Value const& total{jq_counters[jss::total]};
+
565  BEAST_EXPECT(total.size() == 5);
+
566  BEAST_EXPECT(jsonToUint64(total[jss::queued]) == i + 1);
+
567  BEAST_EXPECT(total[jss::started] == "0");
+
568  BEAST_EXPECT(total[jss::finished] == "0");
+
569  BEAST_EXPECT(total[jss::queued_duration_us] == "0");
+
570  BEAST_EXPECT(total[jss::running_duration_us] == "0");
+
571  }
+
572 
+
573  // Even with jobs queued, the perfLog should report nothing current.
+
574  {
+
575  Json::Value current{perfLog->currentJson()};
+
576  BEAST_EXPECT(current.size() == 2);
+
577  BEAST_EXPECT(current.isMember(jss::jobs));
+
578  BEAST_EXPECT(current[jss::jobs].size() == 0);
+
579  BEAST_EXPECT(current.isMember(jss::methods));
+
580  BEAST_EXPECT(current[jss::methods].size() == 0);
+
581  }
+
582 
+
583  // Current jobs are tracked by Worker ID. Even though it's not
+
584  // realistic, crank up the number of workers so we can have many
+
585  // jobs in process simultaneously without problems.
+
586  perfLog->resizeJobs(jobs.size() * 2);
+
587 
+
588  // Start two instances of every job to show that the same job can run
+
589  // simultaneously (on different Worker threads). Admittedly, this
+
590  // will make the jss::queued count look a bit goofy since there will
+
591  // be half as many queued as started...
+
592  for (int i = 0; i < jobs.size(); ++i)
+
593  {
+
594  perfLog->jobStart(
+
595  jobs[i].type, microseconds{i + 1}, steady_clock::now(), i * 2);
+
596  std::this_thread::sleep_for(microseconds(10));
+
597 
+
598  // Check each jobType counter entry.
+
599  Json::Value const jq_counters{
+
600  perfLog->countersJson()[jss::job_queue]};
+
601  for (int j = 0; j < jobs.size(); ++j)
+
602  {
+
603  Json::Value const& counter{jq_counters[jobs[j].typeName]};
+
604  std::uint64_t const queued_dur_us{
+
605  jsonToUint64(counter[jss::queued_duration_us])};
+
606  if (j < i)
+
607  {
+
608  BEAST_EXPECT(counter[jss::started] == "2");
+
609  BEAST_EXPECT(queued_dur_us == j + 1);
+
610  }
+
611  else if (j == i)
+
612  {
+
613  BEAST_EXPECT(counter[jss::started] == "1");
+
614  BEAST_EXPECT(queued_dur_us == j + 1);
+
615  }
+
616  else
+
617  {
+
618  BEAST_EXPECT(counter[jss::started] == "0");
+
619  BEAST_EXPECT(queued_dur_us == 0);
+
620  }
+
621 
+
622  BEAST_EXPECT(counter[jss::queued] == "1");
+
623  BEAST_EXPECT(counter[jss::finished] == "0");
+
624  BEAST_EXPECT(counter[jss::running_duration_us] == "0");
+
625  }
+
626  {
+
627  // Verify values in jss::total are what we expect.
+
628  Json::Value const& total{jq_counters[jss::total]};
+
629  BEAST_EXPECT(jsonToUint64(total[jss::queued]) == jobs.size());
+
630  BEAST_EXPECT(jsonToUint64(total[jss::started]) == (i * 2) + 1);
+
631  BEAST_EXPECT(total[jss::finished] == "0");
+
632 
+
633  // Total queued duration is triangle number of (i + 1).
+
634  BEAST_EXPECT(
+
635  jsonToUint64(total[jss::queued_duration_us]) ==
+
636  (((i * i) + 3 * i + 2) / 2));
+
637  BEAST_EXPECT(total[jss::running_duration_us] == "0");
+
638  }
+
639 
+
640  perfLog->jobStart(
+
641  jobs[i].type,
+
642  microseconds{0},
+
643  steady_clock::now(),
+
644  (i * 2) + 1);
+
645  std::this_thread::sleep_for(microseconds{10});
+
646 
+
647  // Verify that every entry in jobs appears twice in currents.
+
648  // If we sort by duration_us they should be in the order the
+
649  // rpcStart() call was made.
+
650  std::vector<Cur> const currents{
+
651  getSortedCurrent(perfLog->currentJson()[jss::jobs])};
+
652  BEAST_EXPECT(currents.size() == (i + 1) * 2);
+
653 
+
654  std::uint64_t prevDur = std::numeric_limits<std::uint64_t>::max();
+
655  for (int j = 0; j <= i; ++j)
+
656  {
+
657  BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
+
658  BEAST_EXPECT(prevDur > currents[j * 2].dur);
+
659  prevDur = currents[j * 2].dur;
+
660 
+
661  BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
+
662  BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
+
663  prevDur = currents[(j * 2) + 1].dur;
+
664  }
+
665  }
+
666 
+
667  // Finish every job we started. Finish them in reverse.
+
668  for (int i = jobs.size() - 1; i >= 0; --i)
+
669  {
+
670  // A number of the computations in this loop care about the
+
671  // number of jobs that have finished. Make that available.
+
672  int const finished = ((jobs.size() - i) * 2) - 1;
+
673  perfLog->jobFinish(
+
674  jobs[i].type, microseconds(finished), (i * 2) + 1);
+
675  std::this_thread::sleep_for(microseconds(10));
+
676 
+
677  Json::Value const jq_counters{
+
678  perfLog->countersJson()[jss::job_queue]};
+
679  for (int j = 0; j < jobs.size(); ++j)
+
680  {
+
681  Json::Value const& counter{jq_counters[jobs[j].typeName]};
+
682  std::uint64_t const running_dur_us{
+
683  jsonToUint64(counter[jss::running_duration_us])};
+
684  if (j < i)
+
685  {
+
686  BEAST_EXPECT(counter[jss::finished] == "0");
+
687  BEAST_EXPECT(running_dur_us == 0);
+
688  }
+
689  else if (j == i)
+
690  {
+
691  BEAST_EXPECT(counter[jss::finished] == "1");
+
692  BEAST_EXPECT(running_dur_us == ((jobs.size() - j) * 2) - 1);
+
693  }
+
694  else
+
695  {
+
696  BEAST_EXPECT(counter[jss::finished] == "2");
+
697  BEAST_EXPECT(running_dur_us == ((jobs.size() - j) * 4) - 1);
+
698  }
+
699 
+
700  std::uint64_t const queued_dur_us{
+
701  jsonToUint64(counter[jss::queued_duration_us])};
+
702  BEAST_EXPECT(queued_dur_us == j + 1);
+
703  BEAST_EXPECT(counter[jss::queued] == "1");
+
704  BEAST_EXPECT(counter[jss::started] == "2");
+
705  }
+
706  {
+
707  // Verify values in jss::total are what we expect.
+
708  Json::Value const& total{jq_counters[jss::total]};
+
709  BEAST_EXPECT(jsonToUint64(total[jss::queued]) == jobs.size());
+
710  BEAST_EXPECT(
+
711  jsonToUint64(total[jss::started]) == jobs.size() * 2);
+
712  BEAST_EXPECT(jsonToUint64(total[jss::finished]) == finished);
+
713 
+
714  // Total queued duration should be triangle number of
+
715  // jobs.size().
+
716  int const queuedDur = ((jobs.size() * (jobs.size() + 1)) / 2);
+
717  BEAST_EXPECT(
+
718  jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
+
719 
+
720  // Total running duration should be triangle number of finished.
+
721  int const runningDur = ((finished * (finished + 1)) / 2);
+
722  BEAST_EXPECT(
+
723  jsonToUint64(total[jss::running_duration_us]) ==
+
724  runningDur);
+
725  }
+
726 
+
727  perfLog->jobFinish(
+
728  jobs[i].type, microseconds(finished + 1), (i * 2));
+
729  std::this_thread::sleep_for(microseconds(10));
+
730 
+
731  // Verify that the two jobs we just finished no longer appear in
+
732  // currents.
+
733  std::vector<Cur> const currents{
+
734  getSortedCurrent(perfLog->currentJson()[jss::jobs])};
+
735  BEAST_EXPECT(currents.size() == i * 2);
+
736 
+
737  std::uint64_t prevDur = std::numeric_limits<std::uint64_t>::max();
+
738  for (int j = 0; j < i; ++j)
+
739  {
+
740  BEAST_EXPECT(currents[j * 2].name == jobs[j].typeName);
+
741  BEAST_EXPECT(prevDur > currents[j * 2].dur);
+
742  prevDur = currents[j * 2].dur;
+
743 
+
744  BEAST_EXPECT(currents[(j * 2) + 1].name == jobs[j].typeName);
+
745  BEAST_EXPECT(prevDur > currents[(j * 2) + 1].dur);
+
746  prevDur = currents[(j * 2) + 1].dur;
+
747  }
+
748  }
+
749 
+
750  // Validate the final results.
+
751  auto validateFinalCounters = [this,
+
752  &jobs](Json::Value const& countersJson) {
+
753  {
+
754  Json::Value const& rpc = countersJson[jss::rpc];
+
755  BEAST_EXPECT(rpc.isObject());
+
756  BEAST_EXPECT(rpc.size() == 0);
+
757  }
+
758 
+
759  Json::Value const& jobQueue = countersJson[jss::job_queue];
+
760  for (int i = jobs.size() - 1; i >= 0; --i)
+
761  {
+
762  Json::Value const& counter{jobQueue[jobs[i].typeName]};
+
763  std::uint64_t const running_dur_us{
+
764  jsonToUint64(counter[jss::running_duration_us])};
+
765  BEAST_EXPECT(running_dur_us == ((jobs.size() - i) * 4) - 1);
+
766 
+
767  std::uint64_t const queued_dur_us{
+
768  jsonToUint64(counter[jss::queued_duration_us])};
+
769  BEAST_EXPECT(queued_dur_us == i + 1);
+
770 
+
771  BEAST_EXPECT(counter[jss::queued] == "1");
+
772  BEAST_EXPECT(counter[jss::started] == "2");
+
773  BEAST_EXPECT(counter[jss::finished] == "2");
+
774  }
+
775 
+
776  // Verify values in jss::total are what we expect.
+
777  Json::Value const& total{jobQueue[jss::total]};
+
778  const int finished = jobs.size() * 2;
+
779  BEAST_EXPECT(jsonToUint64(total[jss::queued]) == jobs.size());
+
780  BEAST_EXPECT(jsonToUint64(total[jss::started]) == finished);
+
781  BEAST_EXPECT(jsonToUint64(total[jss::finished]) == finished);
+
782 
+
783  // Total queued duration should be triangle number of
+
784  // jobs.size().
+
785  int const queuedDur = ((jobs.size() * (jobs.size() + 1)) / 2);
+
786  BEAST_EXPECT(
+
787  jsonToUint64(total[jss::queued_duration_us]) == queuedDur);
+
788 
+
789  // Total running duration should be triangle number of finished.
+
790  int const runningDur = ((finished * (finished + 1)) / 2);
+
791  BEAST_EXPECT(
+
792  jsonToUint64(total[jss::running_duration_us]) == runningDur);
+
793  };
+
794 
+
795  auto validateFinalCurrent = [this](Json::Value const& currentJson) {
+
796  {
+
797  Json::Value const& j = currentJson[jss::jobs];
+
798  BEAST_EXPECT(j.isArray());
+
799  BEAST_EXPECT(j.size() == 0);
+
800  }
+
801 
+
802  Json::Value const& methods = currentJson[jss::methods];
+
803  BEAST_EXPECT(methods.size() == 0);
+
804  BEAST_EXPECT(methods.isArray());
+
805  };
+
806 
+
807  // Validate the final state of the PerfLog.
+
808  validateFinalCounters(perfLog->countersJson());
+
809  validateFinalCurrent(perfLog->currentJson());
+
810 
+
811  // Give the PerfLog enough time to flush it's state to the file.
+
812  fixture.wait();
+
813 
+
814  // Politely stop the PerfLog.
+
815  perfLog->stop();
+
816 
+
817  // Check file contents if that is appropriate.
+
818  auto const fullPath = fixture.logFile();
+
819 
+
820  if (withFile == WithFile::no)
+
821  {
+
822  BEAST_EXPECT(!exists(fullPath));
+
823  }
+
824  else
+
825  {
+
826  // The last line in the log file should contain the same
+
827  // information that countersJson() and currentJson() returned.
+
828  // Verify that.
+
829 
+
830  // Get the last line of the log.
+
831  std::ifstream logStream(fullPath.c_str());
+
832  std::string lastLine;
+
833  for (std::string line; std::getline(logStream, line);)
+
834  {
+
835  if (!line.empty())
+
836  lastLine = std::move(line);
+
837  }
+
838 
+
839  Json::Value parsedLastLine;
+
840  Json::Reader().parse(lastLine, parsedLastLine);
+
841  if (!BEAST_EXPECT(!RPC::contains_error(parsedLastLine)))
+
842  // Avoid cascade of failures
+
843  return;
+
844 
+
845  // Validate the contents of the last line of the log.
+
846  validateFinalCounters(parsedLastLine[jss::counters]);
+
847  validateFinalCurrent(parsedLastLine[jss::current_activities]);
+
848  }
+
849  }
+
850 
+
851  void
+
852  testInvalidID(WithFile withFile)
+
853  {
+
854  using namespace std::chrono;
+
855 
+
856  // The Worker ID is used to identify jobs in progress. Show that
+
857  // the PerLog behaves as well as possible if an invalid ID is passed.
+
858 
+
859  // Start up the PerfLog that we'll use for testing.
+
860  Fixture fixture{env_.app(), j_};
+
861  auto perfLog{fixture.perfLog(withFile)};
+
862  perfLog->start();
+
863 
+
864  // Randomly select a job type and its name.
+
865  JobType jobType;
+
866  std::string jobTypeName;
+
867  {
+
868  auto const& jobTypes = JobTypes::instance();
+
869 
+
870  std::uniform_int_distribution<> dis(0, jobTypes.size() - 1);
+
871  auto iter{jobTypes.begin()};
+
872  std::advance(iter, dis(default_prng()));
+
873 
+
874  jobType = iter->second.type();
+
875  jobTypeName = iter->second.name();
+
876  }
+
877 
+
878  // Say there's one worker thread.
+
879  perfLog->resizeJobs(1);
+
880 
+
881  // Lambda to validate countersJson for this test.
+
882  auto verifyCounters = [this, jobTypeName](
+
883  Json::Value const& countersJson,
+
884  int started,
+
885  int finished,
+
886  int queued_us,
+
887  int running_us) {
+
888  BEAST_EXPECT(countersJson.isObject());
+
889  BEAST_EXPECT(countersJson.size() == 2);
+
890 
+
891  BEAST_EXPECT(countersJson.isMember(jss::rpc));
+
892  BEAST_EXPECT(countersJson[jss::rpc].isObject());
+
893  BEAST_EXPECT(countersJson[jss::rpc].size() == 0);
+
894 
+
895  BEAST_EXPECT(countersJson.isMember(jss::job_queue));
+
896  BEAST_EXPECT(countersJson[jss::job_queue].isObject());
+
897  BEAST_EXPECT(countersJson[jss::job_queue].size() == 1);
+
898  {
+
899  Json::Value const& job{
+
900  countersJson[jss::job_queue][jobTypeName]};
+
901 
+
902  BEAST_EXPECT(job.isObject());
+
903  BEAST_EXPECT(jsonToUint64(job[jss::queued]) == 0);
+
904  BEAST_EXPECT(jsonToUint64(job[jss::started]) == started);
+
905  BEAST_EXPECT(jsonToUint64(job[jss::finished]) == finished);
+
906 
907  BEAST_EXPECT(
-
908  jsonToUint64(job[jss::running_duration_us]) == running_us);
-
909  }
-
910  };
-
911 
-
912  // Lambda to validate currentJson (always empty) for this test.
-
913  auto verifyEmptyCurrent = [this](Json::Value const& currentJson) {
-
914  BEAST_EXPECT(currentJson.isObject());
-
915  BEAST_EXPECT(currentJson.size() == 2);
-
916 
-
917  BEAST_EXPECT(currentJson.isMember(jss::jobs));
-
918  BEAST_EXPECT(currentJson[jss::jobs].isArray());
-
919  BEAST_EXPECT(currentJson[jss::jobs].size() == 0);
-
920 
-
921  BEAST_EXPECT(currentJson.isMember(jss::methods));
-
922  BEAST_EXPECT(currentJson[jss::methods].isArray());
-
923  BEAST_EXPECT(currentJson[jss::methods].size() == 0);
-
924  };
-
925 
-
926  // Start an ID that's too large.
-
927  perfLog->jobStart(jobType, microseconds{11}, steady_clock::now(), 2);
-
928  std::this_thread::sleep_for(microseconds{10});
-
929  verifyCounters(perfLog->countersJson(), 1, 0, 11, 0);
-
930  verifyEmptyCurrent(perfLog->currentJson());
-
931 
-
932  // Start a negative ID
-
933  perfLog->jobStart(jobType, microseconds{13}, steady_clock::now(), -1);
-
934  std::this_thread::sleep_for(microseconds{10});
-
935  verifyCounters(perfLog->countersJson(), 2, 0, 24, 0);
-
936  verifyEmptyCurrent(perfLog->currentJson());
-
937 
-
938  // Finish the too large ID
-
939  perfLog->jobFinish(jobType, microseconds{17}, 2);
-
940  std::this_thread::sleep_for(microseconds{10});
-
941  verifyCounters(perfLog->countersJson(), 2, 1, 24, 17);
-
942  verifyEmptyCurrent(perfLog->currentJson());
-
943 
-
944  // Finish the negative ID
-
945  perfLog->jobFinish(jobType, microseconds{19}, -1);
-
946  std::this_thread::sleep_for(microseconds{10});
-
947  verifyCounters(perfLog->countersJson(), 2, 2, 24, 36);
-
948  verifyEmptyCurrent(perfLog->currentJson());
-
949 
-
950  // Give the PerfLog enough time to flush it's state to the file.
-
951  fixture.wait();
-
952 
-
953  // Politely stop the PerfLog.
-
954  perfLog->stop();
-
955 
-
956  // Check file contents if that is appropriate.
-
957  auto const fullPath = fixture.logFile();
-
958 
-
959  if (withFile == WithFile::no)
-
960  {
-
961  BEAST_EXPECT(!exists(fullPath));
-
962  }
-
963  else
-
964  {
-
965  // The last line in the log file should contain the same
-
966  // information that countersJson() and currentJson() returned.
-
967  // Verify that.
-
968 
-
969  // Get the last line of the log.
-
970  std::ifstream logStream(fullPath.c_str());
-
971  std::string lastLine;
-
972  for (std::string line; std::getline(logStream, line);)
-
973  {
-
974  if (!line.empty())
-
975  lastLine = std::move(line);
-
976  }
-
977 
-
978  Json::Value parsedLastLine;
-
979  Json::Reader().parse(lastLine, parsedLastLine);
-
980  if (!BEAST_EXPECT(!RPC::contains_error(parsedLastLine)))
-
981  // Avoid cascade of failures
-
982  return;
-
983 
-
984  // Validate the contents of the last line of the log.
-
985  verifyCounters(parsedLastLine[jss::counters], 2, 2, 24, 36);
-
986  verifyEmptyCurrent(parsedLastLine[jss::current_activities]);
-
987  }
-
988  }
-
989 
-
990  void
-
991  testRotate(WithFile withFile)
-
992  {
-
993  // We can't fully test rotate because unit tests must run on Windows,
-
994  // and Windows doesn't (may not?) support rotate. But at least call
-
995  // the interface and see that it doesn't crash.
-
996  using namespace boost::filesystem;
-
997 
-
998  Fixture fixture{env_.app(), j_};
-
999  BEAST_EXPECT(!exists(fixture.logDir()));
-
1000 
-
1001  auto perfLog{fixture.perfLog(withFile)};
+
908  jsonToUint64(job[jss::queued_duration_us]) == queued_us);
+
909  BEAST_EXPECT(
+
910  jsonToUint64(job[jss::running_duration_us]) == running_us);
+
911  }
+
912  };
+
913 
+
914  // Lambda to validate currentJson (always empty) for this test.
+
915  auto verifyEmptyCurrent = [this](Json::Value const& currentJson) {
+
916  BEAST_EXPECT(currentJson.isObject());
+
917  BEAST_EXPECT(currentJson.size() == 2);
+
918 
+
919  BEAST_EXPECT(currentJson.isMember(jss::jobs));
+
920  BEAST_EXPECT(currentJson[jss::jobs].isArray());
+
921  BEAST_EXPECT(currentJson[jss::jobs].size() == 0);
+
922 
+
923  BEAST_EXPECT(currentJson.isMember(jss::methods));
+
924  BEAST_EXPECT(currentJson[jss::methods].isArray());
+
925  BEAST_EXPECT(currentJson[jss::methods].size() == 0);
+
926  };
+
927 
+
928  // Start an ID that's too large.
+
929  perfLog->jobStart(jobType, microseconds{11}, steady_clock::now(), 2);
+
930  std::this_thread::sleep_for(microseconds{10});
+
931  verifyCounters(perfLog->countersJson(), 1, 0, 11, 0);
+
932  verifyEmptyCurrent(perfLog->currentJson());
+
933 
+
934  // Start a negative ID
+
935  perfLog->jobStart(jobType, microseconds{13}, steady_clock::now(), -1);
+
936  std::this_thread::sleep_for(microseconds{10});
+
937  verifyCounters(perfLog->countersJson(), 2, 0, 24, 0);
+
938  verifyEmptyCurrent(perfLog->currentJson());
+
939 
+
940  // Finish the too large ID
+
941  perfLog->jobFinish(jobType, microseconds{17}, 2);
+
942  std::this_thread::sleep_for(microseconds{10});
+
943  verifyCounters(perfLog->countersJson(), 2, 1, 24, 17);
+
944  verifyEmptyCurrent(perfLog->currentJson());
+
945 
+
946  // Finish the negative ID
+
947  perfLog->jobFinish(jobType, microseconds{19}, -1);
+
948  std::this_thread::sleep_for(microseconds{10});
+
949  verifyCounters(perfLog->countersJson(), 2, 2, 24, 36);
+
950  verifyEmptyCurrent(perfLog->currentJson());
+
951 
+
952  // Give the PerfLog enough time to flush it's state to the file.
+
953  fixture.wait();
+
954 
+
955  // Politely stop the PerfLog.
+
956  perfLog->stop();
+
957 
+
958  // Check file contents if that is appropriate.
+
959  auto const fullPath = fixture.logFile();
+
960 
+
961  if (withFile == WithFile::no)
+
962  {
+
963  BEAST_EXPECT(!exists(fullPath));
+
964  }
+
965  else
+
966  {
+
967  // The last line in the log file should contain the same
+
968  // information that countersJson() and currentJson() returned.
+
969  // Verify that.
+
970 
+
971  // Get the last line of the log.
+
972  std::ifstream logStream(fullPath.c_str());
+
973  std::string lastLine;
+
974  for (std::string line; std::getline(logStream, line);)
+
975  {
+
976  if (!line.empty())
+
977  lastLine = std::move(line);
+
978  }
+
979 
+
980  Json::Value parsedLastLine;
+
981  Json::Reader().parse(lastLine, parsedLastLine);
+
982  if (!BEAST_EXPECT(!RPC::contains_error(parsedLastLine)))
+
983  // Avoid cascade of failures
+
984  return;
+
985 
+
986  // Validate the contents of the last line of the log.
+
987  verifyCounters(parsedLastLine[jss::counters], 2, 2, 24, 36);
+
988  verifyEmptyCurrent(parsedLastLine[jss::current_activities]);
+
989  }
+
990  }
+
991 
+
992  void
+
993  testRotate(WithFile withFile)
+
994  {
+
995  // We can't fully test rotate because unit tests must run on Windows,
+
996  // and Windows doesn't (may not?) support rotate. But at least call
+
997  // the interface and see that it doesn't crash.
+
998  using namespace boost::filesystem;
+
999 
+
1000  Fixture fixture{env_.app(), j_};
+
1001  BEAST_EXPECT(!exists(fixture.logDir()));
1002 
-
1003  BEAST_EXPECT(fixture.stopSignaled == false);
-
1004  if (withFile == WithFile::no)
-
1005  {
-
1006  BEAST_EXPECT(!exists(fixture.logDir()));
-
1007  }
-
1008  else
-
1009  {
-
1010  BEAST_EXPECT(exists(fixture.logFile()));
-
1011  BEAST_EXPECT(file_size(fixture.logFile()) == 0);
-
1012  }
-
1013 
-
1014  // Start PerfLog and wait long enough for PerfLog::report()
-
1015  // to write to its file.
-
1016  perfLog->start();
-
1017  fixture.wait();
-
1018 
-
1019  decltype(file_size(fixture.logFile())) firstFileSize{0};
-
1020  if (withFile == WithFile::no)
-
1021  {
-
1022  BEAST_EXPECT(!exists(fixture.logDir()));
-
1023  }
-
1024  else
-
1025  {
-
1026  firstFileSize = file_size(fixture.logFile());
-
1027  BEAST_EXPECT(firstFileSize > 0);
-
1028  }
-
1029 
-
1030  // Rotate and then wait to make sure more stuff is written to the file.
-
1031  perfLog->rotate();
-
1032  fixture.wait();
-
1033 
-
1034  perfLog->stop();
+
1003  auto perfLog{fixture.perfLog(withFile)};
+
1004 
+
1005  BEAST_EXPECT(fixture.stopSignaled == false);
+
1006  if (withFile == WithFile::no)
+
1007  {
+
1008  BEAST_EXPECT(!exists(fixture.logDir()));
+
1009  }
+
1010  else
+
1011  {
+
1012  BEAST_EXPECT(exists(fixture.logFile()));
+
1013  BEAST_EXPECT(file_size(fixture.logFile()) == 0);
+
1014  }
+
1015 
+
1016  // Start PerfLog and wait long enough for PerfLog::report()
+
1017  // to write to its file.
+
1018  perfLog->start();
+
1019  fixture.wait();
+
1020 
+
1021  decltype(file_size(fixture.logFile())) firstFileSize{0};
+
1022  if (withFile == WithFile::no)
+
1023  {
+
1024  BEAST_EXPECT(!exists(fixture.logDir()));
+
1025  }
+
1026  else
+
1027  {
+
1028  firstFileSize = file_size(fixture.logFile());
+
1029  BEAST_EXPECT(firstFileSize > 0);
+
1030  }
+
1031 
+
1032  // Rotate and then wait to make sure more stuff is written to the file.
+
1033  perfLog->rotate();
+
1034  fixture.wait();
1035 
-
1036  if (withFile == WithFile::no)
-
1037  {
-
1038  BEAST_EXPECT(!exists(fixture.logDir()));
-
1039  }
-
1040  else
-
1041  {
-
1042  BEAST_EXPECT(file_size(fixture.logFile()) > firstFileSize);
-
1043  }
-
1044  }
-
1045 
-
1046  void
-
1047  run() override
-
1048  {
-
1049  testFileCreation();
-
1050  testRPC(WithFile::no);
-
1051  testRPC(WithFile::yes);
-
1052  testJobs(WithFile::no);
-
1053  testJobs(WithFile::yes);
-
1054  testInvalidID(WithFile::no);
-
1055  testInvalidID(WithFile::yes);
-
1056  testRotate(WithFile::no);
-
1057  testRotate(WithFile::yes);
-
1058  }
-
1059 };
-
1060 
-
1061 BEAST_DEFINE_TESTSUITE(PerfLog, basics, ripple);
+
1036  perfLog->stop();
+
1037 
+
1038  if (withFile == WithFile::no)
+
1039  {
+
1040  BEAST_EXPECT(!exists(fixture.logDir()));
+
1041  }
+
1042  else
+
1043  {
+
1044  BEAST_EXPECT(file_size(fixture.logFile()) > firstFileSize);
+
1045  }
+
1046  }
+
1047 
+
1048  void
+
1049  run() override
+
1050  {
+
1051  testFileCreation();
+
1052  testRPC(WithFile::no);
+
1053  testRPC(WithFile::yes);
+
1054  testJobs(WithFile::no);
+
1055  testJobs(WithFile::yes);
+
1056  testInvalidID(WithFile::no);
+
1057  testInvalidID(WithFile::yes);
+
1058  testRotate(WithFile::no);
+
1059  testRotate(WithFile::yes);
+
1060  }
+
1061 };
1062 
-
1063 } // namespace ripple
+
1063 BEAST_DEFINE_TESTSUITE(PerfLog, basics, ripple);
+
1064 
+
1065 } // namespace ripple
-
std::unique_ptr< perf::PerfLog > perfLog(WithFile withFile)
+
std::unique_ptr< perf::PerfLog > perfLog(WithFile withFile)
Definition: Application.h:116
T sleep_for(T... args)
T generate_n(T... args)
bool isObject() const
STL class.
-
WithFile
+
WithFile
-
path logFile() const
+
path logFile() const
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, ripple)
T stoull(T... args)
@ kDisabled
Definition: Journal.h:41
-
std::chrono::milliseconds logInterval() const
-
void testRotate(WithFile withFile)
+
std::chrono::milliseconds logInterval() const
+
void testRotate(WithFile withFile)
+
std::set< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:313
T reserve(T... args)
STL class.
-
beast::Journal j_
+
beast::Journal j_
T size(T... args)
-
void testJobs(WithFile withFile)
+
void testJobs(WithFile withFile)
T back_inserter(T... args)
std::unique_ptr< PerfLog > make_PerfLog(PerfLog::Setup const &setup, Application &app, beast::Journal journal, std::function< void()> &&signalStop)
Definition: PerfLogImp.cpp:501
-
static std::vector< Cur > getSortedCurrent(Json::Value const &currentJson)
+
static std::vector< Cur > getSortedCurrent(Json::Value const &currentJson)
Application & app()
Definition: Env.h:242
-
static std::uint64_t jsonToUint64(Json::Value const &jsonUintAsString)
-
-
void testFileCreation()
+
static std::uint64_t jsonToUint64(Json::Value const &jsonUintAsString)
+
+
void testFileCreation()
Unserialize a JSON document into a Value.
Definition: json_reader.h:36
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition: envconfig.h:49
-
std::uint64_t dur
+
std::uint64_t dur
T sort(T... args)
-
beast::Journal j_
-
bool stopSignaled
+
beast::Journal j_
+
bool stopSignaled
Configuration from [perf] section of rippled.cfg.
Definition: PerfLog.h:62
-
Cur(std::uint64_t d, std::string n)
-
void testRPC(WithFile withFile)
+
Cur(std::uint64_t d, std::string n)
+
void testRPC(WithFile withFile)
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
Definition: ErrorCodes.cpp:196
-
-
boost::filesystem::path path
+
+
boost::filesystem::path path
STL class.
-
Fixture(Application &app, beast::Journal j)
-
void run() override
+
Fixture(Application &app, beast::Journal j)
+
void run() override
static JobTypes const & instance()
Definition: JobTypes.h:125
-
path logDir() const
+
path logDir() const
T close(T... args)
beast::xor_shift_engine & default_prng()
Return the default random engine.
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
@@ -1190,33 +1193,32 @@ $(function() {
@ no
A generic endpoint for log messages.
Definition: Journal.h:58
-
+
-
test::jtx::Env env_
-
Application & app_
+
test::jtx::Env env_
+
Application & app_
T advance(T... args)
bool isArray() const
T emplace_back(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
virtual beast::Journal journal(std::string const &name)=0
T endl(T... args)
-
std::string name
+
std::string name
T begin(T... args)
T getline(T... args)
@ yes
STL namespace.
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
Definition: json_reader.cpp:74
JobType
Definition: Job.h:35
-
void testInvalidID(WithFile withFile)
+
void testInvalidID(WithFile withFile)
T end(T... args)
-
void signalStop()
-
~Fixture()
+
void signalStop()
+
~Fixture()
T max(T... args)
-
std::vector< char const * > getHandlerNames()
Return names of all methods.
Definition: Handler.cpp:254
STL class.
T shuffle(T... args)
-
void wait() const
+
void wait() const
T is_open(T... args)
A transaction testing environment.
Definition: Env.h:117
Represents a JSON value.
Definition: json_value.h:145
diff --git a/RPCHandler_8cpp_source.html b/RPCHandler_8cpp_source.html index bf85c3f09f..89e1aa2e14 100644 --- a/RPCHandler_8cpp_source.html +++ b/RPCHandler_8cpp_source.html @@ -303,13 +303,13 @@ $(function() {
@ jtCLIENT
Definition: Job.h:45
STL class.
boost::string_view user
Definition: Context.h:60
-
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:248
+
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:307
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
Role roleRequired(unsigned int version, bool betaEnabled, std::string const &method)
Definition: RPCHandler.cpp:297
void injectReportingWarning(RPC::JsonContext &context, Json::Value &result)
Definition: RPCHandler.cpp:230
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
const Charge feeReferenceRPC
-
const char * name_
Definition: Handler.h:51
+
const char * name_
Definition: Handler.h:52
Headers headers
Definition: Context.h:66
error_code_i
Definition: ErrorCodes.h:40
const beast::Journal j
Definition: Context.h:41
@@ -318,7 +318,7 @@ $(function() {
@ warnRPC_REPORTING
Definition: ErrorCodes.h:159
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
bool reporting() const
Definition: Config.h:351
-
Definition: Handler.h:46
+
Definition: Handler.h:47
@ ADMIN
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
@@ -334,10 +334,10 @@ $(function() {
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:124
Status
Return codes from Backend operations.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
-
Method< Json::Value > valueMethod_
Definition: Handler.h:52
+
Method< Json::Value > valueMethod_
Definition: Handler.h:53
@ rpcUNKNOWN_COMMAND
Definition: ErrorCodes.h:85
bool shouldForwardToP2p(RPC::JsonContext &context)
Whether a request should be forwarded, based on request parameters.
Definition: P2pProxy.cpp:45
-
error_code_i conditionMet(Condition condition_required, T &context)
Definition: Handler.h:78
+
error_code_i conditionMet(Condition condition_required, T &context)
Definition: Handler.h:82
@ rpcNO_PERMISSION
Definition: ErrorCodes.h:53
const Charge feeExceptionRPC
boost::string_view forwardedFor
Definition: Context.h:61
diff --git a/RPCHelpers_8h_source.html b/RPCHelpers_8h_source.html index da3cbdbaef..492689c72b 100644 --- a/RPCHelpers_8h_source.html +++ b/RPCHelpers_8h_source.html @@ -226,52 +226,54 @@ $(function() {
242 constexpr unsigned int apiMinimumSupportedVersion = 1;
243 constexpr unsigned int apiMaximumSupportedVersion = 1;
244 constexpr unsigned int apiBetaVersion = 2;
-
245 
-
246 static_assert(apiMinimumSupportedVersion >= apiVersionIfUnspecified);
-
247 static_assert(apiMaximumSupportedVersion >= apiMinimumSupportedVersion);
-
248 static_assert(apiBetaVersion >= apiMaximumSupportedVersion);
-
249 
-
250 template <class Object>
-
251 void
-
252 setVersion(Object& parent, unsigned int apiVersion, bool betaEnabled)
-
253 {
-
254  assert(apiVersion != apiInvalidVersion);
-
255  auto&& object = addObject(parent, jss::version);
-
256  if (apiVersion == apiVersionIfUnspecified)
-
257  {
-
258  object[jss::first] = firstVersion.print();
-
259  object[jss::good] = goodVersion.print();
-
260  object[jss::last] = lastVersion.print();
-
261  }
-
262  else
-
263  {
-
264  object[jss::first] = apiMinimumSupportedVersion;
-
265  object[jss::last] =
-
266  betaEnabled ? apiBetaVersion : apiMaximumSupportedVersion;
-
267  }
-
268 }
-
269 
-
270 std::pair<RPC::Status, LedgerEntryType>
-
271 chooseLedgerEntryType(Json::Value const& params);
-
272 
-
287 unsigned int
-
288 getAPIVersionNumber(const Json::Value& value, bool betaEnabled);
-
289 
-
292 std::variant<std::shared_ptr<Ledger const>, Json::Value>
-
293 getLedgerByContext(RPC::JsonContext& context);
-
294 
-
295 std::pair<PublicKey, SecretKey>
-
296 keypairForSignature(
-
297  Json::Value const& params,
-
298  Json::Value& error,
-
299  unsigned int apiVersion = apiVersionIfUnspecified);
-
305 ripple::Expected<RPC::SubmitSync, Json::Value>
-
306 getSubmitSyncMode(Json::Value const& params);
-
307 
-
308 } // namespace RPC
-
309 } // namespace ripple
-
310 
-
311 #endif
+
245 constexpr unsigned int apiMaximumValidVersion = apiBetaVersion;
+
246 
+
247 static_assert(apiMinimumSupportedVersion >= apiVersionIfUnspecified);
+
248 static_assert(apiMaximumSupportedVersion >= apiMinimumSupportedVersion);
+
249 static_assert(apiBetaVersion >= apiMaximumSupportedVersion);
+
250 static_assert(apiMaximumValidVersion >= apiMaximumSupportedVersion);
+
251 
+
252 template <class Object>
+
253 void
+
254 setVersion(Object& parent, unsigned int apiVersion, bool betaEnabled)
+
255 {
+
256  assert(apiVersion != apiInvalidVersion);
+
257  auto&& object = addObject(parent, jss::version);
+
258  if (apiVersion == apiVersionIfUnspecified)
+
259  {
+
260  object[jss::first] = firstVersion.print();
+
261  object[jss::good] = goodVersion.print();
+
262  object[jss::last] = lastVersion.print();
+
263  }
+
264  else
+
265  {
+
266  object[jss::first] = apiMinimumSupportedVersion;
+
267  object[jss::last] =
+
268  betaEnabled ? apiBetaVersion : apiMaximumSupportedVersion;
+
269  }
+
270 }
+
271 
+
272 std::pair<RPC::Status, LedgerEntryType>
+
273 chooseLedgerEntryType(Json::Value const& params);
+
274 
+
289 unsigned int
+
290 getAPIVersionNumber(const Json::Value& value, bool betaEnabled);
+
291 
+
294 std::variant<std::shared_ptr<Ledger const>, Json::Value>
+
295 getLedgerByContext(RPC::JsonContext& context);
+
296 
+
297 std::pair<PublicKey, SecretKey>
+
298 keypairForSignature(
+
299  Json::Value const& params,
+
300  Json::Value& error,
+
301  unsigned int apiVersion = apiVersionIfUnspecified);
+
307 ripple::Expected<RPC::SubmitSync, Json::Value>
+
308 getSubmitSyncMode(Json::Value const& params);
+
309 
+
310 } // namespace RPC
+
311 } // namespace ripple
+
312 
+
313 #endif
constexpr unsigned int apiInvalidVersion
API version numbers used in later API versions.
Definition: RPCHelpers.h:240
Definition: Application.h:116
@@ -314,6 +316,7 @@ $(function() {
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool isValidated(LedgerMaster &ledgerMaster, ReadView const &ledger, Application &app)
Definition: RPCHelpers.cpp:604
Status getLedger(T &ledger, uint256 const &ledgerHash, Context &context)
Get ledger by hash If there is no error in the return value, the ledger pointer will have been filled...
Definition: RPCHelpers.cpp:480
+
constexpr unsigned int apiMaximumValidVersion
Definition: RPCHelpers.h:245
std::pair< RPC::Status, LedgerEntryType > chooseLedgerEntryType(Json::Value const &params)
Definition: RPCHelpers.cpp:986
std::uint64_t getStartHint(std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Gets the start hint for traversing account objects.
Definition: RPCHelpers.cpp:97
std::optional< Seed > getSeedFromRPC(Json::Value const &params, Json::Value &error)
Definition: RPCHelpers.cpp:791
@@ -328,7 +331,7 @@ $(function() {
Json::Value accountFromString(AccountID &result, std::string const &strIdent, bool bStrict)
Definition: RPCHelpers.cpp:87
bool isRelatedToAccount(ReadView const &ledger, std::shared_ptr< SLE const > const &sle, AccountID const &accountID)
Tests if a SLE is owned by accountID.
Definition: RPCHelpers.cpp:114
Represents a JSON value.
Definition: json_value.h:145
-
void setVersion(Object &parent, unsigned int apiVersion, bool betaEnabled)
Definition: RPCHelpers.h:252
+
void setVersion(Object &parent, unsigned int apiVersion, bool betaEnabled)
Definition: RPCHelpers.h:254