Skip to content

Commit

Permalink
Grow TxQ expected size quickly, shrink slowly (RIPD-1534):
Browse files Browse the repository at this point in the history
* Stores recent history of "good" ledgers. Uses the maximum as the
  expected ledger size. When a large value drops off, use a 90%
  backoff to go down to to the new maximum.
* If consensus is unhealthy, wipe the history in addition to the current
  clamping.
* Include .md doc files in xcode and VS projects
  • Loading branch information
ximinez authored and bachase committed Nov 29, 2017
1 parent 0a48916 commit c11e186
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 9 deletions.
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

0 comments on commit c11e186

Please sign in to comment.