uint32_t hash{0};
uint16_t qtype{0};
bool tcp{false};
+
+ time_t getTTD() const
+ {
+ return ttd;
+ }
};
struct HashTag{};
bool d_cleanskipped{false};
static const unsigned int s_mincleaninterval=1000, s_maxcleaninterval=300000;
+
+public:
+ void preRemoval(const CacheEntry&)
+ {
+ }
};
mutable time_t ttd{0};
uint16_t qtype{0};
int zoneID{-1};
+
+ time_t getTTD() const
+ {
+ return ttd;
+ }
};
struct HashTag{};
bool d_cleanskipped{false};
static const unsigned int s_mincleaninterval=1000, s_maxcleaninterval=300000;
+
+public:
+ void preRemoval(const CacheEntry&)
+ {
+ }
};
*/
#pragma once
+#include <mutex>
#include "lock.hh"
// 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
for(; iter != sidx.end() && tried < lookAt ; ++tried) {
if(iter->getTTD() < now) {
container.preRemoval(*iter);
- sidx.erase(iter++);
+ iter = sidx.erase(iter);
erased++;
}
else
auto& sidx = boost::multi_index::get<S>(mc.d_map);
uint64_t erased = 0, lookedAt = 0;
for(auto i = sidx.begin(); i != sidx.end(); lookedAt++) {
- if(i->ttd < now) {
+ if (i->getTTD() < now) {
i = sidx.erase(i);
erased++;
} else {
return totErased;
}
+template <typename S, typename C, typename T> uint64_t pruneMutexCollectionsVector(C& container, vector<T>& maps, uint64_t maxCached, uint64_t cacheSize)
+{
+ time_t now = time(nullptr);
+ uint64_t totErased = 0;
+ uint64_t toTrim = 0;
+ uint64_t lookAt = 0;
+
+ // two modes - if toTrim is 0, just look through 10% of the cache and nuke everything that is expired
+ // otherwise, scan first 5*toTrim records, and stop once we've nuked enough
+ if (cacheSize > maxCached) {
+ toTrim = cacheSize - maxCached;
+ lookAt = 5 * toTrim;
+ } else {
+ lookAt = cacheSize / 10;
+ }
+
+ for (auto& mc : maps) {
+ const std::lock_guard<std::mutex> lock(mc.mutex);
+ auto& sidx = boost::multi_index::get<S>(mc.d_map);
+ uint64_t erased = 0, lookedAt = 0;
+ for (auto i = sidx.begin(); i != sidx.end(); lookedAt++) {
+ if (i->getTTD() < now) {
+ container.preRemoval(*i);
+ i = sidx.erase(i);
+ erased++;
+ } else {
+ ++i;
+ }
+
+ if (toTrim && erased >= toTrim / maps.size())
+ break;
+
+ if (lookedAt > lookAt / maps.size())
+ break;
+ }
+ totErased += erased;
+ if (toTrim && totErased >= toTrim)
+ break;
+ }
+
+ if (totErased >= toTrim) { // done
+ return totErased;
+ }
+
+ toTrim -= totErased;
+
+ // XXXX kinda desperate method
+ while (toTrim > 0) {
+ for (auto& mc : maps) {
+ const std::lock_guard<std::mutex> lock(mc.mutex);
+ auto& sidx = boost::multi_index::get<S>(mc.d_map);
+ auto i = sidx.begin();
+ container.preRemoval(*i);
+ i = sidx.erase(i);
+ totErased++;
+ toTrim--;
+ if (toTrim == 0)
+ break;
+ }
+ }
+ return totErased;
+}
+
template <typename T> uint64_t purgeLockedCollectionsVector(vector<T>& maps)
{
uint64_t delcount=0;
#endif /* HAVE_FSTRM */
thread_local std::unique_ptr<MT_t> MT; // the big MTasker
-thread_local std::unique_ptr<MemRecursorCache> t_RC;
+std::unique_ptr<MemRecursorCache> s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
+
+
thread_local std::unique_ptr<RecursorPacketCache> t_packetCache;
thread_local FDMultiplexer* t_fdm{nullptr};
thread_local std::unique_ptr<addrringbuf_t> t_remotes, t_servfailremotes, t_largeanswerremotes, t_bogusremotes;
}
if (sr.d_outqueries || sr.d_authzonequeries) {
- t_RC->cacheMisses++;
+ s_RC->cacheMisses++;
}
else {
- t_RC->cacheHits++;
+ s_RC->cacheHits++;
}
if(spent < 0.001)
past = now;
past.tv_sec -= 5;
if (last_prune < past) {
- t_RC->doPrune(g_maxCacheEntries / g_numThreads); // this function is local to a thread, so fine anyhow
t_packetCache->doPruneTo(g_maxPacketCacheEntries / g_numWorkerThreads);
SyncRes::pruneNegCache(g_maxCacheEntries / (g_numWorkerThreads * 10));
static uint64_t* pleaseDump(int fd)
{
- return new uint64_t(t_RC->doDump(fd) + dumpNegCache(SyncRes::t_sstorage.negcache, fd) + t_packetCache->doDump(fd));
+ return new uint64_t(s_RC->doDump(fd) + dumpNegCache(SyncRes::t_sstorage.negcache, fd) + t_packetCache->doDump(fd));
}
static uint64_t* pleaseDumpEDNSMap(int fd)
uint64_t* pleaseWipeCache(const DNSName& canon, bool subtree, uint16_t qtype)
{
- return new uint64_t(t_RC->doWipeCache(canon, subtree, qtype));
+ return new uint64_t(s_RC->doWipeCache(canon, subtree));
}
uint64_t* pleaseWipePacketCache(const DNSName& canon, bool subtree, uint16_t qtype)
uint64_t* pleaseGetCacheSize()
{
- return new uint64_t(t_RC ? t_RC->size() : 0);
+ return new uint64_t(s_RC ? s_RC->size() : 0);
}
static uint64_t* pleaseGetCacheBytes()
{
- return new uint64_t(t_RC ? t_RC->bytes() : 0);
+ return new uint64_t(s_RC ? s_RC->bytes() : 0);
}
static uint64_t doGetCacheSize()
uint64_t* pleaseGetCacheHits()
{
- return new uint64_t(t_RC ? t_RC->cacheHits : 0);
+ return new uint64_t(s_RC->cacheHits);
}
static uint64_t doGetCacheHits()
uint64_t* pleaseGetCacheMisses()
{
- return new uint64_t(t_RC ? t_RC->cacheMisses : 0);
+ return new uint64_t(s_RC->cacheMisses);
}
static uint64_t doGetCacheMisses()
#include "arguments.hh"
#include "syncres.hh"
#include "recursor_cache.hh"
-#include "cachecleaner.hh"
#include "namespaces.hh"
+#include "cachecleaner.hh"
-unsigned int MemRecursorCache::size() const
+MemRecursorCache::MemRecursorCache(size_t mapsCount) : d_maps(mapsCount)
{
- return (unsigned int)d_cache.size();
}
-size_t MemRecursorCache::ecsIndexSize() const
+MemRecursorCache::~MemRecursorCache()
{
- return d_ecsIndex.size();
+ try {
+ typedef std::unique_ptr<std::lock_guard<std::mutex>> lock_t;
+ vector<lock_t> locks;
+ for (auto& map : d_maps) {
+ locks.push_back(lock_t(new std::lock_guard<std::mutex>(map.mutex)));
+ }
+ }
+ catch(...) {
+ }
}
-// this function is too slow to poll!
-unsigned int MemRecursorCache::bytes() const
+size_t MemRecursorCache::size()
{
- unsigned int ret=0;
+ // XXX!
+ size_t count = 0;
+ for (auto& map : d_maps) {
+ const std::lock_guard<std::mutex> lock(map.mutex);
+ count += map.d_map.size();
+ }
+ return count;
+}
- for(const auto& i : d_cache) {
- ret+=sizeof(struct CacheEntry);
- ret+=(unsigned int)i.d_qname.toString().length();
- for(const auto& record : i.d_records)
- ret+= sizeof(record); // XXX WRONG we don't know the stored size!
+size_t MemRecursorCache::ecsIndexSize()
+{
+ // XXX!
+ size_t count = 0;
+ for (auto& map : d_maps) {
+ const std::lock_guard<std::mutex> lock(map.mutex);
+ count += map.d_ecsIndex.size();
+ }
+ return count;
+}
+
+// this function is too slow to poll!
+size_t MemRecursorCache::bytes()
+{
+ size_t ret = 0;
+ for (auto& map : d_maps) {
+ const std::lock_guard<std::mutex> lock(map.mutex);
+ for (const auto& i : map.d_map) {
+ ret += sizeof(struct CacheEntry);
+ ret += i.d_qname.toString().length();
+ for (const auto& record : i.d_records) {
+ ret += sizeof(record); // XXX WRONG we don't know the stored size!
+ }
+ }
}
return ret;
}
-int32_t MemRecursorCache::handleHit(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)
+int32_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)
{
+ // MUTEX SHOULD BE ACQUIRED
int32_t ttd = entry->d_ttd;
if(variable && !entry->d_netmask.empty()) {
*wasAuth = entry->d_auth;
}
- moveCacheItemToBack<SequencedTag>(d_cache, entry);
+ moveCacheItemToBack<SequencedTag>(map.d_map, entry);
return ttd;
}
-MemRecursorCache::cache_t::const_iterator MemRecursorCache::getEntryUsingECSIndex(time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who)
+MemRecursorCache::cache_t::const_iterator MemRecursorCache::getEntryUsingECSIndex(MapCombo& map, time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who)
{
+ // MUTEX SHOULD BE ACQUIRED
auto ecsIndexKey = tie(qname, qtype);
- auto ecsIndex = d_ecsIndex.find(ecsIndexKey);
- if (ecsIndex != d_ecsIndex.end() && !ecsIndex->isEmpty()) {
+ auto ecsIndex = map.d_ecsIndex.find(ecsIndexKey);
+ if (ecsIndex != map.d_ecsIndex.end() && !ecsIndex->isEmpty()) {
/* we have netmask-specific entries, let's see if we match one */
while (true) {
const Netmask best = ecsIndex->lookupBestMatch(who);
break;
}
auto key = boost::make_tuple(qname, qtype, best);
- auto entry = d_cache.find(key);
- if (entry == d_cache.end()) {
+ auto entry = map.d_map.find(key);
+ if (entry == map.d_map.end()) {
/* ecsIndex is not up-to-date */
ecsIndex->removeNetmask(best);
if (ecsIndex->isEmpty()) {
- d_ecsIndex.erase(ecsIndex);
+ map.d_ecsIndex.erase(ecsIndex);
break;
}
continue;
return entry;
}
/* we need auth data and the best match is not authoritative */
- return d_cache.end();
+ return map.d_map.end();
}
else {
/* this netmask-specific entry has expired */
- moveCacheItemToFront<SequencedTag>(d_cache, entry);
+ moveCacheItemToFront<SequencedTag>(map.d_map, entry);
ecsIndex->removeNetmask(best);
if (ecsIndex->isEmpty()) {
- d_ecsIndex.erase(ecsIndex);
+ map.d_ecsIndex.erase(ecsIndex);
break;
}
}
/* we have nothing specific, let's see if we have a generic one */
auto key = boost::make_tuple(qname, qtype, Netmask());
- auto entry = d_cache.find(key);
- if (entry != d_cache.end()) {
+ auto entry = map.d_map.find(key);
+ if (entry != map.d_map.end()) {
if (entry->d_ttd > now) {
if (!requireAuth || entry->d_auth) {
return entry;
}
}
else {
- moveCacheItemToFront<SequencedTag>(d_cache, entry);
+ moveCacheItemToFront<SequencedTag>(map.d_map, entry);
}
}
/* nothing for you, sorry */
- return d_cache.end();
+ return map.d_map.end();
}
-// returns -1 for no hits
-std::pair<MemRecursorCache::NameOnlyHashedTagIterator_t, MemRecursorCache::NameOnlyHashedTagIterator_t> MemRecursorCache::getEntries(const DNSName &qname, const QType& qt)
+std::pair<MemRecursorCache::NameOnlyHashedTagIterator_t, MemRecursorCache::NameOnlyHashedTagIterator_t> MemRecursorCache::getEntries(MapCombo& map, const DNSName &qname, const QType& qt)
{
- // cerr<<"looking up "<< qname<<"|"+qt.getName()<<"\n";
- if(!d_cachecachevalid || d_cachedqname!= qname) {
- // cerr<<"had cache cache miss"<<endl;
- d_cachedqname = qname;
- const auto& idx = d_cache.get<NameOnlyHashedTag>();
- d_cachecache = idx.equal_range(qname);
- d_cachecachevalid = true;
+ // MUTEX SHOULD BE ACQUIRED
+ if (!map.d_cachecachevalid || map.d_cachedqname != qname) {
+ map.d_cachedqname = qname;
+ const auto& idx = map.d_map.get<NameOnlyHashedTag>();
+ map.d_cachecache = idx.equal_range(qname);
+ map.d_cachecachevalid = true;
}
- // else cerr<<"had cache cache hit!"<<endl;
-
- return d_cachecache;
+ return map.d_cachecache;
}
bool MemRecursorCache::entryMatches(MemRecursorCache::OrderedTagIterator_t& entry, uint16_t qt, bool requireAuth, const ComboAddress& who)
{
+ // MUTEX SHOULD BE ACQUIRED
if (requireAuth && !entry->d_auth)
return false;
if(res) {
res->clear();
}
-
const uint16_t qtype = qt.getCode();
+
+ auto& map = getMap(qname);
+ const std::lock_guard<std::mutex> lock(map.mutex);
+
/* If we don't have any netmask-specific entries at all, let's just skip this
to be able to use the nice d_cachecache hack. */
- if (qtype != QType::ANY && !d_ecsIndex.empty()) {
+ if (qtype != QType::ANY && !map.d_ecsIndex.empty()) {
+
if (qtype == QType::ADDR) {
int32_t ret = -1;
- auto entryA = getEntryUsingECSIndex(now, qname, QType::A, requireAuth, who);
- if (entryA != d_cache.end()) {
- ret = handleHit(entryA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth);
+ auto entryA = getEntryUsingECSIndex(map, now, qname, QType::A, requireAuth, who);
+ if (entryA != map.d_map.end()) {
+ ret = handleHit(map, entryA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth);
}
- auto entryAAAA = getEntryUsingECSIndex(now, qname, QType::AAAA, requireAuth, who);
- if (entryAAAA != d_cache.end()) {
- int32_t ttdAAAA = handleHit(entryAAAA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth);
+ auto entryAAAA = getEntryUsingECSIndex(map, now, qname, QType::AAAA, requireAuth, who);
+ if (entryAAAA != map.d_map.end()) {
+ int32_t ttdAAAA = handleHit(map, entryAAAA, qname, who, res, signatures, authorityRecs, variable, state, wasAuth);
if (ret > 0) {
ret = std::min(ret, ttdAAAA);
} else {
return ret > 0 ? static_cast<int32_t>(ret-now) : ret;
}
else {
- auto entry = getEntryUsingECSIndex(now, qname, qtype, requireAuth, who);
- if (entry != d_cache.end()) {
- return static_cast<int32_t>(handleHit(entry, qname, who, res, signatures, authorityRecs, variable, state, wasAuth) - now);
+ auto entry = getEntryUsingECSIndex(map, now, qname, qtype, requireAuth, who);
+ if (entry != map.d_map.end()) {
+ return static_cast<int32_t>(handleHit(map, entry, qname, who, res, signatures, authorityRecs, variable, state, wasAuth) - now);
}
return -1;
}
}
- auto entries = getEntries(qname, qt);
+ auto entries = getEntries(map, qname, qt);
if(entries.first!=entries.second) {
for(auto i=entries.first; i != entries.second; ++i) {
- auto firstIndexIterator = d_cache.project<OrderedTag>(i);
+ auto firstIndexIterator = map.d_map.project<OrderedTag>(i);
if (i->d_ttd <= now) {
- moveCacheItemToFront<SequencedTag>(d_cache, firstIndexIterator);
+ moveCacheItemToFront<SequencedTag>(map.d_map, firstIndexIterator);
continue;
}
if (!entryMatches(firstIndexIterator, qtype, requireAuth, who))
continue;
- ttd = handleHit(firstIndexIterator, qname, who, res, signatures, authorityRecs, variable, state, wasAuth);
+ ttd = handleHit(map, firstIndexIterator, qname, who, res, signatures, authorityRecs, variable, state, wasAuth);
if(qt.getCode()!=QType::ANY && qt.getCode()!=QType::ADDR) // normally if we have a hit, we are done
break;
void 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)
{
- d_cachecachevalid = false;
+ auto& map = getMap(qname);
+ const std::lock_guard<std::mutex> lock(map.mutex);
+
+ map.d_cachecachevalid = false;
// cerr<<"Replacing "<<qname<<" for "<< (ednsmask ? ednsmask->toString() : "everyone") << endl;
if (ednsmask) {
ednsmask = ednsmask->getNormalized();
}
auto key = boost::make_tuple(qname, qt.getCode(), ednsmask ? *ednsmask : Netmask());
bool isNew = false;
- cache_t::iterator stored = d_cache.find(key);
- if (stored == d_cache.end()) {
- stored = d_cache.insert(CacheEntry(key, auth)).first;
+ cache_t::iterator stored = map.d_map.find(key);
+ if (stored == map.d_map.end()) {
+ stored = map.d_map.insert(CacheEntry(key, auth)).first;
isNew = true;
}
/* don't bother building an ecsIndex if we don't have any netmask-specific entries */
if (ednsmask && !ednsmask->empty()) {
auto ecsIndexKey = boost::make_tuple(qname, qt.getCode());
- auto ecsIndex = d_ecsIndex.find(ecsIndexKey);
- if (ecsIndex == d_ecsIndex.end()) {
- ecsIndex = d_ecsIndex.insert(ECSIndexEntry(qname, qt.getCode())).first;
+ auto ecsIndex = map.d_ecsIndex.find(ecsIndexKey);
+ if (ecsIndex == map.d_ecsIndex.end()) {
+ ecsIndex = map.d_ecsIndex.insert(ECSIndexEntry(qname, qt.getCode())).first;
}
ecsIndex->addMask(*ednsmask);
}
}
if (!isNew) {
- moveCacheItemToBack<SequencedTag>(d_cache, stored);
+ moveCacheItemToBack<SequencedTag>(map.d_map, stored);
}
- d_cache.replace(stored, ce);
+ map.d_map.replace(stored, ce);
}
-int MemRecursorCache::doWipeCache(const DNSName& name, bool sub, uint16_t qtype)
+size_t MemRecursorCache::doWipeCache(const DNSName& name, bool sub, uint16_t qtype)
{
- int count=0;
- d_cachecachevalid=false;
-
- if(!sub) {
- auto& idx = d_cache.get<NameOnlyHashedTag>();
- auto range = idx.equal_range(name);
- for(auto& i=range.first; i != range.second; ) {
- if (qtype == 0xffff || i->d_qtype == qtype) {
- count++;
- idx.erase(i++);
+ size_t count = 0;
+
+ if (!sub) {
+ for (auto& map : d_maps) {
+ const std::lock_guard<std::mutex> lock(map.mutex);
+ map.d_cachecachevalid = false;
+ auto& idx = map.d_map.get<NameOnlyHashedTag>();
+ count += idx.erase(name);
+ if (qtype == 0xffff) {
+ auto& ecsIdx = map.d_ecsIndex.get<OrderedTag>();
+ auto ecsIndexRange = ecsIdx.equal_range(name);
+ ecsIdx.erase(ecsIndexRange.first, ecsIndexRange.second);
}
else {
- ++i;
- }
- }
- if (qtype == 0xffff) {
- auto& ecsIdx = d_ecsIndex.get<OrderedTag>();
- auto ecsIndexRange = ecsIdx.equal_range(name);
- for(auto i = ecsIndexRange.first; i != ecsIndexRange.second; ) {
- ecsIdx.erase(i++);
- }
- }
- else {
- auto& ecsIdx = d_ecsIndex.get<HashedTag>();
- auto ecsIndexRange = ecsIdx.equal_range(tie(name, qtype));
- for(auto i = ecsIndexRange.first; i != ecsIndexRange.second; ) {
- ecsIdx.erase(i++);
+ auto& ecsIdx = map.d_ecsIndex.get<HashedTag>();
+ auto ecsIndexRange = ecsIdx.equal_range(tie(name, qtype));
+ ecsIdx.erase(ecsIndexRange.first, ecsIndexRange.second);
}
}
}
else {
- auto& idx = d_cache.get<OrderedTag>();
- auto& ecsIdx = d_ecsIndex.get<OrderedTag>();
-
- for(auto iter = idx.lower_bound(name); iter != idx.end(); ) {
- if(!iter->d_qname.isPartOf(name))
- break;
- if(iter->d_qtype == qtype || qtype == 0xffff) {
- count++;
- idx.erase(iter++);
- }
- else
- iter++;
- }
- for(auto iter = ecsIdx.lower_bound(name); iter != ecsIdx.end(); ) {
- if(!iter->d_qname.isPartOf(name))
- break;
- if(iter->d_qtype == qtype || qtype == 0xffff) {
- ecsIdx.erase(iter++);
+ for (auto& map : d_maps) {
+ const std::lock_guard<std::mutex> lock(map.mutex);
+ map.d_cachecachevalid = false;
+ auto& idx = map.d_map.get<OrderedTag>();
+ for (auto i = idx.lower_bound(name); i != idx.end(); ) {
+ if (!i->d_qname.isPartOf(name))
+ break;
+ if (i->d_qtype == qtype || qtype == 0xffff) {
+ count++;
+ i = idx.erase(i);
+ } else {
+ ++i;
+ }
}
- else {
- iter++;
+ auto& ecsIdx = map.d_ecsIndex.get<OrderedTag>();
+ for (auto i = ecsIdx.lower_bound(name); i != ecsIdx.end(); ) {
+ if (!i->d_qname.isPartOf(name))
+ break;
+ if (i->d_qtype == qtype || qtype == 0xffff) {
+ i = ecsIdx.erase(i);
+ } else {
+ ++i;
+ }
}
}
}
return count;
}
+// Name should be doLimitTime or so
bool MemRecursorCache::doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL)
{
- cache_t::iterator iter = d_cache.find(tie(name, qtype));
- if(iter == d_cache.end()) {
+ auto& map = getMap(name);
+ const std::lock_guard<std::mutex> lock(map.mutex);
+ cache_t::iterator iter = map.d_map.find(tie(name, qtype));
+ if (iter == map.d_map.end()) {
return false;
}
CacheEntry ce = *iter;
- if(ce.d_ttd < now)
+ if (ce.d_ttd < now)
return false; // would be dead anyhow
uint32_t maxTTL = static_cast<uint32_t>(ce.d_ttd - now);
- if(maxTTL > newTTL) {
- d_cachecachevalid=false;
+ if (maxTTL > newTTL) {
+ map.d_cachecachevalid = false;
time_t newTTD = now + newTTL;
-
- if(ce.d_ttd > newTTD) // do never renew expired or older TTLs
+ if (ce.d_ttd > newTTD) {
ce.d_ttd = newTTD;
-
-
- d_cache.replace(iter, ce);
+ map.d_map.replace(iter, ce);
+ }
return true;
}
return false;
bool MemRecursorCache::updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState, boost::optional<time_t> capTTD)
{
+ auto& map = getMap(qname);
+ const std::lock_guard<std::mutex> lock(map.mutex);
+
bool updated = false;
uint16_t qtype = qt.getCode();
- if (qtype != QType::ANY && qtype != QType::ADDR && !d_ecsIndex.empty()) {
- auto entry = getEntryUsingECSIndex(now, qname, qtype, requireAuth, who);
- if (entry == d_cache.end()) {
+ if (qtype != QType::ANY && qtype != QType::ADDR && !map.d_ecsIndex.empty()) {
+ auto entry = getEntryUsingECSIndex(map, now, qname, qtype, requireAuth, who);
+ if (entry == map.d_map.end()) {
return false;
}
return true;
}
- auto entries = getEntries(qname, qt);
+ auto entries = getEntries(map, qname, qt);
for(auto i = entries.first; i != entries.second; ++i) {
- auto firstIndexIterator = d_cache.project<OrderedTag>(i);
+ auto firstIndexIterator = map.d_map.project<OrderedTag>(i);
if (!entryMatches(firstIndexIterator, qtype, requireAuth, who))
continue;
uint64_t MemRecursorCache::doDump(int fd)
{
- auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(dup(fd), "w"), fclose);
+ int newfd = dup(fd);
+ if (newfd == -1) {
+ return 0;
+ }
+ auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(newfd, "w"), fclose);
if(!fp) { // dup probably failed
+ close(newfd);
return 0;
}
- fprintf(fp.get(), "; main record cache dump from thread follows\n;\n");
- const auto& sidx=d_cache.get<SequencedTag>();
- uint64_t count=0;
- time_t now=time(0);
- for(const auto i : sidx) {
- for(const auto j : i.d_records) {
- count++;
- try {
- 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());
- }
- catch(...) {
- fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str());
- }
- }
- for(const auto &sig : i.d_signatures) {
- count++;
- try {
- 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());
+ fprintf(fp.get(), "; main record cache dump follows\n;\n");
+ uint64_t count = 0;
+
+ for (auto& map : d_maps) {
+ const std::lock_guard<std::mutex> lock(map.mutex);
+ const auto& sidx = map.d_map.get<SequencedTag>();
+
+ time_t now = time(0);
+ for (const auto i : sidx) {
+ for (const auto j : i.d_records) {
+ count++;
+ try {
+ 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());
+ }
+ catch(...) {
+ fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str());
+ }
}
- catch(...) {
- fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str());
+ for (const auto &sig : i.d_signatures) {
+ count++;
+ try {
+ 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());
+ }
+ catch(...) {
+ fprintf(fp.get(), "; error printing '%s'\n", i.d_qname.empty() ? "EMPTY" : i.d_qname.toString().c_str());
+ }
}
}
}
return count;
}
-void MemRecursorCache::doPrune(unsigned int keep)
+void MemRecursorCache::doPrune(size_t keep)
{
- d_cachecachevalid=false;
-
- pruneCollection<SequencedTag>(*this, d_cache, keep);
+ //size_t maxCached = d_maxEntries;
+ size_t cacheSize = size();
+ pruneMutexCollectionsVector<SequencedTag>(*this, d_maps, keep, cacheSize);
}
#pragma once
#include <string>
#include <set>
+#include <mutex>
#include "dns.hh"
#include "qtype.hh"
#include "misc.hh"
class MemRecursorCache : public boost::noncopyable // : public RecursorCache
{
public:
- MemRecursorCache() : d_cachecachevalid(false)
- {
- cacheHits = cacheMisses = 0;
- }
- unsigned int size() const;
- unsigned int bytes() const;
- size_t ecsIndexSize() const;
+ MemRecursorCache(size_t mapsCount = 1024);
+ ~MemRecursorCache();
+
+ size_t size();
+ size_t bytes();
+ size_t ecsIndexSize();
int32_t get(time_t, const DNSName &qname, const QType& qt, bool requireAuth, vector<DNSRecord>* res, const ComboAddress& who, vector<std::shared_ptr<RRSIGRecordContent>>* signatures=nullptr, std::vector<std::shared_ptr<DNSRecord>>* authorityRecs=nullptr, bool* variable=nullptr, vState* state=nullptr, bool* wasAuth=nullptr);
void replace(time_t, 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=boost::none, vState state=Indeterminate);
- void doPrune(unsigned int keep);
+ void doPrune(size_t keep);
uint64_t doDump(int fd);
- int doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff);
+ size_t doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff);
bool doAgeCache(time_t now, const DNSName& name, uint16_t qtype, uint32_t newTTL);
bool updateValidationStatus(time_t now, const DNSName &qname, const QType& qt, const ComboAddress& who, bool requireAuth, vState newState, boost::optional<time_t> capTTD);
- uint64_t cacheHits, cacheMisses;
+ std::atomic<uint64_t> cacheHits{0}, cacheMisses{0};
private:
};
/* The ECS Index (d_ecsIndex) keeps track of whether there is any ECS-specific
- entry for a given (qname,qtype) entry in the cache (d_cache), and if so
+ entry for a given (qname,qtype) entry in the cache (d_map), and if so
provides a NetmaskTree of those ECS entries.
This allows figuring out quickly if we should look for an entry
specific to the requestor IP, and if so which entry is the most
Netmask lookupBestMatch(const ComboAddress& addr) const
{
- Netmask result = Netmask();
-
const auto best = d_nmt.lookup(addr);
if (best != nullptr) {
- result = best->first;
+ return best->first;
}
- return result;
+ return Netmask();
}
void addMask(const Netmask& nm) const
>
> ecsIndex_t;
- cache_t d_cache;
- ecsIndex_t d_ecsIndex;
- std::pair<MemRecursorCache::NameOnlyHashedTagIterator_t, MemRecursorCache::NameOnlyHashedTagIterator_t> d_cachecache;
- DNSName d_cachedqname;
- bool d_cachecachevalid;
+ struct MapCombo
+ {
+ MapCombo()
+ {
+ }
+ ~MapCombo()
+ {
+ }
+ MapCombo(const MapCombo &) = delete;
+ MapCombo & operator=(const MapCombo &) = delete;
+ cache_t d_map;
+ ecsIndex_t d_ecsIndex;
+ DNSName d_cachedqname;
+ std::pair<MemRecursorCache::NameOnlyHashedTagIterator_t, MemRecursorCache::NameOnlyHashedTagIterator_t> d_cachecache;
+ bool d_cachecachevalid{false};
+ std::mutex mutex;
+ };
+
+ vector<MapCombo> d_maps;
+ MapCombo& getMap(const DNSName &qname)
+ {
+ return d_maps[qname.hash() % d_maps.size()];
+ }
bool entryMatches(OrderedTagIterator_t& entry, uint16_t qt, bool requireAuth, const ComboAddress& who);
- std::pair<NameOnlyHashedTagIterator_t, NameOnlyHashedTagIterator_t> getEntries(const DNSName &qname, const QType& qt);
- cache_t::const_iterator getEntryUsingECSIndex(time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who);
- int32_t handleHit(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);
+ std::pair<NameOnlyHashedTagIterator_t, NameOnlyHashedTagIterator_t> getEntries(MapCombo& map, const DNSName &qname, const QType& qt);
+ cache_t::const_iterator getEntryUsingECSIndex(MapCombo& map, time_t now, const DNSName &qname, uint16_t qtype, bool requireAuth, const ComboAddress& who);
+ int32_t handleHit(MapCombo& map, 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);
public:
void preRemoval(const CacheEntry& entry)
}
auto key = tie(entry.d_qname, entry.d_qtype);
- auto ecsIndexEntry = d_ecsIndex.find(key);
- if (ecsIndexEntry != d_ecsIndex.end()) {
+ auto& map = getMap(entry.d_qname);
+ auto ecsIndexEntry = map.d_ecsIndex.find(key);
+ if (ecsIndexEntry != map.d_ecsIndex.end()) {
ecsIndexEntry->removeNetmask(entry.d_netmask);
if (ecsIndexEntry->isEmpty()) {
- d_ecsIndex.erase(ecsIndexEntry);
+ map.d_ecsIndex.erase(ecsIndexEntry);
}
}
}
MRC.replace(now, DNSName("hello"), QType(QType::A), records, signatures, authRecords, true, boost::none);
BOOST_CHECK_EQUAL(MRC.size(), 1U);
BOOST_CHECK_GT(MRC.bytes(), 1U);
- BOOST_CHECK_EQUAL(MRC.doWipeCache(DNSName("hello"), false, QType::A), 1);
+ BOOST_CHECK_EQUAL(MRC.doWipeCache(DNSName("hello"), false, QType::A), 1U);
BOOST_CHECK_EQUAL(MRC.size(), 0U);
BOOST_CHECK_EQUAL(MRC.bytes(), 0U);
uint64_t delcounter = 0;
for (delcounter = 0; delcounter < counter / 100; ++delcounter) {
DNSName a = DNSName("hello ") + DNSName(std::to_string(delcounter));
- BOOST_CHECK_EQUAL(MRC.doWipeCache(a, false, QType::A), 1);
+ BOOST_CHECK_EQUAL(MRC.doWipeCache(a, false, QType::A), 1U);
}
BOOST_CHECK_EQUAL(MRC.size(), counter - delcounter);
BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries)
{
- MemRecursorCache MRC;
+ MemRecursorCache MRC(1);
std::vector<DNSRecord> records;
std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries)
{
- MemRecursorCache MRC;
+ MemRecursorCache MRC(1);
std::vector<DNSRecord> records;
std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
{
- MemRecursorCache MRC;
+ MemRecursorCache MRC(1);
const DNSName power("powerdns.com.");
std::vector<DNSRecord> records;
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 5U);
/* wipe everything under the powerdns.com domain */
- BOOST_CHECK_EQUAL(MRC.doWipeCache(power, true), 3);
+ BOOST_CHECK_EQUAL(MRC.doWipeCache(power, true), 3U);
BOOST_CHECK_EQUAL(MRC.size(), 2U);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 2U);
/* now wipe the other domains too */
- BOOST_CHECK_EQUAL(MRC.doWipeCache(other1, true), 1);
+ BOOST_CHECK_EQUAL(MRC.doWipeCache(other1, true), 1U);
BOOST_CHECK_EQUAL(MRC.size(), 1U);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U);
- BOOST_CHECK_EQUAL(MRC.doWipeCache(other2, true), 1);
+ BOOST_CHECK_EQUAL(MRC.doWipeCache(other2, true), 1U);
BOOST_CHECK_EQUAL(MRC.size(), 0U);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
}
GlobalStateHolder<LuaConfigItems> g_luaconfs;
GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames;
GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks;
-thread_local std::unique_ptr<MemRecursorCache> t_RC{nullptr};
+std::unique_ptr<MemRecursorCache> s_RC{nullptr};
unsigned int g_numThreads = 1;
bool g_lowercaseOutgoing = false;
void primeHints(void)
{
vector<DNSRecord> nsset;
- if (!t_RC)
- t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
+ if (!s_RC)
+ s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
DNSRecord arr, aaaarr, nsrr;
nsrr.d_name = g_rootdnsname;
arr.d_content = std::make_shared<ARecordContent>(ComboAddress(rootIps4[c - 'a']));
vector<DNSRecord> aset;
aset.push_back(arr);
- t_RC->replace(time(nullptr), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
+ s_RC->replace(time(nullptr), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true); // auth, nuke it all
if (rootIps6[c - 'a'] != NULL) {
aaaarr.d_content = std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c - 'a']));
vector<DNSRecord> aaaaset;
aaaaset.push_back(aaaarr);
- t_RC->replace(time(nullptr), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
+ s_RC->replace(time(nullptr), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true);
}
nsset.push_back(nsrr);
}
- t_RC->replace(time(nullptr), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
+ s_RC->replace(time(nullptr), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false); // and stuff in the cache
}
LuaConfigItems::LuaConfigItems()
g_log.toConsole(Logger::Error);
}
- t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
+ s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
SyncRes::s_maxqperq = 50;
SyncRes::s_maxtotusec = 1000 * 7000;
/* should have been cached */
const ComboAddress who("192.0.2.128");
vector<DNSRecord> cached;
- BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
}
/* should have been cached because /24 is more specific than /16 but TTL limit is nof effective */
const ComboAddress who("192.0.2.128");
vector<DNSRecord> cached;
- BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
}
/* should have been cached */
const ComboAddress who("192.0.2.128");
vector<DNSRecord> cached;
- BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
}
/* should have been cached */
const ComboAddress who("192.0.2.128");
vector<DNSRecord> cached;
- BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
}
/* should have NOT been cached because TTL of 60 is too small and /24 is more specific than /16 */
const ComboAddress who("192.0.2.128");
vector<DNSRecord> cached;
- BOOST_REQUIRE_LT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_REQUIRE_LT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 0U);
}
std::vector<shared_ptr<RRSIGRecordContent>> sigs;
addRecordToList(records, target, QType::NS, "pdns-public-ns1.powerdns.com.", DNSResourceRecord::AUTHORITY, now + 3600);
- t_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
+ s_RC->replace(now, target, QType(QType::NS), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
std::vector<shared_ptr<RRSIGRecordContent>> sigs;
addRecordToList(records, target, QType::A, "192.0.2.1", DNSResourceRecord::ANSWER, now + 3600);
- t_RC->replace(now, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
+ s_RC->replace(now, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
const ComboAddress who;
vector<DNSRecord> cached;
- BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
BOOST_REQUIRE_GT(cached[0].d_ttl, now);
BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
cached.clear();
- BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
BOOST_REQUIRE_GT(cached[0].d_ttl, now);
BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
const ComboAddress who("192.0.2.128");
vector<DNSRecord> cached;
- BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
BOOST_REQUIRE_GT(cached[0].d_ttl, now);
BOOST_CHECK_EQUAL((cached[0].d_ttl - now), SyncRes::s_minimumECSTTL);
cached.clear();
- BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::NS), false, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
BOOST_REQUIRE_GT(cached[0].d_ttl, now);
BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_maxcachettl);
cached.clear();
- BOOST_REQUIRE_GT(t_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
BOOST_REQUIRE_GT(cached[0].d_ttl, now);
BOOST_CHECK_LE((cached[0].d_ttl - now), SyncRes::s_minimumTTL);
std::vector<shared_ptr<RRSIGRecordContent>> sigs;
addRecordToList(records, target, QType::A, "192.0.2.42", DNSResourceRecord::ANSWER, now - 60);
- t_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
+ s_RC->replace(now - 3600, target, QType(QType::A), records, sigs, vector<std::shared_ptr<DNSRecord>>(), true, boost::optional<Netmask>());
vector<DNSRecord> ret;
int res = sr->beginResolve(target, QType(QType::A), QClass::IN, ret);
/* check that we correctly cached only the answer entry, not the additional one */
const ComboAddress who;
vector<DNSRecord> cached;
- BOOST_REQUIRE_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_REQUIRE_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
BOOST_REQUIRE_EQUAL(QType(cached.at(0).d_type).getName(), QType(QType::A).getName());
BOOST_CHECK_EQUAL(getRR<ARecordContent>(cached.at(0))->getCA().toString(), ComboAddress("192.0.2.2").toString());
const ComboAddress who;
vector<DNSRecord> cached;
vector<std::shared_ptr<RRSIGRecordContent>> signatures;
- BOOST_REQUIRE_EQUAL(t_RC->get(now, target, QType(QType::A), false, &cached, who, &signatures), -1);
+ BOOST_REQUIRE_EQUAL(s_RC->get(now, target, QType(QType::A), false, &cached, who, &signatures), -1);
}
BOOST_AUTO_TEST_CASE(test_special_types)
const ComboAddress who;
vector<DNSRecord> cached;
vector<std::shared_ptr<RRSIGRecordContent>> signatures;
- BOOST_REQUIRE_EQUAL(t_RC->get(tnow, target, QType(QType::A), true, &cached, who, &signatures), 1);
+ BOOST_REQUIRE_EQUAL(s_RC->get(tnow, target, QType(QType::A), true, &cached, who, &signatures), 1);
BOOST_REQUIRE_EQUAL(cached.size(), 1U);
BOOST_REQUIRE_EQUAL(signatures.size(), 1U);
BOOST_CHECK_EQUAL((cached[0].d_ttl - tnow), 1);
vector<DNSRecord> cached;
bool wasAuth = false;
- auto ttl = t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth);
+ auto ttl = s_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth);
BOOST_REQUIRE_GE(ttl, 1);
BOOST_REQUIRE_LE(ttl, 42);
BOOST_CHECK_EQUAL(cached.size(), 1U);
cached.clear();
/* Also check that the the part in additional is still not auth */
- BOOST_REQUIRE_GE(t_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth), -1);
+ BOOST_REQUIRE_GE(s_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who, nullptr, nullptr, nullptr, nullptr, &wasAuth), -1);
BOOST_CHECK_EQUAL(cached.size(), 1U);
BOOST_CHECK_EQUAL(wasAuth, false);
}
const ComboAddress who;
vector<DNSRecord> cached;
- BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
cached.clear();
- BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::AAAA), true, &cached, who), 0);
- BOOST_CHECK_EQUAL(t_RC->get(now, DNSName("not-sanitization.powerdns.com."), QType(QType::DNAME), true, &cached, who), -1);
- BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::MX), true, &cached, who), 0);
- BOOST_CHECK_EQUAL(t_RC->get(now, DNSName("not-sanitization.powerdns.com."), QType(QType::SOA), true, &cached, who), -1);
- BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::TXT), false, &cached, who), 0);
- BOOST_CHECK_EQUAL(t_RC->get(now, DNSName("powerdns.com."), QType(QType::AAAA), false, &cached, who), -1);
+ BOOST_CHECK_LT(s_RC->get(now, target, QType(QType::AAAA), true, &cached, who), 0);
+ BOOST_CHECK_EQUAL(s_RC->get(now, DNSName("not-sanitization.powerdns.com."), QType(QType::DNAME), true, &cached, who), -1);
+ BOOST_CHECK_LT(s_RC->get(now, target, QType(QType::MX), true, &cached, who), 0);
+ BOOST_CHECK_EQUAL(s_RC->get(now, DNSName("not-sanitization.powerdns.com."), QType(QType::SOA), true, &cached, who), -1);
+ BOOST_CHECK_LT(s_RC->get(now, target, QType(QType::TXT), false, &cached, who), 0);
+ BOOST_CHECK_EQUAL(s_RC->get(now, DNSName("powerdns.com."), QType(QType::AAAA), false, &cached, who), -1);
}
BOOST_AUTO_TEST_CASE(test_records_sanitization_keep_relevant_additional_aaaa)
const ComboAddress who;
vector<DNSRecord> cached;
- BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
cached.clear();
/* not auth since it was in the additional section */
- BOOST_CHECK_LT(t_RC->get(now, target, QType(QType::AAAA), true, &cached, who), 0);
- BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::AAAA), false, &cached, who), 0);
+ BOOST_CHECK_LT(s_RC->get(now, target, QType(QType::AAAA), true, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, target, QType(QType::AAAA), false, &cached, who), 0);
}
BOOST_AUTO_TEST_CASE(test_records_sanitization_keep_glue)
const ComboAddress who;
vector<DNSRecord> cached;
- BOOST_CHECK_GT(t_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, target, QType(QType::A), true, &cached, who), 0);
cached.clear();
- BOOST_CHECK_GT(t_RC->get(now, DNSName("com."), QType(QType::NS), false, &cached, who), 0);
- BOOST_CHECK_GT(t_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who), 0);
- BOOST_CHECK_GT(t_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::AAAA), false, &cached, who), 0);
- BOOST_CHECK_GT(t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who), 0);
- BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns1.powerdns.com."), QType(QType::A), false, &cached, who), 0);
- BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns1.powerdns.com."), QType(QType::AAAA), false, &cached, who), 0);
- BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns2.powerdns.com."), QType(QType::A), false, &cached, who), 0);
- BOOST_CHECK_GT(t_RC->get(now, DNSName("pdns-public-ns2.powerdns.com."), QType(QType::AAAA), false, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, DNSName("com."), QType(QType::NS), false, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::A), false, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, DNSName("a.gtld-servers.net."), QType(QType::AAAA), false, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, DNSName("pdns-public-ns1.powerdns.com."), QType(QType::A), false, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, DNSName("pdns-public-ns1.powerdns.com."), QType(QType::AAAA), false, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, DNSName("pdns-public-ns2.powerdns.com."), QType(QType::A), false, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, DNSName("pdns-public-ns2.powerdns.com."), QType(QType::AAAA), false, &cached, who), 0);
}
BOOST_AUTO_TEST_CASE(test_records_sanitization_scrubs_ns_nxd)
const ComboAddress who;
vector<DNSRecord> cached;
- BOOST_CHECK_GT(t_RC->get(now, DNSName("powerdns.com."), QType(QType::SOA), true, &cached, who), 0);
+ BOOST_CHECK_GT(s_RC->get(now, DNSName("powerdns.com."), QType(QType::SOA), true, &cached, who), 0);
cached.clear();
- BOOST_CHECK_LT(t_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who), 0);
- BOOST_CHECK_LT(t_RC->get(now, DNSName("spoofed.ns."), QType(QType::A), false, &cached, who), 0);
- BOOST_CHECK_LT(t_RC->get(now, DNSName("spoofed.ns."), QType(QType::AAAA), false, &cached, who), 0);
+ BOOST_CHECK_LT(s_RC->get(now, DNSName("powerdns.com."), QType(QType::NS), false, &cached, who), 0);
+ BOOST_CHECK_LT(s_RC->get(now, DNSName("spoofed.ns."), QType(QType::A), false, &cached, who), 0);
+ BOOST_CHECK_LT(s_RC->get(now, DNSName("spoofed.ns."), QType(QType::AAAA), false, &cached, who), 0);
}
BOOST_AUTO_TEST_SUITE_END()
const vState validationState = Insecure;
vector<DNSRecord> nsset;
t_rootNSZones.clear();
- if(!t_RC)
- t_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
if(::arg()["hint-file"].empty()) {
DNSRecord arr, aaaarr, nsrr;
arr.d_content=std::make_shared<ARecordContent>(ComboAddress(rootIps4[c-'a']));
vector<DNSRecord> aset;
aset.push_back(arr);
- t_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState); // auth, nuke it all
+ s_RC->replace(time(0), DNSName(templ), QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState); // auth, nuke it all
if (rootIps6[c-'a'] != NULL) {
aaaarr.d_content=std::make_shared<AAAARecordContent>(ComboAddress(rootIps6[c-'a']));
vector<DNSRecord> aaaaset;
aaaaset.push_back(aaaarr);
- t_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState);
+ s_RC->replace(time(0), DNSName(templ), QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState);
}
nsset.push_back(nsrr);
if(rr.qtype.getCode()==QType::A) {
vector<DNSRecord> aset;
aset.push_back(DNSRecord(rr));
- t_RC->replace(time(0), rr.qname, QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState); // auth, etc see above
+ s_RC->replace(time(0), rr.qname, QType(QType::A), aset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState); // auth, etc see above
} else if(rr.qtype.getCode()==QType::AAAA) {
vector<DNSRecord> aaaaset;
aaaaset.push_back(DNSRecord(rr));
- t_RC->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState);
+ s_RC->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), true, boost::none, validationState);
} else if(rr.qtype.getCode()==QType::NS) {
rr.content=toLower(rr.content);
nsset.push_back(DNSRecord(rr));
insertIntoRootNSZones(rr.qname.getLastLabel());
}
}
- t_RC->doWipeCache(g_rootdnsname, false, QType::NS);
- t_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, boost::none, validationState); // and stuff in the cache
+ s_RC->doWipeCache(g_rootdnsname, false, QType::NS);
+ s_RC->replace(time(0), g_rootdnsname, QType(QType::NS), nsset, vector<std::shared_ptr<RRSIGRecordContent>>(), vector<std::shared_ptr<DNSRecord>>(), false, boost::none, validationState); // and stuff in the cache
}
// so make a local copy
set<DNSName> copy(t_rootNSZones);
for (const auto & qname: copy) {
- t_RC->doWipeCache(qname, false, QType::NS);
+ s_RC->doWipeCache(qname, false, QType::NS);
vector<DNSRecord> ret;
sr.beginResolve(qname, QType(QType::NS), QClass::IN, ret);
}
}
}
}
- } else {
- // We have some IPv4 records, don't bother with going out to get IPv6, but do consult the cache
- // Once IPv6 adoption matters, this needs to be revisited
- res_t cset;
- if (t_RC->get(d_now.tv_sec, qname, QType(QType::AAAA), false, &cset, d_cacheRemote) > 0) {
- for (const auto &i : cset) {
- if (i.d_ttl > (unsigned int)d_now.tv_sec ) {
- if (auto rec = getRR<AAAARecordContent>(i)) {
- ret.push_back(rec->getCA(53));
- }
+ }
+ } else {
+ // We have some IPv4 records, don't bother with going out to get IPv6, but do consult the cache
+ // Once IPv6 adoption matters, this needs to be revisited
+ res_t cset;
+ if (s_RC->get(d_now.tv_sec, qname, QType(QType::AAAA), false, &cset, d_cacheRemote) > 0) {
+ for (const auto &i : cset) {
+ if (i.d_ttl > (unsigned int)d_now.tv_sec ) {
+ if (auto rec = getRR<AAAARecordContent>(i)) {
+ ret.push_back(rec->getCA(53));
}
}
}
vector<DNSRecord> ns;
*flawedNSSet = false;
- if(t_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), false, &ns, d_cacheRemote) > 0) {
+ if(s_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), false, &ns, d_cacheRemote) > 0) {
bestns.reserve(ns.size());
for(auto k=ns.cbegin();k!=ns.cend(); ++k) {
const DNSRecord& dr=*k;
auto nrr = getRR<NSRecordContent>(dr);
- if(nrr && (!nrr->getNS().isPartOf(subdomain) || t_RC->get(d_now.tv_sec, nrr->getNS(), s_doIPv6 ? QType(QType::ADDR) : QType(QType::A),
+ if(nrr && (!nrr->getNS().isPartOf(subdomain) || s_RC->get(d_now.tv_sec, nrr->getNS(), s_doIPv6 ? QType(QType::ADDR) : QType(QType::A),
false, doLog() ? &aset : 0, d_cacheRemote) > 5)) {
bestns.push_back(dr);
LOG(prefix<<qname<<": NS (with ip, or non-glue) in cache for '"<<subdomain<<"' -> '"<<nrr->getNS()<<"'"<<endl);
void SyncRes::updateValidationStatusInCache(const DNSName &qname, const QType& qt, bool aa, vState newState) const
{
if (newState == Bogus) {
- t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, s_maxbogusttl + d_now.tv_sec);
+ s_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, s_maxbogusttl + d_now.tv_sec);
}
else {
- t_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, boost::none);
+ s_RC->updateValidationStatus(d_now.tv_sec, qname, qt, d_cacheRemote, aa, newState, boost::none);
}
}
LOG(prefix<<qname<<": Looking for CNAME cache hit of '"<<qname<<"|CNAME"<<"'"<<endl);
/* we don't require auth data for forward-recurse lookups */
- if (t_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
+ if (s_RC->get(d_now.tv_sec, qname, QType(QType::CNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
foundName = qname;
foundQT = QType(QType::CNAME);
}
if (dnameName == qname && qtype != QType::DNAME) { // The client does not want a DNAME, but we've reached the QNAME already. So there is no match
break;
}
- if (t_RC->get(d_now.tv_sec, dnameName, QType(QType::DNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
+ if (s_RC->get(d_now.tv_sec, dnameName, QType(QType::DNAME), !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &state, &wasAuth) > 0) {
foundName = dnameName;
foundQT = QType(QType::DNAME);
break;
uint32_t ttl=0;
uint32_t capTTL = std::numeric_limits<uint32_t>::max();
bool wasCachedAuth;
- if(t_RC->get(d_now.tv_sec, sqname, sqt, !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth) > 0) {
+ if(s_RC->get(d_now.tv_sec, sqname, sqt, !wasForwardRecurse && d_requireAuthData, &cset, d_cacheRemote, d_doDNSSEC ? &signatures : nullptr, d_doDNSSEC ? &authorityRecs : nullptr, &d_wasVariable, &cachedState, &wasCachedAuth) > 0) {
LOG(prefix<<sqname<<": Found cache hit for "<<sqt.getName()<<": ");
}
}
if (doCache) {
- t_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, recordState);
+ s_RC->replace(d_now.tv_sec, i->first.name, QType(i->first.type), i->second.records, i->second.signatures, authorityRecs, i->first.type == QType::DS ? true : isAA, i->first.place == DNSResourceRecord::ANSWER ? ednsmask : boost::none, recordState);
}
}
if(!auth.isRoot() && flawedNSSet) {
LOG(prefix<<qname<<": Ageing nameservers for level '"<<auth<<"', next query might succeed"<<endl);
- if(t_RC->doAgeCache(d_now.tv_sec, auth, QType::NS, 10))
+ if(s_RC->doAgeCache(d_now.tv_sec, auth, QType::NS, 10))
g_stats.nsSetInvalidations++;
}
return -1;
return a.domain < b.domain;
}
};
-extern thread_local std::unique_ptr<MemRecursorCache> t_RC;
+extern std::unique_ptr<MemRecursorCache> s_RC;
extern thread_local std::unique_ptr<RecursorPacketCache> t_packetCache;
typedef MTasker<PacketID,string> MT_t;
MT_t* getMT();