1//
2// UniqueExpireStrategy.h
3//
4// Library: Foundation
5// Package: Cache
6// Module: UniqueExpireStrategy
7//
8// Definition of the UniqueExpireStrategy class.
9//
10// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
11// and Contributors.
12//
13// SPDX-License-Identifier: BSL-1.0
14//
15
16
17#ifndef Foundation_UniqueExpireStrategy_INCLUDED
18#define Foundation_UniqueExpireStrategy_INCLUDED
19
20
21#include "Poco/KeyValueArgs.h"
22#include "Poco/ValidArgs.h"
23#include "Poco/AbstractStrategy.h"
24#include "Poco/Bugcheck.h"
25#include "Poco/Timestamp.h"
26#include "Poco/EventArgs.h"
27#include <set>
28#include <map>
29
30
31namespace Poco {
32
33
34template <
35 class TKey,
36 class TValue
37>
38class UniqueExpireStrategy: public AbstractStrategy<TKey, TValue>
39 /// An UniqueExpireStrategy implements time based expiration of cache entries. In contrast
40 /// to ExpireStrategy which only allows to set a per cache expiration value, it allows to define
41 /// expiration per CacheEntry.
42 /// Each TValue object must thus offer the following method:
43 ///
44 /// const Poco::Timestamp& getExpiration() const;
45 ///
46 /// which returns the absolute timepoint when the entry will be invalidated.
47{
48public:
49 typedef std::multimap<Timestamp, TKey> TimeIndex;
50 typedef typename TimeIndex::iterator IndexIterator;
51 typedef typename TimeIndex::const_iterator ConstIndexIterator;
52 typedef std::map<TKey, IndexIterator> Keys;
53 typedef typename Keys::iterator Iterator;
54
55public:
56 UniqueExpireStrategy()
57 /// Create an unique expire strategy.
58 {
59 }
60
61 ~UniqueExpireStrategy()
62 {
63 }
64
65 void onAdd(const void*, const KeyValueArgs <TKey, TValue>& args)
66 {
67 // note: we have to insert even if the expire timepoint is in the past (for StrategyCollection classes to avoid inconsistency with LRU)
68 // no problem: will be removed with next get
69 const Timestamp& expire = args.value().getExpiration();
70 IndexIterator it = _keyIndex.insert(std::make_pair(expire, args.key()));
71 std::pair<Iterator, bool> stat = _keys.insert(std::make_pair(args.key(), it));
72 if (!stat.second)
73 {
74 _keyIndex.erase(stat.first->second);
75 stat.first->second = it;
76 }
77 }
78
79 void onRemove(const void*, const TKey& key)
80 {
81 Iterator it = _keys.find(key);
82 if (it != _keys.end())
83 {
84 _keyIndex.erase(it->second);
85 _keys.erase(it);
86 }
87 }
88
89 void onGet(const void*, const TKey& key)
90 {
91 // get triggers no changes in an expire
92 }
93
94 void onClear(const void*, const EventArgs& args)
95 {
96 _keys.clear();
97 _keyIndex.clear();
98 }
99
100 void onIsValid(const void*, ValidArgs<TKey>& args)
101 {
102 Iterator it = _keys.find(args.key());
103 if (it != _keys.end())
104 {
105 Timestamp now;
106 if (it->second->first <= now)
107 {
108 args.invalidate();
109 }
110 }
111 else //not found: probably removed by onReplace
112 args.invalidate();
113 }
114
115 void onReplace(const void*, std::set<TKey>& elemsToRemove)
116 {
117 // Note: replace only informs the cache which elements
118 // it would like to remove!
119 // it does not remove them on its own!
120 IndexIterator it = _keyIndex.begin();
121 Timestamp now;
122 while (it != _keyIndex.end() && it->first < now)
123 {
124 elemsToRemove.insert(it->second);
125 ++it;
126 }
127 }
128
129protected:
130 Keys _keys; /// For faster replacement of keys, the iterator points to the _keyIndex map
131 TimeIndex _keyIndex; /// Maps time to key value
132};
133
134
135} // namespace Poco
136
137
138#endif // Foundation_UniqueExpireStrategy_INCLUDED
139