Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Grow TxQ expected size quickly, shrink slowly (RIPD-1534): #2235

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ list(APPEND non_unity_srcs "${test_srcs}")

if(WIN32 OR is_xcode)
# Rippled headers. Only needed for IDEs.
file(GLOB_RECURSE rippled_headers src/*.h src/*.hpp)
file(GLOB_RECURSE rippled_headers src/*.h src/*.hpp *.md)
list(APPEND rippled_headers Builds/CMake/CMakeFuncs.cmake)
foreach(curdir
beast/asio
Expand Down
15 changes: 11 additions & 4 deletions src/ripple/app/misc/FeeEscalation.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,12 @@ consensus process, but will be at least [5](#other-constants).
* If consensus stays [healthy](#consensus-health), the limit will
be the max of the current limit or the number of transactions in
the validated ledger until it gets to [50](#other-constants), at
which point, the limit will only be updated to the number of
transactions in the validated ledger if it is larger than 50.
which point, the limit will be the largest number of transactions
in the last [20](#other-constants) validated ledgers which had
more than 50 transactions. Any time the limit decreases (ie. a
large ledger is no longer recent), the limit will decrease to the
new largest value by 10% each time the ledger has more than 50
transactions.
* If consensus does not stay [healthy](#consensus-health),
the limit will clamp down to the smaller of [50](#other-constants)
or the number of transactions in the validated ledger.
Expand Down Expand Up @@ -109,7 +113,8 @@ but in practice, either
sequence number and at least a [25% higher fee](#other-constants), or
* it will get dropped when the queue fills up with more valuable transactions.
The size limit is computed dynamically, and can hold transactions for
the next [20 ledgers](#other-constants). The lower the transaction's
the next [20 ledgers](#other-constants) (restricted to a minimum of
[2000 transactions](#other-constants)). The lower the transaction's
fee, the more likely that it will get dropped if the network is busy.

If a transaction is submitted for an account with one or more transactions
Expand Down Expand Up @@ -200,7 +205,9 @@ automatically as the ripple network's performance improves, allowing
more transactions per second, and thus more transactions per ledger
to process successfully. The limit of 20 ledgers was used to provide
a balance between resource (specifically memory) usage, and giving
transactions a realistic chance to be processed. This exact value was
transactions a realistic chance to be processed. The minimum size of
2000 transactions was chosen to allow a decent functional backlog during
network congestion conditions. These exact values were
chosen experimentally, and can easily change in the future.
* *Maximum retries*. A transaction in the queue can attempt to apply
to the open ledger, but get a retry (`ter`) code up to 10 times, at
Expand Down
2 changes: 1 addition & 1 deletion src/ripple/app/misc/NetworkOPs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,7 @@ void NetworkOPsImp::apply (std::unique_lock<std::mutex>& batchLock)
}
else if (e.result == terQUEUED)
{
JLOG(m_journal.info()) << "Transaction is likely to claim a " <<
JLOG(m_journal.debug()) << "Transaction is likely to claim a " <<
"fee, but is queued until fee drops";
e.transaction->setStatus(HELD);
// Add to held transactions, because it could get
Expand Down
5 changes: 5 additions & 0 deletions src/ripple/app/misc/TxQ.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <ripple/protocol/TER.h>
#include <ripple/protocol/STTx.h>
#include <boost/intrusive/set.hpp>
#include <boost/circular_buffer.hpp>

namespace ripple {

Expand Down Expand Up @@ -194,6 +195,9 @@ class TxQ
// One more than this value will be accepted
// before escalation kicks in.
std::size_t txnsExpected_;
// Recent history of transaction counts that
// exceed the targetTxnCount_
boost::circular_buffer<std::size_t> recentTxnCounts_;
// Minimum value of escalationMultiplier.
std::uint64_t const minimumMultiplier_;
// Based on the median fee of the LCL. Used
Expand All @@ -213,6 +217,7 @@ class TxQ
targetTxnCount_ : *setup.maximumTxnInLedger :
boost::optional<std::size_t>(boost::none))
, txnsExpected_(minimumTxnCount_)
, recentTxnCounts_(setup.ledgersInQueue)
, minimumMultiplier_(setup.minimumEscalationMultiplier)
, escalationMultiplier_(minimumMultiplier_)
, j_(j)
Expand Down
23 changes: 20 additions & 3 deletions src/ripple/app/misc/impl/TxQ.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <boost/algorithm/clamp.hpp>
#include <limits>
#include <numeric>
#include <algorithm>

namespace ripple {

Expand Down Expand Up @@ -107,16 +108,32 @@ TxQ::FeeMetrics::update(Application& app,
// so clamp down on limits.
txnsExpected_ = boost::algorithm::clamp(feeLevels.size(),
minimumTxnCount_, targetTxnCount_);
recentTxnCounts_.clear();
}
else if (feeLevels.size() > txnsExpected_ ||
feeLevels.size() > targetTxnCount_)
{
recentTxnCounts_.push_back(feeLevels.size());
auto const iter = std::max_element(recentTxnCounts_.begin(),
recentTxnCounts_.end());
BOOST_ASSERT(iter != recentTxnCounts_.end());
auto const next = [&]
{
// Grow quickly: If the max_element is >= the
// current size limit, use it.
if (*iter >= txnsExpected_)
return *iter;
// Shrink slowly: If the max_element is < the
// current size limit, use a limit that is
// 90% of the way from max_element to the
// current size limit.
return (txnsExpected_ * 9 + *iter) / 10;
}();
// Ledgers are processing in a timely manner,
// so keep the limit high, but don't let it
// grow without bound.
txnsExpected_ = maximumTxnCount_ ?
std::min(feeLevels.size(), *maximumTxnCount_) :
feeLevels.size();
txnsExpected_ = std::min(next,
maximumTxnCount_.value_or(next));
}

if (feeLevels.empty())
Expand Down