diff options
Diffstat (limited to 'cpp/include/IceUtil/Cache.h')
-rw-r--r-- | cpp/include/IceUtil/Cache.h | 362 |
1 files changed, 0 insertions, 362 deletions
diff --git a/cpp/include/IceUtil/Cache.h b/cpp/include/IceUtil/Cache.h deleted file mode 100644 index cb76f4466e0..00000000000 --- a/cpp/include/IceUtil/Cache.h +++ /dev/null @@ -1,362 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2003-2015 ZeroC, Inc. All rights reserved. -// -// This copy of Ice is licensed to you under the terms described in the -// ICE_LICENSE file included in this distribution. -// -// ********************************************************************** - -#ifndef ICE_UTIL_CACHE_H -#define ICE_UTIL_CACHE_H - -#include <IceUtil/Handle.h> -#include <IceUtil/Mutex.h> -#include <IceUtil/CountDownLatch.h> -#include <map> - -namespace IceUtil -{ - -// -// An abstraction to efficiently populate a Cache, without holding -// a lock while loading from a database. -// - -template<typename Key, typename Value> -class Cache -{ -public: - - // - // Latch and CacheValue are implementation details; - // application code should not use them. - // - - struct Latch : public IceUtilInternal::CountDownLatch - { - Latch() : - IceUtilInternal::CountDownLatch(1), - useCount(0) - { - } - int useCount; - }; - - struct CacheValue - { - CacheValue(const Handle<Value>& o) : - obj(o), - latch(0) - { - } - - Handle<Value> obj; - Latch* latch; - }; - - typedef typename std::map<Key, CacheValue>::iterator Position; - - Handle<Value> getIfPinned(const Key&, bool = false) const; - - void unpin(Position); - - void clear(); - size_t size() const; - - bool pin(const Key&, const Handle<Value>&); - - Handle<Value> pin(const Key&); - Handle<Value> putIfAbsent(const Key&, const Handle<Value>&); - -protected: - - virtual Handle<Value> load(const Key&) = 0; - - virtual void pinned(const Handle<Value>&, Position) - { - } - - virtual ~Cache() - { - } - -private: - - Handle<Value> pinImpl(const Key&, const Handle<Value>&); - - typedef std::map<Key, CacheValue> CacheMap; - - Mutex _mutex; - CacheMap _map; -}; - - -template<typename Key, typename Value> Handle<Value> -Cache<Key, Value>::getIfPinned(const Key& key, bool wait) const -{ - Mutex::Lock sync(_mutex); - - for(;;) - { - typename CacheMap::const_iterator p = _map.find(key); - if(p != _map.end()) - { - Handle<Value> result = (*p).second.obj; - if(result != 0 || wait == false) - { - return result; - } - - // - // The object is being loaded: we wait - // - - if(p->second.latch == 0) - { - const_cast<CacheValue&>(p->second).latch = new Latch; - } - - Latch* latch = p->second.latch; - ++latch->useCount; - sync.release(); - latch->await(); - sync.acquire(); - if(--latch->useCount == 0) - { - delete latch; - } - // - // Try again - // - } - else - { - return 0; - } - } -} - -template<typename Key, typename Value> void -Cache<Key, Value>::unpin(typename Cache::Position p) -{ - // - // There is no risk to erase a 'being loaded' position, - // since such position never got outside yet! - // - Mutex::Lock sync(_mutex); - _map.erase(p); -} - -template<typename Key, typename Value> void -Cache<Key, Value>::clear() -{ - // - // Not safe during a pin! - // - Mutex::Lock sync(_mutex); - _map.clear(); -} - -template<typename Key, typename Value> size_t -Cache<Key, Value>::size() const -{ - Mutex::Lock sync(_mutex); - return _map.size(); -} - -template<typename Key, typename Value> bool -Cache<Key, Value>::pin(const Key& key, const Handle<Value>& obj) -{ - Mutex::Lock sync(_mutex); - std::pair<typename CacheMap::iterator, bool> ir = -#ifdef _MSC_VER - _map.insert(CacheMap::value_type(key, CacheValue(obj))); -#else - _map.insert(typename CacheMap::value_type(key, CacheValue(obj))); -#endif - - if(ir.second) - { - pinned(obj, ir.first); - } - return ir.second; -} - -template<typename Key, typename Value> Handle<Value> -Cache<Key, Value>::pin(const Key& key) -{ - return pinImpl(key, 0); -} - -template<typename Key, typename Value> Handle<Value> -Cache<Key, Value>::putIfAbsent(const Key& key, const Handle<Value>& obj) -{ - return pinImpl(key, obj); -} - -template<typename Key, typename Value> Handle<Value> -Cache<Key, Value>::pinImpl(const Key& key, const Handle<Value>& newObj) -{ - Latch* latch = 0; - Position p; - - do - { - { - Mutex::Lock sync(_mutex); - - // - // Clean up latch from previous loop - // - if(latch != 0) - { - if(--latch->useCount == 0) - { - delete latch; - } - latch = 0; - } - - std::pair<typename CacheMap::iterator, bool> ir = -#if defined(_MSC_VER) - _map.insert(CacheMap::value_type(key, CacheValue(0))); -#else - _map.insert(typename CacheMap::value_type(key, CacheValue(0))); -#endif - - if(ir.second == false) - { - CacheValue& val = ir.first->second; - if(val.obj != 0) - { - return val.obj; - } - - // - // Otherwise wait - // - if(val.latch == 0) - { - // - // The first queued thread creates the latch - // - val.latch = new Latch; - } - latch = val.latch; - latch->useCount++; - } - - p = ir.first; - } - - if(latch != 0) - { - // - // Note: only the threads owning a "useCount" wait; upon wake-up, - // they loop back, release this useCount and possibly delete the latch - // - - latch->await(); - - // - // p could be stale now, e.g. some other thread pinned and unpinned the - // object while we were waiting. - // So start over. - } - } while(latch != 0); - - - // - // Load - // - Handle<Value> obj; - try - { - obj = load(key); - } - catch(...) - { - Mutex::Lock sync(_mutex); - latch = p->second.latch; - p->second.latch = 0; - _map.erase(p); - if(latch != 0) - { - // - // It is necessary to call countDown() within the sync - // because countDown may not be atomic, and we don't - // want the "await" thread to delete the latch while - // this thread is still in countDown(). - // - assert(latch->getCount() == 1); - latch->countDown(); - } - throw; - } - - Mutex::Lock sync(_mutex); - - // - // p is still valid here -- nobody knows about it. See also unpin(). - // - latch = p->second.latch; - p->second.latch = 0; - - try - { - if(obj != 0) - { - p->second.obj = obj; - pinned(obj, p); - } - else - { - if(newObj == 0) - { - // - // pin() did not find the object - // - - // - // The waiting threads will have to call load() to see by themselves. - // - _map.erase(p); - } - else - { - // - // putIfAbsent() inserts key/newObj - // - p->second.obj = newObj; - pinned(newObj, p); - } - } - } - catch(...) - { - if(latch != 0) - { - // - // Must be called within sync; see ->countDown() note above. - // - assert(latch->getCount() == 1); - latch->countDown(); - } - throw; - } - - if(latch != 0) - { - // - // Must be called within sync; see ->countDown() note above. - // - assert(latch->getCount() == 1); - latch->countDown(); - } - return obj; -} - -} - -#endif |