diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index d9845c3ae0..833bc9e191 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -2371,6 +2371,7 @@ + diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index ab5e19a0ae..f293b033e4 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -1772,6 +1772,9 @@ [2] Old Ripple\ripple_app\ledger + + [2] Old Ripple\ripple_app\ledger + [2] Old Ripple\ripple_app\ledger diff --git a/src/ripple_app/consensus/LedgerConsensus.cpp b/src/ripple_app/consensus/LedgerConsensus.cpp index 935231ef2f..bc60446881 100644 --- a/src/ripple_app/consensus/LedgerConsensus.cpp +++ b/src/ripple_app/consensus/LedgerConsensus.cpp @@ -1764,7 +1764,8 @@ private: mCloseTime = getApp().getOPs ().getCloseTimeNC (); getApp().getOPs ().setLastCloseTime (mCloseTime); statusChange (protocol::neCLOSING_LEDGER, *mPreviousLedger); - takeInitialPosition (*getApp().getLedgerMaster ().closeLedger (true)); + getApp().getLedgerMaster().closeLedger (true); + takeInitialPosition (*getApp().getLedgerMaster ().getCurrentLedger ()); } void checkOurValidation () diff --git a/src/ripple_app/ledger/LedgerHolder.h b/src/ripple_app/ledger/LedgerHolder.h new file mode 100644 index 0000000000..8b912f28bc --- /dev/null +++ b/src/ripple_app/ledger/LedgerHolder.h @@ -0,0 +1,77 @@ +//------------------------------------------------------------------------------ +/* + 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. +*/ +//============================================================================== + +#ifndef RIPPLE_LEDGERHOLDER_H +#define RIPPLE_LEDGERHOLDER_H + +// Can std::atomic> make this lock free? + +/** Hold a ledger in a thread-safe way. +*/ +class LedgerHolder +{ +public: + typedef RippleMutex LockType; + typedef LockType::ScopedLockType ScopedLockType; + + // Update the held ledger + void set (Ledger::pointer ledger) + { + // The held ledger must always be immutable + if (ledger && !ledger->isImmutable ()) + ledger = boost::make_shared (*ledger, false); + + { + ScopedLockType sl (m_lock, __FILE__, __LINE__); + + m_heldLedger = ledger; + } + } + + // Return the (immutable) held ledger + Ledger::pointer get () + { + ScopedLockType sl (m_lock, __FILE__, __LINE__); + + return m_heldLedger; + } + + // Return a mutable snapshot of the held ledger + Ledger::pointer getMutable () + { + Ledger::pointer ret = get (); + return ret ? boost::make_shared (*ret, true) : ret; + } + + + bool empty () + { + ScopedLockType sl (m_lock, __FILE__, __LINE__); + + return m_heldLedger == nullptr; + } + +private: + + LockType m_lock; + Ledger::pointer m_heldLedger; + +}; + +#endif diff --git a/src/ripple_app/ledger/LedgerMaster.cpp b/src/ripple_app/ledger/LedgerMaster.cpp index 47fc3188fd..77ccee06a6 100644 --- a/src/ripple_app/ledger/LedgerMaster.cpp +++ b/src/ripple_app/ledger/LedgerMaster.cpp @@ -42,10 +42,9 @@ public: TransactionEngine mEngine; - Ledger::pointer mCurrentLedger; // The ledger we are currently processiong - Ledger::pointer mCurrentSnapshot; // Snapshot of the current ledger - Ledger::pointer mClosedLedger; // The ledger that most recently closed - Ledger::pointer mValidLedger; // The highest-sequence ledger we have fully accepted + LedgerHolder mCurrentLedger; // The ledger we are currently processiong + LedgerHolder mClosedLedger; // The ledger that most recently closed + LedgerHolder mValidLedger; // The highest-sequence ledger we have fully accepted Ledger::pointer mPubLedger; // The last ledger we have published Ledger::pointer mPathLedger; // The last ledger we did pathfinding against @@ -104,17 +103,7 @@ public: uint32 getCurrentLedgerIndex () { - return mCurrentLedger->getLedgerSeq (); - } - - // An immutable snapshot of the current ledger - Ledger::ref getCurrentSnapshot () - { - if (!mCurrentSnapshot || (mCurrentSnapshot->getHash () != mCurrentLedger->getHash ())) - mCurrentSnapshot = boost::make_shared (boost::ref (*mCurrentLedger), false); - - assert (mCurrentSnapshot->isImmutable ()); - return mCurrentSnapshot; + return mCurrentLedger.get ()->getLedgerSeq (); } int getPublishedLedgerAge () @@ -175,7 +164,7 @@ public: void setValidLedger(Ledger::ref l) { - mValidLedger = l; + mValidLedger.set (l); mValidLedgerClose = l->getCloseTimeNC(); mValidLedgerSeq = l->getLedgerSeq(); } @@ -203,14 +192,15 @@ public: { ScopedLockType ml (m_mutex, __FILE__, __LINE__); - if (mClosedLedger) + Ledger::pointer closedLedger = mCurrentLedger.getMutable (); + if (closedLedger) { - mClosedLedger->setClosed (); - WriteLog (lsTRACE, LedgerMaster) << "Finalizes: " << mClosedLedger->getHash (); - } + closedLedger->setClosed (); + closedLedger->setImmutable (); + mClosedLedger.set (closedLedger); + } - mClosedLedger = mCurrentLedger; - mCurrentLedger = newLedger; + mCurrentLedger.set (newLedger); mEngine.setLedger (newLedger); } @@ -231,8 +221,8 @@ public: { ScopedLockType ml (m_mutex, __FILE__, __LINE__); - mClosedLedger = newLCL; - mCurrentLedger = newOL; + mClosedLedger.set (newLCL); + mCurrentLedger.set (newOL); mEngine.setLedger (newOL); } @@ -254,13 +244,15 @@ public: { ScopedLockType ml (m_mutex, __FILE__, __LINE__); - mClosedLedger = lastClosed; - mClosedLedger->setClosed (); - mClosedLedger->setAccepted (); - mCurrentLedger = current; - assert (!mCurrentLedger->isClosed ()); - mEngine.setLedger (mCurrentLedger); + lastClosed->setClosed (); + lastClosed->setAccepted (); + + mCurrentLedger.set (current); + mClosedLedger.set (lastClosed); + + assert (!current->isClosed ()); + mEngine.setLedger (current); } checkAccept (lastClosed); } @@ -281,10 +273,10 @@ public: setFullLedger(ledger, true, false); } - Ledger::pointer closeLedger (bool recover) + void closeLedger (bool recover) { ScopedLockType sl (m_mutex, __FILE__, __LINE__); - Ledger::pointer closingLedger = mCurrentLedger; + Ledger::pointer closingLedger = mCurrentLedger.getMutable (); if (recover) { @@ -318,10 +310,8 @@ public: mHeldTransactions.reset (closingLedger->getHash ()); } - mCurrentLedger = boost::make_shared (boost::ref (*closingLedger), true); - mEngine.setLedger (mCurrentLedger); - - return Ledger::pointer (new Ledger (*closingLedger, true)); + mCurrentLedger.set (closingLedger); + mEngine.setLedger (mCurrentLedger.getMutable ()); } TER doTransaction (SerializedTransaction::ref txn, TransactionEngineParams params, bool& didApply) @@ -335,7 +325,10 @@ public: ledger = mEngine.getLedger (); } if (didApply) + { + mCurrentLedger.set (ledger); getApp().getOPs ().pubProposedTransaction (ledger, txn, result); + } return result; } @@ -583,7 +576,7 @@ public: ScopedLockType ml (m_mutex, __FILE__, __LINE__); - if (!mValidLedger || (ledger->getLedgerSeq() > mValidLedger->getLedgerSeq())) + if (ledger->getLedgerSeq() > mValidLedgerSeq) setValidLedger(ledger); if (!mPubLedger) { @@ -642,13 +635,13 @@ public: void checkAccept (Ledger::ref ledger) { - if (ledger->getLedgerSeq() <= mValidLedgerSeq.load()) + if (ledger->getLedgerSeq() <= mValidLedgerSeq) return; // Can we advance the last fully-validated ledger? If so, can we publish? ScopedLockType ml (m_mutex, __FILE__, __LINE__); - if (mValidLedger && (ledger->getLedgerSeq() <= mValidLedger->getLedgerSeq ())) + if (ledger->getLedgerSeq() <= mValidLedgerSeq) return; int minVal = mMinValidations; @@ -704,7 +697,7 @@ public: void advanceThread() { ScopedLockType sl (m_mutex, __FILE__, __LINE__); - assert (mValidLedger && mAdvanceThread); + assert (!mValidLedger.empty () && mAdvanceThread); WriteLog (lsTRACE, LedgerMaster) << "advanceThread<"; @@ -734,7 +727,7 @@ public: { if (!getConfig().RUN_STANDALONE && !getApp().getFeeTrack().isLoadedLocal() && (getApp().getJobQueue().getJobCount(jtPUBOLDLEDGER) < 10) && - (mValidLedger->getLedgerSeq() == mPubLedger->getLedgerSeq())) + (mValidLedgerSeq == mPubLedgerSeq)) { // We are in sync, so can acquire uint32 missing; { @@ -743,7 +736,7 @@ public: } WriteLog (lsTRACE, LedgerMaster) << "tryAdvance discovered missing " << missing; if ((missing != RangeSet::absent) && (missing > 0) && - shouldAcquire(mValidLedger->getLedgerSeq(), getConfig().LEDGER_HISTORY, missing) && + shouldAcquire(mValidLedgerSeq, getConfig().LEDGER_HISTORY, missing) && ((mFillInProgress == 0) || (missing > mFillInProgress))) { WriteLog (lsTRACE, LedgerMaster) << "advanceThread should acquire"; @@ -809,13 +802,13 @@ public: else { WriteLog (lsFATAL, LedgerMaster) << "Unable to find ledger following prevMissing " << missing; - WriteLog (lsFATAL, LedgerMaster) << "Pub:" << mPubLedger->getLedgerSeq() << " Val:" << mValidLedger->getLedgerSeq(); + WriteLog (lsFATAL, LedgerMaster) << "Pub:" << mPubLedgerSeq << " Val:" << mValidLedgerSeq; WriteLog (lsFATAL, LedgerMaster) << "Ledgers: " << getApp().getLedgerMaster().getCompleteLedgers(); clearLedger (missing + 1); progress = true; } } - if (mValidLedger->getLedgerSeq() != mPubLedger->getLedgerSeq()) + if (mValidLedgerSeq != mPubLedgerSeq) { WriteLog (lsDEBUG, LedgerMaster) << "tryAdvance found last valid changed"; progress = true; @@ -857,24 +850,25 @@ public: WriteLog (lsTRACE, LedgerMaster) << "findNewLedgersToPublish<"; if (!mPubLedger) { - WriteLog (lsINFO, LedgerMaster) << "First published ledger will be " << mValidLedger->getLedgerSeq(); - ret.push_back (mValidLedger); + WriteLog (lsINFO, LedgerMaster) << "First published ledger will be " << mValidLedgerSeq; + ret.push_back (mValidLedger.get ()); } - else if (mValidLedger->getLedgerSeq () > (mPubLedger->getLedgerSeq () + MAX_LEDGER_GAP)) + else if (mValidLedgerSeq > (mPubLedgerSeq + MAX_LEDGER_GAP)) { - WriteLog (lsWARNING, LedgerMaster) << "Gap in validated ledger stream " << mPubLedger->getLedgerSeq () << " - " << - mValidLedger->getLedgerSeq () - 1; - ret.push_back (mValidLedger); - setPubLedger (mValidLedger); - getApp().getOrderBookDB().setup(mValidLedger); + WriteLog (lsWARNING, LedgerMaster) << "Gap in validated ledger stream " << mPubLedgerSeq << " - " << + mValidLedgerSeq - 1; + Ledger::pointer valLedger = mValidLedger.get (); + ret.push_back (valLedger); + setPubLedger (valLedger); + getApp().getOrderBookDB().setup(valLedger); } - else if (mValidLedger->getLedgerSeq () > mPubLedger->getLedgerSeq ()) + else if (mValidLedgerSeq > mPubLedgerSeq) { int acqCount = 0; - uint32 pubSeq = mPubLedger->getLedgerSeq() + 1; // Next sequence to publish - uint32 valSeq = mValidLedger->getLedgerSeq(); - Ledger::pointer valLedger = mValidLedger; + uint32 pubSeq = mPubLedgerSeq + 1; // Next sequence to publish + Ledger::pointer valLedger = mValidLedger.get (); + uint32 valSeq = valLedger->getLedgerSeq (); ScopedUnlockType sul(m_mutex, __FILE__, __LINE__); try @@ -953,7 +947,7 @@ public: // Can't advance without at least one fully-valid ledger mAdvanceWork = true; - if (!mAdvanceThread && mValidLedger) + if (!mAdvanceThread && !mValidLedger.empty ()) { mAdvanceThread = true; getApp().getJobQueue ().addJob (jtADVANCE, "advanceLedger", @@ -995,7 +989,7 @@ public: { { ScopedLockType ml (m_mutex, __FILE__, __LINE__); - if (getApp().getOPs().isNeedNetworkLedger () || !mCurrentLedger) + if (getApp().getOPs().isNeedNetworkLedger () || mCurrentLedger.empty ()) { --mPathFindThread; return; @@ -1009,15 +1003,15 @@ public: { ScopedLockType ml (m_mutex, __FILE__, __LINE__); - if (mValidLedger && - (!mPathLedger || (mPathLedger->getLedgerSeq() != mValidLedger->getLedgerSeq()))) + if (!mValidLedger.empty() && + (!mPathLedger || (mPathLedger->getLedgerSeq() != mValidLedgerSeq))) { // We have a new valid ledger since the last full pathfinding - mPathLedger = mValidLedger; + mPathLedger = mValidLedger.get (); lastLedger = mPathLedger; } else if (mPathFindNewRequest) { // We have a new request but no new ledger - lastLedger = boost::make_shared (boost::ref (*mCurrentLedger), false); + lastLedger = mCurrentLedger.get (); } else { // Nothing to do @@ -1095,21 +1089,21 @@ public: } // The current ledger is the ledger we believe new transactions should go in - Ledger::ref getCurrentLedger () + Ledger::pointer getCurrentLedger () { - return mCurrentLedger; + return mCurrentLedger.get (); } // The finalized ledger is the last closed/accepted ledger - Ledger::ref getClosedLedger () + Ledger::pointer getClosedLedger () { - return mClosedLedger; + return mClosedLedger.get (); } // The validated ledger is the last fully validated ledger - Ledger::ref getValidatedLedger () + Ledger::pointer getValidatedLedger () { - return mValidLedger; + return mValidLedger.get (); } // This is the last ledger we published to clients and can lag the validated ledger @@ -1164,10 +1158,7 @@ public: uint256 ledgerHash; Ledger::pointer referenceLedger; - { - ScopedLockType sl (m_mutex, __FILE__, __LINE__); - referenceLedger = mValidLedger; - } + referenceLedger = mValidLedger.get (); if (referenceLedger) ledgerHash = walkHashBySeq (index, referenceLedger); return ledgerHash; @@ -1211,20 +1202,18 @@ public: Ledger::pointer getLedgerBySeq (uint32 index) { - { - ScopedLockType sl (m_mutex, __FILE__, __LINE__); - if (mCurrentLedger && (mCurrentLedger->getLedgerSeq () == index)) - return mCurrentLedger; - - if (mClosedLedger && (mClosedLedger->getLedgerSeq () == index)) - return mClosedLedger; - } - Ledger::pointer ret = mLedgerHistory.getLedgerBySeq (index); - if (ret) return ret; + ret = mCurrentLedger.get (); + if (ret && (ret->getLedgerSeq () == index)) + return ret; + + ret = mClosedLedger.get (); + if (ret && (ret->getLedgerSeq () == index)) + return ret; + clearLedger (index); return ret; } @@ -1232,15 +1221,21 @@ public: Ledger::pointer getLedgerByHash (uint256 const& hash) { if (hash.isZero ()) - return boost::make_shared (boost::ref (*mCurrentLedger), false); + return mCurrentLedger.get (); - if (mCurrentLedger && (mCurrentLedger->getHash () == hash)) - return boost::make_shared (boost::ref (*mCurrentLedger), false); + Ledger::pointer ret = mLedgerHistory.getLedgerByHash (hash); + if (ret) + return ret; - if (mClosedLedger && (mClosedLedger->getHash () == hash)) - return mClosedLedger; + ret = mCurrentLedger.get (); + if (ret && (ret->getHash () == hash)) + return ret; - return mLedgerHistory.getLedgerByHash (hash); + ret = mClosedLedger.get (); + if (ret && (ret->getHash () == hash)) + return ret; + + return Ledger::pointer (); } void doLedgerCleaner(const Json::Value& parameters) diff --git a/src/ripple_app/ledger/LedgerMaster.h b/src/ripple_app/ledger/LedgerMaster.h index c03e9a4093..9038527ddf 100644 --- a/src/ripple_app/ledger/LedgerMaster.h +++ b/src/ripple_app/ledger/LedgerMaster.h @@ -50,16 +50,13 @@ public: virtual LockType& peekMutex () = 0; // The current ledger is the ledger we believe new transactions should go in - virtual Ledger::ref getCurrentLedger () = 0; - - // An immutable snapshot of the current ledger - virtual Ledger::ref getCurrentSnapshot () = 0; + virtual Ledger::pointer getCurrentLedger () = 0; // The finalized ledger is the last closed/accepted ledger - virtual Ledger::ref getClosedLedger () = 0; + virtual Ledger::pointer getClosedLedger () = 0; // The validated ledger is the last fully validated ledger - virtual Ledger::ref getValidatedLedger () = 0; + virtual Ledger::pointer getValidatedLedger () = 0; // This is the last ledger we published to clients and can lag the validated ledger virtual Ledger::ref getPublishedLedger () = 0; @@ -89,7 +86,7 @@ public: virtual std::string getCompleteLedgers () = 0; - virtual Ledger::pointer closeLedger (bool recoverHeldTransactions) = 0; + virtual void closeLedger (bool recoverHeldTransactions) = 0; /** Get a ledger's hash by sequence number using the cache */ diff --git a/src/ripple_app/misc/NetworkOPs.cpp b/src/ripple_app/misc/NetworkOPs.cpp index 96485891c2..d12158d7ba 100644 --- a/src/ripple_app/misc/NetworkOPs.cpp +++ b/src/ripple_app/misc/NetworkOPs.cpp @@ -75,26 +75,22 @@ public: } std::string strOperatingMode (); - Ledger::ref getClosedLedger () + Ledger::pointer getClosedLedger () { return m_ledgerMaster.getClosedLedger (); } - Ledger::ref getValidatedLedger () + Ledger::pointer getValidatedLedger () { return m_ledgerMaster.getValidatedLedger (); } - Ledger::ref getPublishedLedger () + Ledger::pointer getPublishedLedger () { return m_ledgerMaster.getPublishedLedger (); } - Ledger::ref getCurrentLedger () + Ledger::pointer getCurrentLedger () { return m_ledgerMaster.getCurrentLedger (); } - Ledger::ref getCurrentSnapshot () - { - return m_ledgerMaster.getCurrentSnapshot (); - } Ledger::pointer getLedgerByHash (uint256 const& hash) { return m_ledgerMaster.getLedgerByHash (hash); @@ -2289,7 +2285,7 @@ void NetworkOPsImp::pubProposedTransaction (Ledger::ref lpCurrent, SerializedTra } AcceptedLedgerTx alt (stTxn, terResult); m_journal.trace << "pubProposed: " << alt.getJson (); - pubAccountTransaction (lpCurrent, AcceptedLedgerTx (stTxn, terResult), false); + pubAccountTransaction (lpCurrent, alt, false); } void NetworkOPsImp::pubLedger (Ledger::ref accepted) diff --git a/src/ripple_app/misc/NetworkOPs.h b/src/ripple_app/misc/NetworkOPs.h index b2c0d5aacc..ed3b08bc50 100644 --- a/src/ripple_app/misc/NetworkOPs.h +++ b/src/ripple_app/misc/NetworkOPs.h @@ -103,11 +103,10 @@ public: virtual OperatingMode getOperatingMode () = 0; virtual std::string strOperatingMode () = 0; - virtual Ledger::ref getClosedLedger () = 0; - virtual Ledger::ref getValidatedLedger () = 0; - virtual Ledger::ref getPublishedLedger () = 0; - virtual Ledger::ref getCurrentLedger () = 0; - virtual Ledger::ref getCurrentSnapshot () = 0; + virtual Ledger::pointer getClosedLedger () = 0; + virtual Ledger::pointer getValidatedLedger () = 0; + virtual Ledger::pointer getPublishedLedger () = 0; + virtual Ledger::pointer getCurrentLedger () = 0; virtual Ledger::pointer getLedgerByHash (uint256 const& hash) = 0; virtual Ledger::pointer getLedgerBySeq (const uint32 seq) = 0; virtual void missingNodeInLedger (const uint32 seq) = 0; diff --git a/src/ripple_app/ripple_app.h b/src/ripple_app/ripple_app.h index 65325e3a71..f9c6c28ed8 100644 --- a/src/ripple_app/ripple_app.h +++ b/src/ripple_app/ripple_app.h @@ -108,6 +108,7 @@ namespace ripple { #include "ledger/LedgerEntrySet.h" #include "tx/TransactionEngine.h" #include "misc/CanonicalTXSet.h" +#include "ledger/LedgerHolder.h" #include "ledger/LedgerHistory.h" #include "ledger/LedgerCleaner.h" #include "ledger/LedgerMaster.h" diff --git a/src/ripple_app/rpc/RPCHandler.cpp b/src/ripple_app/rpc/RPCHandler.cpp index 480f2604cb..192e132bf7 100644 --- a/src/ripple_app/rpc/RPCHandler.cpp +++ b/src/ripple_app/rpc/RPCHandler.cpp @@ -86,7 +86,7 @@ Json::Value RPCHandler::transactionSign (Json::Value params, bool bSubmit, bool } std::string sType = txJSON["TransactionType"].asString (); - Ledger::pointer lSnapshot = mNetOps->getCurrentSnapshot (); + Ledger::pointer lSnapshot = mNetOps->getCurrentLedger (); AccountState::pointer asSrc = bOffline ? AccountState::pointer () // Don't look up address if offline. : mNetOps->getAccountState (lSnapshot, raSrcAddressID); @@ -3045,7 +3045,7 @@ Json::Value RPCHandler::lookupLedger (Json::Value params, Ledger::pointer& lpLed switch (iLedgerIndex) { case LEDGER_CURRENT: - lpLedger = mNetOps->getCurrentSnapshot (); + lpLedger = mNetOps->getCurrentLedger (); iLedgerIndex = lpLedger->getLedgerSeq (); assert (lpLedger->isImmutable () && !lpLedger->isClosed ()); break;