]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/recursor_cache.cc
Contention stats plus variable # of shards
[thirdparty/pdns.git] / pdns / recursor_cache.cc
CommitLineData
870a0fe4
AT
1#ifdef HAVE_CONFIG_H
2#include "config.h"
3#endif
6b68a4e3
RG
4
5#include <cinttypes>
6
eec1087c
BH
7#include "recursor_cache.hh"
8#include "misc.hh"
9#include <iostream>
ea634573 10#include "dnsrecords.hh"
bec87d21 11#include "arguments.hh"
0ba0f794 12#include "syncres.hh"
34264879 13#include "recursor_cache.hh"
61b26744 14#include "namespaces.hh"
a7956123 15#include "cachecleaner.hh"
eec1087c 16
a7956123 17MemRecursorCache::MemRecursorCache(size_t mapsCount) : d_maps(mapsCount)
eec1087c 18{
43a2b29c
BH
19}
20
a7956123 21MemRecursorCache::~MemRecursorCache()
1ffea92c 22{
a7956123 23 try {
7ce9aad6 24 typedef std::unique_ptr<lock> lock_t;
a7956123
OM
25 vector<lock_t> locks;
26 for (auto& map : d_maps) {
7ce9aad6 27 locks.push_back(lock_t(new lock(map)));
a7956123
OM
28 }
29 }
30 catch(...) {
31 }
1ffea92c
RG
32}
33
a7956123 34size_t MemRecursorCache::size()
43a2b29c 35{
a7956123
OM
36 size_t count = 0;
37 for (auto& map : d_maps) {
cdde2458 38 count += map.d_entriesCount;
a7956123
OM
39 }
40 return count;
41}
43a2b29c 42
7ce9aad6
OM
43pair<uint64_t,uint64_t> MemRecursorCache::stats()
44{
45 uint64_t c = 0, a = 0;
46 for (auto& map : d_maps) {
47 const lock l(map);
48 c += map.d_contended_count;
49 a += map.d_acuired_count;
50 }
51 return pair<uint64_t,uint64_t>(c, a);
52}
53
a7956123
OM
54size_t MemRecursorCache::ecsIndexSize()
55{
56 // XXX!
57 size_t count = 0;
58 for (auto& map : d_maps) {
7ce9aad6 59 const lock l(map);
a7956123
OM
60 count += map.d_ecsIndex.size();
61 }
62 return count;
63}
64
65// this function is too slow to poll!
66size_t MemRecursorCache::bytes()
67{
68 size_t ret = 0;
69 for (auto& map : d_maps) {
7ce9aad6 70 const lock l(map);
a7956123
OM
71 for (const auto& i : map.d_map) {
72 ret += sizeof(struct CacheEntry);
73 ret += i.d_qname.toString().length();
74 for (const auto& record : i.d_records) {
75 ret += sizeof(record); // XXX WRONG we don't know the stored size!
76 }
77 }
43a2b29c
BH
78 }
79 return ret;
eec1087c
BH
80}
81
a7956123 82int32_t MemRecursorCache::handleHit(MapCombo& map, MemRecursorCache::OrderedTagIterator_t& entry, const DNSName& qname, const ComboAddress& who, vector<DNSRecord>* res, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* state, bool* wasAuth)
e74f866a 83{
a7956123 84 // MUTEX SHOULD BE ACQUIRED
e74f866a
RG
85 int32_t ttd = entry->d_ttd;
86
87 if(variable && !entry->d_netmask.empty()) {
88 *variable = true;
89 }
90
91 // cerr<<"Looking at "<<entry->d_records.size()<<" records for this name"<<endl;
92 if (res) {
4c8d2585
RG
93 res->reserve(res->size() + entry->d_records.size());
94
e74f866a
RG
95 for(const auto& k : entry->d_records) {
96 DNSRecord dr;
97 dr.d_name = qname;
98 dr.d_type = entry->d_qtype;
99 dr.d_class = QClass::IN;
100 dr.d_content = k;
101 dr.d_ttl = static_cast<uint32_t>(entry->d_ttd);
102 dr.d_place = DNSResourceRecord::ANSWER;
4c8d2585 103 res->push_back(std::move(dr));
e74f866a
RG
104 }
105 }
106
107 if(signatures) { // if you do an ANY lookup you are hosed XXXX
108 *signatures = entry->d_signatures;
109 }
110
111 if(authorityRecs) {
112 *authorityRecs = entry->d_authorityRecs;
113 }
114
115 if (state) {
116 *state = entry->d_state;
117 }
118
119 if (wasAuth) {
120 *wasAuth = entry->d_auth;
121 }
122
a7956123 123 moveCacheItemToBack<SequencedTag>(map.d_map, entry);
e74f866a
RG
124
125 return ttd;
126}
127
a7956123 128MemRecursorCache::cache_t::const_iterator MemRecursorCache::getEntryUsingECSIndex(MapCombo& map, time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who)
e74f866a 129{
a7956123 130 // MUTEX SHOULD BE ACQUIRED
b0274132 131 auto ecsIndexKey = tie(qname, qtype);
a7956123
OM
132 auto ecsIndex = map.d_ecsIndex.find(ecsIndexKey);
133 if (ecsIndex != map.d_ecsIndex.end() && !ecsIndex->isEmpty()) {
e74f866a
RG
134 /* we have netmask-specific entries, let's see if we match one */
135 while (true) {
b0274132 136 const Netmask best = ecsIndex->lookupBestMatch(who);
e74f866a
RG
137 if (best.empty()) {
138 /* we have nothing more specific for you */
139 break;
140 }
e74f866a 141 auto key = boost::make_tuple(qname, qtype, best);
a7956123
OM
142 auto entry = map.d_map.find(key);
143 if (entry == map.d_map.end()) {
b0274132
RG
144 /* ecsIndex is not up-to-date */
145 ecsIndex->removeNetmask(best);
146 if (ecsIndex->isEmpty()) {
a7956123 147 map.d_ecsIndex.erase(ecsIndex);
e74f866a
RG
148 break;
149 }
150 continue;
151 }
152
153 if (entry->d_ttd > now) {
154 if (!requireAuth || entry->d_auth) {
155 return entry;
156 }
c8d4f498 157 /* we need auth data and the best match is not authoritative */
a7956123 158 return map.d_map.end();
e74f866a
RG
159 }
160 else {
161 /* this netmask-specific entry has expired */
a7956123 162 moveCacheItemToFront<SequencedTag>(map.d_map, entry);
b0274132
RG
163 ecsIndex->removeNetmask(best);
164 if (ecsIndex->isEmpty()) {
a7956123 165 map.d_ecsIndex.erase(ecsIndex);
e74f866a
RG
166 break;
167 }
168 }
169 }
170 }
171
172 /* we have nothing specific, let's see if we have a generic one */
173 auto key = boost::make_tuple(qname, qtype, Netmask());
a7956123
OM
174 auto entry = map.d_map.find(key);
175 if (entry != map.d_map.end()) {
e74f866a
RG
176 if (entry->d_ttd > now) {
177 if (!requireAuth || entry->d_auth) {
178 return entry;
179 }
180 }
181 else {
a7956123 182 moveCacheItemToFront<SequencedTag>(map.d_map, entry);
e74f866a
RG
183 }
184 }
185
186 /* nothing for you, sorry */
a7956123 187 return map.d_map.end();
e74f866a
RG
188}
189
a7956123 190std::pair<MemRecursorCache::NameOnlyHashedTagIterator_t, MemRecursorCache::NameOnlyHashedTagIterator_t> MemRecursorCache::getEntries(MapCombo& map, const DNSName &qname, const QType& qt)
eec1087c 191{
a7956123
OM
192 // MUTEX SHOULD BE ACQUIRED
193 if (!map.d_cachecachevalid || map.d_cachedqname != qname) {
194 map.d_cachedqname = qname;
195 const auto& idx = map.d_map.get<NameOnlyHashedTag>();
196 map.d_cachecache = idx.equal_range(qname);
197 map.d_cachecachevalid = true;
cf98aa40 198 }
a7956123 199 return map.d_cachecache;
787737ae
RG
200}
201
4c8d2585 202bool MemRecursorCache::entryMatches(MemRecursorCache::OrderedTagIterator_t& entry, uint16_t qt, bool requireAuth, const ComboAddress& who)
787737ae 203{
a7956123 204 // MUTEX SHOULD BE ACQUIRED
787737ae
RG
205 if (requireAuth && !entry->d_auth)
206 return false;
207
e74f866a
RG
208 return ((entry->d_qtype == qt || qt == QType::ANY ||
209 (qt == QType::ADDR && (entry->d_qtype == QType::A || entry->d_qtype == QType::AAAA)))
787737ae
RG
210 && (entry->d_netmask.empty() || entry->d_netmask.match(who)));
211}
212
213// returns -1 for no hits
214int32_t MemRecursorCache::get(time_t now, const DNSName &qname, const QType& qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, vector<std::shared_ptr<RRSIGRecordContent>>* signatures, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs, bool* variable, vState* state, bool* wasAuth)
215{
216 time_t ttd=0;
217 // cerr<<"looking up "<< qname<<"|"+qt.getName()<<"\n";
e74f866a
RG
218 if(res) {
219 res->clear();
220 }
e74f866a 221 const uint16_t qtype = qt.getCode();
a7956123
OM
222
223 auto& map = getMap(qname);
7ce9aad6 224 const lock l(map);
a7956123 225
e74f866a
RG
226 /* If we don't have any netmask-specific entries at all, let's just skip this
227 to be able to use the nice d_cachecache hack. */
a7956123
OM
228 if (qtype != QType::ANY && !map.d_ecsIndex.empty()) {
229
e74f866a
RG
230 if (qtype == QType::ADDR) {
231 int32_t ret = -1;
787737ae 232
a7956123
OM
233 auto entryA = getEntryUsingECSIndex(map, now, qname, QType::A, requireAuth, who);
234 if (entryA != map.d_map.end()) {
235 ret = handleHit(map, entryA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth);
e74f866a 236 }
a7956123
OM
237 auto entryAAAA = getEntryUsingECSIndex(map, now, qname, QType::AAAA, requireAuth, who);
238 if (entryAAAA != map.d_map.end()) {
239 int32_t ttdAAAA = handleHit(map, entryAAAA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth);
e74f866a
RG
240 if (ret > 0) {
241 ret = std::min(ret, ttdAAAA);
242 } else {
243 ret = ttdAAAA;
244 }
245 }
246 return ret > 0 ? static_cast<int32_t>(ret-now) : ret;
247 }
248 else {
a7956123
OM
249 auto entry = getEntryUsingECSIndex(map, now, qname, qtype, requireAuth, who);
250 if (entry != map.d_map.end()) {
251 return static_cast<int32_t>(handleHit(map, entry, qname, who, res, signatures, authorityRecs, variable, state, wasAuth) - now);
e74f866a
RG
252 }
253 return -1;
254 }
255 }
256
a7956123 257 auto entries = getEntries(map, qname, qt);
ea634573 258
787737ae 259 if(entries.first!=entries.second) {
4c8d2585 260 for(auto i=entries.first; i != entries.second; ++i) {
787737ae 261
a7956123 262 auto firstIndexIterator = map.d_map.project<OrderedTag>(i);
787737ae 263 if (i->d_ttd <= now) {
a7956123 264 moveCacheItemToFront<SequencedTag>(map.d_map, firstIndexIterator);
24bb9b58 265 continue;
787737ae 266 }
24bb9b58 267
4c8d2585 268 if (!entryMatches(firstIndexIterator, qtype, requireAuth, who))
787737ae
RG
269 continue;
270
a7956123 271 ttd = handleHit(map, firstIndexIterator, qname, who, res, signatures, authorityRecs, variable, state, wasAuth);
787737ae
RG
272
273 if(qt.getCode()!=QType::ANY && qt.getCode()!=QType::ADDR) // normally if we have a hit, we are done
274 break;
24bb9b58 275 }
b0d4fb45 276
4d2be65d 277 // cerr<<"time left : "<<ttd - now<<", "<< (res ? res->size() : 0) <<"\n";
6b68a4e3 278 return static_cast<int32_t>(ttd-now);
eec1087c 279 }
eec1087c
BH
280 return -1;
281}
34264879 282
e74f866a 283void MemRecursorCache::replace(time_t now, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, boost::optional<Netmask> ednsmask, vState state)
eec1087c 284{
a7956123 285 auto& map = getMap(qname);
7ce9aad6 286 const lock l(map);
a7956123
OM
287
288 map.d_cachecachevalid = false;
f9c681bf 289 // cerr<<"Replacing "<<qname<<" for "<< (ednsmask ? ednsmask->toString() : "everyone") << endl;
80462253
SB
290 if (ednsmask) {
291 ednsmask = ednsmask->getNormalized();
292 }
e74f866a 293 auto key = boost::make_tuple(qname, qt.getCode(), ednsmask ? *ednsmask : Netmask());
a072ce44 294 bool isNew = false;
a7956123
OM
295 cache_t::iterator stored = map.d_map.find(key);
296 if (stored == map.d_map.end()) {
297 stored = map.d_map.insert(CacheEntry(key, auth)).first;
cdde2458 298 map.d_entriesCount++;
a072ce44 299 isNew = true;
f9c681bf 300 }
e74f866a 301
d0fcc32b
RG
302 /* if we are inserting a new entry or updating an expired one (in which case the
303 ECS index might have been removed but the entry still exists because it has not
304 been garbage collected yet) we might need to update the ECS index.
305 Otherwise it should already be indexed and we don't need to update it.
306 */
307 if (isNew || stored->d_ttd <= now) {
308 /* don't bother building an ecsIndex if we don't have any netmask-specific entries */
309 if (ednsmask && !ednsmask->empty()) {
310 auto ecsIndexKey = boost::make_tuple(qname, qt.getCode());
a7956123
OM
311 auto ecsIndex = map.d_ecsIndex.find(ecsIndexKey);
312 if (ecsIndex == map.d_ecsIndex.end()) {
313 ecsIndex = map.d_ecsIndex.insert(ECSIndexEntry(qname, qt.getCode())).first;
d0fcc32b
RG
314 }
315 ecsIndex->addMask(*ednsmask);
e74f866a 316 }
6c674e9a 317 }
318
6b68a4e3 319 time_t maxTTD=std::numeric_limits<time_t>::max();
d0cd0376 320 CacheEntry ce=*stored; // this is a COPY
e325f20c 321 ce.d_qtype=qt.getCode();
57769f13 322 ce.d_signatures=signatures;
2b984251 323 ce.d_authorityRecs=authorityRecs;
4d2be65d 324 ce.d_state=state;
fbb356b6 325
d0cd0376 326 // cerr<<"asked to store "<< (qname.empty() ? "EMPTY" : qname.toString()) <<"|"+qt.getName()<<" -> '";
327 // cerr<<(content.empty() ? string("EMPTY CONTENT") : content.begin()->d_content->getZoneRepresentation())<<"', auth="<<auth<<", ce.auth="<<ce.d_auth;
4d2be65d 328 // cerr<<", ednsmask: " << (ednsmask ? ednsmask->toString() : "none") <<endl;
a85eb653
BH
329
330 if(!auth && ce.d_auth) { // unauth data came in, we have some auth data, but is it fresh?
e325f20c 331 if(ce.d_ttd > now) { // we still have valid data, ignore unauth data
bf4ab707 332 // cerr<<"\tStill hold valid auth data, and the new data is unauth, return\n";
a85eb653 333 return;
609a76b3
BH
334 }
335 else {
336 ce.d_auth = false; // new data won't be auth
337 }
a85eb653 338 }
d0cd0376 339
48f19abe
RG
340 // refuse any attempt to *raise* the TTL of auth NS records, as it would make it possible
341 // for an auth to keep a "ghost" zone alive forever, even after the delegation is gone from
342 // the parent
343 // BUT make sure that we CAN refresh the root
fbb356b6 344 if(ce.d_auth && auth && qt.getCode()==QType::NS && !isNew && !qname.isRoot()) {
345 // cerr<<"\tLimiting TTL of auth->auth NS set replace to "<<ce.d_ttd<<endl;
e325f20c 346 maxTTD = ce.d_ttd;
fc202159
PD
347 }
348
48f19abe 349 if(auth) {
34264879 350 ce.d_auth = true;
34264879 351 }
09a6f097 352
48f19abe
RG
353 ce.d_records.clear();
354 ce.d_records.reserve(content.size());
6196f908 355
e74f866a 356 for(const auto i : content) {
6b68a4e3
RG
357 /* Yes, we have altered the d_ttl value by adding time(nullptr) to it
358 prior to calling this function, so the TTL actually holds a TTD. */
e74f866a
RG
359 ce.d_ttd=min(maxTTD, static_cast<time_t>(i.d_ttl)); // XXX this does weird things if TTLs differ in the set
360 // cerr<<"To store: "<<i.d_content->getZoneRepresentation()<<" with ttl/ttd "<<i.d_ttl<<", capped at: "<<maxTTD<<endl;
361 ce.d_records.push_back(i.d_content);
ea634573 362 }
bf4ab707 363
a072ce44 364 if (!isNew) {
a7956123 365 moveCacheItemToBack<SequencedTag>(map.d_map, stored);
a072ce44 366 }
a7956123 367 map.d_map.replace(stored, ce);
eec1087c 368}
92294b60 369
a7956123 370size_t MemRecursorCache::doWipeCache(const DNSName& name, bool sub, uint16_t qtype)
748eff9f 371{
a7956123
OM
372 size_t count = 0;
373
374 if (!sub) {
cdde2458 375 auto& map = getMap(name);
7ce9aad6 376 const lock l(map);
cdde2458
OM
377 map.d_cachecachevalid = false;
378 auto& idx = map.d_map.get<NameOnlyHashedTag>();
379 size_t n = idx.erase(name);
380 count += n;
381 map.d_entriesCount -= n;
382 if (qtype == 0xffff) {
383 auto& ecsIdx = map.d_ecsIndex.get<OrderedTag>();
384 auto ecsIndexRange = ecsIdx.equal_range(name);
385 ecsIdx.erase(ecsIndexRange.first, ecsIndexRange.second);
386 }
387 else {
388 auto& ecsIdx = map.d_ecsIndex.get<HashedTag>();
389 auto ecsIndexRange = ecsIdx.equal_range(tie(name, qtype));
390 ecsIdx.erase(ecsIndexRange.first, ecsIndexRange.second);
e74f866a 391 }
86f3ca51 392 }
393 else {
a7956123 394 for (auto& map : d_maps) {
7ce9aad6 395 const lock l(map);
a7956123
OM
396 map.d_cachecachevalid = false;
397 auto& idx = map.d_map.get<OrderedTag>();
398 for (auto i = idx.lower_bound(name); i != idx.end(); ) {
399 if (!i->d_qname.isPartOf(name))
400 break;
401 if (i->d_qtype == qtype || qtype == 0xffff) {
402 count++;
403 i = idx.erase(i);
cdde2458 404 map.d_entriesCount--;
a7956123
OM
405 } else {
406 ++i;
407 }
e74f866a 408 }
a7956123
OM
409 auto& ecsIdx = map.d_ecsIndex.get<OrderedTag>();
410 for (auto i = ecsIdx.lower_bound(name); i != ecsIdx.end(); ) {
411 if (!i->d_qname.isPartOf(name))
412 break;
413 if (i->d_qtype == qtype || qtype == 0xffff) {
414 i = ecsIdx.erase(i);
415 } else {
416 ++i;
417 }
e74f866a
RG
418 }
419 }
85c143a2
BH
420 }
421 return count;
748eff9f 422}
92294b60 423
a7956123 424// Name should be doLimitTime or so
6b68a4e3 425bool MemRecursorCache::doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL)
a2b4f72f 426{
a7956123 427 auto& map = getMap(name);
7ce9aad6 428 const lock l(map);
a7956123
OM
429 cache_t::iterator iter = map.d_map.find(tie(name, qtype));
430 if (iter == map.d_map.end()) {
a2b4f72f 431 return false;
e06f9f15
PD
432 }
433
434 CacheEntry ce = *iter;
a7956123 435 if (ce.d_ttd < now)
a2b4f72f
BH
436 return false; // would be dead anyhow
437
6b68a4e3 438 uint32_t maxTTL = static_cast<uint32_t>(ce.d_ttd - now);
a7956123
OM
439 if (maxTTL > newTTL) {
440 map.d_cachecachevalid = false;
a2b4f72f 441
6b68a4e3 442 time_t newTTD = now + newTTL;
3ddb9247 443
a7956123 444 if (ce.d_ttd > newTTD) {
e325f20c 445 ce.d_ttd = newTTD;
a7956123
OM
446 map.d_map.replace(iter, ce);
447 }
a2b4f72f
BH
448 return true;
449 }
450 return false;
451}
452
b9473937 453bool MemRecursorCache::updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState, boost::optional<time_t> capTTD)
787737ae 454{
a7956123 455 auto& map = getMap(qname);
7ce9aad6 456 const lock l(map);
a7956123 457
787737ae 458 bool updated = false;
e74f866a 459 uint16_t qtype = qt.getCode();
a7956123
OM
460 if (qtype != QType::ANY && qtype != QType::ADDR && !map.d_ecsIndex.empty()) {
461 auto entry = getEntryUsingECSIndex(map, now, qname, qtype, requireAuth, who);
462 if (entry == map.d_map.end()) {
e74f866a
RG
463 return false;
464 }
465
466 entry->d_state = newState;
b9473937
RG
467 if (capTTD) {
468 entry->d_ttd = std::min(entry->d_ttd, *capTTD);
469 }
e74f866a
RG
470 return true;
471 }
472
a7956123 473 auto entries = getEntries(map, qname, qt);
787737ae
RG
474
475 for(auto i = entries.first; i != entries.second; ++i) {
a7956123 476 auto firstIndexIterator = map.d_map.project<OrderedTag>(i);
4c8d2585
RG
477
478 if (!entryMatches(firstIndexIterator, qtype, requireAuth, who))
787737ae
RG
479 continue;
480
481 i->d_state = newState;
b9473937
RG
482 if (capTTD) {
483 i->d_ttd = std::min(i->d_ttd, *capTTD);
484 }
787737ae
RG
485 updated = true;
486
e74f866a 487 if(qtype != QType::ANY && qtype != QType::ADDR) // normally if we have a hit, we are done
787737ae 488 break;
787737ae
RG
489 }
490
491 return updated;
492}
493
d7948528 494uint64_t MemRecursorCache::doDump(int fd)
748eff9f 495{
a7956123
OM
496 int newfd = dup(fd);
497 if (newfd == -1) {
498 return 0;
499 }
500 auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(newfd, "w"), fclose);
d7948528 501 if(!fp) { // dup probably failed
a7956123 502 close(newfd);
d7948528 503 return 0;
748eff9f 504 }
bec87d21 505
a7956123
OM
506 fprintf(fp.get(), "; main record cache dump follows\n;\n");
507 uint64_t count = 0;
508
509 for (auto& map : d_maps) {
7ce9aad6 510 const lock l(map);
a7956123
OM
511 const auto& sidx = map.d_map.get<SequencedTag>();
512
513 time_t now = time(0);
514 for (const auto i : sidx) {
515 for (const auto j : i.d_records) {
516 count++;
517 try {
518 fprintf(fp.get(), "%s %" PRId64 " IN %s %s ; (%s) auth=%i %s\n", i.d_qname.toString().c_str(), static_cast<int64_t>(i.d_ttd - now), DNSRecordContent::NumberToType(i.d_qtype).c_str(), j->getZoneRepresentation().c_str(), vStates[i.d_state], i.d_auth, i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str());
519 }
520 catch(...) {
521 fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str());
522 }
d50e9bc8 523 }
a7956123
OM
524 for (const auto &sig : i.d_signatures) {
525 count++;
526 try {
527 fprintf(fp.get(), "%s %" PRId64 " IN RRSIG %s ; %s\n", i.d_qname.toString().c_str(), static_cast<int64_t>(i.d_ttd - now), sig->getZoneRepresentation().c_str(), i.d_netmask.empty() ? "" : i.d_netmask.toString().c_str());
528 }
529 catch(...) {
530 fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str());
531 }
d50e9bc8
PL
532 }
533 }
748eff9f 534 }
d7948528 535 return count;
748eff9f 536}
43a2b29c 537
a7956123 538void MemRecursorCache::doPrune(size_t keep)
eec1087c 539{
a7956123
OM
540 //size_t maxCached = d_maxEntries;
541 size_t cacheSize = size();
542 pruneMutexCollectionsVector<SequencedTag>(*this, d_maps, keep, cacheSize);
c68ae9fa
RG
543}
544