mirror of
https://github.com/pocoproject/poco.git
synced 2025-01-19 00:46:03 +01:00
Added UniqueAccess caches
This commit is contained in:
parent
9381a34928
commit
4d71a6e1d5
105
Foundation/include/Poco/AccessExpirationDecorator.h
Normal file
105
Foundation/include/Poco/AccessExpirationDecorator.h
Normal file
@ -0,0 +1,105 @@
|
||||
//
|
||||
// AccessExpirationDecorator.h
|
||||
//
|
||||
// $Id: //poco/Main/Foundation/include/Poco/AccessExpirationDecorator.h#1 $
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Events
|
||||
// Module: AccessExpirationDecorator
|
||||
//
|
||||
// Implementation of the AccessExpirationDecorator template.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
// obtaining a copy of the software and accompanying documentation covered by
|
||||
// this license (the "Software") to use, reproduce, display, distribute,
|
||||
// execute, and transmit the Software, and to prepare derivative works of the
|
||||
// Software, and to permit third-parties to whom the Software is furnished to
|
||||
// do so, all subject to the following:
|
||||
//
|
||||
// The copyright notices in the Software and this entire statement, including
|
||||
// the above license grant, this restriction and the following disclaimer,
|
||||
// must be included in all copies of the Software, in whole or in part, and
|
||||
// all derivative works of the Software, unless such copies or derivative
|
||||
// works are solely in the form of machine-executable object code generated by
|
||||
// a source language processor.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
|
||||
#ifndef Foundation_AccessExpirationDecorator_INCLUDED
|
||||
#define Foundation_AccessExpirationDecorator_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Timestamp.h"
|
||||
#include "Poco/Timespan.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
|
||||
|
||||
template <typename TArgs>
|
||||
class AccessExpirationDecorator
|
||||
/// AccessExpirationDecorator adds an expiration method to values so that they can be used
|
||||
/// with the UniqueAccessExpireCache
|
||||
{
|
||||
public:
|
||||
AccessExpirationDecorator():
|
||||
_value(),
|
||||
_expiresAt()
|
||||
{
|
||||
}
|
||||
|
||||
AccessExpirationDecorator(const TArgs& p, const Poco::Timespan::TimeDiff& diffInMs):
|
||||
/// Creates an element that will expire in diff milliseconds
|
||||
_value(p),
|
||||
_expiresAt(diffInMs*1000)
|
||||
{
|
||||
}
|
||||
|
||||
AccessExpirationDecorator(const TArgs& p, const Poco::Timespan& timeSpan):
|
||||
/// Creates an element that will expire after the given timeSpan
|
||||
_value(p),
|
||||
_expiresAt(timeSpan)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~AccessExpirationDecorator()
|
||||
{
|
||||
}
|
||||
|
||||
const Poco::Timespan& getExpiration() const
|
||||
{
|
||||
return _expiresAt;
|
||||
}
|
||||
|
||||
const TArgs& value() const
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
TArgs& value()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
private:
|
||||
TArgs _value;
|
||||
Timespan _expiresAt;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
#endif
|
@ -39,31 +39,51 @@
|
||||
#ifndef Foundation_UniqueAccessExpireCache_INCLUDED
|
||||
#define Foundation_UniqueAccessExpireCache_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/AbstractCache.h"
|
||||
#include "Poco/UniqueExpireCache.h"
|
||||
#include "Poco/UniqueAccessExpireStrategy.h"
|
||||
|
||||
namespace Poco
|
||||
{
|
||||
template <class TKey, class TValue>
|
||||
class UniqueAccessExpireCache: public Poco::AbstractCache<TKey, TValue, Poco::UniqueAccessExpireStrategy<TKey, TValue> >
|
||||
|
||||
namespace Poco {
|
||||
|
||||
|
||||
template <class TKey, class TValue>
|
||||
class UniqueAccessExpireCache: public AbstractCache<TKey, TValue, UniqueAccessExpireStrategy<TKey, TValue> >
|
||||
/// An UniqueAccessExpireCache caches entries for a given time span. In contrast
|
||||
/// to ExpireCache which only allows to set a per cache expiration value, it allows to define
|
||||
/// expiration per CacheEntry.
|
||||
/// Each TValue object must thus offer the following method:
|
||||
///
|
||||
/// const Poco::Timespan& getExpiration() const;
|
||||
///
|
||||
/// which returns the relative timespan for how long the entry should be valid without being accessed!
|
||||
/// The absolute expire timepoint is calculated as now() + getExpiration().
|
||||
/// Accessing an object will update this absolute expire timepoint.
|
||||
/// You can use the Poco::AccessExpirationDecorator to add the getExpiration
|
||||
/// method to values that do not have a getExpiration function.
|
||||
///
|
||||
/// Be careful when using an UniqueAccessExpireCache. A cache is often used
|
||||
/// like cache.has(x) followed by cache.get x). Note that it could happen
|
||||
/// that the "has" call works, then the current execution thread gets descheduled, time passes,
|
||||
/// the entry gets invalid, thus leading to an empty SharedPtr being returned
|
||||
/// when "get" is invoked.
|
||||
{
|
||||
public:
|
||||
UniqueAccessExpireCache():
|
||||
AbstractCache<TKey, TValue, UniqueAccessExpireStrategy<TKey, TValue> >(UniqueAccessExpireStrategy<TKey, TValue>())
|
||||
{
|
||||
friend class Poco::UniqueAccessExpireStrategy<TKey, TValue>;
|
||||
|
||||
public:
|
||||
UniqueAccessExpireCache ():
|
||||
Poco::AbstractCache<TKey, TValue, Poco::UniqueAccessExpireStrategy<TKey, TValue> > (UniqueAccessExpireStrategy<TKey, TValue> (this))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
~UniqueAccessExpireCache()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
UniqueAccessExpireCache(const UniqueAccessExpireCache& aCache);
|
||||
UniqueAccessExpireCache& operator = (const UniqueAccessExpireCache& aCache);
|
||||
};
|
||||
|
||||
~UniqueAccessExpireCache ()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
UniqueAccessExpireCache (const Poco::UniqueExpireCache<TKey, TValue>& aCache);
|
||||
UniqueAccessExpireCache& operator = (const Poco::UniqueExpireCache<TKey, TValue>& aCache);
|
||||
};
|
||||
} // namespace Poco
|
||||
|
||||
#endif
|
||||
|
91
Foundation/include/Poco/UniqueAccessExpireLRUCache.h
Normal file
91
Foundation/include/Poco/UniqueAccessExpireLRUCache.h
Normal file
@ -0,0 +1,91 @@
|
||||
//
|
||||
// UniqueAccessExpireLRUCache.h
|
||||
//
|
||||
// $Id: //poco/Main/Foundation/include/Poco/UniqueAccessExpireLRUCache.h#1 $
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Cache
|
||||
// Module: UniqueAccessExpireLRUCache
|
||||
//
|
||||
// Definition of the UniqueAccessExpireLRUCache class.
|
||||
//
|
||||
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
// obtaining a copy of the software and accompanying documentation covered by
|
||||
// this license (the "Software") to use, reproduce, display, distribute,
|
||||
// execute, and transmit the Software, and to prepare derivative works of the
|
||||
// Software, and to permit third-parties to whom the Software is furnished to
|
||||
// do so, all subject to the following:
|
||||
//
|
||||
// The copyright notices in the Software and this entire statement, including
|
||||
// the above license grant, this restriction and the following disclaimer,
|
||||
// must be included in all copies of the Software, in whole or in part, and
|
||||
// all derivative works of the Software, unless such copies or derivative
|
||||
// works are solely in the form of machine-executable object code generated by
|
||||
// a source language processor.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
|
||||
#ifndef Foundation_UniqueAccessExpireLRUCache_INCLUDED
|
||||
#define Foundation_UniqueAccessExpireLRUCache_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/AbstractCache.h"
|
||||
#include "Poco/StrategyCollection.h"
|
||||
#include "Poco/UniqueAccessExpireStrategy.h"
|
||||
#include "Poco/LRUStrategy.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
|
||||
|
||||
template <
|
||||
class TKey,
|
||||
class TValue
|
||||
>
|
||||
class UniqueAccessExpireLRUCache: public AbstractCache<TKey, TValue, StrategyCollection<TKey, TValue> >
|
||||
/// A UniqueAccessExpireLRUCache combines LRU caching and time based per entry expire caching.
|
||||
/// One can define for each cache entry a seperate timepoint
|
||||
/// but also limit the size of the cache (per default: 1024).
|
||||
/// Each TValue object must thus offer the following method:
|
||||
///
|
||||
/// const Poco::Timespan& getExpiration() const;
|
||||
///
|
||||
/// which returns the relative timespan for how long the entry should be valid without being accessed!
|
||||
/// The absolute expire timepoint is calculated as now() + getExpiration().
|
||||
/// Accessing an object will update this absolute expire timepoint.
|
||||
/// You can use the Poco::AccessExpirationDecorator to add the getExpiration
|
||||
/// method to values that do not have a getExpiration function.
|
||||
{
|
||||
public:
|
||||
UniqueAccessExpireLRUCache(long cacheSize = 1024):
|
||||
AbstractCache<TKey, TValue, StrategyCollection<TKey, TValue> >(StrategyCollection<TKey, TValue>())
|
||||
{
|
||||
this->_strategy.pushBack(new LRUStrategy<TKey, TValue>(cacheSize));
|
||||
this->_strategy.pushBack(new UniqueAccessExpireStrategy<TKey, TValue>());
|
||||
}
|
||||
|
||||
~UniqueAccessExpireLRUCache()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
UniqueAccessExpireLRUCache(const UniqueAccessExpireLRUCache& aCache);
|
||||
UniqueAccessExpireLRUCache& operator = (const UniqueAccessExpireLRUCache& aCache);
|
||||
};
|
||||
|
||||
|
||||
} // namespace Poco
|
||||
|
||||
|
||||
#endif
|
@ -44,66 +44,133 @@
|
||||
#include "Poco/AbstractStrategy.h"
|
||||
#include "Poco/Bugcheck.h"
|
||||
#include "Poco/Timestamp.h"
|
||||
#include "Poco/Timespan.h"
|
||||
#include "Poco/EventArgs.h"
|
||||
#include "Poco/UniqueExpireStrategy.h"
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
|
||||
namespace Poco
|
||||
|
||||
namespace Poco {
|
||||
|
||||
|
||||
|
||||
template <
|
||||
class TKey,
|
||||
class TValue
|
||||
>
|
||||
class UniqueAccessExpireStrategy: public AbstractStrategy<TKey, TValue>
|
||||
/// An UniqueExpireStrategy implements time based expiration of cache entries. In contrast
|
||||
/// to ExpireStrategy which only allows to set a per cache expiration value, it allows to define
|
||||
/// expiration per CacheEntry.
|
||||
/// Each TValue object must thus offer the following method:
|
||||
///
|
||||
/// const Poco::Timestamp& getExpiration() const;
|
||||
///
|
||||
/// which returns the absolute timepoint when the entry will be invalidated.
|
||||
{
|
||||
template <class TKey, class TValue>
|
||||
class UniqueAccessExpireCache;
|
||||
|
||||
template <class TKey, class TValue>
|
||||
class UniqueAccessExpireStrategy : public Poco::UniqueExpireStrategy <TKey, TValue>
|
||||
public:
|
||||
typedef std::pair<TKey, Timespan> KeyExpire;
|
||||
typedef std::multimap<Timestamp, KeyExpire> TimeIndex;
|
||||
typedef typename TimeIndex::iterator IndexIterator;
|
||||
typedef typename TimeIndex::const_iterator ConstIndexIterator;
|
||||
typedef std::map<TKey, IndexIterator> Keys;
|
||||
typedef typename Keys::iterator Iterator;
|
||||
|
||||
public:
|
||||
UniqueAccessExpireStrategy()
|
||||
/// Create an unique expire strategy.
|
||||
{
|
||||
public:
|
||||
typedef std::map<TKey, SharedPtr<TValue > > DataHolder;
|
||||
typedef typename DataHolder::iterator DataIterator;
|
||||
}
|
||||
|
||||
typedef std::multimap<Poco::Timestamp, TKey> TimeIndex;
|
||||
typedef typename TimeIndex::iterator IndexIterator;
|
||||
typedef typename TimeIndex::const_iterator ConstIndexIterator;
|
||||
typedef std::map<TKey, IndexIterator> Keys;
|
||||
typedef typename Keys::iterator Iterator;
|
||||
~UniqueAccessExpireStrategy()
|
||||
{
|
||||
}
|
||||
|
||||
UniqueAccessExpireStrategy (const Poco::UniqueAccessExpireCache<TKey, TValue>* cache)
|
||||
: _cache (cache)
|
||||
void onAdd(const void*, const KeyValueArgs <TKey, TValue>& args)
|
||||
{
|
||||
// the expire value defines how many millisecs in the future the
|
||||
// value will expire, even insert negative values!
|
||||
Timestamp expire;
|
||||
expire += args.value().getExpiration().totalMicroseconds();
|
||||
|
||||
IndexIterator it = _keyIndex.insert(std::make_pair(expire, std::make_pair(args.key(), args.value().getExpiration())));
|
||||
std::pair<Iterator, bool> stat = _keys.insert(std::make_pair(args.key(), it));
|
||||
if (!stat.second)
|
||||
{
|
||||
_keyIndex.erase(stat.first->second);
|
||||
stat.first->second = it;
|
||||
}
|
||||
}
|
||||
|
||||
void onRemove(const void*, const TKey& key)
|
||||
{
|
||||
Iterator it = _keys.find(key);
|
||||
if (it != _keys.end())
|
||||
{
|
||||
_keyIndex.erase(it->second);
|
||||
_keys.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void onGet(const void*, const TKey& key)
|
||||
{
|
||||
// get updates the expiration time stamp
|
||||
Iterator it = _keys.find(key);
|
||||
if (it != _keys.end())
|
||||
{
|
||||
KeyExpire ke = it->second->second;
|
||||
// gen new absolute expire value
|
||||
Timestamp expire;
|
||||
expire += ke.second.totalMicroseconds();
|
||||
// delete old index
|
||||
_keyIndex.erase(it->second);
|
||||
IndexIterator itt = _keyIndex.insert(std::make_pair(expire, ke));
|
||||
// update iterator
|
||||
it->second = itt;
|
||||
}
|
||||
}
|
||||
|
||||
void onClear(const void*, const EventArgs& args)
|
||||
{
|
||||
_keys.clear();
|
||||
_keyIndex.clear();
|
||||
}
|
||||
|
||||
void onIsValid(const void*, ValidArgs<TKey>& args)
|
||||
{
|
||||
Iterator it = _keys.find(args.key());
|
||||
if (it != _keys.end())
|
||||
{
|
||||
Timestamp now;
|
||||
if (it->second->first <= now)
|
||||
{
|
||||
args.invalidate();
|
||||
}
|
||||
|
||||
virtual void onAdd(const void*, const KeyValueArgs <TKey, TValue>& args)
|
||||
{
|
||||
const Timestamp& expire = args.value().getExpiration();
|
||||
Timestamp now;
|
||||
IndexIterator it = this->_keyIndex.insert(std::make_pair(now + (expire.epochMicroseconds () * 1000), args.key()));
|
||||
std::pair<Iterator, bool> stat = this->_keys.insert(std::make_pair(args.key(), it));
|
||||
if (!stat.second)
|
||||
{
|
||||
this->_keyIndex.erase(stat.first->second);
|
||||
stat.first->second = it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onReplace(const void*, std::set<TKey>& elemsToRemove)
|
||||
{
|
||||
// Note: replace only informs the cache which elements
|
||||
// it would like to remove!
|
||||
// it does not remove them on its own!
|
||||
IndexIterator it = _keyIndex.begin();
|
||||
Timestamp now;
|
||||
while (it != _keyIndex.end() && it->first < now)
|
||||
{
|
||||
elemsToRemove.insert(it->second.first);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Keys _keys; /// For faster replacement of keys, the iterator points to the _keyIndex map
|
||||
TimeIndex _keyIndex; /// Maps time to key value
|
||||
};
|
||||
|
||||
virtual void onGet (const void*, const TKey& key)
|
||||
{
|
||||
Iterator it = this->_keys.find (key);
|
||||
if (it != this->_keys.end ()) {
|
||||
DataIterator itd = _cache->_data.find (key);
|
||||
if (itd != _cache->_data.end ()) {
|
||||
this->_keyIndex.erase(it->second);
|
||||
const Timestamp& expire = itd->second->getExpiration ();
|
||||
Poco::Timestamp now;
|
||||
IndexIterator itIdx = this->_keyIndex.insert (typename TimeIndex::value_type (now + (expire.epochMicroseconds () * 1000), key));
|
||||
it->second = itIdx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
const Poco::UniqueAccessExpireCache<TKey, TValue>* _cache;
|
||||
};
|
||||
} // namespace Poco
|
||||
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// UniqueExpireCache.h
|
||||
//
|
||||
// $Id: //poco/Main/Foundation/include/Poco/UniqueExpireCache.h#2 $
|
||||
// $Id: //poco/Main/Foundation/include/Poco/UniqueExpireCache.h#3 $
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Cache
|
||||
@ -57,6 +57,9 @@ class UniqueExpireCache: public AbstractCache<TKey, TValue, UniqueExpireStrategy
|
||||
/// const Poco::Timestamp& getExpiration() const;
|
||||
///
|
||||
/// which returns the absolute timepoint when the entry will be invalidated.
|
||||
/// Accessing an object will NOT update this absolute expire timepoint.
|
||||
/// You can use the Poco::ExpirationDecorator to add the getExpiration
|
||||
/// method to values that do not have a getExpiration function.
|
||||
///
|
||||
/// Be careful when using an UniqueExpireCache. A cache is often used
|
||||
/// like cache.has(x) followed by cache.get x). Note that it could happen
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// UniqueExpireLRUCache.h
|
||||
//
|
||||
// $Id: //poco/Main/Foundation/include/Poco/UniqueExpireLRUCache.h#2 $
|
||||
// $Id: //poco/Main/Foundation/include/Poco/UniqueExpireLRUCache.h#3 $
|
||||
//
|
||||
// Library: Foundation
|
||||
// Package: Cache
|
||||
@ -55,13 +55,16 @@ template <
|
||||
>
|
||||
class UniqueExpireLRUCache: public AbstractCache<TKey, TValue, StrategyCollection<TKey, TValue> >
|
||||
/// A UniqueExpireLRUCache combines LRU caching and time based per entry expire caching.
|
||||
/// Once can define for each cache entry a seperate timepoint
|
||||
/// One can define for each cache entry a seperate timepoint
|
||||
/// but also limit the size of the cache (per default: 1024).
|
||||
/// Each TValue object must thus offer the following method:
|
||||
///
|
||||
/// const Poco::Timestamp& getExpiration() const;
|
||||
///
|
||||
/// which returns the absolute timepoint when the entry will be invalidated.
|
||||
/// Accessing an object will NOT update this absolute expire timepoint.
|
||||
/// You can use the Poco::ExpirationDecorator to add the getExpiration
|
||||
/// method to values that do not have a getExpiration function.
|
||||
{
|
||||
public:
|
||||
UniqueExpireLRUCache(long cacheSize = 1024):
|
||||
|
Loading…
x
Reference in New Issue
Block a user