]>
Commit | Line | Data |
---|---|---|
12471842 PL |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
e7135447 | 22 | #pragma once |
38c9ceaa | 23 | |
a7956123 | 24 | #include <mutex> |
bf269e28 RG |
25 | #include "lock.hh" |
26 | ||
e74f866a | 27 | // this function can clean any cache that has a getTTD() method on its entries, a preRemoval() method and a 'sequence' index as its second index |
c2567ad1 BH |
28 | // the ritual is that the oldest entries are in *front* of the sequence collection, so on a hit, move an item to the end |
29 | // on a miss, move it to the beginning | |
94306029 | 30 | template <typename S, typename C, typename T> void pruneCollection(C& container, T& collection, unsigned int maxCached, unsigned int scanFraction=1000) |
38c9ceaa | 31 | { |
6b68a4e3 | 32 | time_t now=time(0); |
38c9ceaa BH |
33 | unsigned int toTrim=0; |
34 | ||
35 | unsigned int cacheSize=collection.size(); | |
36 | ||
157f806e | 37 | if(cacheSize > maxCached) { |
38c9ceaa BH |
38 | toTrim = cacheSize - maxCached; |
39 | } | |
40 | ||
41 | // cout<<"Need to trim "<<toTrim<<" from cache to meet target!\n"; | |
42 | ||
94306029 OM |
43 | typedef typename T::template index<S>::type sequence_t; |
44 | sequence_t& sidx=collection.template get<S>(); | |
38c9ceaa BH |
45 | |
46 | unsigned int tried=0, lookAt, erased=0; | |
47 | ||
1a16adf0 BH |
48 | // two modes - if toTrim is 0, just look through 1/scanFraction of all records |
49 | // and nuke everything that is expired | |
38c9ceaa BH |
50 | // otherwise, scan first 5*toTrim records, and stop once we've nuked enough |
51 | if(toTrim) | |
52 | lookAt=5*toTrim; | |
53 | else | |
1a16adf0 | 54 | lookAt=cacheSize/scanFraction; |
38c9ceaa BH |
55 | |
56 | typename sequence_t::iterator iter=sidx.begin(), eiter; | |
57 | for(; iter != sidx.end() && tried < lookAt ; ++tried) { | |
e74f866a RG |
58 | if(iter->getTTD() < now) { |
59 | container.preRemoval(*iter); | |
a7956123 | 60 | iter = sidx.erase(iter); |
38c9ceaa BH |
61 | erased++; |
62 | } | |
63 | else | |
64 | ++iter; | |
65 | ||
9a4cb110 | 66 | if(toTrim && erased >= toTrim) |
38c9ceaa BH |
67 | break; |
68 | } | |
69 | ||
70 | //cout<<"erased "<<erased<<" records based on ttd\n"; | |
71 | ||
72 | if(erased >= toTrim) // done | |
73 | return; | |
74 | ||
75 | toTrim -= erased; | |
76 | ||
77 | //if(toTrim) | |
78 | // cout<<"Still have "<<toTrim - erased<<" entries left to erase to meet target\n"; | |
79 | ||
80 | eiter=iter=sidx.begin(); | |
e74f866a RG |
81 | std::advance(eiter, toTrim); |
82 | // just lob it off from the beginning | |
83 | for (auto i = iter; ; ) { | |
84 | if (i == eiter) { | |
85 | break; | |
86 | } | |
87 | ||
88 | container.preRemoval(*i); | |
89 | sidx.erase(i++); | |
90 | } | |
38c9ceaa BH |
91 | } |
92 | ||
94306029 OM |
93 | // note: this expects iterator from first index |
94 | template <typename S, typename T> void moveCacheItemToFrontOrBack(T& collection, typename T::iterator& iter, bool front) | |
c2567ad1 | 95 | { |
94306029 OM |
96 | typedef typename T::template index<S>::type sequence_t; |
97 | sequence_t& sidx=collection.template get<S>(); | |
98 | typename sequence_t::iterator si=collection.template project<S>(iter); | |
c2567ad1 BH |
99 | if(front) |
100 | sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue | |
101 | else | |
102 | sidx.relocate(sidx.end(), si); // back | |
103 | } | |
104 | ||
94306029 | 105 | template <typename S, typename T> void moveCacheItemToFront(T& collection, typename T::iterator& iter) |
c2567ad1 | 106 | { |
94306029 | 107 | moveCacheItemToFrontOrBack<S>(collection, iter, true); |
c2567ad1 BH |
108 | } |
109 | ||
94306029 | 110 | template <typename S, typename T> void moveCacheItemToBack(T& collection, typename T::iterator& iter) |
c2567ad1 | 111 | { |
94306029 | 112 | moveCacheItemToFrontOrBack<S>(collection, iter, false); |
c2567ad1 BH |
113 | } |
114 | ||
09d5ac48 | 115 | template <typename S, typename T> uint64_t pruneLockedCollectionsVector(vector<T>& maps) |
bf269e28 | 116 | { |
bf269e28 | 117 | uint64_t totErased = 0; |
09d5ac48 | 118 | time_t now = time(nullptr); |
bf269e28 RG |
119 | |
120 | for(auto& mc : maps) { | |
121 | WriteLock wl(&mc.d_mut); | |
09d5ac48 KM |
122 | |
123 | uint64_t lookAt = (mc.d_map.size() + 9) / 10; // Look at 10% of this shard | |
124 | uint64_t erased = 0; | |
125 | ||
94306029 | 126 | auto& sidx = boost::multi_index::get<S>(mc.d_map); |
09d5ac48 KM |
127 | for(auto i = sidx.begin(); i != sidx.end() && lookAt > 0; lookAt--) { |
128 | if(i->ttd < now) { | |
bf269e28 RG |
129 | i = sidx.erase(i); |
130 | erased++; | |
131 | } else { | |
132 | ++i; | |
133 | } | |
bf269e28 RG |
134 | } |
135 | totErased += erased; | |
136 | } | |
137 | ||
138 | return totErased; | |
139 | } | |
140 | ||
a7956123 OM |
141 | template <typename S, typename C, typename T> uint64_t pruneMutexCollectionsVector(C& container, vector<T>& maps, uint64_t maxCached, uint64_t cacheSize) |
142 | { | |
143 | time_t now = time(nullptr); | |
144 | uint64_t totErased = 0; | |
145 | uint64_t toTrim = 0; | |
146 | uint64_t lookAt = 0; | |
147 | ||
148 | // two modes - if toTrim is 0, just look through 10% of the cache and nuke everything that is expired | |
149 | // otherwise, scan first 5*toTrim records, and stop once we've nuked enough | |
150 | if (cacheSize > maxCached) { | |
151 | toTrim = cacheSize - maxCached; | |
152 | lookAt = 5 * toTrim; | |
153 | } else { | |
154 | lookAt = cacheSize / 10; | |
155 | } | |
04bd5303 OM |
156 | |
157 | uint64_t maps_size = maps.size(); | |
158 | if (maps_size == 0) | |
159 | return 0; | |
160 | ||
a7956123 | 161 | for (auto& mc : maps) { |
7ce9aad6 | 162 | const typename C::lock l(mc); |
4cda5b6e | 163 | mc.d_cachecachevalid = false; |
a7956123 OM |
164 | auto& sidx = boost::multi_index::get<S>(mc.d_map); |
165 | uint64_t erased = 0, lookedAt = 0; | |
166 | for (auto i = sidx.begin(); i != sidx.end(); lookedAt++) { | |
167 | if (i->getTTD() < now) { | |
168 | container.preRemoval(*i); | |
169 | i = sidx.erase(i); | |
170 | erased++; | |
cdde2458 | 171 | mc.d_entriesCount--; |
a7956123 OM |
172 | } else { |
173 | ++i; | |
174 | } | |
175 | ||
04bd5303 | 176 | if (toTrim && erased >= toTrim / maps_size) |
a7956123 OM |
177 | break; |
178 | ||
04bd5303 | 179 | if (lookedAt > lookAt / maps_size) |
a7956123 OM |
180 | break; |
181 | } | |
182 | totErased += erased; | |
183 | if (toTrim && totErased >= toTrim) | |
184 | break; | |
185 | } | |
186 | ||
187 | if (totErased >= toTrim) { // done | |
188 | return totErased; | |
189 | } | |
190 | ||
191 | toTrim -= totErased; | |
192 | ||
a7956123 | 193 | while (toTrim > 0) { |
79a09893 | 194 | size_t pershard = toTrim / maps_size + 1; |
a7956123 | 195 | for (auto& mc : maps) { |
7ce9aad6 | 196 | const typename C::lock l(mc); |
4cda5b6e | 197 | mc.d_cachecachevalid = false; |
a7956123 | 198 | auto& sidx = boost::multi_index::get<S>(mc.d_map); |
79a09893 OM |
199 | size_t removed = 0; |
200 | for (auto i = sidx.begin(); i != sidx.end() && removed < pershard; removed++) { | |
201 | container.preRemoval(*i); | |
202 | i = sidx.erase(i); | |
203 | mc.d_entriesCount--; | |
204 | totErased++; | |
205 | toTrim--; | |
206 | if (toTrim == 0) { | |
207 | break; | |
208 | } | |
209 | } | |
a7956123 OM |
210 | } |
211 | } | |
212 | return totErased; | |
213 | } | |
214 | ||
bf269e28 RG |
215 | template <typename T> uint64_t purgeLockedCollectionsVector(vector<T>& maps) |
216 | { | |
217 | uint64_t delcount=0; | |
218 | ||
219 | for(auto& mc : maps) { | |
220 | WriteLock wl(&mc.d_mut); | |
221 | delcount += mc.d_map.size(); | |
222 | mc.d_map.clear(); | |
223 | } | |
224 | ||
225 | return delcount; | |
226 | } | |
227 | ||
94306029 | 228 | template <typename N, typename T> uint64_t purgeLockedCollectionsVector(vector<T>& maps, const std::string& match) |
bf269e28 RG |
229 | { |
230 | uint64_t delcount=0; | |
231 | string prefix(match); | |
232 | prefix.resize(prefix.size()-1); | |
233 | DNSName dprefix(prefix); | |
234 | for(auto& mc : maps) { | |
235 | WriteLock wl(&mc.d_mut); | |
94306029 | 236 | auto& idx = boost::multi_index::get<N>(mc.d_map); |
bf269e28 RG |
237 | auto iter = idx.lower_bound(dprefix); |
238 | auto start = iter; | |
239 | ||
240 | for(; iter != idx.end(); ++iter) { | |
241 | if(!iter->qname.isPartOf(dprefix)) { | |
242 | break; | |
243 | } | |
244 | delcount++; | |
245 | } | |
246 | idx.erase(start, iter); | |
247 | } | |
248 | ||
249 | return delcount; | |
250 | } | |
251 | ||
94306029 | 252 | template <typename N, typename T> uint64_t purgeExactLockedCollection(T& mc, const DNSName& qname) |
bf269e28 RG |
253 | { |
254 | uint64_t delcount=0; | |
255 | WriteLock wl(&mc.d_mut); | |
94306029 | 256 | auto& idx = boost::multi_index::get<N>(mc.d_map); |
bf269e28 RG |
257 | auto range = idx.equal_range(qname); |
258 | if(range.first != range.second) { | |
259 | delcount += distance(range.first, range.second); | |
260 | idx.erase(range.first, range.second); | |
261 | } | |
262 | ||
263 | return delcount; | |
264 | } | |
1d704752 | 265 | |
94306029 | 266 | template<typename S, typename Index> |
1d704752 RG |
267 | std::pair<typename Index::iterator,bool> |
268 | lruReplacingInsert(Index& i,const typename Index::value_type& x) | |
269 | { | |
270 | std::pair<typename Index::iterator,bool> res = i.insert(x); | |
271 | if (!res.second) { | |
94306029 | 272 | moveCacheItemToBack<S>(i, res.first); |
1d704752 RG |
273 | res.second = i.replace(res.first, x); |
274 | } | |
275 | return res; | |
276 | } |