AbstractCache.h 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. //
  2. // AbstractCache.h
  3. //
  4. // $Id: //poco/1.4/Foundation/include/Poco/AbstractCache.h#1 $
  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. // SPDX-License-Identifier: BSL-1.0
  16. //
  17. #ifndef Foundation_AbstractCache_INCLUDED
  18. #define Foundation_AbstractCache_INCLUDED
  19. #include "Poco/KeyValueArgs.h"
  20. #include "Poco/ValidArgs.h"
  21. #include "Poco/Mutex.h"
  22. #include "Poco/Exception.h"
  23. #include "Poco/FIFOEvent.h"
  24. #include "Poco/EventArgs.h"
  25. #include "Poco/Delegate.h"
  26. #include "Poco/SharedPtr.h"
  27. #include <map>
  28. #include <set>
  29. #include <cstddef>
  30. namespace Poco {
  31. template <class TKey, class TValue, class TStrategy, class TMutex = FastMutex, class TEventMutex = FastMutex>
  32. class AbstractCache
  33. /// An AbstractCache is the interface of all caches.
  34. {
  35. public:
  36. FIFOEvent<const KeyValueArgs<TKey, TValue >, TEventMutex > Add;
  37. FIFOEvent<const KeyValueArgs<TKey, TValue >, TEventMutex > Update;
  38. FIFOEvent<const TKey, TEventMutex> Remove;
  39. FIFOEvent<const TKey, TEventMutex> Get;
  40. FIFOEvent<const EventArgs, TEventMutex> Clear;
  41. typedef std::map<TKey, SharedPtr<TValue > > DataHolder;
  42. typedef typename DataHolder::iterator Iterator;
  43. typedef typename DataHolder::const_iterator ConstIterator;
  44. typedef std::set<TKey> KeySet;
  45. AbstractCache()
  46. {
  47. initialize();
  48. }
  49. AbstractCache(const TStrategy& strat): _strategy(strat)
  50. {
  51. initialize();
  52. }
  53. virtual ~AbstractCache()
  54. {
  55. try
  56. {
  57. uninitialize();
  58. }
  59. catch (...)
  60. {
  61. poco_unexpected();
  62. }
  63. }
  64. void add(const TKey& key, const TValue& val)
  65. /// Adds the key value pair to the cache.
  66. /// If for the key already an entry exists, it will be overwritten.
  67. {
  68. typename TMutex::ScopedLock lock(_mutex);
  69. doAdd(key, val);
  70. }
  71. void update(const TKey& key, const TValue& val)
  72. /// Adds the key value pair to the cache. Note that adding a NULL SharedPtr will fail!
  73. /// If for the key already an entry exists, it will be overwritten.
  74. /// The difference to add is that no remove or add events are thrown in this case,
  75. /// just a simply silent update is performed
  76. /// If the key doesnot exist the behavior is equal to add, ie. an add event is thrown
  77. {
  78. typename TMutex::ScopedLock lock(_mutex);
  79. doUpdate(key, val);
  80. }
  81. void add(const TKey& key, SharedPtr<TValue > val)
  82. /// Adds the key value pair to the cache. Note that adding a NULL SharedPtr will fail!
  83. /// If for the key already an entry exists, it will be overwritten, ie. first a remove event
  84. /// is thrown, then a add event
  85. {
  86. typename TMutex::ScopedLock lock(_mutex);
  87. doAdd(key, val);
  88. }
  89. void update(const TKey& key, SharedPtr<TValue > val)
  90. /// Adds the key value pair to the cache. Note that adding a NULL SharedPtr will fail!
  91. /// If for the key already an entry exists, it will be overwritten.
  92. /// The difference to add is that no remove or add events are thrown in this case,
  93. /// just an Update is thrown
  94. /// If the key doesnot exist the behavior is equal to add, ie. an add event is thrown
  95. {
  96. typename TMutex::ScopedLock lock(_mutex);
  97. doUpdate(key, val);
  98. }
  99. void remove(const TKey& key)
  100. /// Removes an entry from the cache. If the entry is not found,
  101. /// the remove is ignored.
  102. {
  103. typename TMutex::ScopedLock lock(_mutex);
  104. Iterator it = _data.find(key);
  105. doRemove(it);
  106. }
  107. bool has(const TKey& key) const
  108. /// Returns true if the cache contains a value for the key.
  109. {
  110. typename TMutex::ScopedLock lock(_mutex);
  111. return doHas(key);
  112. }
  113. SharedPtr<TValue> get(const TKey& key)
  114. /// Returns a SharedPtr of the value. The SharedPointer will remain valid
  115. /// even when cache replacement removes the element.
  116. /// If for the key no value exists, an empty SharedPtr is returned.
  117. {
  118. typename TMutex::ScopedLock lock(_mutex);
  119. return doGet (key);
  120. }
  121. void clear()
  122. /// Removes all elements from the cache.
  123. {
  124. typename TMutex::ScopedLock lock(_mutex);
  125. doClear();
  126. }
  127. std::size_t size()
  128. /// Returns the number of cached elements
  129. {
  130. typename TMutex::ScopedLock lock(_mutex);
  131. doReplace();
  132. return _data.size();
  133. }
  134. void forceReplace()
  135. /// Forces cache replacement. Note that Poco's cache strategy use for efficiency reason no background thread
  136. /// which periodically triggers cache replacement. Cache Replacement is only started when the cache is modified
  137. /// from outside, i.e. add is called, or when a user tries to access an cache element via get.
  138. /// In some cases, i.e. expire based caching where for a long time no access to the cache happens,
  139. /// it might be desirable to be able to trigger cache replacement manually.
  140. {
  141. typename TMutex::ScopedLock lock(_mutex);
  142. doReplace();
  143. }
  144. std::set<TKey> getAllKeys()
  145. /// Returns a copy of all keys stored in the cache
  146. {
  147. typename TMutex::ScopedLock lock(_mutex);
  148. doReplace();
  149. ConstIterator it = _data.begin();
  150. ConstIterator itEnd = _data.end();
  151. std::set<TKey> result;
  152. for (; it != itEnd; ++it)
  153. result.insert(it->first);
  154. return result;
  155. }
  156. protected:
  157. mutable FIFOEvent<ValidArgs<TKey> > IsValid;
  158. mutable FIFOEvent<KeySet> Replace;
  159. void initialize()
  160. /// Sets up event registration.
  161. {
  162. Add += Delegate<TStrategy, const KeyValueArgs<TKey, TValue> >(&_strategy, &TStrategy::onAdd);
  163. Update += Delegate<TStrategy, const KeyValueArgs<TKey, TValue> >(&_strategy, &TStrategy::onUpdate);
  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 uninitialize()
  171. /// Reverts event registration.
  172. {
  173. Add -= Delegate<TStrategy, const KeyValueArgs<TKey, TValue> >(&_strategy, &TStrategy::onAdd );
  174. Update -= Delegate<TStrategy, const KeyValueArgs<TKey, TValue> >(&_strategy, &TStrategy::onUpdate);
  175. Remove -= Delegate<TStrategy, const TKey>(&_strategy, &TStrategy::onRemove);
  176. Get -= Delegate<TStrategy, const TKey>(&_strategy, &TStrategy::onGet);
  177. Clear -= Delegate<TStrategy, const EventArgs>(&_strategy, &TStrategy::onClear);
  178. IsValid -= Delegate<TStrategy, ValidArgs<TKey> >(&_strategy, &TStrategy::onIsValid);
  179. Replace -= Delegate<TStrategy, KeySet>(&_strategy, &TStrategy::onReplace);
  180. }
  181. void doAdd(const TKey& key, const 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, SharedPtr<TValue>(new TValue(val))));
  190. doReplace();
  191. }
  192. void doAdd(const TKey& key, SharedPtr<TValue>& val)
  193. /// Adds the key value pair to the cache.
  194. /// If for the key already an entry exists, it will be overwritten.
  195. {
  196. Iterator it = _data.find(key);
  197. doRemove(it);
  198. KeyValueArgs<TKey, TValue> args(key, *val);
  199. Add.notify(this, args);
  200. _data.insert(std::make_pair(key, val));
  201. doReplace();
  202. }
  203. void doUpdate(const TKey& key, const TValue& val)
  204. /// Adds the key value pair to the cache.
  205. /// If for the key already an entry exists, it will be overwritten.
  206. {
  207. KeyValueArgs<TKey, TValue> args(key, val);
  208. Iterator it = _data.find(key);
  209. if (it == _data.end())
  210. {
  211. Add.notify(this, args);
  212. _data.insert(std::make_pair(key, SharedPtr<TValue>(new TValue(val))));
  213. }
  214. else
  215. {
  216. Update.notify(this, args);
  217. it->second = SharedPtr<TValue>(new TValue(val));
  218. }
  219. doReplace();
  220. }
  221. void doUpdate(const TKey& key, SharedPtr<TValue>& val)
  222. /// Adds the key value pair to the cache.
  223. /// If for the key already an entry exists, it will be overwritten.
  224. {
  225. KeyValueArgs<TKey, TValue> args(key, *val);
  226. Iterator it = _data.find(key);
  227. if (it == _data.end())
  228. {
  229. Add.notify(this, args);
  230. _data.insert(std::make_pair(key, val));
  231. }
  232. else
  233. {
  234. Update.notify(this, args);
  235. it->second = val;
  236. }
  237. doReplace();
  238. }
  239. void doRemove(Iterator it)
  240. /// Removes an entry from the cache. If the entry is not found
  241. /// the remove is ignored.
  242. {
  243. if (it != _data.end())
  244. {
  245. Remove.notify(this, it->first);
  246. _data.erase(it);
  247. }
  248. }
  249. bool doHas(const TKey& key) const
  250. /// Returns true if the cache contains a value for the key
  251. {
  252. // ask the strategy if the key is valid
  253. ConstIterator it = _data.find(key);
  254. bool result = false;
  255. if (it != _data.end())
  256. {
  257. ValidArgs<TKey> args(key);
  258. IsValid.notify(this, args);
  259. result = args.isValid();
  260. }
  261. return result;
  262. }
  263. SharedPtr<TValue> doGet(const TKey& key)
  264. /// Returns a SharedPtr of the cache entry, returns 0 if for
  265. /// the key no value was found
  266. {
  267. Iterator it = _data.find(key);
  268. SharedPtr<TValue> result;
  269. if (it != _data.end())
  270. {
  271. // inform all strategies that a read-access to an element happens
  272. Get.notify(this, key);
  273. // ask all strategies if the key is valid
  274. ValidArgs<TKey> args(key);
  275. IsValid.notify(this, args);
  276. if (!args.isValid())
  277. {
  278. doRemove(it);
  279. }
  280. else
  281. {
  282. result = it->second;
  283. }
  284. }
  285. return result;
  286. }
  287. void doClear()
  288. {
  289. static EventArgs _emptyArgs;
  290. Clear.notify(this, _emptyArgs);
  291. _data.clear();
  292. }
  293. void doReplace()
  294. {
  295. std::set<TKey> delMe;
  296. Replace.notify(this, delMe);
  297. // delMe contains the to be removed elements
  298. typename std::set<TKey>::const_iterator it = delMe.begin();
  299. typename std::set<TKey>::const_iterator endIt = delMe.end();
  300. for (; it != endIt; ++it)
  301. {
  302. Iterator itH = _data.find(*it);
  303. doRemove(itH);
  304. }
  305. }
  306. TStrategy _strategy;
  307. mutable DataHolder _data;
  308. mutable TMutex _mutex;
  309. private:
  310. AbstractCache(const AbstractCache& aCache);
  311. AbstractCache& operator = (const AbstractCache& aCache);
  312. };
  313. } // namespace Poco
  314. #endif // Foundation_AbstractCache_INCLUDED