AbstractCache.h 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. //
  2. // AbstractCache.h
  3. //
  4. // $Id: //poco/Main/Foundation/include/Poco/AbstractCache.h#14 $
  5. //
  6. // Library: Foundation
  7. // Package: Cache
  8. // Module: AbstractCache
  9. //
  10. // Definition of the AbstractCache class.
  11. //
  12. // Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
  13. // and Contributors.
  14. //
  15. // Permission is hereby granted, free of charge, to any person or organization
  16. // obtaining a copy of the software and accompanying documentation covered by
  17. // this license (the "Software") to use, reproduce, display, distribute,
  18. // execute, and transmit the Software, and to prepare derivative works of the
  19. // Software, and to permit third-parties to whom the Software is furnished to
  20. // do so, all subject to the following:
  21. //
  22. // The copyright notices in the Software and this entire statement, including
  23. // the above license grant, this restriction and the following disclaimer,
  24. // must be included in all copies of the Software, in whole or in part, and
  25. // all derivative works of the Software, unless such copies or derivative
  26. // works are solely in the form of machine-executable object code generated by
  27. // a source language processor.
  28. //
  29. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  30. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  31. // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  32. // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  33. // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  34. // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  35. // DEALINGS IN THE SOFTWARE.
  36. //
  37. #ifndef Foundation_AbstractCache_INCLUDED
  38. #define Foundation_AbstractCache_INCLUDED
  39. #include "Poco/KeyValueArgs.h"
  40. #include "Poco/ValidArgs.h"
  41. #include "Poco/Mutex.h"
  42. #include "Poco/Exception.h"
  43. #include "Poco/FIFOEvent.h"
  44. #include "Poco/EventArgs.h"
  45. #include "Poco/Delegate.h"
  46. #include "Poco/SharedPtr.h"
  47. #include <map>
  48. #include <set>
  49. #include <cstddef>
  50. namespace Poco {
  51. template <class TKey, class TValue, class TStrategy>
  52. class AbstractCache
  53. /// An AbstractCache is the interface of all caches.
  54. {
  55. public:
  56. FIFOEvent<const KeyValueArgs<TKey, TValue > > Add;
  57. FIFOEvent<const TKey> Remove;
  58. FIFOEvent<const TKey> Get;
  59. FIFOEvent<const EventArgs> Clear;
  60. typedef std::map<TKey, SharedPtr<TValue > > DataHolder;
  61. typedef typename DataHolder::iterator Iterator;
  62. typedef typename DataHolder::const_iterator ConstIterator;
  63. typedef std::set<TKey> KeySet;
  64. AbstractCache()
  65. {
  66. initialize();
  67. }
  68. AbstractCache(const TStrategy& strat): _strategy(strat)
  69. {
  70. initialize();
  71. }
  72. virtual ~AbstractCache()
  73. {
  74. uninitialize();
  75. }
  76. void add(const TKey& key, const TValue& val)
  77. /// Adds the key value pair to the cache.
  78. /// If for the key already an entry exists, it will be overwritten.
  79. {
  80. FastMutex::ScopedLock lock(_mutex);
  81. doAdd(key, val);
  82. }
  83. void add(const TKey& key, SharedPtr<TValue > val)
  84. /// Adds the key value pair to the cache. Note that adding a NULL SharedPtr will fail!
  85. /// If for the key already an entry exists, it will be overwritten.
  86. {
  87. FastMutex::ScopedLock lock(_mutex);
  88. doAdd(key, val);
  89. }
  90. void remove(const TKey& key)
  91. /// Removes an entry from the cache. If the entry is not found,
  92. /// the remove is ignored.
  93. {
  94. FastMutex::ScopedLock lock(_mutex);
  95. Iterator it = _data.find(key);
  96. doRemove(it);
  97. }
  98. bool has(const TKey& key) const
  99. /// Returns true if the cache contains a value for the key.
  100. {
  101. FastMutex::ScopedLock lock(_mutex);
  102. return doHas(key);
  103. }
  104. SharedPtr<TValue> get(const TKey& key)
  105. /// Returns a SharedPtr of the value. The SharedPointer will remain valid
  106. /// even when cache replacement removes the element.
  107. /// If for the key no value exists, an empty SharedPtr is returned.
  108. {
  109. FastMutex::ScopedLock lock(_mutex);
  110. return doGet (key);
  111. }
  112. void clear()
  113. /// Removes all elements from the cache.
  114. {
  115. FastMutex::ScopedLock lock(_mutex);
  116. doClear();
  117. }
  118. std::size_t size()
  119. /// Returns the number of cached elements
  120. {
  121. FastMutex::ScopedLock lock(_mutex);
  122. doReplace();
  123. return _data.size();
  124. }
  125. void forceReplace()
  126. /// Forces cache replacement. Note that Poco's cache strategy use for efficiency reason no background thread
  127. /// which periodically triggers cache replacement. Cache Replacement is only started when the cache is modified
  128. /// from outside, i.e. add is called, or when a user tries to access an cache element via get.
  129. /// In some cases, i.e. expire based caching where for a long time no access to the cache happens,
  130. /// it might be desirable to be able to trigger cache replacement manually.
  131. {
  132. FastMutex::ScopedLock lock(_mutex);
  133. doReplace();
  134. }
  135. std::set<TKey> getAllKeys()
  136. /// Returns a copy of all keys stored in the cache
  137. {
  138. FastMutex::ScopedLock lock(_mutex);
  139. doReplace();
  140. ConstIterator it = _data.begin();
  141. ConstIterator itEnd = _data.end();
  142. std::set<TKey> result;
  143. for (; it != itEnd; ++it)
  144. result.insert(it->first);
  145. return result;
  146. }
  147. protected:
  148. mutable FIFOEvent<ValidArgs<TKey> > IsValid;
  149. mutable FIFOEvent<KeySet> Replace;
  150. void initialize()
  151. /// Sets up event registration.
  152. {
  153. Add += Delegate<TStrategy, const KeyValueArgs<TKey, TValue> >(&_strategy, &TStrategy::onAdd);
  154. Remove += Delegate<TStrategy, const TKey>(&_strategy, &TStrategy::onRemove);
  155. Get += Delegate<TStrategy, const TKey>(&_strategy, &TStrategy::onGet);
  156. Clear += Delegate<TStrategy, const EventArgs>(&_strategy, &TStrategy::onClear);
  157. IsValid += Delegate<TStrategy, ValidArgs<TKey> >(&_strategy, &TStrategy::onIsValid);
  158. Replace += Delegate<TStrategy, KeySet>(&_strategy, &TStrategy::onReplace);
  159. }
  160. void uninitialize()
  161. /// Reverts event registration.
  162. {
  163. Add -= Delegate<TStrategy, const KeyValueArgs<TKey, TValue> >(&_strategy, &TStrategy::onAdd );
  164. Remove -= Delegate<TStrategy, const TKey>(&_strategy, &TStrategy::onRemove);
  165. Get -= Delegate<TStrategy, const TKey>(&_strategy, &TStrategy::onGet);
  166. Clear -= Delegate<TStrategy, const EventArgs>(&_strategy, &TStrategy::onClear);
  167. IsValid -= Delegate<TStrategy, ValidArgs<TKey> >(&_strategy, &TStrategy::onIsValid);
  168. Replace -= Delegate<TStrategy, KeySet>(&_strategy, &TStrategy::onReplace);
  169. }
  170. void doAdd(const TKey& key, const TValue& val)
  171. /// Adds the key value pair to the cache.
  172. /// If for the key already an entry exists, it will be overwritten.
  173. {
  174. Iterator it = _data.find(key);
  175. doRemove(it);
  176. KeyValueArgs<TKey, TValue> args(key, val);
  177. Add.notify(this, args);
  178. _data.insert(std::make_pair(key, SharedPtr<TValue>(new TValue(val))));
  179. doReplace();
  180. }
  181. void doAdd(const TKey& key, SharedPtr<TValue>& val)
  182. /// Adds the key value pair to the cache.
  183. /// If for the key already an entry exists, it will be overwritten.
  184. {
  185. Iterator it = _data.find(key);
  186. doRemove(it);
  187. KeyValueArgs<TKey, TValue> args(key, *val);
  188. Add.notify(this, args);
  189. _data.insert(std::make_pair(key, val));
  190. doReplace();
  191. }
  192. void doRemove(Iterator it)
  193. /// Removes an entry from the cache. If the entry is not found
  194. /// the remove is ignored.
  195. {
  196. if (it != _data.end())
  197. {
  198. Remove.notify(this, it->first);
  199. _data.erase(it);
  200. }
  201. }
  202. bool doHas(const TKey& key) const
  203. /// Returns true if the cache contains a value for the key
  204. {
  205. // ask the strategy if the key is valid
  206. ConstIterator it = _data.find(key);
  207. bool result = false;
  208. if (it != _data.end())
  209. {
  210. ValidArgs<TKey> args(key);
  211. IsValid.notify(this, args);
  212. result = args.isValid();
  213. }
  214. return result;
  215. }
  216. SharedPtr<TValue> doGet(const TKey& key)
  217. /// Returns a SharedPtr of the cache entry, returns 0 if for
  218. /// the key no value was found
  219. {
  220. Iterator it = _data.find(key);
  221. SharedPtr<TValue> result;
  222. if (it != _data.end())
  223. {
  224. // inform all strategies that a read-access to an element happens
  225. Get.notify(this, key);
  226. // ask all strategies if the key is valid
  227. ValidArgs<TKey> args(key);
  228. IsValid.notify(this, args);
  229. if (!args.isValid())
  230. {
  231. doRemove(it);
  232. }
  233. else
  234. {
  235. result = it->second;
  236. }
  237. }
  238. return result;
  239. }
  240. void doClear()
  241. {
  242. static EventArgs _emptyArgs;
  243. Clear.notify(this, _emptyArgs);
  244. _data.clear();
  245. }
  246. void doReplace()
  247. {
  248. std::set<TKey> delMe;
  249. Replace.notify(this, delMe);
  250. // delMe contains the to be removed elements
  251. typename std::set<TKey>::const_iterator it = delMe.begin();
  252. typename std::set<TKey>::const_iterator endIt = delMe.end();
  253. for (; it != endIt; ++it)
  254. {
  255. Iterator itH = _data.find(*it);
  256. doRemove(itH);
  257. }
  258. }
  259. TStrategy _strategy;
  260. mutable DataHolder _data;
  261. mutable FastMutex _mutex;
  262. private:
  263. AbstractCache(const AbstractCache& aCache);
  264. AbstractCache& operator = (const AbstractCache& aCache);
  265. };
  266. } // namespace Poco
  267. #endif