diff --git a/LedgerHistory.cpp b/LedgerHistory.cpp index 80ec1b1e5..918bcb206 100644 --- a/LedgerHistory.cpp +++ b/LedgerHistory.cpp @@ -7,55 +7,63 @@ #include "Config.h" #include "Application.h" +#ifndef CACHED_LEDGER_NUM +#define CACHED_LEDGER_NUM 512 +#endif + +#ifndef CACHED_LEDGER_AGE +#define CACHED_LEDGER_AGE 60 +#endif + +LedgerHistory::LedgerHistory() : mLedgersByHash(CACHED_LEDGER_NUM, CACHED_LEDGER_AGE) +{ +; +} + void LedgerHistory::addLedger(Ledger::pointer ledger) { - uint256 h(ledger->getHash()); - boost::recursive_mutex::scoped_lock sl(mLock); - mLedgersByHash.insert(std::make_pair(h, ledger)); + mLedgersByHash.canonicalize(ledger->getHash(), ledger); } void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger) { assert(ledger && ledger->isAccepted()); uint256 h(ledger->getHash()); - boost::recursive_mutex::scoped_lock sl(mLock); + boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); + mLedgersByHash.canonicalize(h, ledger); mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger)); - mLedgersByHash.insert(std::make_pair(h, ledger)); theApp->getIOService().post(boost::bind(&Ledger::saveAcceptedLedger, ledger)); } Ledger::pointer LedgerHistory::getLedgerBySeq(uint32 index) { - boost::recursive_mutex::scoped_lock sl(mLock); + boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); std::map::iterator it(mLedgersByIndex.find(index)); if(it!=mLedgersByIndex.end()) return it->second; sl.unlock(); Ledger::pointer ret(Ledger::loadByIndex(index)); if(!ret) return ret; - assert(ret->getLedgerSeq()==index); - uint256 h=ret->getHash(); + sl.lock(); + mLedgersByHash.canonicalize(ret->getHash(), ret); mLedgersByIndex.insert(std::make_pair(index, ret)); - mLedgersByHash.insert(std::make_pair(h, ret)); return ret; } Ledger::pointer LedgerHistory::getLedgerByHash(const uint256& hash) { - boost::recursive_mutex::scoped_lock sl(mLock); - std::map::iterator it(mLedgersByHash.find(hash)); - if(it!=mLedgersByHash.end()) return it->second; - sl.unlock(); + Ledger::pointer ret=mLedgersByHash.fetch(hash); + if(ret) return ret; - Ledger::pointer ret=Ledger::loadByHash(hash); + ret=Ledger::loadByHash(hash); if(!ret) return ret; - assert(ret->getHash()==hash); - sl.lock(); - mLedgersByHash.insert(std::make_pair(hash, ret)); - if(ret->isAccepted()) mLedgersByIndex.insert(std::make_pair(ret->getLedgerSeq(), ret)); + + boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); + mLedgersByHash.canonicalize(hash, ret); + if(ret->isAccepted()) mLedgersByIndex[ret->getLedgerSeq()]=ret; return ret; } @@ -63,20 +71,16 @@ Ledger::pointer LedgerHistory::canonicalizeLedger(Ledger::pointer ledger, bool s { uint256 h(ledger->getHash()); - boost::recursive_mutex::scoped_lock sl(mLock); if(!save) { // return input ledger if not in map, otherwise, return corresponding map ledger - std::map::iterator it(mLedgersByHash.find(h)); - if(it!=mLedgersByHash.end()) return it->second; - } - else - { // save input ledger in map if not in map, otherwise return corresponding map ledger - std::pair::iterator, bool> sp(mLedgersByHash.insert(std::make_pair(h, ledger))); - if(!sp.second) // ledger was not inserted - return sp.first->second; - if(ledger->isAccepted()) - mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger)); + Ledger::pointer ret=mLedgersByHash.fetch(h); + if(ret) return ret; + return ledger; } + + // save input ledger in map if not in map, otherwise return corresponding map ledger + boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex()); + mLedgersByHash.canonicalize(h, ledger); + if(ledger->isAccepted()) mLedgersByIndex[ledger->getLedgerSeq()]=ledger; return ledger; } diff --git a/LedgerHistory.h b/LedgerHistory.h index 205a2a7bb..9073adf26 100644 --- a/LedgerHistory.h +++ b/LedgerHistory.h @@ -1,17 +1,16 @@ #ifndef __LEDGERHISTORY__ #define __LEDGERHISTORY__ +#include "TaggedCache.h" #include "Ledger.h" class LedgerHistory { - boost::recursive_mutex mLock; - - std::map mLedgersByIndex; - std::map mLedgersByHash; + TaggedCache mLedgersByHash; + std::map mLedgersByIndex; // accepted ledgers public: - LedgerHistory() { ; } + LedgerHistory(); void addLedger(Ledger::pointer ledger); void addAcceptedLedger(Ledger::pointer ledger); @@ -21,4 +20,4 @@ public: Ledger::pointer canonicalizeLedger(Ledger::pointer, bool cache); }; -#endif \ No newline at end of file +#endif diff --git a/TaggedCache.h b/TaggedCache.h index 6ae3185ee..a77709b81 100644 --- a/TaggedCache.h +++ b/TaggedCache.h @@ -3,6 +3,7 @@ #include +#include #include // This class implemented a cache and a map. The cache keeps objects alive @@ -21,7 +22,7 @@ public: typedef std::pair cache_entry; protected: - mutable boost::mutex mLock; + mutable boost::recursive_mutex mLock; int mTargetSize, mTargetAge; std::map mCache; // Hold strong reference to recent objects @@ -43,8 +44,10 @@ public: bool touch(const key_type& key); bool del(const key_type& key); - boost::shared_ptr canonicalize(const key_type& key, boost::shared_ptr data); + bool canonicalize(const key_type& key, boost::shared_ptr& data); boost::shared_ptr fetch(const key_type& key); + + boost::recursive_mutex& peekMutex() { return mLock; } }; template int TaggedCache::getTargetSize() const @@ -65,13 +68,13 @@ template int TaggedCache::getTar template int TaggedCache::getCacheSize() { - boost::mutex::scoped_lock sl(mLock); + boost::recursive_mutex::scoped_lock sl(mLock); return mCache.size(); } template void TaggedCache::sweep() { - boost::mutex::scoped_lock sl(mLock); + boost::recursive_mutex::scoped_lock sl(mLock); if(mCache.size() void TaggedCache::sweep template bool TaggedCache::touch(const key_type& key) { // If present, make current in cache - boost::mutex::scoped_lock sl(mLock); + boost::recursive_mutex::scoped_lock sl(mLock); // Is the object in the map? typename std::map::iterator mit=mMap.find(key); @@ -136,7 +139,7 @@ template bool TaggedCache::touch template bool TaggedCache::del(const key_type& key) { // Remove from cache, map unaffected - boost::mutex::scoped_lock sl(mLock); + boost::recursive_mutex::scoped_lock sl(mLock); typename std::map::iterator cit=mCache.find(key); if(cit==mCache.end()) return false; @@ -145,57 +148,62 @@ template bool TaggedCache::del(c } template -boost::shared_ptr TaggedCache::canonicalize(const key_type& key, - boost::shared_ptr data) +bool TaggedCache::canonicalize(const key_type& key, boost::shared_ptr& data) { // Return canonical value, store if needed, refresh in cache - boost::mutex::scoped_lock sl(mLock); + // Return values: true=we had the data already + boost::recursive_mutex::scoped_lock sl(mLock); typename std::map::iterator mit=mMap.find(key); if(mit==mMap.end()) { // not in map mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data))); mMap.insert(std::make_pair(key, data)); - return data; + return false; } - if(mit->second->expired()) + if(mit->second.expired()) { // in map, but expired mit->second=data; mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data))); - return data; + return false; } + + data=mit->second.lock(); + assert(!!data); // Valid in map, is it in cache? typename std::map::iterator cit=mCache.find(key); if(cit!=mCache.end()) - cit->second->first=time(NULL); // Yes, refesh + cit->second.first=time(NULL); // Yes, refesh else // no, add to cache - cit.insert(std::make_pair(key, std::make_pair(time(NULL), weak_data_ptr(mit->second)))); + mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data))); - return mit->second; + return true; } template boost::shared_ptr TaggedCache::fetch(const key_type& key) { - boost::mutex::scoped_lock sl(mLock); + boost::recursive_mutex::scoped_lock sl(mLock); // Is it in the map? typename std::map::iterator mit=mMap.find(key); if(mit==mMap.end()) return data_ptr(); // No, we're done - if(mit->second->expired()) + if(mit->second.expired()) { // in map, but expired mMap.erase(mit); return data_ptr(); } + boost::shared_ptr data=mit->second.lock(); + // Valid in map, is it in the cache? typename std::map::iterator cit=mCache.find(key); if(cit!=mCache.end()) - cit->second->first=time(NULL); // Yes, refresh + cit->second.first=time(NULL); // Yes, refresh else // No, add to cache - cit.insert(std::make_pair(key, std::make_pair(time(NULL), weak_data_ptr(mit->second)))); + mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data))); - return mit->second; + return data; } #endif