]>
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 | |
bf269e28 RG |
24 | #include "lock.hh" |
25 | ||
e74f866a | 26 | // 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 |
27 | // the ritual is that the oldest entries are in *front* of the sequence collection, so on a hit, move an item to the end |
28 | // on a miss, move it to the beginning | |
e74f866a | 29 | template <typename C, typename T> void pruneCollection(C& container, T& collection, unsigned int maxCached, unsigned int scanFraction=1000) |
38c9ceaa | 30 | { |
6b68a4e3 | 31 | time_t now=time(0); |
38c9ceaa BH |
32 | unsigned int toTrim=0; |
33 | ||
34 | unsigned int cacheSize=collection.size(); | |
35 | ||
157f806e | 36 | if(cacheSize > maxCached) { |
38c9ceaa BH |
37 | toTrim = cacheSize - maxCached; |
38 | } | |
39 | ||
40 | // cout<<"Need to trim "<<toTrim<<" from cache to meet target!\n"; | |
41 | ||
42 | typedef typename T::template nth_index<1>::type sequence_t; | |
e9ea6916 | 43 | sequence_t& sidx=collection.template get<1>(); |
38c9ceaa BH |
44 | |
45 | unsigned int tried=0, lookAt, erased=0; | |
46 | ||
1a16adf0 BH |
47 | // two modes - if toTrim is 0, just look through 1/scanFraction of all records |
48 | // and nuke everything that is expired | |
38c9ceaa BH |
49 | // otherwise, scan first 5*toTrim records, and stop once we've nuked enough |
50 | if(toTrim) | |
51 | lookAt=5*toTrim; | |
52 | else | |
1a16adf0 | 53 | lookAt=cacheSize/scanFraction; |
38c9ceaa BH |
54 | |
55 | typename sequence_t::iterator iter=sidx.begin(), eiter; | |
56 | for(; iter != sidx.end() && tried < lookAt ; ++tried) { | |
e74f866a RG |
57 | if(iter->getTTD() < now) { |
58 | container.preRemoval(*iter); | |
38c9ceaa BH |
59 | sidx.erase(iter++); |
60 | erased++; | |
61 | } | |
62 | else | |
63 | ++iter; | |
64 | ||
9a4cb110 | 65 | if(toTrim && erased >= toTrim) |
38c9ceaa BH |
66 | break; |
67 | } | |
68 | ||
69 | //cout<<"erased "<<erased<<" records based on ttd\n"; | |
70 | ||
71 | if(erased >= toTrim) // done | |
72 | return; | |
73 | ||
74 | toTrim -= erased; | |
75 | ||
76 | //if(toTrim) | |
77 | // cout<<"Still have "<<toTrim - erased<<" entries left to erase to meet target\n"; | |
78 | ||
79 | eiter=iter=sidx.begin(); | |
e74f866a RG |
80 | std::advance(eiter, toTrim); |
81 | // just lob it off from the beginning | |
82 | for (auto i = iter; ; ) { | |
83 | if (i == eiter) { | |
84 | break; | |
85 | } | |
86 | ||
87 | container.preRemoval(*i); | |
88 | sidx.erase(i++); | |
89 | } | |
38c9ceaa BH |
90 | } |
91 | ||
7687f95d | 92 | // note: this expects iterator from first index, and sequence MUST be second index! |
c2567ad1 BH |
93 | template <typename T> void moveCacheItemToFrontOrBack(T& collection, typename T::iterator& iter, bool front) |
94 | { | |
95 | typedef typename T::template nth_index<1>::type sequence_t; | |
e9ea6916 BH |
96 | sequence_t& sidx=collection.template get<1>(); |
97 | typename sequence_t::iterator si=collection.template project<1>(iter); | |
c2567ad1 BH |
98 | if(front) |
99 | sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue | |
100 | else | |
101 | sidx.relocate(sidx.end(), si); // back | |
102 | } | |
103 | ||
104 | template <typename T> void moveCacheItemToFront(T& collection, typename T::iterator& iter) | |
105 | { | |
106 | moveCacheItemToFrontOrBack(collection, iter, true); | |
107 | } | |
108 | ||
109 | template <typename T> void moveCacheItemToBack(T& collection, typename T::iterator& iter) | |
110 | { | |
111 | moveCacheItemToFrontOrBack(collection, iter, false); | |
112 | } | |
113 | ||
bf269e28 RG |
114 | template <typename T> uint64_t pruneLockedCollectionsVector(vector<T>& maps, uint64_t maxCached, uint64_t cacheSize) |
115 | { | |
116 | time_t now = time(nullptr); | |
117 | uint64_t totErased = 0; | |
118 | uint64_t toTrim = 0; | |
119 | uint64_t lookAt = 0; | |
120 | ||
121 | // two modes - if toTrim is 0, just look through 10% of the cache and nuke everything that is expired | |
122 | // otherwise, scan first 5*toTrim records, and stop once we've nuked enough | |
123 | if (maxCached && cacheSize > maxCached) { | |
124 | toTrim = cacheSize - maxCached; | |
125 | lookAt = 5 * toTrim; | |
126 | } else { | |
127 | lookAt = cacheSize / 10; | |
128 | } | |
129 | ||
130 | for(auto& mc : maps) { | |
131 | WriteLock wl(&mc.d_mut); | |
132 | auto& sidx = boost::multi_index::get<2>(mc.d_map); | |
133 | uint64_t erased = 0, lookedAt = 0; | |
134 | for(auto i = sidx.begin(); i != sidx.end(); lookedAt++) { | |
135 | if(i->ttd < now) { | |
136 | i = sidx.erase(i); | |
137 | erased++; | |
138 | } else { | |
139 | ++i; | |
140 | } | |
141 | ||
142 | if(toTrim && erased > toTrim / maps.size()) | |
143 | break; | |
144 | ||
145 | if(lookedAt > lookAt / maps.size()) | |
146 | break; | |
147 | } | |
148 | totErased += erased; | |
149 | } | |
150 | ||
151 | return totErased; | |
152 | } | |
153 | ||
154 | template <typename T> uint64_t purgeLockedCollectionsVector(vector<T>& maps) | |
155 | { | |
156 | uint64_t delcount=0; | |
157 | ||
158 | for(auto& mc : maps) { | |
159 | WriteLock wl(&mc.d_mut); | |
160 | delcount += mc.d_map.size(); | |
161 | mc.d_map.clear(); | |
162 | } | |
163 | ||
164 | return delcount; | |
165 | } | |
166 | ||
167 | template <typename T> uint64_t purgeLockedCollectionsVector(vector<T>& maps, const std::string& match) | |
168 | { | |
169 | uint64_t delcount=0; | |
170 | string prefix(match); | |
171 | prefix.resize(prefix.size()-1); | |
172 | DNSName dprefix(prefix); | |
173 | for(auto& mc : maps) { | |
174 | WriteLock wl(&mc.d_mut); | |
175 | auto& idx = boost::multi_index::get<1>(mc.d_map); | |
176 | auto iter = idx.lower_bound(dprefix); | |
177 | auto start = iter; | |
178 | ||
179 | for(; iter != idx.end(); ++iter) { | |
180 | if(!iter->qname.isPartOf(dprefix)) { | |
181 | break; | |
182 | } | |
183 | delcount++; | |
184 | } | |
185 | idx.erase(start, iter); | |
186 | } | |
187 | ||
188 | return delcount; | |
189 | } | |
190 | ||
191 | template <typename T> uint64_t purgeExactLockedCollection(T& mc, const DNSName& qname) | |
192 | { | |
193 | uint64_t delcount=0; | |
194 | WriteLock wl(&mc.d_mut); | |
195 | auto& idx = boost::multi_index::get<1>(mc.d_map); | |
196 | auto range = idx.equal_range(qname); | |
197 | if(range.first != range.second) { | |
198 | delcount += distance(range.first, range.second); | |
199 | idx.erase(range.first, range.second); | |
200 | } | |
201 | ||
202 | return delcount; | |
203 | } | |
1d704752 RG |
204 | |
205 | template<typename Index> | |
206 | std::pair<typename Index::iterator,bool> | |
207 | lruReplacingInsert(Index& i,const typename Index::value_type& x) | |
208 | { | |
209 | std::pair<typename Index::iterator,bool> res = i.insert(x); | |
210 | if (!res.second) { | |
211 | moveCacheItemToBack(i, res.first); | |
212 | res.second = i.replace(res.first, x); | |
213 | } | |
214 | return res; | |
215 | } |