1 | // |
2 | // UniqueAccessExpireStrategy.h |
3 | // |
4 | // Library: Foundation |
5 | // Package: Cache |
6 | // Module: UniqueAccessExpireStrategy |
7 | // |
8 | // Definition of the UniqueAccessExpireStrategy 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_UniqueAccessExpireStrategy_INCLUDED |
18 | #define Foundation_UniqueAccessExpireStrategy_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/Timespan.h" |
27 | #include "Poco/EventArgs.h" |
28 | #include "Poco/UniqueExpireStrategy.h" |
29 | #include <set> |
30 | #include <map> |
31 | |
32 | |
33 | namespace Poco { |
34 | |
35 | |
36 | template < |
37 | class TKey, |
38 | class TValue |
39 | > |
40 | class UniqueAccessExpireStrategy: public AbstractStrategy<TKey, TValue> |
41 | /// An UniqueExpireStrategy implements time based expiration of cache entries. In contrast |
42 | /// to ExpireStrategy which only allows to set a per cache expiration value, it allows to define |
43 | /// expiration per CacheEntry. |
44 | /// Each TValue object must thus offer the following method: |
45 | /// |
46 | /// const Poco::Timestamp& getTimeout() const; |
47 | /// |
48 | /// which returns the timespan for how long an object will be valid without being accessed. |
49 | { |
50 | public: |
51 | typedef std::pair<TKey, Timespan> KeyExpire; |
52 | typedef std::multimap<Timestamp, KeyExpire> TimeIndex; |
53 | typedef typename TimeIndex::iterator IndexIterator; |
54 | typedef typename TimeIndex::const_iterator ConstIndexIterator; |
55 | typedef std::map<TKey, IndexIterator> Keys; |
56 | typedef typename Keys::iterator Iterator; |
57 | |
58 | public: |
59 | UniqueAccessExpireStrategy() |
60 | /// Create an unique expire strategy. |
61 | { |
62 | } |
63 | |
64 | ~UniqueAccessExpireStrategy() |
65 | { |
66 | } |
67 | |
68 | void onAdd(const void*, const KeyValueArgs <TKey, TValue>& args) |
69 | { |
70 | // the expire value defines how many millisecs in the future the |
71 | // value will expire, even insert negative values! |
72 | Timestamp expire; |
73 | expire += args.value().getTimeout().totalMicroseconds(); |
74 | |
75 | IndexIterator it = _keyIndex.insert(std::make_pair(expire, std::make_pair(args.key(), args.value().getTimeout()))); |
76 | std::pair<Iterator, bool> stat = _keys.insert(std::make_pair(args.key(), it)); |
77 | if (!stat.second) |
78 | { |
79 | _keyIndex.erase(stat.first->second); |
80 | stat.first->second = it; |
81 | } |
82 | } |
83 | |
84 | void onRemove(const void*, const TKey& key) |
85 | { |
86 | Iterator it = _keys.find(key); |
87 | if (it != _keys.end()) |
88 | { |
89 | _keyIndex.erase(it->second); |
90 | _keys.erase(it); |
91 | } |
92 | } |
93 | |
94 | void onGet(const void*, const TKey& key) |
95 | { |
96 | // get updates the expiration time stamp |
97 | Iterator it = _keys.find(key); |
98 | if (it != _keys.end()) |
99 | { |
100 | KeyExpire ke = it->second->second; |
101 | // gen new absolute expire value |
102 | Timestamp expire; |
103 | expire += ke.second.totalMicroseconds(); |
104 | // delete old index |
105 | _keyIndex.erase(it->second); |
106 | IndexIterator itt = _keyIndex.insert(std::make_pair(expire, ke)); |
107 | // update iterator |
108 | it->second = itt; |
109 | } |
110 | } |
111 | |
112 | void onClear(const void*, const EventArgs& args) |
113 | { |
114 | _keys.clear(); |
115 | _keyIndex.clear(); |
116 | } |
117 | |
118 | void onIsValid(const void*, ValidArgs<TKey>& args) |
119 | { |
120 | Iterator it = _keys.find(args.key()); |
121 | if (it != _keys.end()) |
122 | { |
123 | Timestamp now; |
124 | if (it->second->first <= now) |
125 | { |
126 | args.invalidate(); |
127 | } |
128 | } |
129 | else //not found: probably removed by onReplace |
130 | args.invalidate(); |
131 | } |
132 | |
133 | void onReplace(const void*, std::set<TKey>& elemsToRemove) |
134 | { |
135 | // Note: replace only informs the cache which elements |
136 | // it would like to remove! |
137 | // it does not remove them on its own! |
138 | IndexIterator it = _keyIndex.begin(); |
139 | Timestamp now; |
140 | while (it != _keyIndex.end() && it->first < now) |
141 | { |
142 | elemsToRemove.insert(it->second.first); |
143 | ++it; |
144 | } |
145 | } |
146 | |
147 | protected: |
148 | Keys _keys; /// For faster replacement of keys, the iterator points to the _keyIndex map |
149 | TimeIndex _keyIndex; /// Maps time to key value |
150 | }; |
151 | |
152 | |
153 | } // namespace Poco |
154 | |
155 | |
156 | #endif // Foundation_UniqueAccessExpireStrategy_INCLUDED |
157 | |