]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/syncres.hh
Comment out empty else clauses
[thirdparty/pdns.git] / pdns / syncres.hh
CommitLineData
00a19ff7
BH
1#ifndef PDNS_SYNCRES_HH
2#define PDNS_SYNCRES_HH
3#include <string>
4#include "dns.hh"
5#include "qtype.hh"
6#include <vector>
7#include <set>
8#include <map>
eefd15f9
BH
9#include <cmath>
10#include <iostream>
11#include <utility>
c836dc19 12#include "misc.hh"
00a19ff7 13#include "lwres.hh"
d6d5dea7 14#include <boost/utility.hpp>
1d5b3ce6 15#include "sstuff.hh"
9fdf67d5 16#include "recursor_cache.hh"
16beeaa4 17#include "recpacketcache.hh"
1d5b3ce6 18#include <boost/tuple/tuple.hpp>
71dea98d 19#include <boost/optional.hpp>
1d5b3ce6
BH
20#include <boost/tuple/tuple_comparison.hpp>
21#include "mtasker.hh"
a9af3782 22#include "iputils.hh"
eefd15f9 23
bdf40704 24void primeHints(void);
00a19ff7 25
38e22b5a
BH
26struct NegCacheEntry
27{
f4df5e89 28 string d_name;
be718669 29 QType d_qtype;
33988bfb 30 string d_qname;
33988bfb 31 uint32_t d_ttd;
92733ee6
BH
32 uint32_t getTTD() const
33 {
34 return d_ttd;
35 }
38e22b5a 36};
00a19ff7 37
49f076e8 38
bb4bdbaf 39template<class Thing> class Throttle : public boost::noncopyable
49f076e8
BH
40{
41public:
42 Throttle()
43 {
44 d_limit=3;
45 d_ttl=60;
46 d_last_clean=time(0);
47 }
87da00e7 48 bool shouldThrottle(time_t now, const Thing& t)
49f076e8 49 {
cd7bf56b 50 if(now > d_last_clean + 300 ) {
bb4bdbaf 51
49f076e8 52 d_last_clean=now;
594c2ee7 53 for(typename cont_t::iterator i=d_cont.begin();i!=d_cont.end();) {
4957a608
BH
54 if( i->second.ttd < now) {
55 d_cont.erase(i++);
56 }
57 else
58 ++i;
594c2ee7 59 }
49f076e8
BH
60 }
61
49f076e8
BH
62 typename cont_t::iterator i=d_cont.find(t);
63 if(i==d_cont.end())
64 return false;
014c60c3 65 if(now > i->second.ttd || i->second.count-- < 0) {
49f076e8 66 d_cont.erase(i);
139c2911 67 return false;
49f076e8 68 }
014c60c3
BH
69
70 return true; // still listed, still blocked
49f076e8 71 }
87da00e7 72 void throttle(time_t now, const Thing& t, unsigned int ttl=0, unsigned int tries=0)
49f076e8
BH
73 {
74 typename cont_t::iterator i=d_cont.find(t);
87da00e7 75 entry e={ now+(ttl ? ttl : d_ttl), tries ? tries : d_limit};
49f076e8 76
c214232f 77 if(i==d_cont.end()) {
49f076e8 78 d_cont[t]=e;
c214232f
BH
79 }
80 else if(i->second.ttd > e.ttd || (i->second.count) < e.count)
81 d_cont[t]=e;
8a5602d4
BH
82 }
83
84 unsigned int size()
85 {
705f31ae 86 return (unsigned int)d_cont.size();
49f076e8
BH
87 }
88private:
89 int d_limit;
90 int d_ttl;
91 time_t d_last_clean;
92 struct entry
93 {
94 time_t ttd;
95 int count;
96 };
97 typedef map<Thing,entry> cont_t;
98 cont_t d_cont;
99};
100
101
eefd15f9 102/** Class that implements a decaying EWMA.
36c5ee42 103 This class keeps an exponentially weighted moving average which, additionally, decays over time.
eefd15f9
BH
104 The decaying is only done on get.
105*/
106class DecayingEwma
107{
108public:
71dea98d
BH
109 DecayingEwma() : d_val(0.0)
110 {
111 d_needinit=true;
118dcc93 112 d_last.tv_sec = d_last.tv_usec = 0;
71dea98d 113 d_lastget=d_last;
36c5ee42 114 }
d6d5dea7 115
71dea98d 116 DecayingEwma(const DecayingEwma& orig) : d_last(orig.d_last), d_lastget(orig.d_lastget), d_val(orig.d_val), d_needinit(orig.d_needinit)
eefd15f9 117 {
71dea98d 118 }
d6d5dea7 119
71dea98d
BH
120 struct timeval getOrMakeTime(struct timeval* tv)
121 {
122 if(tv)
123 return *tv;
124 else {
125 struct timeval ret;
f2b6ccd6 126 Utility::gettimeofday(&ret, 0);
71dea98d
BH
127 return ret;
128 }
d6d5dea7
BH
129 }
130
5a26bb53 131 void submit(int val, struct timeval* tv)
d6d5dea7 132 {
71dea98d
BH
133 struct timeval now=getOrMakeTime(tv);
134
135 if(d_needinit) {
136 d_last=now;
21f0f88b 137 d_lastget=now;
71dea98d 138 d_needinit=false;
21f0f88b 139 d_val = val;
71dea98d 140 }
21f0f88b
BH
141 else {
142 float diff= makeFloat(d_last - now);
71dea98d 143
21f0f88b
BH
144 d_last=now;
145 double factor=exp(diff)/2.0; // might be '0.5', or 0.0001
146 d_val=(float)((1-factor)*val+ (float)factor*d_val);
147 }
eefd15f9 148 }
d6d5dea7 149
5a26bb53 150 double get(struct timeval* tv)
71dea98d
BH
151 {
152 struct timeval now=getOrMakeTime(tv);
153 float diff=makeFloat(d_lastget-now);
36c5ee42 154 d_lastget=now;
705f31ae 155 float factor=exp(diff/60.0f); // is 1.0 or less
eefd15f9
BH
156 return d_val*=factor;
157 }
158
a82ce718
PD
159 double peek(void)
160 {
161 return d_val;
162 }
163
996c89cc 164 bool stale(time_t limit) const
9fdf67d5 165 {
71dea98d 166 return limit > d_lastget.tv_sec;
9fdf67d5
BH
167 }
168
eefd15f9 169private:
71dea98d
BH
170 struct timeval d_last; // stores time
171 struct timeval d_lastget; // stores time
172 float d_val;
173 bool d_needinit;
174};
175
176
bb4bdbaf 177class SyncRes : public boost::noncopyable
00a19ff7
BH
178{
179public:
77499b05
BH
180 enum LogMode { LogNone, Log, Store};
181
ac0e821b 182 explicit SyncRes(const struct timeval& now);
bb4bdbaf 183
a9af3782 184 int beginResolve(const string &qname, const QType &qtype, uint16_t qclass, vector<DNSResourceRecord>&ret);
c836dc19
BH
185 void setId(int id)
186 {
77499b05 187 if(doLog())
9fdf67d5 188 d_prefix="["+itoa(id)+"] ";
c836dc19 189 }
77499b05
BH
190 static void setDefaultLogMode(LogMode lm)
191 {
192 s_lm = lm;
193 }
194
195 void setLogMode(LogMode lm)
196 {
197 d_lm = lm;
198 }
199
200 bool doLog()
c836dc19 201 {
77499b05 202 return d_lm != LogNone;
c836dc19 203 }
77499b05 204
c836dc19
BH
205 void setCacheOnly(bool state=true)
206 {
207 d_cacheonly=state;
208 }
209 void setNoCache(bool state=true)
210 {
211 d_nocache=state;
212 }
2188dcc3
BH
213
214 void setDoEDNS0(bool state=true)
215 {
216 d_doEDNS0=state;
217 }
218
77499b05
BH
219 string getTrace() const
220 {
221 return d_trace.str();
222 }
223
c1d73d94 224 int asyncresolveWrapper(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, LWResult* res);
ff1872cf
BH
225
226 static void doEDNSDumpAndClose(int fd);
c0ea6e55 227
c836dc19 228 static unsigned int s_queries;
7becf07f 229 static unsigned int s_outgoingtimeouts;
3de83124 230 static unsigned int s_throttledqueries;
66e0b6ea 231 static unsigned int s_dontqueries;
c836dc19 232 static unsigned int s_outqueries;
5c633640 233 static unsigned int s_tcpoutqueries;
525b8a7c 234 static unsigned int s_nodelegated;
c571588b 235 static unsigned int s_unreachables;
ee8d569b
BH
236 static bool s_doAAAAAdditionalProcessing;
237 static bool s_doAdditionalProcessing;
996c89cc 238 static bool s_doIPv6;
c836dc19 239 unsigned int d_outqueries;
5c633640 240 unsigned int d_tcpoutqueries;
3de83124 241 unsigned int d_throttledqueries;
d77df2e1 242 unsigned int d_timeouts;
c571588b
BH
243 unsigned int d_unreachables;
244
33988bfb
BH
245 // typedef map<string,NegCacheEntry> negcache_t;
246
247 typedef multi_index_container <
248 NegCacheEntry,
249 indexed_by <
250 ordered_unique<
f4df5e89
BH
251 composite_key<
252 NegCacheEntry,
253 member<NegCacheEntry, string, &NegCacheEntry::d_name>,
254 member<NegCacheEntry, QType, &NegCacheEntry::d_qtype>
7738a23f
BH
255 >,
256 composite_key_compare<CIStringCompare, std::less<QType> >
33988bfb 257 >,
92733ee6 258 sequenced<>
33988bfb 259 >
49a699c4
BH
260 > negcache_t;
261
abc1d928 262 //! This represents a number of decaying Ewmas, used to store performance per nameserver-name.
996c89cc
BH
263 /** Modelled to work mostly like the underlying DecayingEwma. After you've called get,
264 d_best is filled out with the best address for this collection */
265 struct DecayingEwmaCollection
266 {
267 void submit(const ComboAddress& remote, int usecs, struct timeval* now)
268 {
269 collection_t::iterator pos;
270 for(pos=d_collection.begin(); pos != d_collection.end(); ++pos)
4957a608
BH
271 if(pos->first==remote)
272 break;
996c89cc 273 if(pos!=d_collection.end()) {
4957a608 274 pos->second.submit(usecs, now);
996c89cc
BH
275 }
276 else {
4957a608
BH
277 DecayingEwma de;
278 de.submit(usecs, now);
279 d_collection.push_back(make_pair(remote, de));
996c89cc
BH
280 }
281 }
282
283 double get(struct timeval* now)
284 {
285 if(d_collection.empty())
4957a608 286 return 0;
18e7758c 287 double ret=std::numeric_limits<double>::max();
996c89cc
BH
288 double tmp;
289 for(collection_t::iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) {
4957a608
BH
290 if((tmp=pos->second.get(now)) < ret) {
291 ret=tmp;
292 d_best=pos->first;
293 }
996c89cc
BH
294 }
295
296 return ret;
297 }
298
299 bool stale(time_t limit) const
300 {
301 for(collection_t::const_iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos)
4957a608
BH
302 if(!pos->second.stale(limit))
303 return false;
996c89cc
BH
304 return true;
305 }
306
307 typedef vector<pair<ComboAddress, DecayingEwma> > collection_t;
308 collection_t d_collection;
309 ComboAddress d_best;
310 };
311
5ea6f7de 312 typedef map<string, DecayingEwmaCollection, CIStringCompare> nsspeeds_t;
9fdf67d5 313
c0ea6e55
BH
314 struct EDNSStatus
315 {
316 EDNSStatus() : mode(UNKNOWN), modeSetAt(0), EDNSPingHitCount(0) {}
317 enum EDNSMode { CONFIRMEDPINGER=-1, UNKNOWN=0, EDNSNOPING=1, EDNSPINGOK=2, EDNSIGNORANT=3, NOEDNS=4 } mode;
318 time_t modeSetAt;
319 int EDNSPingHitCount;
320 };
321
322 typedef map<ComboAddress, EDNSStatus> ednsstatus_t;
bb4bdbaf 323
840c10ec 324 static bool s_noEDNSPing;
4bfae16d 325 static bool s_noEDNS;
c0ea6e55 326
5605c067
BH
327 struct AuthDomain
328 {
2e5ae2b2 329 vector<ComboAddress> d_servers;
3b608765 330 bool d_rdForward;
5605c067
BH
331 typedef multi_index_container <
332 DNSResourceRecord,
333 indexed_by <
334 ordered_non_unique<
335 composite_key< DNSResourceRecord,
4957a608
BH
336 member<DNSResourceRecord, string, &DNSResourceRecord::qname>,
337 member<DNSResourceRecord, QType, &DNSResourceRecord::qtype>
5605c067
BH
338 >,
339 composite_key_compare<CIStringCompare, std::less<QType> >
340 >
341 >
342 > records_t;
343 records_t d_records;
344 };
345
346
347 typedef map<string, AuthDomain, CIStringCompare> domainmap_t;
49a699c4 348
5605c067 349
996c89cc 350 typedef Throttle<tuple<ComboAddress,string,uint16_t> > throttle_t;
49a699c4 351
fe213470 352 struct timeval d_now;
a9af3782 353 static unsigned int s_maxnegttl;
c3e753c7 354 static unsigned int s_maxcachettl;
1051f8a9
BH
355 static unsigned int s_packetcachettl;
356 static unsigned int s_packetcacheservfailttl;
357 static bool s_nopacketcache;
a9af3782 358 static string s_serverID;
77499b05
BH
359
360
49a699c4
BH
361 struct StaticStorage {
362 negcache_t negcache;
363 nsspeeds_t nsSpeeds;
364 ednsstatus_t ednsstatus;
365 throttle_t throttle;
366 domainmap_t* domainmap;
367 };
49a699c4 368
00a19ff7
BH
369private:
370 struct GetBestNSAnswer;
7305df82 371 int doResolveAt(set<string, CIStringCompare> nameservers, string auth, bool flawedNSSet, const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret,
4957a608 372 int depth, set<GetBestNSAnswer>&beenthere);
00a19ff7 373 int doResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, set<GetBestNSAnswer>& beenthere);
e93c956b 374 bool doOOBResolve(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
5605c067 375 domainmap_t::const_iterator getBestAuthZone(string* qname);
00a19ff7
BH
376 bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
377 bool doCacheCheck(const string &qname, const QType &qtype, vector<DNSResourceRecord>&ret, int depth, int &res);
7305df82 378 void getBestNSFromCache(const string &qname, set<DNSResourceRecord>&bestns, bool* flawedNSSet, int depth, set<GetBestNSAnswer>& beenthere);
00a19ff7 379 void addCruft(const string &qname, vector<DNSResourceRecord>& ret);
7305df82 380 string getBestNSNamesFromCache(const string &qname,set<string, CIStringCompare>& nsset, bool* flawedNSSet, int depth, set<GetBestNSAnswer>&beenthere);
00a19ff7
BH
381 void addAuthorityRecords(const string& qname, vector<DNSResourceRecord>& ret, int depth);
382
5ea6f7de 383 inline vector<string> shuffleInSpeedOrder(set<string, CIStringCompare> &nameservers, const string &prefix);
00a19ff7 384 bool moreSpecificThan(const string& a, const string &b);
d96e88da 385 vector<ComboAddress> getAddrs(const string &qname, int depth, set<GetBestNSAnswer>& beenthere);
c75a6a9e 386
00a19ff7 387private:
77499b05 388 ostringstream d_trace;
c836dc19 389 string d_prefix;
c836dc19
BH
390 bool d_cacheonly;
391 bool d_nocache;
2188dcc3 392 bool d_doEDNS0;
77499b05
BH
393 static LogMode s_lm;
394 LogMode d_lm;
c75a6a9e 395
00a19ff7
BH
396 struct GetBestNSAnswer
397 {
398 string qname;
399 set<DNSResourceRecord> bestns;
400 bool operator<(const GetBestNSAnswer &b) const
401 {
402 if(qname<b.qname)
4957a608 403 return true;
00a19ff7 404 if(qname==b.qname)
4957a608 405 return bestns<b.bestns;
00a19ff7
BH
406 return false;
407 }
408 };
409
410};
ac0e821b
BH
411extern __thread SyncRes::StaticStorage* t_sstorage;
412
5c633640 413class Socket;
a9af3782 414/* external functions, opaque to us */
5c633640
BH
415int asendtcp(const string& data, Socket* sock);
416int arecvtcp(string& data, int len, Socket* sock);
1d5b3ce6
BH
417
418
419struct PacketID
420{
787e5eab 421 PacketID() : id(0), type(0), sock(0), inNeeded(0), outPos(0), nearMisses(0), fd(-1)
67770277
BH
422 {
423 memset(&remote, 0, sizeof(remote));
424 }
1d5b3ce6
BH
425
426 uint16_t id; // wait for a specific id/remote pair
996c89cc 427 ComboAddress remote; // this is the remote
0d5f0a9f 428 string domain; // this is the question
787e5eab 429 uint16_t type; // and this is its type
1d5b3ce6
BH
430
431 Socket* sock; // or wait for an event on a TCP fd
432 int inNeeded; // if this is set, we'll read until inNeeded bytes are read
433 string inMSG; // they'll go here
434
435 string outMSG; // the outgoing message that needs to be sent
436 string::size_type outPos; // how far we are along in the outMSG
437
35ce8576 438 mutable uint32_t nearMisses; // number of near misses - host correct, id wrong
96f81a93
BH
439 typedef set<uint16_t > chain_t;
440 mutable chain_t chain;
4ef015cd 441 int fd;
35ce8576 442
1d5b3ce6
BH
443 bool operator<(const PacketID& b) const
444 {
445 int ourSock= sock ? sock->getHandle() : 0;
446 int bSock = b.sock ? b.sock->getHandle() : 0;
787e5eab 447 if( tie(remote, ourSock, type) < tie(b.remote, bSock, b.type))
0d5f0a9f 448 return true;
787e5eab 449 if( tie(remote, ourSock, type) > tie(b.remote, bSock, b.type))
0d5f0a9f
BH
450 return false;
451
ec6480f3 452 if(pdns_ilexicographical_compare(domain, b.domain))
96f81a93 453 return true;
ec6480f3 454 if(pdns_ilexicographical_compare(b.domain, domain))
96f81a93
BH
455 return false;
456
457 return tie(fd, id) < tie(b.fd, b.id);
1d5b3ce6
BH
458 }
459};
460
18e7758c 461struct PacketIDBirthdayCompare: public std::binary_function<PacketID, PacketID, bool>
96f81a93
BH
462{
463 bool operator()(const PacketID& a, const PacketID& b) const
464 {
465 int ourSock= a.sock ? a.sock->getHandle() : 0;
466 int bSock = b.sock ? b.sock->getHandle() : 0;
787e5eab 467 if( tie(a.remote, ourSock, a.type) < tie(b.remote, bSock, b.type))
96f81a93 468 return true;
787e5eab 469 if( tie(a.remote, ourSock, a.type) > tie(b.remote, bSock, b.type))
96f81a93
BH
470 return false;
471
ec6480f3 472 return pdns_ilexicographical_compare(a.domain, b.domain);
96f81a93
BH
473 }
474};
49a699c4 475extern __thread MemRecursorCache* t_RC;
16beeaa4 476extern __thread RecursorPacketCache* t_packetCache;
d2392145 477typedef MTasker<PacketID,string> MT_t;
bb4bdbaf 478extern __thread MT_t* MT;
1d5b3ce6 479
b3b5459d 480
1d5b3ce6
BH
481struct RecursorStats
482{
483 uint64_t servFails;
484 uint64_t nxDomains;
485 uint64_t noErrors;
fe213470 486 uint64_t answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow;
574af7ea 487 uint64_t avgLatencyUsec;
aaacf7f2 488 uint64_t qcounter;
d7f10541 489 uint64_t ipv6qcounter;
aaacf7f2 490 uint64_t tcpqcounter;
c8ddb7c2
BH
491 uint64_t unauthorizedUDP;
492 uint64_t unauthorizedTCP;
4e120339 493 uint64_t tcpClientOverflow;
0e9d9ce2
BH
494 uint64_t clientParseError;
495 uint64_t serverParseError;
01ed3112 496 uint64_t unexpectedCount;
7a132082 497 uint64_t caseMismatchCount;
0d5f0a9f 498 uint64_t spoofCount;
998a4334 499 uint64_t resourceLimits;
85c32340 500 uint64_t overCapacityDrops;
996c89cc 501 uint64_t ipv6queries;
96f81a93 502 uint64_t chainResends;
1ef00ba1 503 uint64_t nsSetInvalidations;
c0ea6e55
BH
504 uint64_t ednsPingMatches;
505 uint64_t ednsPingMismatches;
506 uint64_t noPingOutQueries, noEdnsOutQueries;
61b26744 507 uint64_t packetCacheHits;
9326cae1 508 uint64_t noPacketError;
5e3de507 509 time_t startupTime;
ec6eacbc 510 unsigned int maxMThreadStackUsage;
b3b5459d 511};
996c89cc 512
0e408828 513//! represents a running TCP/IP client session
cd989c87 514class TCPConnection : public boost::noncopyable
0e408828 515{
50a5ef72 516public:
cd989c87
BH
517 TCPConnection(int fd, const ComboAddress& addr);
518 ~TCPConnection();
519
520 int getFD()
521 {
522 return d_fd;
523 }
0e408828
BH
524 enum stateenum {BYTE0, BYTE1, GETQUESTION, DONE} state;
525 int qlen;
526 int bytesread;
cd989c87
BH
527 const ComboAddress d_remote;
528 char data[65535]; // damn
0e408828 529
50a5ef72 530 static unsigned int getCurrentConnections() { return s_currentConnections; }
50a5ef72 531private:
cd989c87 532 const int d_fd;
1bc9e6bd 533 static AtomicCounter s_currentConnections; //!< total number of current TCP connections
0e408828
BH
534};
535
536
b3b5459d
BH
537struct RemoteKeeper
538{
a9af3782
BH
539 typedef vector<ComboAddress> remotes_t;
540 remotes_t remotes;
541 int d_remotepos;
542 void addRemote(const ComboAddress& remote)
543 {
544 if(!remotes.size())
545 return;
546
547 remotes[(d_remotepos++) % remotes.size()]=remote;
548 }
1d5b3ce6 549};
b3b5459d 550extern __thread RemoteKeeper* t_remotes;
674cf0f6 551string doQueueReloadLuaScript(vector<string>::const_iterator begin, vector<string>::const_iterator end);
77499b05 552string doTraceRegex(vector<string>::const_iterator begin, vector<string>::const_iterator end);
18af64a8 553void parseACLs();
1d5b3ce6 554extern RecursorStats g_stats;
c3828c03 555extern unsigned int g_numThreads;
739f6278 556
ee1ada80 557std::string reloadAuthAndForwards();
c1d73d94 558ComboAddress parseIPAndPort(const std::string& input, uint16_t port);
1652a63e 559ComboAddress getQueryLocalAddress(int family, uint16_t port);
3427fa8a 560typedef boost::function<void*(void)> pipefunc_t;
49a699c4 561void broadcastFunction(const pipefunc_t& func, bool skipSelf = false);
00c9b8c1 562void distributeAsyncFunction(const pipefunc_t& func);
3427fa8a 563
bd53ea9d 564int directResolve(const std::string& qname, const QType& qtype, int qclass, vector<DNSResourceRecord>& ret);
3427fa8a 565
13034931 566template<class T> T broadcastAccFunction(const boost::function<T*()>& func, bool skipSelf=false);
3427fa8a 567
49a699c4 568SyncRes::domainmap_t* parseAuthAndForwards();
3427fa8a 569
13034931
BH
570uint64_t* pleaseGetNsSpeedsSize();
571uint64_t* pleaseGetCacheSize();
572uint64_t* pleaseGetNegCacheSize();
573uint64_t* pleaseGetCacheHits();
574uint64_t* pleaseGetCacheMisses();
575uint64_t* pleaseGetConcurrentQueries();
576uint64_t* pleaseGetThrottleSize();
16beeaa4
BH
577uint64_t* pleaseGetPacketCacheHits();
578uint64_t* pleaseGetPacketCacheSize();
54ea3a27 579uint64_t* pleaseWipeCache(const std::string& canon);
1c13e3c1 580uint64_t* pleaseWipeAndCountNegCache(const std::string& canon);
16beeaa4 581
00a19ff7 582#endif