From 50be7dd7e43d75f636ad4a4c9fff8879c3b55cd2 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 27 Feb 2013 15:17:06 -0800 Subject: [PATCH 1/3] Some quick changes to improve pathfinding performance. (20% faster roughly) --- src/cpp/ripple/LedgerEntrySet.cpp | 2 +- src/cpp/ripple/RippleCalc.cpp | 20 ++++++++-------- src/cpp/ripple/RippleState.cpp | 40 ++++++++++++++++++------------- 3 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/cpp/ripple/LedgerEntrySet.cpp b/src/cpp/ripple/LedgerEntrySet.cpp index 860247768..e47ed099d 100644 --- a/src/cpp/ripple/LedgerEntrySet.cpp +++ b/src/cpp/ripple/LedgerEntrySet.cpp @@ -1025,7 +1025,7 @@ uint32 LedgerEntrySet::rippleQualityIn(const uint160& uToAccountID, const uint16 } } - cLog(lsINFO) << boost::str(boost::format("rippleQuality: %s uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQuality=%f") + cLog(lsTRACE) << boost::str(boost::format("rippleQuality: %s uToAccountID=%s uFromAccountID=%s uCurrencyID=%s bLine=%d uQuality=%f") % (sfLow == sfLowQualityIn ? "in" : "out") % RippleAddress::createHumanAccountID(uToAccountID) % RippleAddress::createHumanAccountID(uFromAccountID) diff --git a/src/cpp/ripple/RippleCalc.cpp b/src/cpp/ripple/RippleCalc.cpp index 5bf438bbb..e1c41077a 100644 --- a/src/cpp/ripple/RippleCalc.cpp +++ b/src/cpp/ripple/RippleCalc.cpp @@ -72,7 +72,7 @@ TER PathState::pushImply( const PaymentNode& pnPrv = vpnNodes.back(); TER terResult = tesSUCCESS; - cLog(lsINFO) << "pushImply> " + cLog(lsTRACE) << "pushImply> " << RippleAddress::createHumanAccountID(uAccountID) << " " << STAmount::createHumanCurrency(uCurrencyID) << " " << RippleAddress::createHumanAccountID(uIssuerID); @@ -107,7 +107,7 @@ TER PathState::pushImply( uIssuerID); } - cLog(lsINFO) << boost::str(boost::format("pushImply< : %s") % transToken(terResult)); + cLog(lsTRACE) << boost::str(boost::format("pushImply< : %s") % transToken(terResult)); return terResult; } @@ -133,7 +133,7 @@ TER PathState::pushNode( const bool bIssuer = isSetBit(iType, STPathElement::typeIssuer); TER terResult = tesSUCCESS; - cLog(lsDEBUG) << "pushNode> " + cLog(lsTRACE) << "pushNode> " << iType << ": " << (bAccount ? RippleAddress::createHumanAccountID(uAccountID) : "-") << " " << (bCurrency ? STAmount::createHumanCurrency(uCurrencyID) : "-") @@ -209,7 +209,7 @@ TER PathState::pushNode( if (!sleRippleState) { - cLog(lsINFO) << "pushNode: No credit line between " + cLog(lsTRACE) << "pushNode: No credit line between " << RippleAddress::createHumanAccountID(pnBck.uAccountID) << " and " << RippleAddress::createHumanAccountID(pnCur.uAccountID) @@ -217,13 +217,13 @@ TER PathState::pushNode( << STAmount::createHumanCurrency(pnCur.uCurrencyID) << "." ; - cLog(lsINFO) << getJson(); + cLog(lsTRACE) << getJson(); terResult = terNO_LINE; } else { - cLog(lsINFO) << "pushNode: Credit line found between " + cLog(lsDEBUG) << "pushNode: Credit line found between " << RippleAddress::createHumanAccountID(pnBck.uAccountID) << " and " << RippleAddress::createHumanAccountID(pnCur.uAccountID) @@ -280,7 +280,7 @@ TER PathState::pushNode( vpnNodes.push_back(pnCur); } } - cLog(lsINFO) << boost::str(boost::format("pushNode< : %s") % transToken(terResult)); + cLog(lsDEBUG) << boost::str(boost::format("pushNode< : %s") % transToken(terResult)); return terResult; } @@ -1660,7 +1660,7 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState& psCur, c ? lesActive.rippleOwed(uCurAccountID, uNxtAccountID, uCurrencyID) : STAmount(uCurrencyID, uCurAccountID); - cLog(lsDEBUG) << boost::str(boost::format("calcNodeAccountRev> uNode=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") + cLog(lsTRACE) << boost::str(boost::format("calcNodeAccountRev> uNode=%d/%d uPrvAccountID=%s uCurAccountID=%s uNxtAccountID=%s uCurrencyID=%s uQualityIn=%d uQualityOut=%d saPrvOwed=%s saPrvLimit=%s") % uNode % uLast % RippleAddress::createHumanAccountID(uPrvAccountID) @@ -1695,14 +1695,14 @@ TER RippleCalc::calcNodeAccountRev(const unsigned int uNode, PathState& psCur, c const STAmount& saCurDeliverReq = pnCur.saRevDeliver; STAmount saCurDeliverAct(saCurDeliverReq.getCurrency(), saCurDeliverReq.getIssuer()); - cLog(lsDEBUG) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurRedeemReq=%s saCurIssueReq=%s saNxtOwed=%s") + cLog(lsTRACE) << boost::str(boost::format("calcNodeAccountRev: saPrvRedeemReq=%s saPrvIssueReq=%s saCurRedeemReq=%s saCurIssueReq=%s saNxtOwed=%s") % saPrvRedeemReq.getFullText() % saPrvIssueReq.getFullText() % saCurRedeemReq.getFullText() % saCurIssueReq.getFullText() % saNxtOwed.getFullText()); - cLog(lsDEBUG) << psCur.getJson(); + cLog(lsTRACE) << psCur.getJson(); assert(!saCurRedeemReq || (-saNxtOwed) >= saCurRedeemReq); // Current redeem req can't be more than IOUs on hand. assert(!saCurIssueReq // If not issuing, fine. diff --git a/src/cpp/ripple/RippleState.cpp b/src/cpp/ripple/RippleState.cpp index 1ec6ebdaf..3babaebb7 100644 --- a/src/cpp/ripple/RippleState.cpp +++ b/src/cpp/ripple/RippleState.cpp @@ -11,24 +11,32 @@ AccountItem::pointer RippleState::makeItem(const uint160& accountID, SerializedL } RippleState::RippleState(SerializedLedgerEntry::ref ledgerEntry) : AccountItem(ledgerEntry), - mValid(false), - mViewLowest(true) + mValid(false), mViewLowest(true) { - mFlags = mLedgerEntry->getFieldU32(sfFlags); + for (int i = 0, iMax = mLedgerEntry->getCount(); i < iMax; ++i) + { + const SerializedType* entry = mLedgerEntry->peekAtPIndex(i); + assert(entry); - mLowLimit = mLedgerEntry->getFieldAmount(sfLowLimit); - mHighLimit = mLedgerEntry->getFieldAmount(sfHighLimit); - - mLowID = RippleAddress::createAccountID(mLowLimit.getIssuer()); - mHighID = RippleAddress::createAccountID(mHighLimit.getIssuer()); - - mLowQualityIn = mLedgerEntry->getFieldU32(sfLowQualityIn); - mLowQualityOut = mLedgerEntry->getFieldU32(sfLowQualityOut); - - mHighQualityIn = mLedgerEntry->getFieldU32(sfHighQualityIn); - mHighQualityOut = mLedgerEntry->getFieldU32(sfHighQualityOut); - - mBalance = mLedgerEntry->getFieldAmount(sfBalance); + if (entry->getFName() == sfFlags) + mFlags = static_cast(entry)->getValue(); + else if (entry->getFName() == sfLowLimit) + { + mLowLimit = *static_cast(entry); + mLowID = RippleAddress::createAccountID(mLowLimit.getIssuer()); + } + else if (entry->getFName() == sfHighLimit) + { + mHighLimit = *static_cast(entry); + mHighID = RippleAddress::createAccountID(mHighLimit.getIssuer()); + } + else if (entry->getFName() == sfLowQualityIn) + mLowQualityIn = static_cast(entry)->getValue(); + else if (entry->getFName() == sfHighQualityIn) + mHighQualityIn = static_cast(entry)->getValue(); + else if (entry->getFName() == sfBalance) + mBalance = *static_cast(entry); + } mValid = true; } From ab89fbdcf66071770064114a1c567e15dd04ff05 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 27 Feb 2013 15:52:33 -0800 Subject: [PATCH 2/3] Use the job queue rather than an ephemeral thread for validation writeouts. --- src/cpp/ripple/ValidationCollection.cpp | 5 ++--- src/cpp/ripple/ValidationCollection.h | 3 ++- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/cpp/ripple/ValidationCollection.cpp b/src/cpp/ripple/ValidationCollection.cpp index 5fff5a120..cfdec56cd 100644 --- a/src/cpp/ripple/ValidationCollection.cpp +++ b/src/cpp/ripple/ValidationCollection.cpp @@ -293,11 +293,10 @@ void ValidationCollection::condWrite() if (mWriting) return; mWriting = true; - boost::thread thread(boost::bind(&ValidationCollection::doWrite, this)); - thread.detach(); + theApp->getJobQueue().addJob(jtWRITE, boost::bind(&ValidationCollection::doWrite, this, _1)); } -void ValidationCollection::doWrite() +void ValidationCollection::doWrite(Job&) { LoadEvent::autoptr event(theApp->getJobQueue().getLoadEventAP(jtDISK)); static boost::format insVal("INSERT INTO Validations " diff --git a/src/cpp/ripple/ValidationCollection.h b/src/cpp/ripple/ValidationCollection.h index e6973886d..648ea173c 100644 --- a/src/cpp/ripple/ValidationCollection.h +++ b/src/cpp/ripple/ValidationCollection.h @@ -10,6 +10,7 @@ #include "types.h" #include "SerializedValidation.h" #include "TaggedCache.h" +#include "JobQueue.h" typedef boost::unordered_map ValidationSet; @@ -26,7 +27,7 @@ protected: bool mWriting; - void doWrite(); + void doWrite(Job&); void condWrite(); boost::shared_ptr findCreateSet(const uint256& ledgerHash); From 312e476898a874e453f510dde545844b7b12d133 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 27 Feb 2013 18:23:24 -0800 Subject: [PATCH 3/3] Fix a bug where a cached copy of a txn might not have a reference to the ledger it was applied in, causing commands like 'tx' not to return metadata. --- src/cpp/ripple/Ledger.cpp | 2 ++ src/cpp/ripple/TransactionMaster.cpp | 15 +++++++++++++-- src/cpp/ripple/TransactionMaster.h | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/cpp/ripple/Ledger.cpp b/src/cpp/ripple/Ledger.cpp index 609f08787..a43d2bee4 100644 --- a/src/cpp/ripple/Ledger.cpp +++ b/src/cpp/ripple/Ledger.cpp @@ -451,9 +451,11 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event) std::string escMeta(sqlEscape(rawMeta.peekData())); SerializerIterator txnIt(rawTxn); + SerializedTransaction txn(txnIt); assert(txn.getTransactionID() == item->getTag()); TransactionMetaSet meta(item->getTag(), mLedgerSeq, rawMeta.peekData()); + theApp->getMasterTransaction().inLedger(item->getTag(), mLedgerSeq); // Make sure transaction is in AccountTransactions. if (!SQL_EXISTS(db, boost::str(AcctTransExists % item->getTag().GetHex()))) diff --git a/src/cpp/ripple/TransactionMaster.cpp b/src/cpp/ripple/TransactionMaster.cpp index d92aa5e90..3c7991350 100644 --- a/src/cpp/ripple/TransactionMaster.cpp +++ b/src/cpp/ripple/TransactionMaster.cpp @@ -18,13 +18,24 @@ TransactionMaster::TransactionMaster() : mCache("TransactionCache", CACHED_TRANS ; } +bool TransactionMaster::inLedger(const uint256& hash, uint32 ledger) +{ + Transaction::pointer txn = mCache.fetch(hash); + if (!txn) + return false; + txn->setStatus(COMMITTED, ledger); + return true; +} + Transaction::pointer TransactionMaster::fetch(const uint256& txnID, bool checkDisk) { Transaction::pointer txn = mCache.fetch(txnID); - if (!checkDisk || txn) return txn; + if (!checkDisk || txn) + return txn; txn = Transaction::load(txnID); - if (!txn) return txn; + if (!txn) + return txn; mCache.canonicalize(txnID, txn); diff --git a/src/cpp/ripple/TransactionMaster.h b/src/cpp/ripple/TransactionMaster.h index 2db5eb170..59b486280 100644 --- a/src/cpp/ripple/TransactionMaster.h +++ b/src/cpp/ripple/TransactionMaster.h @@ -20,6 +20,7 @@ public: bool checkDisk, uint32 uCommitLedger); // return value: true = we had the transaction already + bool inLedger(const uint256& hash, uint32 ledger); bool canonicalize(Transaction::pointer& txn, bool maybeNew); void sweep(void) { mCache.sweep(); } };