diff --git a/src/cpp/ripple/Application.h b/src/cpp/ripple/Application.h index 343d592637..a7518299e4 100644 --- a/src/cpp/ripple/Application.h +++ b/src/cpp/ripple/Application.h @@ -35,7 +35,7 @@ public: DatabaseCon(const std::string& name, const char *initString[], int countInit); ~DatabaseCon(); Database* getDB() { return mDatabase; } - ScopedLock getDBLock() { return ScopedLock(mLock); } + boost::recursive_mutex& getDBLock() { return mLock; } }; class Application diff --git a/src/cpp/ripple/HashedObject.cpp b/src/cpp/ripple/HashedObject.cpp index 7765574ad6..d430272a37 100644 --- a/src/cpp/ripple/HashedObject.cpp +++ b/src/cpp/ripple/HashedObject.cpp @@ -12,7 +12,7 @@ SETUP_LOG(); DECLARE_INSTANCE(HashedObject); HashedObjectStore::HashedObjectStore(int cacheSize, int cacheAge) : - mCache("HashedObjectStore", cacheSize, cacheAge), mWritePending(false) + mCache("HashedObjectStore", cacheSize, cacheAge), mWritePending(false), mWriteGeneration(0) { mWriteSet.reserve(128); } @@ -53,27 +53,29 @@ bool HashedObjectStore::store(HashedObjectType type, uint32 index, void HashedObjectStore::waitWrite() { - boost::unique_lock sl(mWriteMutex); - while (mWritePending) + boost::mutex::scoped_lock sl(mWriteMutex); + int gen = mWriteGeneration; + while (mWritePending && (mWriteGeneration == gen)) mWriteCondition.wait(sl); } void HashedObjectStore::bulkWrite() { - LoadEvent::pointer event = theApp->getJobQueue().getLoadEvent(jtDISK); + LoadEvent::autoptr event(theApp->getJobQueue().getLoadEventAP(jtDISK)); while (1) { std::vector< boost::shared_ptr > set; set.reserve(128); { - boost::unique_lock sl(mWriteMutex); + boost::mutex::scoped_lock sl(mWriteMutex); mWriteSet.swap(set); assert(mWriteSet.empty()); + ++mWriteGeneration; + mWriteCondition.notify_all(); if (set.empty()) { mWritePending = false; - mWriteCondition.notify_all(); return; } } @@ -85,7 +87,7 @@ void HashedObjectStore::bulkWrite() Database* db = theApp->getHashNodeDB()->getDB(); { - ScopedLock sl = theApp->getHashNodeDB()->getDBLock(); + ScopedLock sl( theApp->getHashNodeDB()->getDBLock()); db->executeSQL("BEGIN TRANSACTION;"); diff --git a/src/cpp/ripple/HashedObject.h b/src/cpp/ripple/HashedObject.h index 20a187fb72..69c5e55f79 100644 --- a/src/cpp/ripple/HashedObject.h +++ b/src/cpp/ripple/HashedObject.h @@ -47,8 +47,9 @@ class HashedObjectStore protected: TaggedCache mCache; - boost::mutex mWriteMutex; - boost::condition_variable mWriteCondition; + boost::mutex mWriteMutex; + boost::condition_variable mWriteCondition; + int mWriteGeneration; std::vector< boost::shared_ptr > mWriteSet; bool mWritePending; diff --git a/src/cpp/ripple/JobQueue.h b/src/cpp/ripple/JobQueue.h index ca91a06f19..6dc495da7e 100644 --- a/src/cpp/ripple/JobQueue.h +++ b/src/cpp/ripple/JobQueue.h @@ -104,6 +104,8 @@ public: LoadEvent::pointer getLoadEvent(JobType t) { return boost::make_shared(boost::ref(mJobLoads[t]), true, 1); } + LoadEvent::autoptr getLoadEventAP(JobType t) + { return LoadEvent::autoptr(new LoadEvent(mJobLoads[t], true, 1)); } Json::Value getJson(int c = 0); }; diff --git a/src/cpp/ripple/Ledger.cpp b/src/cpp/ripple/Ledger.cpp index 334f561549..2e9482e0fe 100644 --- a/src/cpp/ripple/Ledger.cpp +++ b/src/cpp/ripple/Ledger.cpp @@ -339,9 +339,8 @@ uint256 Ledger::getHash() return mHash; } -void Ledger::saveAcceptedLedger(bool fromConsensus) +void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event) { // can be called in a different thread - LoadEvent::pointer event = theApp->getJobQueue().getLoadEvent(jtDISK); cLog(lsTRACE) << "saveAcceptedLedger " << (fromConsensus ? "fromConsensus " : "fromAcquire ") << getLedgerSeq(); static boost::format ledgerExists("SELECT LedgerSeq FROM Ledgers where LedgerSeq = %d;"); static boost::format deleteLedger("DELETE FROM Ledgers WHERE LedgerSeq = %d;"); @@ -369,7 +368,7 @@ void Ledger::saveAcceptedLedger(bool fromConsensus) SHAMap& txSet = *peekTransactionMap(); Database *db = theApp->getTxnDB()->getDB(); - ScopedLock dbLock = theApp->getTxnDB()->getDBLock(); + ScopedLock dbLock(theApp->getTxnDB()->getDBLock()); db->executeSQL("BEGIN TRANSACTION;"); SHAMapTreeNode::TNType type; for (SHAMapItem::pointer item = txSet.peekFirstItem(type); !!item; @@ -439,7 +438,7 @@ void Ledger::saveAcceptedLedger(bool fromConsensus) } theApp->getLedgerMaster().setFullLedger(shared_from_this()); - event = LoadEvent::pointer(); + event->stop(); theApp->getOPs().pubLedger(shared_from_this()); @@ -1136,7 +1135,8 @@ void Ledger::pendSave(bool fromConsensus) if (!fromConsensus && !theApp->isNewFlag(getHash(), SF_SAVED)) return; - boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, shared_from_this(), fromConsensus)); + boost::thread thread(boost::bind(&Ledger::saveAcceptedLedger, shared_from_this(), + fromConsensus, theApp->getJobQueue().getLoadEvent(jtDISK))); thread.detach(); boost::recursive_mutex::scoped_lock sl(sPendingSaveLock); diff --git a/src/cpp/ripple/Ledger.h b/src/cpp/ripple/Ledger.h index 64bf9ef4a6..7f9556c3ed 100644 --- a/src/cpp/ripple/Ledger.h +++ b/src/cpp/ripple/Ledger.h @@ -19,6 +19,7 @@ #include "BitcoinUtil.h" #include "SHAMap.h" #include "InstanceCounter.h" +#include "LoadMonitor.h" enum LedgerStateParms { @@ -93,7 +94,7 @@ protected: static void incPendingSaves(); static void decPendingSaves(); - void saveAcceptedLedger(bool fromConsensus); + void saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer); public: Ledger(const RippleAddress& masterID, uint64 startAmount); // used for the starting bootstrap ledger diff --git a/src/cpp/ripple/LedgerConsensus.cpp b/src/cpp/ripple/LedgerConsensus.cpp index ef32c11531..e3e867d90a 100644 --- a/src/cpp/ripple/LedgerConsensus.cpp +++ b/src/cpp/ripple/LedgerConsensus.cpp @@ -1251,7 +1251,7 @@ void LedgerConsensus::accept(SHAMap::ref set, LoadEvent::pointer) cLog(lsINFO) << "CNF newLCL " << newLCLHash; Ledger::pointer newOL = boost::make_shared(true, boost::ref(*newLCL)); - ScopedLock sl = theApp->getLedgerMaster().getLock(); + ScopedLock sl( theApp->getLedgerMaster().getLock()); // Apply disputed transactions that didn't get in TransactionEngine engine(newOL); diff --git a/src/cpp/ripple/LoadMonitor.h b/src/cpp/ripple/LoadMonitor.h index 992046c178..6eb259a792 100644 --- a/src/cpp/ripple/LoadMonitor.h +++ b/src/cpp/ripple/LoadMonitor.h @@ -36,7 +36,8 @@ public: class LoadEvent { public: - typedef boost::shared_ptr pointer; + typedef boost::shared_ptr pointer; + typedef std::auto_ptr autoptr; protected: LoadMonitor& mMonitor; diff --git a/src/cpp/ripple/NetworkOPs.cpp b/src/cpp/ripple/NetworkOPs.cpp index 97adc8e9f2..e67d8eb927 100644 --- a/src/cpp/ripple/NetworkOPs.cpp +++ b/src/cpp/ripple/NetworkOPs.cpp @@ -888,7 +888,7 @@ std::vector< std::pair > { Database* db = theApp->getTxnDB()->getDB(); - ScopedLock dbLock = theApp->getTxnDB()->getDBLock(); + ScopedLock sl(theApp->getTxnDB()->getDBLock()); SQL_FOREACH(db, sql) { @@ -909,7 +909,7 @@ std::vector RippleAddress acct; { Database* db = theApp->getTxnDB()->getDB(); - ScopedLock dblock = theApp->getTxnDB()->getDBLock(); + ScopedLock sl(theApp->getTxnDB()->getDBLock()); SQL_FOREACH(db, sql) { if (acct.setAccountID(db->getStrBinary("Account"))) @@ -1002,7 +1002,7 @@ void NetworkOPs::pubLedger(Ledger::ref lpAccepted) if (NetworkOPs::omDISCONNECTED == getOperatingMode()) return; - LoadEvent::pointer event = theApp->getJobQueue().getLoadEvent(jtPUBLEDGER); + LoadEvent::autoptr event(theApp->getJobQueue().getLoadEventAP(jtPUBLEDGER)); { boost::recursive_mutex::scoped_lock sl(mMonitorLock); diff --git a/src/cpp/ripple/Peer.cpp b/src/cpp/ripple/Peer.cpp index f14b4411ba..f207cba9b1 100644 --- a/src/cpp/ripple/Peer.cpp +++ b/src/cpp/ripple/Peer.cpp @@ -373,7 +373,7 @@ void Peer::processReadBuffer() // std::cerr << "Peer::processReadBuffer: " << mIpPort.first << " " << mIpPort.second << std::endl; - LoadEvent::pointer event = theApp->getJobQueue().getLoadEvent(jtPEER); + LoadEvent::autoptr event(theApp->getJobQueue().getLoadEventAP(jtPEER)); boost::recursive_mutex::scoped_lock sl(theApp->getMasterLock()); diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index cc181caaba..653231d479 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -1169,7 +1169,7 @@ Json::Value RPCHandler::doTxHistory(const Json::Value& params) { Database* db = theApp->getTxnDB()->getDB(); - ScopedLock dbLock = theApp->getTxnDB()->getDBLock(); + ScopedLock sl (theApp->getTxnDB()->getDBLock()); SQL_FOREACH(db, sql) { @@ -1493,7 +1493,7 @@ 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); + LoadEvent::autoptr le(theApp->getJobQueue().getLoadEventAP(jtRPC)); mRole = role; diff --git a/src/cpp/ripple/ScopedLock.h b/src/cpp/ripple/ScopedLock.h index 5f85b83ed3..e0859fd774 100644 --- a/src/cpp/ripple/ScopedLock.h +++ b/src/cpp/ripple/ScopedLock.h @@ -6,16 +6,18 @@ #include #include +typedef boost::recursive_mutex::scoped_lock ScopedLock; + // A lock holder that can be returned and copied by value // When the last reference goes away, the lock is released -class ScopedLock +class SharedScopedLock { protected: mutable boost::shared_ptr mHolder; public: - ScopedLock(boost::recursive_mutex& mutex) : + SharedScopedLock(boost::recursive_mutex& mutex) : mHolder(boost::make_shared(boost::ref(mutex))) { ; } void lock() const { mHolder->lock(); } diff --git a/src/cpp/ripple/Transaction.cpp b/src/cpp/ripple/Transaction.cpp index 304494826c..5305c784f4 100644 --- a/src/cpp/ripple/Transaction.cpp +++ b/src/cpp/ripple/Transaction.cpp @@ -146,12 +146,13 @@ bool Transaction::save() default: status = TXN_SQL_UNKNOWN; } - std::string exists = boost::str(boost::format("SELECT Status FROM Transactions WHERE TransID = '%s';") - % mTransaction->getTransactionID().GetHex()); + static boost::format selStat("SELECT Status FROM Transactions WHERE TransID = '%s';"); + std::string exists = boost::str(selStat % mTransaction->getTransactionID().GetHex()); Database *db = theApp->getTxnDB()->getDB(); - ScopedLock dbLock = theApp->getTxnDB()->getDBLock(); - if (SQL_EXISTS(db, exists)) return false; + ScopedLock dbLock(theApp->getTxnDB()->getDBLock()); + if (SQL_EXISTS(db, exists)) + return false; return db->executeSQL(mTransaction->getSQLInsertHeader() + mTransaction->getSQL(getLedger(), status) + ";"); } diff --git a/src/cpp/ripple/ValidationCollection.cpp b/src/cpp/ripple/ValidationCollection.cpp index cab64a9508..f663b2c2a1 100644 --- a/src/cpp/ripple/ValidationCollection.cpp +++ b/src/cpp/ripple/ValidationCollection.cpp @@ -289,7 +289,7 @@ void ValidationCollection::condWrite() void ValidationCollection::doWrite() { - LoadEvent::pointer event = theApp->getJobQueue().getLoadEvent(jtDISK); + LoadEvent::autoptr event(theApp->getJobQueue().getLoadEventAP(jtDISK)); static boost::format insVal("INSERT INTO LedgerValidations " "(LedgerHash,NodePubKey,Flags,SignTime,Signature) VALUES ('%s','%s','%u','%u',%s);"); diff --git a/src/cpp/ripple/Wallet.cpp b/src/cpp/ripple/Wallet.cpp index 1d21fb5eb6..8843e693c3 100644 --- a/src/cpp/ripple/Wallet.cpp +++ b/src/cpp/ripple/Wallet.cpp @@ -78,7 +78,7 @@ bool Wallet::nodeIdentityCreate() { #ifdef CREATE_NEW_DH_PARAMS std::string strDh512 = DH_der_gen(512); #else - static char dh512Param[] = { + static const unsigned char dh512Param[] = { 0x30, 0x46, 0x02, 0x41, 0x00, 0x98, 0x15, 0xd2, 0xd0, 0x08, 0x32, 0xda, 0xaa, 0xac, 0xc4, 0x71, 0xa3, 0x1b, 0x11, 0xf0, 0x6c, 0x62, 0xb2, 0x35, 0x8a, 0x10, 0x92, 0xc6, 0x0a, 0xa3, 0x84, 0x7e, 0xaf, 0x17, 0x29, 0x0b, @@ -86,7 +86,7 @@ bool Wallet::nodeIdentityCreate() { 0x6e, 0xdb, 0x57, 0x72, 0x4a, 0x7e, 0xcd, 0xaf, 0xbd, 0x3a, 0x97, 0x55, 0x51, 0x77, 0x5a, 0x34, 0x7c, 0xe8, 0xc5, 0x71, 0x63, 0x02, 0x01, 0x02 }; - std::string strDh512(dh512Param, sizeof(dh512Param)); + std::string strDh512(reinterpret_cast(dh512Param), sizeof(dh512Param)); #endif diff --git a/src/cpp/ripple/utils.h b/src/cpp/ripple/utils.h index 7667df578a..c6568d5104 100644 --- a/src/cpp/ripple/utils.h +++ b/src/cpp/ripple/utils.h @@ -154,7 +154,8 @@ inline std::string strHex(const uint64 uiHost) inline static std::string sqlEscape(const std::string& strSrc) { - return str(boost::format("X'%s'") % strHex(strSrc)); + static boost::format f("X'%s'"); + return str(f % strHex(strSrc)); } template diff --git a/src/js/amount.js b/src/js/amount.js index 8921a5092b..b50d4e39ac 100644 --- a/src/js/amount.js +++ b/src/js/amount.js @@ -478,8 +478,15 @@ Amount.prototype.to_human = function (opts) { opts = opts || {}; - var int_part = this._value.divide(consts.bi_xns_unit).toString(10); - var fraction_part = this._value.mod(consts.bi_xns_unit).toString(10); + // Default options + if ("undefined" === typeof opts.group_sep) opts.group_sep = true; + opts.group_width = opts.group_width || 3; + + var denominator = this._is_native ? + consts.bi_xns_unit : + consts.bi_10.clone().pow(-this._offset); + var int_part = this._value.divide(denominator).toString(10); + var fraction_part = this._value.mod(denominator).toString(10); int_part = int_part.replace(/^0*/, ''); fraction_part = fraction_part.replace(/0*$/, ''); @@ -488,6 +495,13 @@ Amount.prototype.to_human = function (opts) fraction_part = fraction_part.slice(0, opts.precision); } + if (opts.group_sep) { + if ("string" !== typeof opts.group_sep) { + opts.group_sep = ','; + } + int_part = utils.chunkString(int_part, opts.group_width, true).join(opts.group_sep); + } + var formatted = ''; formatted += int_part.length ? int_part : '0'; formatted += fraction_part.length ? '.'+fraction_part : ''; @@ -597,7 +611,7 @@ Amount.prototype.parse_human = function(j) { this._is_native = false; var multiplier = consts.bi_10.clone().pow(precision); - this._value = this._value.multiply(multiplier).add(fraction); + this._value = this._value.multiply(multiplier).add(new BigInteger(fraction)); this._offset = -precision; this.canonicalize(); diff --git a/src/js/remote.js b/src/js/remote.js index af2e012891..8ebadb6a2a 100644 --- a/src/js/remote.js +++ b/src/js/remote.js @@ -39,23 +39,16 @@ var Request = function (remote, command) { }; this.remote = remote; this.requested = false; - - this.on('request', function () { - self.request_default(); - }); }; Request.prototype = new EventEmitter; // Send the request to a remote. Request.prototype.request = function (remote) { - this.emit('request', remote); -}; - -Request.prototype.request_default = function () { if (!this.requested) { this.requested = true; this.remote.request(this); + this.emit('request', remote); } }; @@ -595,7 +588,8 @@ Remote.prototype.request_ledger_entry = function (type) { this.type = type; // Transparent caching: - request.on('request', function (remote) { // Intercept default request. + this.request_default = this.request; + this.request = function () { // Intercept default request. if (self._ledger_hash) { // XXX Add caching. } @@ -613,7 +607,7 @@ Remote.prototype.request_ledger_entry = function (type) { if (node) { // Emulate fetch of ledger entry. - this.request.emit('success', { + self.emit('success', { // YYY Missing lots of fields. 'node' : node, }); @@ -637,7 +631,7 @@ Remote.prototype.request_ledger_entry = function (type) { this.request_default(); } } - }); + }; return request; }; diff --git a/src/js/utils.js b/src/js/utils.js index 563969fee4..31d2a72d63 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -70,6 +70,19 @@ var stringToArray = function (s) { return a; }; +var chunkString = function (str, n, leftAlign) { + var ret = []; + var i=0, len=str.length; + if (leftAlign) { + i = str.length % n; + if (i) ret.push(str.slice(0, i)); + } + for(; i < len; i += n) { + ret.push(str.slice(i, n+i)); + } + return ret; +}; + var logObject = function (msg, obj) { console.log(msg, JSON.stringify(obj, undefined, 2)); }; @@ -81,5 +94,6 @@ exports.hexToString = hexToString; exports.stringToArray = stringToArray; exports.stringToHex = stringToHex; exports.logObject = logObject; +exports.chunkString = chunkString; // vim:sw=2:sts=2:ts=8:et