From f0970174f378825bad953a4c1aba5ab499a6d54d Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Mon, 19 Nov 2012 14:07:54 -0800 Subject: [PATCH 1/7] JS: Add missing require. --- src/js/remote.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/js/remote.js b/src/js/remote.js index c7040e2396..dcc85cb91e 100644 --- a/src/js/remote.js +++ b/src/js/remote.js @@ -19,6 +19,7 @@ var WebSocket = require('ws'); var EventEmitter = require('events').EventEmitter; var Amount = require('./amount.js').Amount; +var Currency = require('./amount.js').Currency; var UInt160 = require('./amount.js').UInt160; // Request events emitted: From 5ac22ff31b552e744b3792fafed8e31eab087fc4 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 20 Nov 2012 12:09:51 -0800 Subject: [PATCH 2/7] Two more load monitoring hooks. --- src/cpp/ripple/JobQueue.cpp | 1 + src/cpp/ripple/JobQueue.h | 1 + src/cpp/ripple/LedgerConsensus.cpp | 9 ++++++--- src/cpp/ripple/LedgerConsensus.h | 3 ++- src/cpp/ripple/TransactionMaster.cpp | 8 +++++++- 5 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/cpp/ripple/JobQueue.cpp b/src/cpp/ripple/JobQueue.cpp index a72e8ddae0..dd730dcb6a 100644 --- a/src/cpp/ripple/JobQueue.cpp +++ b/src/cpp/ripple/JobQueue.cpp @@ -23,6 +23,7 @@ const char* Job::toString(JobType t) case jtCLIENT: return "clientCommand"; case jtPEER: return "peerCommand"; case jtDISK: return "diskAccess"; + case jtLEDGER: return "acceptLedger"; default: assert(false); return "unknown"; } } diff --git a/src/cpp/ripple/JobQueue.h b/src/cpp/ripple/JobQueue.h index 339804d206..1101cc2f75 100644 --- a/src/cpp/ripple/JobQueue.h +++ b/src/cpp/ripple/JobQueue.h @@ -36,6 +36,7 @@ enum JobType jtCLIENT = 10, jtPEER = 11, jtDISK = 12, + jtLEDGER = 13, }; #define NUM_JOB_TYPES 16 diff --git a/src/cpp/ripple/LedgerConsensus.cpp b/src/cpp/ripple/LedgerConsensus.cpp index 8daade3bdf..7cc01870db 100644 --- a/src/cpp/ripple/LedgerConsensus.cpp +++ b/src/cpp/ripple/LedgerConsensus.cpp @@ -1021,9 +1021,12 @@ void LedgerConsensus::beginAccept(bool synchronous) theApp->getOPs().newLCL(mPeerPositions.size(), mCurrentMSeconds, mNewLedgerHash); if (synchronous) - accept(consensusSet); + accept(consensusSet, LoadEvent::pointer()); else - theApp->getIOService().post(boost::bind(&LedgerConsensus::accept, shared_from_this(), consensusSet)); + { + theApp->getIOService().post(boost::bind(&LedgerConsensus::accept, shared_from_this(), consensusSet, + theApp->getJobQueue().getLoadEvent(jtLEDGER))); + } } void LedgerConsensus::playbackProposals() @@ -1170,7 +1173,7 @@ uint32 LedgerConsensus::roundCloseTime(uint32 closeTime) return closeTime - (closeTime % mCloseResolution); } -void LedgerConsensus::accept(SHAMap::ref set) +void LedgerConsensus::accept(SHAMap::ref set, LoadEvent::pointer) { boost::recursive_mutex::scoped_lock masterLock(theApp->getMasterLock()); assert(set->getHash() == mOurPosition->getCurrentHash()); diff --git a/src/cpp/ripple/LedgerConsensus.h b/src/cpp/ripple/LedgerConsensus.h index 3b66fa9f42..1db7069961 100644 --- a/src/cpp/ripple/LedgerConsensus.h +++ b/src/cpp/ripple/LedgerConsensus.h @@ -18,6 +18,7 @@ #include "CanonicalTXSet.h" #include "TransactionEngine.h" #include "InstanceCounter.h" +#include "LoadMonitor.h" DEFINE_INSTANCE(LedgerConsensus); @@ -120,7 +121,7 @@ protected: boost::unordered_set mDeadNodes; // final accept logic - void accept(SHAMap::ref txSet); + void accept(SHAMap::ref txSet, LoadEvent::pointer); void weHave(const uint256& id, Peer::ref avoidPeer); void startAcquiring(const TransactionAcquire::pointer&); diff --git a/src/cpp/ripple/TransactionMaster.cpp b/src/cpp/ripple/TransactionMaster.cpp index 196845bfdb..bfa0a8b720 100644 --- a/src/cpp/ripple/TransactionMaster.cpp +++ b/src/cpp/ripple/TransactionMaster.cpp @@ -53,13 +53,19 @@ SerializedTransaction::pointer TransactionMaster::fetch(SHAMapItem::ref item, bo return txn; } +static void saveTransactionHelper(Transaction::pointer txn, LoadEvent::pointer) +{ + Transaction::saveTransaction(txn); +} + bool TransactionMaster::canonicalize(Transaction::pointer& txn, bool may_be_new) { uint256 tid = txn->getID(); if (!tid) return false; if (mCache.canonicalize(tid, txn)) return true; if (may_be_new) - theApp->getAuxService().post(boost::bind(&Transaction::saveTransaction, txn)); + theApp->getAuxService().post(boost::bind(&saveTransactionHelper, txn, + theApp->getJobQueue().getLoadEvent(jtDISK))); return false; } // vim:ts=4 From db7a1ef4ba18f5c46cec9d0a478e2cf6bd03e664 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 12:42:25 -0800 Subject: [PATCH 3/7] Fixes for rippling through offers. --- src/cpp/ripple/RippleCalc.cpp | 118 ++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 40 deletions(-) diff --git a/src/cpp/ripple/RippleCalc.cpp b/src/cpp/ripple/RippleCalc.cpp index e364344698..24508b8633 100644 --- a/src/cpp/ripple/RippleCalc.cpp +++ b/src/cpp/ripple/RippleCalc.cpp @@ -287,11 +287,15 @@ TER RippleCalc::calcNodeDeliverRev( const STAmount& saTransferRate = pnCur.saTransferRate; STAmount& saPrvDlvReq = pnPrv.saRevDeliver; // To be set. + STAmount& saCurDlvFwd = pnCur.saFwdDeliver; + uint256& uDirectTip = pnCur.uDirectTip; uDirectTip = 0; // Restart book searching. + saCurDlvFwd.zero(saOutReq); // For forward pass zero deliver. + saPrvDlvReq.zero(pnPrv.uCurrencyID, pnPrv.uIssuerID); saOutAct.zero(saOutReq); @@ -472,14 +476,15 @@ TER RippleCalc::calcNodeDeliverRev( } // For current offer, get input from deliver/limbo and output to next account or deliver for next offers. +// <-- pnCur.saFwdDeliver: For calcNodeAccountFwd to know how much went through TER RippleCalc::calcNodeDeliverFwd( const unsigned int uNode, // 0 < uNode < uLast PathState::ref pspCur, const bool bMultiQuality, const uint160& uInAccountID, // --> Input owner's account. const STAmount& saInReq, // --> Amount to deliver. - STAmount& saInAct, // <-- Amount delivered. - STAmount& saInFees) // <-- Fees charged. + STAmount& saInAct, // <-- Amount delivered, this invokation. + STAmount& saInFees) // <-- Fees charged, this invokation. { TER terResult = tesSUCCESS; @@ -492,9 +497,9 @@ TER RippleCalc::calcNodeDeliverFwd( const uint160& uCurIssuerID = pnCur.uIssuerID; const uint160& uPrvCurrencyID = pnPrv.uCurrencyID; const uint160& uPrvIssuerID = pnPrv.uIssuerID; - const STAmount& saTransferRate = pnPrv.saTransferRate; + const STAmount& saInTransRate = pnPrv.saTransferRate; - STAmount& saCurDeliverAct = pnCur.saFwdDeliver; + STAmount& saCurDeliverAct = pnCur.saFwdDeliver; // Zeroed in reverse pass. uint256& uDirectTip = pnCur.uDirectTip; @@ -502,11 +507,11 @@ TER RippleCalc::calcNodeDeliverFwd( saInAct.zero(saInReq); saInFees.zero(saInReq); - saCurDeliverAct.zero(uCurCurrencyID, uCurIssuerID); while (tesSUCCESS == terResult && saInAct + saInFees != saInReq) // Did not deliver all funds. { + // Determine values for pass to adjust saInAct, saInFees, and saCurDeliverAct terResult = calcNodeAdvance(uNode, pspCur, bMultiQuality, false); // If needed, advance to next funded offer. if (tesSUCCESS == terResult) @@ -522,28 +527,33 @@ TER RippleCalc::calcNodeDeliverFwd( STAmount& saTakerPays = pnCur.saTakerPays; STAmount& saTakerGets = pnCur.saTakerGets; - const STAmount saInFeeRate = !!uPrvCurrencyID - ? uInAccountID == uPrvIssuerID || uOfrOwnerID == uPrvIssuerID // Issuer receiving or sending. - ? saOne // No fee. - : saTransferRate // Transfer rate of issuer. - : saOne; + const STAmount saInFeeRate = !uPrvCurrencyID // XRP. + || uInAccountID == uPrvIssuerID // Sender is issuer. + || uOfrOwnerID == uPrvIssuerID // Reciever is issuer. + ? saOne // No fee. + : saInTransRate; // Transfer rate of issuer. - // - // First calculate assuming no output fees. - // XXX Make sure derived in does not exceed actual saTakerPays due to rounding. + // First calculate assuming no output fees: saInPassAct, saInPassFees, saOutPassAct - STAmount saOutFunded = std::max(saOfferFunds, saTakerGets); // Offer maximum out - There are no out fees. - STAmount saInFunded = STAmount::multiply(saOutFunded, saOfrRate, saInReq); // Offer maximum in - Limited by by payout. - STAmount saInTotal = STAmount::multiply(saInFunded, saTransferRate); // Offer maximum in with fees. - STAmount saInSum = std::min(saInTotal, saInReq-saInAct-saInFees); // In limited by saInReq. + STAmount saOutFunded = std::min(saOfferFunds, saTakerGets); // Offer maximum out - If there are no out fees. + STAmount saInFunded = STAmount::multiply(saOutFunded, saOfrRate, saTakerPays); // Offer maximum in - Limited by by payout. + STAmount saInTotal = STAmount::multiply(saInFunded, saInTransRate); // Offer maximum in with fees. + STAmount saInSum = std::min(saInTotal, saInReq-saInAct-saInFees); // In limited by remaining. STAmount saInPassAct = STAmount::divide(saInSum, saInFeeRate); // In without fees. - STAmount saOutPassMax = STAmount::divide(saInPassAct, saOfrRate, saOutFunded); // Out. + STAmount saOutPassMax = STAmount::divide(saInPassAct, saOfrRate, saTakerGets); // Out limited by in remaining. - STAmount saInPassFees(saInReq.getCurrency(), saInReq.getIssuer()); - STAmount saOutPassAct(saOfferFunds.getCurrency(), saOfferFunds.getIssuer()); + STAmount saInPassFeesMax = saInSum-saInPassAct; - cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saOutFunded=%s saInFunded=%s saInTotal=%s saInSum=%s saInPassAct=%s saOutPassMax=%s") + STAmount saOutPassAct; // Will be determined by next node. + STAmount saInPassFees; // Will be determined by adjusted saInPassAct. + + + cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: uNode=%d saOutFunded=%s saInReq=%s saInAct=%s saInFees=%s saInFunded=%s saInTotal=%s saInSum=%s saInPassAct=%s saOutPassMax=%s") + % uNode % saOutFunded + % saInReq + % saInAct + % saInFees % saInFunded % saInTotal % saInSum @@ -557,13 +567,14 @@ TER RippleCalc::calcNodeDeliverFwd( // Output fees: none as XRP or the destination account is the issuer. saOutPassAct = saOutPassMax; + saInPassFees = saInPassFeesMax; cLog(lsDEBUG) << boost::str(boost::format("calcNodeDeliverFwd: ? --> OFFER --> account: uOfrOwnerID=%s uNxtAccountID=%s saOutPassAct=%s") % RippleAddress::createHumanAccountID(uOfrOwnerID) % RippleAddress::createHumanAccountID(uNxtAccountID) % saOutPassAct.getFullText()); - // Debit offer owner, send XRP or non-XPR to next account. + // Output: Debit offer owner, send XRP or non-XPR to next account. lesActive.accountSend(uOfrOwnerID, uNxtAccountID, saOutPassAct); } else @@ -571,43 +582,60 @@ TER RippleCalc::calcNodeDeliverFwd( // ? --> OFFER --> offer // Offer to offer means current order book's output currency and issuer match next order book's input current and // issuer. + // Output fees: possible if issuer has fees and is not on either side. STAmount saOutPassFees; + // Output fees vary as the next nodes offer owners may vary. + // Therefore, immediately push through output for current offer. terResult = RippleCalc::calcNodeDeliverFwd( uNode+1, pspCur, bMultiQuality, - uOfrOwnerID, - saOutPassMax, + uOfrOwnerID, // --> Current holder. + saOutPassMax, // --> Amount available. saOutPassAct, // <-- Amount delivered. saOutPassFees); // <-- Fees charged. if (tesSUCCESS != terResult) break; - // Offer maximum in split into fees by next payout. - saInPassAct = STAmount::multiply(saOutPassAct, saOfrRate); - saInPassFees = STAmount::multiply(saInFunded, saInFeeRate)-saInPassAct; + if (saOutPassAct == saOutPassMax) + { + // No fees and entire output amount. + + saInPassFees = saInPassFeesMax; + } + else + { + // Fraction of output amount. + // Output fees are paid by offer owner and not passed to previous. + saInPassAct = STAmount::multiply(saOutPassAct, saOfrRate, saInReq); + saInPassFees = std::min(saInPassFeesMax, STAmount::multiply(saInPassAct, saInFeeRate)); + } // Do outbound debiting. - // Send to issuer/limbo total amount (no fees to issuer). - lesActive.accountSend(uOfrOwnerID, !!uCurCurrencyID ? uCurIssuerID : ACCOUNT_XRP, saOutPassAct); + // Send to issuer/limbo total amount including fees (issuer gets fees). + lesActive.accountSend(uOfrOwnerID, !!uCurCurrencyID ? uCurIssuerID : ACCOUNT_XRP, saOutPassAct+saOutPassFees); - cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: ? --> OFFER --> offer: saOutPassAct=%s") - % saOutPassAct); + cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: ? --> OFFER --> offer: saOutPassAct=%s saOutPassFees=%s") + % saOutPassAct + % saOutPassFees); } - cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: saTakerGets=%s saTakerPays=%s saInPassAct=%s saOutPassAct=%s") - % saTakerGets.getFullText() - % saTakerPays.getFullText() - % saInPassAct.getFullText() - % saOutPassAct.getFullText()); + cLog(lsINFO) << boost::str(boost::format("calcNodeDeliverFwd: uNode=%d saTakerGets=%s saTakerPays=%s saInPassAct=%s saInPassFees=%s saOutPassAct=%s saOutFunded=%s") + % uNode + % saTakerGets + % saTakerPays + % saInPassAct + % saInPassFees + % saOutPassAct + % saOutFunded); // Funds were spent. bFundsDirty = true; // Do inbound crediting. - // Credit offer owner from in issuer/limbo (don't take transfer fees). + // Credit offer owner from in issuer/limbo (input transfer fees left with owner). lesActive.accountSend(!!uPrvCurrencyID ? uInAccountID : ACCOUNT_XRP, uOfrOwnerID, saInPassAct); // Adjust offer @@ -617,7 +645,7 @@ TER RippleCalc::calcNodeDeliverFwd( lesActive.entryModify(sleOffer); - if (saOutPassAct == saTakerGets) + if (saOutPassAct == saOutFunded) { // Offer became unfunded. pspCur->vUnfundedBecame.push_back(uOfferIndex); @@ -632,6 +660,11 @@ TER RippleCalc::calcNodeDeliverFwd( } } + cLog(lsDEBUG) << boost::str(boost::format("calcNodeDeliverFwd< uNode=%d saInAct=%s saInFees=%s") + % uNode + % saInAct + % saInFees); + return terResult; } @@ -696,7 +729,7 @@ TER RippleCalc::calcNodeOfferFwd( pspCur, bMultiQuality, pnPrv.uAccountID, - pnPrv.saFwdDeliver, + pnPrv.saFwdDeliver, // Previous is sending this much. saInAct, saInFees); @@ -1354,6 +1387,11 @@ TER RippleCalc::calcNodeAccountFwd( } else if (bPrvAccount && !bNxtAccount) { + // Current account is issuer to next offer. + // Determine deliver to offer amount. + // Don't adjust outbound balances- keep funds with issuer as limbo. + // If issuer hold's an offer owners inbound IOUs, there is no fee and redeem/issue will transparently happen. + if (uNode) { // Non-XRP, current node is the issuer. @@ -1444,7 +1482,7 @@ TER RippleCalc::calcNodeAccountFwd( saCurIssueAct.zero(saCurIssueReq); // deliver -> redeem - if (saPrvDeliverReq) // Previous wants to deliver. + if (saPrvDeliverReq && saCurRedeemReq) // Previous wants to deliver and can current redeem. { // Rate : 1.0 : quality out calcNodeRipple(QUALITY_ONE, uQualityOut, saPrvDeliverReq, saCurRedeemReq, saPrvDeliverAct, saCurRedeemAct, uRateMax); From 42248ca3ef2f2df445a0f41115209d4b96713668 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Tue, 20 Nov 2012 12:43:27 -0800 Subject: [PATCH 4/7] UT: Test cross currency bridged payment and fixes. --- test/offer-test.js | 54 ++++++++++++++++++++++++---------------------- test/testutils.js | 6 +++--- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/test/offer-test.js b/test/offer-test.js index ef83dd5901..0c12c48013 100644 --- a/test/offer-test.js +++ b/test/offer-test.js @@ -335,6 +335,7 @@ buster.testCase("Offer tests", { }, "ripple currency conversion : entire offer" : + // mtgox in, XRP out function (done) { var self = this; var seq; @@ -380,7 +381,7 @@ buster.testCase("Offer tests", { function (callback) { self.what = "Verify offer balance."; - testutils.verify_offer(self.remote, "bob", seq, "500", "100/USD/mtgox", callback); + testutils.verify_offer(self.remote, "bob", seq, "100/USD/mtgox", "500", callback); }, function (callback) { self.what = "Alice converts USD to XRP."; @@ -475,7 +476,7 @@ buster.testCase("Offer tests", { function (callback) { self.what = "Verify offer balance."; - testutils.verify_offer(self.remote, "bob", seq, "300", "60/USD/mtgox", callback); + testutils.verify_offer(self.remote, "bob", seq, "60/USD/mtgox", "300", callback); }, function (callback) { self.what = "Verify balances."; @@ -696,7 +697,7 @@ buster.testCase("Offer cross currency", { function (callback) { self.what = "Verify offer partially consumed."; - testutils.verify_offer(self.remote, "carol", seq, "250", "25/USD/mtgox", callback); + testutils.verify_offer(self.remote, "carol", seq, "25/USD/mtgox", "250", callback); }, ], function (error) { buster.refute(error, self.what); @@ -704,7 +705,7 @@ buster.testCase("Offer cross currency", { }); }, - "// ripple cross currency bridged payment" : + "ripple cross currency bridged payment" : // alice --> [USD/mtgox --> carol --> XRP] --> [XRP --> dan --> EUR/bitstamp] --> bob function (done) { @@ -774,6 +775,7 @@ buster.testCase("Offer cross currency", { self.remote.transaction() .payment("alice", "bob", "30/EUR/bitstamp") .send_max("333/USD/mtgox") + .path_add( [ { currency: "XRP" } ]) .on('proposed', function (m) { // console.log("proposed: %s", JSON.stringify(m)); @@ -781,28 +783,28 @@ buster.testCase("Offer cross currency", { }) .submit(); }, -// function (callback) { -// self.what = "Verify balances."; -// -// testutils.verify_balances(self.remote, -// { -// "alice" : "470/USD/mtgox", -// "bob" : "30/EUR/bitstamp", -// "carol" : "30/USD/mtgox", -// "dan" : "370/EUR/bitstamp", -// }, -// callback); -// }, -// function (callback) { -// self.what = "Verify carol offer partially consumed."; -// -// testutils.verify_offer(self.remote, "carol", seq_carol, "250", "25/USD/mtgox", callback); -// }, -// function (callback) { -// self.what = "Verify dan offer partially consumed."; -// -// testutils.verify_offer(self.remote, "dan", seq_dan, "250", "25/USD/mtgox", callback); -// }, + function (callback) { + self.what = "Verify balances."; + + testutils.verify_balances(self.remote, + { + "alice" : "470/USD/mtgox", + "bob" : "30/EUR/bitstamp", + "carol" : "30/USD/mtgox", + "dan" : "370/EUR/bitstamp", + }, + callback); + }, + function (callback) { + self.what = "Verify carol offer partially consumed."; + + testutils.verify_offer(self.remote, "carol", seq_carol, "20/USD/mtgox", "200", callback); + }, + function (callback) { + self.what = "Verify dan offer partially consumed."; + + testutils.verify_offer(self.remote, "dan", seq_dan, "200", "20/EUR/mtgox", callback); + }, ], function (error) { buster.refute(error, self.what); done(); diff --git a/test/testutils.js b/test/testutils.js index bea65eb8a1..3b2a1acf69 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -326,7 +326,7 @@ var verify_balances = function (remote, balances, callback) { // --> seq: sequence number of creating transaction. // --> taker_gets: json amount // --> taker_pays: json amount -var verify_offer = function (remote, owner, seq, taker_gets, taker_pays, callback) { +var verify_offer = function (remote, owner, seq, taker_pays, taker_gets, callback) { assert(6 === arguments.length); remote.request_ledger_entry('offer') @@ -349,12 +349,12 @@ var verify_offer_not_found = function (remote, owner, seq, callback) { remote.request_ledger_entry('offer') .offer_id(owner, seq) .on('success', function (m) { - console.log("verify_no_offer: found offer: %s", JSON.stringify(m)); + console.log("verify_offer_not_found: found offer: %s", JSON.stringify(m)); callback('entryFound'); }) .on('error', function (m) { - // console.log("verify_no_offer: success: %s", JSON.stringify(m)); + // console.log("verify_offer_not_found: success: %s", JSON.stringify(m)); callback('remoteError' !== m.error || 'entryNotFound' !== m.remote.error); From 61df47658c0bff798c5e6df25c63cd7fdf13e164 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 20 Nov 2012 12:54:47 -0800 Subject: [PATCH 5/7] Fixed huge performance-sapping bug. --- src/cpp/ripple/HashedObject.cpp | 46 +++++++++++++++++---------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/src/cpp/ripple/HashedObject.cpp b/src/cpp/ripple/HashedObject.cpp index 7505a4c24e..68ba89e8d4 100644 --- a/src/cpp/ripple/HashedObject.cpp +++ b/src/cpp/ripple/HashedObject.cpp @@ -84,30 +84,32 @@ void HashedObjectStore::bulkWrite() fAdd("INSERT INTO CommittedObjects (Hash,ObjType,LedgerIndex,Object) VALUES ('%s','%c','%u',%s);"); Database* db = theApp->getHashNodeDB()->getDB(); - ScopedLock sl = theApp->getHashNodeDB()->getDBLock(); - - db->executeSQL("BEGIN TRANSACTION;"); - - BOOST_FOREACH(const boost::shared_ptr& it, set) { - if (!SQL_EXISTS(db, boost::str(fExists % it->getHash().GetHex()))) - { - char type; - switch(it->getType()) - { - case hotLEDGER: type = 'L'; break; - case hotTRANSACTION: type = 'T'; break; - case hotACCOUNT_NODE: type = 'A'; break; - case hotTRANSACTION_NODE: type = 'N'; break; - default: type = 'U'; - } - std::string rawData; - db->escape(&(it->getData().front()), it->getData().size(), rawData); - db->executeSQL(boost::str(fAdd % it->getHash().GetHex() % type % it->getIndex() % rawData )); - } - } + ScopedLock sl = theApp->getHashNodeDB()->getDBLock(); - db->executeSQL("END TRANSACTION;"); + db->executeSQL("BEGIN TRANSACTION;"); + + BOOST_FOREACH(const boost::shared_ptr& it, set) + { + if (!SQL_EXISTS(db, boost::str(fExists % it->getHash().GetHex()))) + { + char type; + switch(it->getType()) + { + case hotLEDGER: type = 'L'; break; + case hotTRANSACTION: type = 'T'; break; + case hotACCOUNT_NODE: type = 'A'; break; + case hotTRANSACTION_NODE: type = 'N'; break; + default: type = 'U'; + } + std::string rawData; + db->escape(&(it->getData().front()), it->getData().size(), rawData); + db->executeSQL(boost::str(fAdd % it->getHash().GetHex() % type % it->getIndex() % rawData )); + } + } + + db->executeSQL("END TRANSACTION;"); + } } } From b4ff61b9e6a614991eae5a3629f7400f30190973 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 20 Nov 2012 12:57:25 -0800 Subject: [PATCH 6/7] Fix the other half. --- src/cpp/ripple/HashedObject.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cpp/ripple/HashedObject.cpp b/src/cpp/ripple/HashedObject.cpp index 68ba89e8d4..7765574ad6 100644 --- a/src/cpp/ripple/HashedObject.cpp +++ b/src/cpp/ripple/HashedObject.cpp @@ -117,7 +117,6 @@ HashedObject::pointer HashedObjectStore::retrieve(const uint256& hash) { HashedObject::pointer obj; { - ScopedLock sl(theApp->getHashNodeDB()->getDBLock()); obj = mCache.fetch(hash); if (obj) { From 7d4d18bf8de1e86d0b81a11488bfec51a1bbfac9 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Tue, 20 Nov 2012 13:04:17 -0800 Subject: [PATCH 7/7] Add RPC to load tracking. --- src/cpp/ripple/JobQueue.cpp | 1 + src/cpp/ripple/JobQueue.h | 1 + src/cpp/ripple/RPCHandler.cpp | 2 ++ 3 files changed, 4 insertions(+) diff --git a/src/cpp/ripple/JobQueue.cpp b/src/cpp/ripple/JobQueue.cpp index dd730dcb6a..e8840537be 100644 --- a/src/cpp/ripple/JobQueue.cpp +++ b/src/cpp/ripple/JobQueue.cpp @@ -24,6 +24,7 @@ const char* Job::toString(JobType t) case jtPEER: return "peerCommand"; case jtDISK: return "diskAccess"; case jtLEDGER: return "acceptLedger"; + case jtRPC: return "rpc"; default: assert(false); return "unknown"; } } diff --git a/src/cpp/ripple/JobQueue.h b/src/cpp/ripple/JobQueue.h index 1101cc2f75..4f0ce559cc 100644 --- a/src/cpp/ripple/JobQueue.h +++ b/src/cpp/ripple/JobQueue.h @@ -37,6 +37,7 @@ enum JobType jtPEER = 11, jtDISK = 12, jtLEDGER = 13, + jtRPC = 14, }; #define NUM_JOB_TYPES 16 diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index ba9f6f78b9..a9564872c7 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -1318,6 +1318,8 @@ Json::Value RPCHandler::doCommand(const std::string& command, Json::Value& param cLog(lsTRACE) << "RPC:" << command; cLog(lsTRACE) << "RPC params:" << params; + LoadEvent::pointer le = theApp->getJobQueue().getLoadEvent(jtRPC); + mRole = role; static struct {