Modify the ledger history code to use the tagged cache.

This commit is contained in:
JoelKatz
2012-01-25 16:32:27 -08:00
parent 8a0625a477
commit 1896348b7b
3 changed files with 67 additions and 56 deletions

View File

@@ -7,55 +7,63 @@
#include "Config.h" #include "Config.h"
#include "Application.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) void LedgerHistory::addLedger(Ledger::pointer ledger)
{ {
uint256 h(ledger->getHash()); mLedgersByHash.canonicalize(ledger->getHash(), ledger);
boost::recursive_mutex::scoped_lock sl(mLock);
mLedgersByHash.insert(std::make_pair(h, ledger));
} }
void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger) void LedgerHistory::addAcceptedLedger(Ledger::pointer ledger)
{ {
assert(ledger && ledger->isAccepted()); assert(ledger && ledger->isAccepted());
uint256 h(ledger->getHash()); 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)); mLedgersByIndex.insert(std::make_pair(ledger->getLedgerSeq(), ledger));
mLedgersByHash.insert(std::make_pair(h, ledger));
theApp->getIOService().post(boost::bind(&Ledger::saveAcceptedLedger, ledger)); theApp->getIOService().post(boost::bind(&Ledger::saveAcceptedLedger, ledger));
} }
Ledger::pointer LedgerHistory::getLedgerBySeq(uint32 index) Ledger::pointer LedgerHistory::getLedgerBySeq(uint32 index)
{ {
boost::recursive_mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex());
std::map<uint32, Ledger::pointer>::iterator it(mLedgersByIndex.find(index)); std::map<uint32, Ledger::pointer>::iterator it(mLedgersByIndex.find(index));
if(it!=mLedgersByIndex.end()) return it->second; if(it!=mLedgersByIndex.end()) return it->second;
sl.unlock(); sl.unlock();
Ledger::pointer ret(Ledger::loadByIndex(index)); Ledger::pointer ret(Ledger::loadByIndex(index));
if(!ret) return ret; if(!ret) return ret;
assert(ret->getLedgerSeq()==index); assert(ret->getLedgerSeq()==index);
uint256 h=ret->getHash();
sl.lock(); sl.lock();
mLedgersByHash.canonicalize(ret->getHash(), ret);
mLedgersByIndex.insert(std::make_pair(index, ret)); mLedgersByIndex.insert(std::make_pair(index, ret));
mLedgersByHash.insert(std::make_pair(h, ret));
return ret; return ret;
} }
Ledger::pointer LedgerHistory::getLedgerByHash(const uint256& hash) Ledger::pointer LedgerHistory::getLedgerByHash(const uint256& hash)
{ {
boost::recursive_mutex::scoped_lock sl(mLock); Ledger::pointer ret=mLedgersByHash.fetch(hash);
std::map<uint256, Ledger::pointer>::iterator it(mLedgersByHash.find(hash)); if(ret) return ret;
if(it!=mLedgersByHash.end()) return it->second;
sl.unlock();
Ledger::pointer ret=Ledger::loadByHash(hash); ret=Ledger::loadByHash(hash);
if(!ret) return ret; if(!ret) return ret;
assert(ret->getHash()==hash); assert(ret->getHash()==hash);
sl.lock();
mLedgersByHash.insert(std::make_pair(hash, ret)); boost::recursive_mutex::scoped_lock sl(mLedgersByHash.peekMutex());
if(ret->isAccepted()) mLedgersByIndex.insert(std::make_pair(ret->getLedgerSeq(), ret)); mLedgersByHash.canonicalize(hash, ret);
if(ret->isAccepted()) mLedgersByIndex[ret->getLedgerSeq()]=ret;
return ret; return ret;
} }
@@ -63,20 +71,16 @@ Ledger::pointer LedgerHistory::canonicalizeLedger(Ledger::pointer ledger, bool s
{ {
uint256 h(ledger->getHash()); uint256 h(ledger->getHash());
boost::recursive_mutex::scoped_lock sl(mLock);
if(!save) if(!save)
{ // return input ledger if not in map, otherwise, return corresponding map ledger { // return input ledger if not in map, otherwise, return corresponding map ledger
std::map<uint256, Ledger::pointer>::iterator it(mLedgersByHash.find(h)); Ledger::pointer ret=mLedgersByHash.fetch(h);
if(it!=mLedgersByHash.end()) return it->second; if(ret) return ret;
} return ledger;
else
{ // save input ledger in map if not in map, otherwise return corresponding map ledger
std::pair<std::map<uint256,
Ledger::pointer>::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));
} }
// 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; return ledger;
} }

View File

@@ -1,17 +1,16 @@
#ifndef __LEDGERHISTORY__ #ifndef __LEDGERHISTORY__
#define __LEDGERHISTORY__ #define __LEDGERHISTORY__
#include "TaggedCache.h"
#include "Ledger.h" #include "Ledger.h"
class LedgerHistory class LedgerHistory
{ {
boost::recursive_mutex mLock; TaggedCache<uint256, Ledger> mLedgersByHash;
std::map<uint32, Ledger::pointer> mLedgersByIndex; // accepted ledgers
std::map<uint32, Ledger::pointer> mLedgersByIndex;
std::map<uint256, Ledger::pointer> mLedgersByHash;
public: public:
LedgerHistory() { ; } LedgerHistory();
void addLedger(Ledger::pointer ledger); void addLedger(Ledger::pointer ledger);
void addAcceptedLedger(Ledger::pointer ledger); void addAcceptedLedger(Ledger::pointer ledger);
@@ -21,4 +20,4 @@ public:
Ledger::pointer canonicalizeLedger(Ledger::pointer, bool cache); Ledger::pointer canonicalizeLedger(Ledger::pointer, bool cache);
}; };
#endif #endif

View File

@@ -3,6 +3,7 @@
#include <map> #include <map>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
// This class implemented a cache and a map. The cache keeps objects alive // This class implemented a cache and a map. The cache keeps objects alive
@@ -21,7 +22,7 @@ public:
typedef std::pair<time_t, data_ptr> cache_entry; typedef std::pair<time_t, data_ptr> cache_entry;
protected: protected:
mutable boost::mutex mLock; mutable boost::recursive_mutex mLock;
int mTargetSize, mTargetAge; int mTargetSize, mTargetAge;
std::map<key_type, cache_entry> mCache; // Hold strong reference to recent objects std::map<key_type, cache_entry> mCache; // Hold strong reference to recent objects
@@ -43,8 +44,10 @@ public:
bool touch(const key_type& key); bool touch(const key_type& key);
bool del(const key_type& key); bool del(const key_type& key);
boost::shared_ptr<c_Data> canonicalize(const key_type& key, boost::shared_ptr<c_Data> data); bool canonicalize(const key_type& key, boost::shared_ptr<c_Data>& data);
boost::shared_ptr<c_Data> fetch(const key_type& key); boost::shared_ptr<c_Data> fetch(const key_type& key);
boost::recursive_mutex& peekMutex() { return mLock; }
}; };
template<typename c_Key, typename c_Data> int TaggedCache<c_Key, c_Data>::getTargetSize() const template<typename c_Key, typename c_Data> int TaggedCache<c_Key, c_Data>::getTargetSize() const
@@ -65,13 +68,13 @@ template<typename c_Key, typename c_Data> int TaggedCache<c_Key, c_Data>::getTar
template<typename c_Key, typename c_Data> int TaggedCache<c_Key, c_Data>::getCacheSize() template<typename c_Key, typename c_Data> int TaggedCache<c_Key, c_Data>::getCacheSize()
{ {
boost::mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
return mCache.size(); return mCache.size();
} }
template<typename c_Key, typename c_Data> void TaggedCache<c_Key, c_Data>::sweep() template<typename c_Key, typename c_Data> void TaggedCache<c_Key, c_Data>::sweep()
{ {
boost::mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
if(mCache.size()<mTargetSize) return; if(mCache.size()<mTargetSize) return;
@@ -110,7 +113,7 @@ template<typename c_Key, typename c_Data> void TaggedCache<c_Key, c_Data>::sweep
template<typename c_Key, typename c_Data> bool TaggedCache<c_Key, c_Data>::touch(const key_type& key) template<typename c_Key, typename c_Data> bool TaggedCache<c_Key, c_Data>::touch(const key_type& key)
{ // If present, make current in cache { // 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? // Is the object in the map?
typename std::map<key_type, weak_data_ptr>::iterator mit=mMap.find(key); typename std::map<key_type, weak_data_ptr>::iterator mit=mMap.find(key);
@@ -136,7 +139,7 @@ template<typename c_Key, typename c_Data> bool TaggedCache<c_Key, c_Data>::touch
template<typename c_Key, typename c_Data> bool TaggedCache<c_Key, c_Data>::del(const key_type& key) template<typename c_Key, typename c_Data> bool TaggedCache<c_Key, c_Data>::del(const key_type& key)
{ // Remove from cache, map unaffected { // Remove from cache, map unaffected
boost::mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
typename std::map<key_type, cache_entry>::iterator cit=mCache.find(key); typename std::map<key_type, cache_entry>::iterator cit=mCache.find(key);
if(cit==mCache.end()) return false; if(cit==mCache.end()) return false;
@@ -145,57 +148,62 @@ template<typename c_Key, typename c_Data> bool TaggedCache<c_Key, c_Data>::del(c
} }
template<typename c_Key, typename c_Data> template<typename c_Key, typename c_Data>
boost::shared_ptr<c_Data> TaggedCache<c_Key, c_Data>::canonicalize(const key_type& key, bool TaggedCache<c_Key, c_Data>::canonicalize(const key_type& key, boost::shared_ptr<c_Data>& data)
boost::shared_ptr<c_Data> data)
{ // Return canonical value, store if needed, refresh in cache { // 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<key_type, weak_data_ptr>::iterator mit=mMap.find(key); typename std::map<key_type, weak_data_ptr>::iterator mit=mMap.find(key);
if(mit==mMap.end()) if(mit==mMap.end())
{ // not in map { // not in map
mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data))); mCache.insert(std::make_pair(key, std::make_pair(time(NULL), data)));
mMap.insert(std::make_pair(key, data)); mMap.insert(std::make_pair(key, data));
return data; return false;
} }
if(mit->second->expired()) if(mit->second.expired())
{ // in map, but expired { // in map, but expired
mit->second=data; mit->second=data;
mCache.insert(std::make_pair(key, std::make_pair(time(NULL), 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? // Valid in map, is it in cache?
typename std::map<key_type, cache_entry>::iterator cit=mCache.find(key); typename std::map<key_type, cache_entry>::iterator cit=mCache.find(key);
if(cit!=mCache.end()) if(cit!=mCache.end())
cit->second->first=time(NULL); // Yes, refesh cit->second.first=time(NULL); // Yes, refesh
else // no, add to cache 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<typename c_Key, typename c_Data> template<typename c_Key, typename c_Data>
boost::shared_ptr<c_Data> TaggedCache<c_Key, c_Data>::fetch(const key_type& key) boost::shared_ptr<c_Data> TaggedCache<c_Key, c_Data>::fetch(const key_type& key)
{ {
boost::mutex::scoped_lock sl(mLock); boost::recursive_mutex::scoped_lock sl(mLock);
// Is it in the map? // Is it in the map?
typename std::map<key_type, weak_data_ptr>::iterator mit=mMap.find(key); typename std::map<key_type, weak_data_ptr>::iterator mit=mMap.find(key);
if(mit==mMap.end()) return data_ptr(); // No, we're done if(mit==mMap.end()) return data_ptr(); // No, we're done
if(mit->second->expired()) if(mit->second.expired())
{ // in map, but expired { // in map, but expired
mMap.erase(mit); mMap.erase(mit);
return data_ptr(); return data_ptr();
} }
boost::shared_ptr<c_Data> data=mit->second.lock();
// Valid in map, is it in the cache? // Valid in map, is it in the cache?
typename std::map<key_type, cache_entry>::iterator cit=mCache.find(key); typename std::map<key_type, cache_entry>::iterator cit=mCache.find(key);
if(cit!=mCache.end()) if(cit!=mCache.end())
cit->second->first=time(NULL); // Yes, refresh cit->second.first=time(NULL); // Yes, refresh
else // No, add to cache 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 #endif