diff --git a/modules/ripple_basics/ripple_basics.h b/modules/ripple_basics/ripple_basics.h index b7552056c0..e74d17c337 100644 --- a/modules/ripple_basics/ripple_basics.h +++ b/modules/ripple_basics/ripple_basics.h @@ -129,11 +129,6 @@ namespace boost { #include "utility/ripple_IntegerTypes.h" // must come first #include "utility/ripple_Log.h" // Needed by others -#include "containers/ripple_KeyCache.h" -#include "containers/ripple_RangeSet.h" -#include "containers/ripple_SecureAllocator.h" -#include "containers/ripple_TaggedCache.h" - #include "types/ripple_BasicTypes.h" #include "utility/ripple_ByteOrder.h" #include "utility/ripple_DiffieHellmanUtil.h" @@ -151,4 +146,9 @@ namespace boost { #include "utility/ripple_HashUtilities.h" // requires UInt256 #include "types/ripple_HashMaps.h" +#include "containers/ripple_KeyCache.h" +#include "containers/ripple_RangeSet.h" +#include "containers/ripple_SecureAllocator.h" +#include "containers/ripple_TaggedCache.h" + #endif diff --git a/modules/ripple_client/ripple_client.cpp b/modules/ripple_client/ripple_client.cpp index 42b0bb38a8..eeb3011ca7 100644 --- a/modules/ripple_client/ripple_client.cpp +++ b/modules/ripple_client/ripple_client.cpp @@ -37,7 +37,7 @@ #include "src/cpp/ripple/ripple_InfoSub.h" // Order and indentation reflect the hierarchy of dependencies - #include "src/cpp/ripple/JSONCache.h" +// VFALCO NOTE Don't add anything here!!! #include "src/cpp/ripple/ripple_HashedObject.h" #include "src/cpp/ripple/ripple_SHAMapItem.h" #include "src/cpp/ripple/ripple_SHAMapNode.h" diff --git a/modules/ripple_data/ripple_data.cpp b/modules/ripple_data/ripple_data.cpp index 9e0a3d7254..639e560211 100644 --- a/modules/ripple_data/ripple_data.cpp +++ b/modules/ripple_data/ripple_data.cpp @@ -95,6 +95,8 @@ static const uint64 tenTo17m1 = tenTo17 - 1; #include "protocol/ripple_STAmount.cpp" #include "protocol/ripple_STAmountRound.cpp" +#include "utility/ripple_JSONCache.cpp" + // VFALCO TODO Fix this for SConstruct #ifdef _MSC_VER #include "ripple.pb.cc" // BROKEN because of SConstruct diff --git a/modules/ripple_data/ripple_data.h b/modules/ripple_data/ripple_data.h index cb899428ee..f5238c7e4a 100644 --- a/modules/ripple_data/ripple_data.h +++ b/modules/ripple_data/ripple_data.h @@ -87,6 +87,7 @@ #include "protocol/ripple_LedgerFormat.h" // needs SOTemplate from SerializedObject #include "protocol/ripple_TransactionFormat.h" +#include "utility/ripple_JSONCache.h" #include "utility/ripple_UptimeTimerAdapter.h" #endif diff --git a/modules/ripple_data/utility/ripple_JSONCache.cpp b/modules/ripple_data/utility/ripple_JSONCache.cpp new file mode 100644 index 0000000000..887da4ec84 --- /dev/null +++ b/modules/ripple_data/utility/ripple_JSONCache.cpp @@ -0,0 +1,157 @@ + +//------------------------------------------------------------------------------ + +JSONCache::Key::Key (int op, uint256 const& ledger, uint160 const& object, int lastUse) + : mLedger (ledger) + , mObject (object) + , mOperation (op) + , mLastUse (lastUse) +{ + mHash = static_cast (mOperation); + + mLedger.hash_combine (mHash); + + mObject.hash_combine (mHash); +} + +int JSONCache::Key::compare (Key const& other) const +{ + if (mHash < other.mHash) return -1; + if (mHash > other.mHash) return 1; + if (mOperation < other.mOperation) return -1; + if (mOperation > other.mOperation) return 1; + if (mLedger < other.mLedger) return -1; + if (mLedger > other.mLedger) return 1; + if (mObject < other.mObject) return -1; + if (mObject > other.mObject) return 1; + return 0; +} + +bool JSONCache::Key::operator< (Key const& rhs) const { return compare (rhs) < 0; } +bool JSONCache::Key::operator> (Key const& rhs) const { return compare (rhs) > 0; } +bool JSONCache::Key::operator<= (Key const& rhs) const { return compare (rhs) <= 0; } +bool JSONCache::Key::operator>= (Key const& rhs) const { return compare (rhs) >= 0; } +bool JSONCache::Key::operator!= (Key const& rhs) const { return compare (rhs) != 0; } +bool JSONCache::Key::operator== (Key const& rhs) const { return compare (rhs) == 0; } + +void JSONCache::Key::touch (Key const& key) const +{ + mLastUse = key.mLastUse; +} + +bool JSONCache::Key::isExpired (int expireTimeSeconds) const +{ + return mLastUse < expireTimeSeconds; +} + +std::size_t JSONCache::Key::getHash () const +{ + return mHash; +} + +//------------------------------------------------------------------------------ + +JSONCache::JSONCache (int expirationTimeInSeconds) + : m_expirationTime (expirationTimeInSeconds) + , mHits (0) + , mMisses (0) +{ +} + +//------------------------------------------------------------------------------ + +float JSONCache::getHitRate () +{ + boost::recursive_mutex::scoped_lock sl (m_lock); + + return (static_cast (mHits) * 100.f) / (1.0f + mHits + mMisses); +} + +//------------------------------------------------------------------------------ + +int JSONCache::getNumberOfEntries () +{ + boost::recursive_mutex::scoped_lock sl (m_lock); + + return m_cache.size (); +} + +//------------------------------------------------------------------------------ + +JSONCache::data_t JSONCache::getEntry (Kind kind, LedgerHash const& ledger, uint160 const& object) +{ + JSONCache::data_t result; // default constructor indicates not found + + Key key (kind, ledger, object, getUptime ()); + + { + boost::recursive_mutex::scoped_lock sl(m_lock); + + boost::unordered_map ::iterator it = m_cache.find (key); + + if (it != m_cache.end ()) + { + ++mHits; + + it->first.touch (key); + + result = it->second; + } + else + { + ++mMisses; + } + } + + return result; +} + +//------------------------------------------------------------------------------ + +void JSONCache::storeEntry (Kind kind, uint256 const& ledger, uint160 const& object, data_t const& data) +{ + Key key (kind, ledger, object, getUptime ()); + + { + boost::recursive_mutex::scoped_lock sl(m_lock); + + m_cache.insert (std::pair (key, data)); + } +} + +//------------------------------------------------------------------------------ + +void JSONCache::sweep () +{ + int sweepTime = getUptime (); + + if (sweepTime >= m_expirationTime) + { + sweepTime -= m_expirationTime; + + { + boost::recursive_mutex::scoped_lock sl(m_lock); + + boost::unordered_map ::iterator it = m_cache.begin(); + + while (it != m_cache.end ()) + { + if (it->first.isExpired (sweepTime)) + { + it = m_cache.erase(it); + } + else + { + ++it; + } + } + } + } +} + +//------------------------------------------------------------------------------ + +int JSONCache::getUptime () const +{ + return UptimeTimer::getInstance().getElapsedSeconds(); +} diff --git a/modules/ripple_data/utility/ripple_JSONCache.h b/modules/ripple_data/utility/ripple_JSONCache.h new file mode 100644 index 0000000000..aab62e900b --- /dev/null +++ b/modules/ripple_data/utility/ripple_JSONCache.h @@ -0,0 +1,92 @@ +#ifndef RIPPLE_JSCONCACHE_H +#define RIPPLE_JSCONCACHE_H + +/** A simple cache for JSON. + + @note All member functions are thread-safe. +*/ +class JSONCache +{ +public: + class Key + { + public: + Key (int op, const uint256& ledger, const uint160& object, int lastUse); + int compare(const Key& k) const; + bool operator<(const Key &k) const; + bool operator>(const Key &k) const; + bool operator<=(const Key &k) const; + bool operator>=(const Key &k) const; + bool operator!=(const Key &k) const; + bool operator==(const Key &k) const; + + void touch (Key const& key) const; + bool isExpired (int expireTime) const; + + std::size_t getHash () const; + + private: + uint256 mLedger; + uint160 mObject; + int mOperation; + mutable int mLastUse; + std::size_t mHash; + }; + +public: + typedef boost::shared_ptr data_t; + +public: + enum Kind + { + kindLines, + kindOffers + }; + + /** Construct the cache. + + @param expirationTimeInSeconds The time until cached items expire, in seconds. + */ + explicit JSONCache (int expirationTimeInSeconds); + + /** Return the fraction of cache hits. + */ + float getHitRate (); + + /** Return the number of cached items. + */ + int getNumberOfEntries (); + + /** Retrieve a cached item. + + @return The item, or a default constructed container if it was not found. + */ + data_t getEntry (Kind kind, LedgerHash const& ledger, uint160 const& object); + + /** Store an item in the cache. + */ + void storeEntry (Kind kind, LedgerHash const& ledger, uint160 const& object, data_t const& data); + + /** Purge expired items. + + This must be called periodically. + */ + void sweep (); + +private: + int getUptime () const; + +private: + int const m_expirationTime; + boost::unordered_map m_cache; + boost::recursive_mutex m_lock; + uint64 mHits; + uint64 mMisses; +}; + +inline std::size_t hash_value (JSONCache::Key const& key) +{ + return key.getHash (); +} + +#endif diff --git a/modules/ripple_main/ripple_main.cpp b/modules/ripple_main/ripple_main.cpp index 40e19fbefb..0f72e445a1 100644 --- a/modules/ripple_main/ripple_main.cpp +++ b/modules/ripple_main/ripple_main.cpp @@ -185,7 +185,6 @@ #include "src/cpp/ripple/LedgerEntrySet.h" #include "src/cpp/ripple/TransactionEngine.h" #include "src/cpp/ripple/ripple_CanonicalTXSet.h" -#include "src/cpp/ripple/JSONCache.h" #include "src/cpp/ripple/ripple_LedgerHistory.h" #include "src/cpp/ripple/LedgerMaster.h" diff --git a/newcoin.vcxproj b/newcoin.vcxproj index bd058cc8bd..214174924b 100644 --- a/newcoin.vcxproj +++ b/newcoin.vcxproj @@ -354,6 +354,12 @@ true + + true + true + true + true + true @@ -1367,6 +1373,8 @@ + + diff --git a/newcoin.vcxproj.filters b/newcoin.vcxproj.filters index a3f77cb535..db5d2c773a 100644 --- a/newcoin.vcxproj.filters +++ b/newcoin.vcxproj.filters @@ -133,6 +133,9 @@ {97c96b68-70fd-4679-89fc-c1c8c87c265e} + + {ba524810-8446-4c50-ad59-d284747ba220} + @@ -837,6 +840,9 @@ 1. Modules\ripple_main\_unfactored\main + + 1. Modules\ripple_data\utility + @@ -1580,6 +1586,12 @@ 1. Modules\ripple_main\_unfactored\main + + 1. Modules\ripple_data\utility + + + 1. Modules\ripple_data\utility + diff --git a/src/cpp/ripple/JSONCache.h b/src/cpp/ripple/JSONCache.h deleted file mode 100644 index d9802f3752..0000000000 --- a/src/cpp/ripple/JSONCache.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef JSONCACHE_H -#define JSONCACHE_H - -#define JC_OP_ACCOUNT_LINES 1 -#define JC_OP_ACCOUNT_OFFERS 2 - -class JSONCacheKey -{ -private: - uint256 mLedger; - uint160 mObject; - int mOperation; - mutable int mLastUse; - std::size_t mHash; - -public: - - JSONCacheKey(int op, const uint256& ledger, const uint160& object, int lastUse) - : mLedger(ledger), mObject(object), mOperation(op), mLastUse(lastUse) - { - mHash = static_cast(mOperation); - mLedger.hash_combine(mHash); - mObject.hash_combine(mHash); - } - - int compare(const JSONCacheKey& k) const - { - if (mHash < k.mHash) return -1; - if (mHash > k.mHash) return 1; - if (mOperation < k.mOperation) return -1; - if (mOperation > k.mOperation) return 1; - if (mLedger < k.mLedger) return -1; - if (mLedger > k.mLedger) return 1; - if (mObject < k.mObject) return -1; - if (mObject > k.mObject) return 1; - return 0; - } - - bool operator<(const JSONCacheKey &k) const { return compare(k) < 0; } - bool operator>(const JSONCacheKey &k) const { return compare(k) > 0; } - bool operator<=(const JSONCacheKey &k) const { return compare(k) <= 0; } - bool operator>=(const JSONCacheKey &k) const { return compare(k) >= 0; } - bool operator!=(const JSONCacheKey &k) const { return compare(k) != 0; } - bool operator==(const JSONCacheKey &k) const { return compare(k) == 0; } - - void touch(const JSONCacheKey& key) const { mLastUse = key.mLastUse; } - bool expired(int expireTime) const { return mLastUse < expireTime; } - - std::size_t getHash() const { return mHash; } -}; - -inline std::size_t hash_value(const JSONCacheKey& key) { return key.getHash(); } - -template -class JSONCache -{ -public: - typedef boost::shared_ptr data_t; - -protected: - boost::recursive_mutex mLock; - boost::unordered_map mCache; - int mCacheTime; - uint64 mHits, mMisses; - -public: - JSONCache(int cacheTime) : mCacheTime(cacheTime), mHits(0), mMisses(0) { ; } - - int upTime() { return Timer::getElapsedSeconds(); } - - float getHitRate() - { - boost::recursive_mutex::scoped_lock sl(mLock); - return (static_cast(mHits) * 100) / (1.0f + mHits + mMisses); - } - - int getCount() - { - boost::recursive_mutex::scoped_lock sl(mLock); - return mCache.size(); - } - - data_t getEntry(int operation, const uint256& ledger, const uint160& object) - { - JSONCacheKey key(operation, ledger, object, upTime()); - - boost::recursive_mutex::scoped_lock sl(mLock); - boost::unordered_map::iterator it = mCache.find(key); - if (it == mCache.end()) - { - ++mMisses; - return data_t(); - } - ++mHits; - it->first.touch(key); - return it->second; - } - - void storeEntry(int operation, const uint256& ledger, const uint160& object, const data_t& data) - { - JSONCacheKey key(operation, ledger, object, upTime()); - - boost::recursive_mutex::scoped_lock sl(mLock); - mCache.insert(std::pair(key, data)); - } - - void sweep() - { - int sweepTime = upTime(); - if (sweepTime < mCacheTime) - return; - sweepTime -= mCacheTime; - - boost::recursive_mutex::scoped_lock sl(mLock); - boost::unordered_map::iterator it = mCache.begin(); - while (it != mCache.end()) - { - if (it->first.expired(sweepTime)) - it = mCache.erase(it); - else - ++it; - } - } - -}; - -#endif diff --git a/src/cpp/ripple/NetworkOPs.h b/src/cpp/ripple/NetworkOPs.h index ba31ba8abe..ba438d44c5 100644 --- a/src/cpp/ripple/NetworkOPs.h +++ b/src/cpp/ripple/NetworkOPs.h @@ -177,14 +177,16 @@ public: void sweepFetchPack(); float getJSONHitRate() { return mJSONCache.getHitRate(); } - int getJSONEntries() { return mJSONCache.getCount(); } - void storeJSONCache(int operation, const uint256& ledger, const uint160& object, - const boost::shared_ptr& data) - { mJSONCache.storeEntry(operation, ledger, object, data); } + // VFALCO TODO Rename this to getNumberOfCachedJSONItems or something similar + int getJSONEntries() { return mJSONCache.getNumberOfEntries(); } - boost::shared_ptr getJSONCache(int operation, const uint256& ledger, const uint160& object) - { return mJSONCache.getEntry(operation, ledger, object); } + void storeJSONCache(JSONCache::Kind kind, const uint256& ledger, const uint160& object, + const boost::shared_ptr & data) + { mJSONCache.storeEntry(kind, ledger, object, data); } + + boost::shared_ptr getJSONCache(JSONCache::Kind kind, const uint256& ledger, const uint160& object) + { return mJSONCache.getEntry(kind, ledger, object); } // network state machine void checkState(const boost::system::error_code& result); @@ -313,7 +315,7 @@ private: subMapType mSubTransactions; // all accepted transactions subMapType mSubRTTransactions; // all proposed and accepted transactions - JSONCache mJSONCache; + JSONCache mJSONCache; TaggedCache< uint256, Blob , UptimeTimerAdapter > mFetchPack; uint32 mLastFetchPack; diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index 9eda3b06f1..130bb32b5e 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -1093,7 +1093,7 @@ Json::Value RPCHandler::doAccountLines(Json::Value jvRequest, int& cost, ScopedL jvResult["account"] = raAccount.humanAccountID(); boost::shared_ptr jvsLines = - theApp->getOPs().getJSONCache(JC_OP_ACCOUNT_LINES, lpLedger->getHash(), raAccount.getAccountID()); + theApp->getOPs().getJSONCache(JSONCache::kindLines, lpLedger->getHash(), raAccount.getAccountID()); if (!jvsLines) { @@ -1126,7 +1126,7 @@ Json::Value RPCHandler::doAccountLines(Json::Value jvRequest, int& cost, ScopedL } } - theApp->getOPs().storeJSONCache(JC_OP_ACCOUNT_LINES, lpLedger->getHash(), + theApp->getOPs().storeJSONCache(JSONCache::kindLines, lpLedger->getHash(), raAccount.getAccountID(), jvsLines); } if (!bUnlocked) @@ -1199,13 +1199,13 @@ Json::Value RPCHandler::doAccountOffers(Json::Value jvRequest, int& cost, Scoped return rpcError(rpcACT_NOT_FOUND); boost::shared_ptr jvsOffers = - theApp->getOPs().getJSONCache(JC_OP_ACCOUNT_OFFERS, lpLedger->getHash(), raAccount.getAccountID()); + theApp->getOPs().getJSONCache(JSONCache::kindOffers, lpLedger->getHash(), raAccount.getAccountID()); if (!jvsOffers) { jvsOffers = boost::make_shared(Json::arrayValue); lpLedger->visitAccountItems(raAccount.getAccountID(), BIND_TYPE(&offerAdder, boost::ref(*jvsOffers), P_1)); - theApp->getOPs().storeJSONCache(JC_OP_ACCOUNT_OFFERS, lpLedger->getHash(), raAccount.getAccountID(), jvsOffers); + theApp->getOPs().storeJSONCache(JSONCache::kindOffers, lpLedger->getHash(), raAccount.getAccountID(), jvsOffers); } if (!bUnlocked) MasterLockHolder.unlock();