]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/cachecleaner.hh
Limit the number of queries sent out to get NS addresses per query.
[thirdparty/pdns.git] / pdns / cachecleaner.hh
CommitLineData
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 30template <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
94template <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 105template <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 110template <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 115template <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
141template <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
215template <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 228template <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 252template <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 266template<typename S, typename Index>
1d704752
RG
267std::pair<typename Index::iterator,bool>
268lruReplacingInsert(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}