From 8f09d3449dfcc209704edb6cf0bf9edeeb661cfa Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Thu, 3 Sep 2015 10:51:16 -0700 Subject: [PATCH] Improve ledger replay logic Build a replay structure holding the transactions in execution order along with the close time. Use this structure when replaying a ledger close. --- src/ripple/app/ledger/LedgerConsensus.h | 13 +++++++ src/ripple/app/ledger/LedgerMaster.h | 12 ++++++ .../app/ledger/impl/LedgerConsensusImp.cpp | 39 +++++++++++++------ src/ripple/app/ledger/impl/LedgerMaster.cpp | 13 +++++++ src/ripple/app/main/Application.cpp | 26 ++++++++++--- 5 files changed, 85 insertions(+), 18 deletions(-) diff --git a/src/ripple/app/ledger/LedgerConsensus.h b/src/ripple/app/ledger/LedgerConsensus.h index bd2a19d8b..da45a4189 100644 --- a/src/ripple/app/ledger/LedgerConsensus.h +++ b/src/ripple/app/ledger/LedgerConsensus.h @@ -87,6 +87,19 @@ void applyTransactions ( CanonicalTXSet& retriableTransactions, ApplyFlags flags); +/** Apply a single transaction to a ledger + @param view The open view to apply to + @param txn The transaction to apply + @param retryAssured True if another pass is assured + @param flags Flags for transactor + @return resultSuccess, resultFail or resultRetry +*/ +int applyTransaction ( + OpenView& view, + std::shared_ptr const& txn, + bool retryAssured, + ApplyFlags flags); + } // ripple #endif diff --git a/src/ripple/app/ledger/LedgerMaster.h b/src/ripple/app/ledger/LedgerMaster.h index 5aab15570..60ed708cd 100644 --- a/src/ripple/app/ledger/LedgerMaster.h +++ b/src/ripple/app/ledger/LedgerMaster.h @@ -38,6 +38,14 @@ namespace ripple { class Peer; +struct LedgerReplay +{ + std::map< int, std::shared_ptr > txns_; + std::uint32_t closeTime_; + int closeFlags_; + Ledger::pointer prevLedger_; +}; + // Tracks the current ledger and any ledgers in the process of closing // Tracks ledger history // Tracks held transactions @@ -167,6 +175,10 @@ public: virtual void clearLedgerCachePrior (LedgerIndex seq) = 0; + // ledger replay + virtual void takeReplay (std::unique_ptr replay) = 0; + virtual std::unique_ptr releaseReplay () = 0; + // Fetch Packs virtual void gotFetchPack ( diff --git a/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp b/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp index 1b6eb5898..9b1796bad 100644 --- a/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp +++ b/src/ripple/app/ledger/impl/LedgerConsensusImp.cpp @@ -970,8 +970,21 @@ void LedgerConsensusImp::accept (std::shared_ptr set) consensus_.peekStoredProposals ().clear (); } - std::uint32_t closeTime = roundCloseTime ( - mOurPosition->getCloseTime (), mCloseResolution); + auto closeTime = mOurPosition->getCloseTime(); + + auto replay = ledgerMaster_.releaseReplay(); + + if (replay) + { + // If we're replaying a close, use the time the ledger + // we're replaying closed + closeTime = replay->closeTime_; + + if ((replay->closeFlags_ & sLCF_NoConsensusTime) != 0) + closeTime = 0; + } + + closeTime = roundCloseTime (closeTime, mCloseResolution); // If we don't have a close time, then we just agree to disagree bool const closeTimeCorrect = (closeTime != 0); @@ -1018,8 +1031,18 @@ void LedgerConsensusImp::accept (std::shared_ptr set) { OpenView accum(&*newLCL); assert(accum.closed()); - applyTransactions (app_, set.get(), accum, - newLCL, retriableTxs, tapNONE); + if (replay) + { + // Special case, we are replaying a ledger close + for (auto& tx : replay->txns_) + applyTransaction (accum, tx.second, false, tapNO_CHECK_SIGN); + } + else + { + // Normal case, we are not replaying a ledger close + applyTransactions (app_, set.get(), accum, + newLCL, retriableTxs, tapNONE); + } accum.apply(*newLCL); } @@ -1782,14 +1805,6 @@ make_LedgerConsensus (Application& app, ConsensusImp& consensus, int previousPro //------------------------------------------------------------------------------ -/** Apply a transaction to a ledger - - @param engine The transaction engine containing the ledger. - @param txn The transaction to be applied to ledger. - @param retryAssured true if the transaction should be retried on failure. - @return One of resultSuccess, resultFail or resultRetry. -*/ -static int applyTransaction (Application& app, OpenView& view, std::shared_ptr const& txn, diff --git a/src/ripple/app/ledger/impl/LedgerMaster.cpp b/src/ripple/app/ledger/impl/LedgerMaster.cpp index 27b36584c..e3aa053a5 100644 --- a/src/ripple/app/ledger/impl/LedgerMaster.cpp +++ b/src/ripple/app/ledger/impl/LedgerMaster.cpp @@ -96,6 +96,9 @@ public: CanonicalTXSet mHeldTransactions; + // A set of transactions to replay during the next close + std::unique_ptr replayData; + LockType mCompleteLock; RangeSet mCompleteLedgers; @@ -1538,6 +1541,16 @@ public: mLedgerHistory.clearLedgerCachePrior (seq); } + void takeReplay (std::unique_ptr replay) override + { + replayData = std::move (replay); + } + + std::unique_ptr releaseReplay () override + { + return std::move (replayData); + } + // Fetch packs: void gotFetchPack ( bool progress, diff --git a/src/ripple/app/main/Application.cpp b/src/ripple/app/main/Application.cpp index 88b96880d..efed23e8e 100644 --- a/src/ripple/app/main/Application.cpp +++ b/src/ripple/app/main/Application.cpp @@ -1345,22 +1345,36 @@ bool ApplicationImp::loadOldLedger ( if (replay) { // inject transaction(s) from the replayLedger into our open ledger + // and build replay structure auto const& txns = replayLedger->txMap(); + auto replayData = std::make_unique (); + + replayData->prevLedger_ = replayLedger; + replayData->closeTime_ = replayLedger->info().closeTime; + replayData->closeFlags_ = replayLedger->info().closeFlags; for (auto const& item : txns) { - getHashRouter().setFlags (item.key(), SF_SIGGOOD); + auto txID = item.key(); + auto txPair = replayLedger->txRead (txID); + auto txIndex = (*txPair.second)[sfTransactionIndex]; + + auto s = std::make_shared (); + txPair.first->add(*s); + + getHashRouter().setFlags (txID, SF_SIGGOOD); + + replayData->txns_.emplace (txIndex, txPair.first); + openLedger_->modify( - [&replayLedger, &item](OpenView& view, beast::Journal j) + [&txID, &s](OpenView& view, beast::Journal j) { - auto s = std::make_shared (); - replayLedger->txRead(item.key()).first->add(*s); - view.rawTxInsert (item.key(), std::move (s), nullptr); + view.rawTxInsert (txID, std::move (s), nullptr); return true; }); } - m_ledgerMaster->switchLCL (loadLedger); + m_ledgerMaster->takeReplay (std::move (replayData)); } } catch (SHAMapMissingNode&)