diff --git a/Builds/CMake/RippledCore.cmake b/Builds/CMake/RippledCore.cmake index cc3441af5b..c777717642 100644 --- a/Builds/CMake/RippledCore.cmake +++ b/Builds/CMake/RippledCore.cmake @@ -588,6 +588,7 @@ target_sources (rippled PRIVATE src/ripple/resource/impl/Consumer.cpp src/ripple/resource/impl/Fees.cpp src/ripple/resource/impl/ResourceManager.cpp + src/ripple/resource/impl/Tuning.cpp #[===============================[ main sources: subdir: rpc diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg index 0a66931306..0e923ac28f 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/rippled-example.cfg @@ -23,7 +23,9 @@ # # 9. Misc Settings # -# 10. Example Settings +# 10. Resource Settings +# +# 11. Example Settings # #------------------------------------------------------------------------------- # @@ -1565,7 +1567,41 @@ # #------------------------------------------------------------------------------- # -# 10. Example Settings +# 10. Resource Settings +# +#-------------------- +# [resource] +# +# A set of key/value pair parameters to tune the performance of the +# transaction queue. +# +# warning_threshold = +# +# Lorem Epsium.... +# +# drop_threshold = +# +# Lorem Epsium.... +# +# decay_window_seconds = +# +# Lorem Epsium.... +# +# minimum_gossip_balance = +# +# Lorem Epsium.... +# +# seconds_until_expiration = +# +# Lorem Epsium.... +# +# gossip_expiration_seconds = +# +# Lorem Epsium.... +# +# +# +# 11. Example Settings # #-------------------- # diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 9134df0355..be639fb40d 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -352,6 +352,7 @@ class ApplicationImp : public Application, public BasicApp , validatorKeys_(*config_, m_journal) , m_resourceManager(Resource::make_Manager( + config_->section("resource"), m_collectorManager->collector(), logs_->journal("Resource"))) diff --git a/src/ripple/core/ConfigSections.h b/src/ripple/core/ConfigSections.h index 27f38bc6e4..18d68cc1c2 100644 --- a/src/ripple/core/ConfigSections.h +++ b/src/ripple/core/ConfigSections.h @@ -101,6 +101,7 @@ struct ConfigSection #define SECTION_SWEEP_INTERVAL "sweep_interval" #define SECTION_NETWORK_ID "network_id" #define SECTION_IMPORT_VL_KEYS "import_vl_keys" +#define SECTION_RESOURCE "resource" } // namespace ripple diff --git a/src/ripple/resource/ResourceManager.h b/src/ripple/resource/ResourceManager.h index 7471a37ab3..ca89954762 100644 --- a/src/ripple/resource/ResourceManager.h +++ b/src/ripple/resource/ResourceManager.h @@ -80,6 +80,7 @@ class Manager : public beast::PropertyStream::Source std::unique_ptr make_Manager( + Section const& section, beast::insight::Collector::ptr const& collector, beast::Journal journal); diff --git a/src/ripple/resource/impl/Entry.h b/src/ripple/resource/impl/Entry.h index 126f254645..36a4dc7f7b 100644 --- a/src/ripple/resource/impl/Entry.h +++ b/src/ripple/resource/impl/Entry.h @@ -89,7 +89,7 @@ struct Entry : public beast::List::Node int refcount; // Exponentially decaying balance of resource consumption - DecayingSample local_balance; + DecayingSample local_balance; // Normalized balance contribution from imports int remote_balance; diff --git a/src/ripple/resource/impl/Logic.h b/src/ripple/resource/impl/Logic.h index 07d89403b6..652c85468b 100644 --- a/src/ripple/resource/impl/Logic.h +++ b/src/ripple/resource/impl/Logic.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -88,11 +89,27 @@ class Logic //-------------------------------------------------------------------------- public: Logic( + Section const& section, beast::insight::Collector::ptr const& collector, clock_type& clock, beast::Journal journal) : m_stats(collector), m_clock(clock), m_journal(journal) { + std::uint32_t warningThreshold; + if (get_if_exists(section, "warning_threshold", warningThreshold)) + Tuning::warningThreshold = warningThreshold; + + std::uint32_t dropThreshold; + if (get_if_exists(section, "drop_threshold", dropThreshold)) + Tuning::dropThreshold = dropThreshold; + + // std::uint32_t decayWindowSeconds; + // if (get_if_exists(section, "decay_window_seconds", decayWindowSeconds)) + // Tuning::decayWindowSeconds = decayWindowSeconds; + + std::uint32_t minimumGossipBalance; + if (get_if_exists(section, "minimum_gossip_balance", minimumGossipBalance)) + Tuning::minimumGossipBalance = minimumGossipBalance; } ~Logic() @@ -200,7 +217,7 @@ class Logic Json::Value getJson() { - return getJson(warningThreshold); + return getJson(Tuning::warningThreshold); } /** Returns a Json::objectValue. */ @@ -266,7 +283,7 @@ class Logic { Gossip::Item item; item.balance = inboundEntry.local_balance.value(now); - if (item.balance >= minimumGossipBalance) + if (item.balance >= Tuning::minimumGossipBalance) { item.address = inboundEntry.key->address; gossip.items.push_back(item); @@ -294,7 +311,7 @@ class Logic { // This is a new import Import& next(resultIt->second); - next.whenExpires = elapsed + gossipExpirationSeconds; + next.whenExpires = elapsed + Tuning::gossipExpirationSeconds; next.items.reserve(gossip.items.size()); for (auto const& gossipItem : gossip.items) @@ -312,7 +329,7 @@ class Logic // balances and then deduct the old remote balances. Import next; - next.whenExpires = elapsed + gossipExpirationSeconds; + next.whenExpires = elapsed + Tuning::gossipExpirationSeconds; next.items.reserve(gossip.items.size()); for (auto const& gossipItem : gossip.items) { @@ -387,10 +404,10 @@ class Logic static Disposition disposition(int balance) { - if (balance >= dropThreshold) + if (balance >= Tuning::dropThreshold) return Disposition::drop; - if (balance >= warningThreshold) + if (balance >= Tuning::warningThreshold) return Disposition::warn; return Disposition::ok; @@ -437,7 +454,7 @@ class Logic break; } inactive_.push_back(entry); - entry.whenExpires = m_clock.now() + secondsUntilExpiration; + entry.whenExpires = m_clock.now() + Tuning::secondsUntilExpiration; } } @@ -460,7 +477,7 @@ class Logic std::lock_guard _(lock_); bool notify(false); auto const elapsed = m_clock.now(); - if (entry.balance(m_clock.now()) >= warningThreshold && + if (entry.balance(m_clock.now()) >= Tuning::warningThreshold && elapsed != entry.lastWarningTime) { charge(entry, feeWarning); @@ -485,11 +502,11 @@ class Logic bool drop(false); clock_type::time_point const now(m_clock.now()); int const balance(entry.balance(now)); - if (balance >= dropThreshold) + if (balance >= Tuning::dropThreshold) { JLOG(m_journal.warn()) << "Consumer entry " << entry << " dropped with balance " - << balance << " at or above drop threshold " << dropThreshold; + << balance << " at or above drop threshold " << Tuning::dropThreshold; // Adding feeDrop at this point keeps the dropped connection // from re-connecting for at least a little while after it is diff --git a/src/ripple/resource/impl/ResourceManager.cpp b/src/ripple/resource/impl/ResourceManager.cpp index 1a7e74ec1f..4bb4fadc8a 100644 --- a/src/ripple/resource/impl/ResourceManager.cpp +++ b/src/ripple/resource/impl/ResourceManager.cpp @@ -45,9 +45,10 @@ class ManagerImp : public Manager public: ManagerImp( + Section const& section, beast::insight::Collector::ptr const& collector, beast::Journal journal) - : journal_(journal), logic_(collector, stopwatch(), journal) + : journal_(journal), logic_(section, collector, stopwatch(), journal) { thread_ = std::thread{&ManagerImp::run, this}; } @@ -173,10 +174,11 @@ Manager::~Manager() = default; std::unique_ptr make_Manager( + Section const& section, beast::insight::Collector::ptr const& collector, beast::Journal journal) { - return std::make_unique(collector, journal); + return std::make_unique(section, collector, journal); } } // namespace Resource diff --git a/src/ripple/resource/impl/Tuning.cpp b/src/ripple/resource/impl/Tuning.cpp new file mode 100644 index 0000000000..51e4ad57f5 --- /dev/null +++ b/src/ripple/resource/impl/Tuning.cpp @@ -0,0 +1,34 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2012, 2013 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include "Tuning.h" + +namespace ripple { +namespace Resource { + +uint32_t Tuning::warningThreshold = 5000; +uint32_t Tuning::dropThreshold = 15000; +// uint32_t Tuning::decayWindowSeconds = 32; +uint32_t Tuning::minimumGossipBalance = 1000; + +std::chrono::seconds constexpr Tuning::secondsUntilExpiration{300}; +std::chrono::seconds constexpr Tuning::gossipExpirationSeconds{30}; + +} // namespace Resource +} // namespace ripple diff --git a/src/ripple/resource/impl/Tuning.h b/src/ripple/resource/impl/Tuning.h index b57d57348b..3496905e98 100644 --- a/src/ripple/resource/impl/Tuning.h +++ b/src/ripple/resource/impl/Tuning.h @@ -17,6 +17,7 @@ */ //============================================================================== +// Tuning.h #ifndef RIPPLE_RESOURCE_TUNING_H_INCLUDED #define RIPPLE_RESOURCE_TUNING_H_INCLUDED @@ -25,31 +26,23 @@ namespace ripple { namespace Resource { -/** Tunable constants. */ -enum { - // Balance at which a warning is issued - warningThreshold = 5000 - - // Balance at which the consumer is disconnected - , - dropThreshold = 15000 - - // The number of seconds in the exponential decay window - // (This should be a power of two) - , - decayWindowSeconds = 32 - - // The minimum balance required in order to include a load source in gossip - , - minimumGossipBalance = 1000 +class Tuning +{ +public: + static std::uint32_t warningThreshold; + static std::uint32_t dropThreshold; + // static std::uint32_t decayWindowSeconds; + static std::uint32_t minimumGossipBalance; + + static std::chrono::seconds const secondsUntilExpiration; + static std::chrono::seconds const gossipExpirationSeconds; + + static constexpr std::uint32_t getDecayWindowSeconds() + { + return 32; + } }; -// The number of seconds until an inactive table item is removed -std::chrono::seconds constexpr secondsUntilExpiration{300}; - -// Number of seconds until imported gossip expires -std::chrono::seconds constexpr gossipExpirationSeconds{30}; - } // namespace Resource } // namespace ripple diff --git a/src/test/resource/Logic_test.cpp b/src/test/resource/Logic_test.cpp index 25379370f4..d45ced0afd 100644 --- a/src/test/resource/Logic_test.cpp +++ b/src/test/resource/Logic_test.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -42,8 +43,8 @@ class ResourceManager_test : public beast::unit_test::suite using clock_type = boost::base_from_member; public: - explicit TestLogic(beast::Journal journal) - : Logic(beast::insight::NullCollector::New(), member, journal) + explicit TestLogic(Section const& section, beast::Journal journal) + : Logic(section, beast::insight::NullCollector::New(), member, journal) { } @@ -89,9 +90,13 @@ class ResourceManager_test : public beast::unit_test::suite else testcase("Unlimited warn/drop"); - TestLogic logic(j); + auto const config = test::jtx::envconfig([](std::unique_ptr cfg) { + return cfg; + }); - Charge const fee(dropThreshold + 1); + TestLogic logic(config->section("resource"), j); + + Charge const fee(Tuning::dropThreshold + 1); beast::IP::Endpoint const addr( beast::IP::Endpoint::from_string("192.0.2.2")); @@ -173,7 +178,7 @@ class ResourceManager_test : public beast::unit_test::suite using namespace std::chrono_literals; // Give Consumer time to become readmitted. Should never // exceed expiration time. - auto n = secondsUntilExpiration + 1s; + auto n = Tuning::secondsUntilExpiration + 1s; while (--n > 0s) { ++logic.clock(); @@ -199,7 +204,11 @@ class ResourceManager_test : public beast::unit_test::suite { testcase("Imports"); - TestLogic logic(j); + auto const config = test::jtx::envconfig([](std::unique_ptr cfg) { + return cfg; + }); + + TestLogic logic(config->section("resource"), j); Gossip g[5]; @@ -217,7 +226,11 @@ class ResourceManager_test : public beast::unit_test::suite { testcase("Import"); - TestLogic logic(j); + auto const config = test::jtx::envconfig([](std::unique_ptr cfg) { + return cfg; + }); + + TestLogic logic(config->section("resource"), j); Gossip g; Gossip::Item item; @@ -236,7 +249,11 @@ class ResourceManager_test : public beast::unit_test::suite { testcase("Charge"); - TestLogic logic(j); + auto const config = test::jtx::envconfig([](std::unique_ptr cfg) { + return cfg; + }); + + TestLogic logic(config->section("resource"), j); { beast::IP::Endpoint address( @@ -275,6 +292,41 @@ class ResourceManager_test : public beast::unit_test::suite pass(); } + void + testConfig(beast::Journal j) + { + + std::cout << "warningThreshold: " << Tuning::warningThreshold << "\n"; + std::cout << "dropThreshold: " << Tuning::dropThreshold << "\n"; + std::cout << "getDecayWindowSeconds: " << Tuning::getDecayWindowSeconds() << "\n"; + std::cout << "minimumGossipBalance: " << Tuning::minimumGossipBalance << "\n"; + + BEAST_EXPECT(Tuning::warningThreshold == 5000); + BEAST_EXPECT(Tuning::dropThreshold == 15000); + BEAST_EXPECT(Tuning::getDecayWindowSeconds() == 32); + BEAST_EXPECT(Tuning::minimumGossipBalance == 1000); + BEAST_EXPECT(Tuning::secondsUntilExpiration == std::chrono::seconds{300}); + BEAST_EXPECT(Tuning::gossipExpirationSeconds == std::chrono::seconds{30}); + + auto const config = test::jtx::envconfig([](std::unique_ptr cfg) { + cfg->section("resource").set("warning_threshold", "15000"); + cfg->section("resource").set("drop_threshold", "25000"); + cfg->section("resource").set("minimum_gossip_balance", "2000"); + cfg->section("resource").set("seconds_until_expiration", "600"); + cfg->section("resource").set("gossip_expiration_seconds", "60"); + return cfg; + }); + + TestLogic logic(config->section("resource"), j); + + BEAST_EXPECT(Tuning::warningThreshold == 15000); + BEAST_EXPECT(Tuning::dropThreshold == 25000); + BEAST_EXPECT(Tuning::getDecayWindowSeconds() == 32); + BEAST_EXPECT(Tuning::minimumGossipBalance == 2000); + // BEAST_EXPECT(Tuning::secondsUntilExpiration == 600); + // BEAST_EXPECT(Tuning::gossipExpirationSeconds == 60); + } + void run() override { @@ -286,6 +338,7 @@ class ResourceManager_test : public beast::unit_test::suite testCharges(journal); testImports(journal); testImport(journal); + testConfig(journal); } }; diff --git a/src/test/rpc/NoRippleCheck_test.cpp b/src/test/rpc/NoRippleCheck_test.cpp index 73934899e0..84b00b4dfc 100644 --- a/src/test/rpc/NoRippleCheck_test.cpp +++ b/src/test/rpc/NoRippleCheck_test.cpp @@ -276,11 +276,11 @@ class NoRippleCheckLimits_test : public beast::unit_test::suite Endpoint::from_string(test::getEnvLocalhostAddr())); // if we go above the warning threshold, reset - if (c.balance() > warningThreshold) + if (c.balance() > Tuning::warningThreshold) { using ct = beast::abstract_clock; c.entry().local_balance = - DecayingSample{steady_clock::now()}; + DecayingSample{steady_clock::now()}; } };