From 58d81ca9377424d7540f9bd44dbd951946765485 Mon Sep 17 00:00:00 2001 From: JoelKatz Date: Wed, 25 Jan 2012 15:27:14 -0800 Subject: [PATCH] Map/Cache to track objects by name and canonicalize references. Will be used for transactions and closed ledgers. --- TaggedCache.h | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 TaggedCache.h diff --git a/TaggedCache.h b/TaggedCache.h new file mode 100644 index 0000000000..6ae3185ee9 --- /dev/null +++ b/TaggedCache.h @@ -0,0 +1,201 @@ +#ifndef __TAGGEDCACHE__ +#define __TAGGEDCACHE__ + +#include + +#include + +// This class implemented a cache and a map. The cache keeps objects alive +// in the map. The map allows multiple code paths that reference objects +// with the same tag to get the same actual object. + +template class TaggedCache +{ +public: + typedef c_Key key_type; + typedef c_Data data_type; + + typedef boost::weak_ptr weak_data_ptr; + typedef boost::shared_ptr data_ptr; + + typedef std::pair cache_entry; + +protected: + mutable boost::mutex mLock; + + int mTargetSize, mTargetAge; + std::map mCache; // Hold strong reference to recent objects + time_t mLastSweep; + + std::map mMap; // Track stored objects + +public: + TaggedCache(int size, int age) : mTargetSize(size), mTargetAge(age), mLastSweep(0) { ; } + int getTargetSize() const; + int getTargetAge() const; + + int getCacheSize(); + int getSweepAge(); + + void setTargetSize(int size); + void setTargetAge(int age); + void sweep(); + + bool touch(const key_type& key); + bool del(const key_type& key); + boost::shared_ptr canonicalize(const key_type& key, boost::shared_ptr data); + boost::shared_ptr fetch(const key_type& key); +}; + +template int TaggedCache::getTargetSize() const +{ + mLock.lock(); + int ret=mTargetSize; + mLock.unlock(); + return ret; +} + +template int TaggedCache::getTargetAge() const +{ + mLock.lock(); + int ret=mTargetAge; + mLock.unlock(); + return ret; +} + +template int TaggedCache::getCacheSize() +{ + boost::mutex::scoped_lock sl(mLock); + return mCache.size(); +} + +template void TaggedCache::sweep() +{ + boost::mutex::scoped_lock sl(mLock); + + if(mCache.size()::iterator cit=mCache.begin(); + while(cit!=mCache.end()) + { + if(cit->second->second.first::iterator cit2=cit; + ++cit; + mCache.erase(cit2); + } + else ++cit; + } + + // Pass 2, remove dead objects from map + typename std::map::iterator mit=mMap.begin(); + while(mit!=mMap.end()) + { + if(mit->second->expired()) + { + typename std::map::iterator mit2=mit; + ++mit; + mMap.erase(mit2); + } + else ++mit; + } +} + +template bool TaggedCache::touch(const key_type& key) +{ // If present, make current in cache + boost::mutex::scoped_lock sl(mLock); + + // Is the object in the map? + typename std::map::iterator mit=mMap.find(key); + if(mit==mMap.end()) return false; + if(mit->second->expired()) + { // in map, but expired + mMap.erase(mit); + return false; + } + + // Is the object in the cache? + typename std::map::iterator cit=mCache.find(key); + if(cit!=mCache.end()) + { // in both map and cache + cit->second->first=time(NULL); + return true; + } + + // In map but not cache, put in cache + mCache.insert(std::make_pair(key, std::make_pair(time(NULL), weak_data_ptr(cit->second->second)))); + return true; +} + +template bool TaggedCache::del(const key_type& key) +{ // Remove from cache, map unaffected + boost::mutex::scoped_lock sl(mLock); + + typename std::map::iterator cit=mCache.find(key); + if(cit==mCache.end()) return false; + mCache.erase(cit); + return true; +} + +template +boost::shared_ptr 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); + + 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; + } + 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; + } + + // 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 + else // no, add to cache + cit.insert(std::make_pair(key, std::make_pair(time(NULL), weak_data_ptr(mit->second)))); + + return mit->second; +} + +template +boost::shared_ptr TaggedCache::fetch(const key_type& key) +{ + boost::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()) + { // in map, but expired + mMap.erase(mit); + return data_ptr(); + } + + // 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 + else // No, add to cache + cit.insert(std::make_pair(key, std::make_pair(time(NULL), weak_data_ptr(mit->second)))); + + return mit->second; +} + +#endif