}
template<typename S, typename Index>
-std::pair<typename Index::iterator,bool>
-lruReplacingInsert(Index& i,const typename Index::value_type& x)
+bool lruReplacingInsert(Index& i, const typename Index::value_type& x)
{
- std::pair<typename Index::iterator,bool> res = i.insert(x);
- if (!res.second) {
- moveCacheItemToBack<S>(i, res.first);
- res.second = i.replace(res.first, x);
+ auto inserted = i.insert(x);
+ if (!inserted.second) {
+ moveCacheItemToBack<S>(i, inserted.first);
+ i.replace(inserted.first, x);
+ return false;
}
- return res;
+ return true;
}
thread_local std::unique_ptr<MT_t> MT; // the big MTasker
std::unique_ptr<MemRecursorCache> s_RC;
+std::unique_ptr<NegCache> s_negcache;
thread_local std::unique_ptr<RecursorPacketCache> t_packetCache;
thread_local FDMultiplexer* t_fdm{nullptr};
past.tv_sec -= 5;
if (last_prune < past) {
t_packetCache->doPruneTo(g_maxPacketCacheEntries / g_numWorkerThreads);
- SyncRes::pruneNegCache(g_maxCacheEntries / (g_numWorkerThreads * 10));
time_t limit;
if(!((cleanCounter++)%40)) { // this is a full scan!
if(isHandlerThread()) {
if (now.tv_sec - last_RC_prune > 5) {
s_RC->doPrune(g_maxCacheEntries);
+ s_negcache->prune(g_maxCacheEntries / 10);
last_RC_prune = now.tv_sec;
}
// XXX !!! global
}
s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache(::arg().asNum("record-cache-shards")));
+ s_negcache = std::unique_ptr<NegCache>(new NegCache(::arg().asNum("record-cache-shards")));
Logger::Urgency logUrgency = (Logger::Urgency)::arg().asNum("loglevel");
}
-static uint64_t dumpNegCache(NegCache& negcache, int fd)
+static uint64_t dumpNegCache(int fd)
{
auto fp = std::unique_ptr<FILE, int(*)(FILE*)>(fdopen(dup(fd), "w"), fclose);
if(!fp) { // dup probably failed
return 0;
}
uint64_t ret;
- fprintf(fp.get(), "; negcache dump from thread follows\n;\n");
- ret = negcache.dumpToFile(fp.get());
+ fprintf(fp.get(), "; negcache dump follows\n;\n");
+ ret = s_negcache->dumpToFile(fp.get());
return ret;
}
static uint64_t* pleaseDump(int fd)
{
- return new uint64_t(dumpNegCache(SyncRes::t_sstorage.negcache, fd) + t_packetCache->doDump(fd));
+ return new uint64_t(t_packetCache->doDump(fd));
}
static uint64_t* pleaseDumpEDNSMap(int fd)
return "Error opening dump file for writing: "+stringerror()+"\n";
uint64_t total = 0;
try {
- total = s_RC->doDump(fd) + broadcastAccFunction<uint64_t>([=]{ return pleaseDump(fd); });
+ total = s_RC->doDump(fd) + dumpNegCache(fd) + broadcastAccFunction<uint64_t>([=]{ return pleaseDump(fd); });
}
catch(...){}
uint64_t* pleaseWipeAndCountNegCache(const DNSName& canon, bool subtree)
{
- uint64_t ret = SyncRes::wipeNegCache(canon, subtree);
+ uint64_t ret = s_negcache->wipe(canon, subtree);
return new uint64_t(ret);
}
uint64_t* pleaseGetNegCacheSize()
{
- uint64_t tmp=(SyncRes::getNegCacheSize());
+ uint64_t tmp = s_negcache->size();
return new uint64_t(tmp);
}
#include "cachecleaner.hh"
#include "utility.hh"
+NegCache::NegCache(size_t mapsCount) : d_maps(mapsCount)
+{
+}
+
+NegCache::~NegCache()
+{
+ try {
+ typedef std::unique_ptr<lock> lock_t;
+ vector<lock_t> locks;
+ for (auto& map : d_maps) {
+ locks.push_back(lock_t(new lock(map)));
+ }
+ }
+ catch(...) {
+ }
+}
+
+size_t NegCache::size()
+{
+ size_t count = 0;
+ for (auto& map : d_maps) {
+ count += map.d_entriesCount;
+ }
+ return count;
+}
+
/*!
* Set ne to the NegCacheEntry for the last label in qname and return true if there
* was one.
// An 'ENT' QType entry, used as "whole name" in the neg-cache context.
static const QType qtnull(0);
DNSName lastLabel = qname.getLastLabel();
- negcache_t::const_iterator ni = d_negcache.find(tie(lastLabel, qtnull));
- while (ni != d_negcache.end() && ni->d_name == lastLabel && ni->d_auth.isRoot() && ni->d_qtype == qtnull) {
+ auto& map = getMap(lastLabel);
+ const lock l(map);
+
+ negcache_t::const_iterator ni = map.d_map.find(tie(lastLabel, qtnull));
+
+ while (ni != map.d_map.end() && ni->d_name == lastLabel && ni->d_auth.isRoot() && ni->d_qtype == qtnull) {
// We have something
- if ((uint32_t)now.tv_sec < ni->d_ttd) {
+ if (now.tv_sec < ni->d_ttd) {
ne = *ni;
- moveCacheItemToBack<SequenceTag>(d_negcache, ni);
+ moveCacheItemToBack<SequenceTag>(map.d_map, ni);
return true;
}
- moveCacheItemToFront<SequenceTag>(d_negcache, ni);
+ moveCacheItemToFront<SequenceTag>(map.d_map, ni);
++ni;
}
return false;
*/
bool NegCache::get(const DNSName& qname, const QType& qtype, const struct timeval& now, NegCacheEntry& ne, bool typeMustMatch)
{
- const auto& idx = d_negcache.get<2>();
+ auto& map = getMap(qname);
+ const lock l(map);
+
+ const auto& idx = map.d_map.get<2>();
auto range = idx.equal_range(qname);
auto ni = range.first;
// We have an entry
if ((!typeMustMatch && ni->d_qtype.getCode() == 0) || ni->d_qtype == qtype) {
// We match the QType or the whole name is denied
- auto firstIndexIterator = d_negcache.project<0>(ni);
+ auto firstIndexIterator = map.d_map.project<0>(ni);
- if ((uint32_t)now.tv_sec < ni->d_ttd) {
+ if (now.tv_sec < ni->d_ttd) {
// Not expired
ne = *ni;
- moveCacheItemToBack<SequenceTag>(d_negcache, firstIndexIterator);
+ moveCacheItemToBack<SequenceTag>(map.d_map, firstIndexIterator);
return true;
}
// expired
- moveCacheItemToFront<SequenceTag>(d_negcache, firstIndexIterator);
+ moveCacheItemToFront<SequenceTag>(map.d_map, firstIndexIterator);
}
++ni;
}
*/
void NegCache::add(const NegCacheEntry& ne)
{
- lruReplacingInsert<SequenceTag>(d_negcache, ne);
+ auto& map = getMap(ne.d_name);
+ const lock l(map);
+ bool inserted = lruReplacingInsert<SequenceTag>(map.d_map, ne);
+ if (inserted) {
+ map.d_entriesCount++;
+ }
}
/*!
* \param qtype The type of the entry to replace
* \param newState The new validation state
*/
-void NegCache::updateValidationStatus(const DNSName& qname, const QType& qtype, const vState newState, boost::optional<uint32_t> capTTD)
+void NegCache::updateValidationStatus(const DNSName& qname, const QType& qtype, const vState newState, boost::optional<time_t> capTTD)
{
- auto range = d_negcache.equal_range(tie(qname, qtype));
+ auto& map = getMap(qname);
+ const lock l(map);
+ auto range = map.d_map.equal_range(tie(qname, qtype));
if (range.first != range.second) {
range.first->d_validationState = newState;
*
* \param qname The name of the entries to be counted
*/
-uint64_t NegCache::count(const DNSName& qname) const
+size_t NegCache::count(const DNSName& qname)
{
- return d_negcache.count(tie(qname));
+ auto& map = getMap(qname);
+ const lock l(map);
+ return map.d_map.count(tie(qname));
}
/*!
* \param qname The name of the entries to be counted
* \param qtype The type of the entries to be counted
*/
-uint64_t NegCache::count(const DNSName& qname, const QType qtype) const
+size_t NegCache::count(const DNSName& qname, const QType qtype)
{
- return d_negcache.count(tie(qname, qtype));
+ auto& map = getMap(qname);
+ const lock l(map);
+ return map.d_map.count(tie(qname, qtype));
}
/*!
* \param name The DNSName of the entries to wipe
* \param subtree Should all entries under name be removed?
*/
-uint64_t NegCache::wipe(const DNSName& name, bool subtree)
+size_t NegCache::wipe(const DNSName& name, bool subtree)
{
- uint64_t ret(0);
+ size_t ret = 0;
if (subtree) {
- for (auto i = d_negcache.lower_bound(tie(name)); i != d_negcache.end();) {
- if (!i->d_name.isPartOf(name))
- break;
- i = d_negcache.erase(i);
- ret++;
+ for (auto& m : d_maps) {
+ const lock l(m);
+ for (auto i = m.d_map.lower_bound(tie(name)); i != m.d_map.end();) {
+ if (!i->d_name.isPartOf(name))
+ break;
+ i = m.d_map.erase(i);
+ ret++;
+ m.d_entriesCount--;
+ }
}
return ret;
}
- ret = count(name);
- auto range = d_negcache.equal_range(tie(name));
- d_negcache.erase(range.first, range.second);
+ auto& map = getMap(name);
+ const lock l(map);
+ auto range = map.d_map.equal_range(tie(name));
+ auto i = range.first;
+ while (i != range.second) {
+ i = map.d_map.erase(i);
+ ret++;
+ map.d_entriesCount--;
+ }
return ret;
}
*/
void NegCache::clear()
{
- d_negcache.clear();
+ for (auto& m : d_maps) {
+ const lock l(m);
+ m.d_map.clear();
+ m.d_entriesCount = 0;
+ }
}
/*!
*/
void NegCache::prune(size_t maxEntries)
{
- pruneCollection<SequenceTag>(*this, d_negcache, maxEntries, 200);
+ size_t cacheSize = size();
+ pruneMutexCollectionsVector<SequenceTag>(*this, d_maps, maxEntries, cacheSize);
}
/*!
*
* \param fp A pointer to an open FILE object
*/
-uint64_t NegCache::dumpToFile(FILE* fp)
+size_t NegCache::dumpToFile(FILE* fp)
{
- uint64_t ret(0);
+ size_t ret(0);
struct timeval now;
Utility::gettimeofday(&now, nullptr);
- negcache_sequence_t& sidx = d_negcache.get<SequenceTag>();
- for (const NegCacheEntry& ne : sidx) {
- ret++;
- fprintf(fp, "%s %" PRId64 " IN %s VIA %s ; (%s)\n", ne.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), ne.d_qtype.getName().c_str(), ne.d_auth.toString().c_str(), vStateToString(ne.d_validationState).c_str());
- for (const auto& rec : ne.authoritySOA.records) {
- fprintf(fp, "%s %" PRId64 " IN %s %s ; (%s)\n", rec.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), DNSRecordContent::NumberToType(rec.d_type).c_str(), rec.d_content->getZoneRepresentation().c_str(), vStateToString(ne.d_validationState).c_str());
- }
- for (const auto& sig : ne.authoritySOA.signatures) {
- fprintf(fp, "%s %" PRId64 " IN RRSIG %s ;\n", sig.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), sig.d_content->getZoneRepresentation().c_str());
- }
- for (const auto& rec : ne.DNSSECRecords.records) {
- fprintf(fp, "%s %" PRId64 " IN %s %s ; (%s)\n", rec.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), DNSRecordContent::NumberToType(rec.d_type).c_str(), rec.d_content->getZoneRepresentation().c_str(), vStateToString(ne.d_validationState).c_str());
- }
- for (const auto& sig : ne.DNSSECRecords.signatures) {
- fprintf(fp, "%s %" PRId64 " IN RRSIG %s ;\n", sig.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), sig.d_content->getZoneRepresentation().c_str());
+ for (auto& m : d_maps) {
+ const lock l(m);
+ auto& sidx = m.d_map.get<SequenceTag>();
+ for (const NegCacheEntry& ne : sidx) {
+ ret++;
+ fprintf(fp, "%s %" PRId64 " IN %s VIA %s ; (%s)\n", ne.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), ne.d_qtype.getName().c_str(), ne.d_auth.toString().c_str(), vStateToString(ne.d_validationState).c_str());
+ for (const auto& rec : ne.authoritySOA.records) {
+ fprintf(fp, "%s %" PRId64 " IN %s %s ; (%s)\n", rec.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), DNSRecordContent::NumberToType(rec.d_type).c_str(), rec.d_content->getZoneRepresentation().c_str(), vStateToString(ne.d_validationState).c_str());
+ }
+ for (const auto& sig : ne.authoritySOA.signatures) {
+ fprintf(fp, "%s %" PRId64 " IN RRSIG %s ;\n", sig.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), sig.d_content->getZoneRepresentation().c_str());
+ }
+ for (const auto& rec : ne.DNSSECRecords.records) {
+ fprintf(fp, "%s %" PRId64 " IN %s %s ; (%s)\n", rec.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), DNSRecordContent::NumberToType(rec.d_type).c_str(), rec.d_content->getZoneRepresentation().c_str(), vStateToString(ne.d_validationState).c_str());
+ }
+ for (const auto& sig : ne.DNSSECRecords.signatures) {
+ fprintf(fp, "%s %" PRId64 " IN RRSIG %s ;\n", sig.d_name.toString().c_str(), static_cast<int64_t>(ne.d_ttd - now.tv_sec), sig.d_content->getZoneRepresentation().c_str());
+ }
}
}
return ret;
class NegCache : public boost::noncopyable
{
public:
+
+ NegCache(size_t mapsCount = 1024);
+ ~NegCache();
+
struct NegCacheEntry
{
- DNSName d_name; // The denied name
- QType d_qtype; // The denied type
- DNSName d_auth; // The denying name (aka auth)
- mutable uint32_t d_ttd; // Timestamp when this entry should die
recordsAndSignatures authoritySOA; // The upstream SOA record and RRSIGs
recordsAndSignatures DNSSECRecords; // The upstream NSEC(3) and RRSIGs
+ DNSName d_name; // The denied name
+ DNSName d_auth; // The denying name (aka auth)
+ mutable time_t d_ttd; // Timestamp when this entry should die
mutable vState d_validationState{vState::Indeterminate};
- uint32_t getTTD() const
+ QType d_qtype; // The denied type
+ time_t getTTD() const
{
return d_ttd;
};
};
void add(const NegCacheEntry& ne);
- void updateValidationStatus(const DNSName& qname, const QType& qtype, const vState newState, boost::optional<uint32_t> capTTD);
+ void updateValidationStatus(const DNSName& qname, const QType& qtype, const vState newState, boost::optional<time_t> capTTD);
bool get(const DNSName& qname, const QType& qtype, const struct timeval& now, NegCacheEntry& ne, bool typeMustMatch = false);
bool getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& ne);
- uint64_t count(const DNSName& qname) const;
- uint64_t count(const DNSName& qname, const QType qtype) const;
+ size_t count(const DNSName& qname);
+ size_t count(const DNSName& qname, const QType qtype);
void prune(size_t maxEntries);
void clear();
- uint64_t dumpToFile(FILE* fd);
- uint64_t wipe(const DNSName& name, bool subtree = false);
-
- uint64_t size()
- {
- return d_negcache.size();
- };
+ size_t dumpToFile(FILE* fd);
+ size_t wipe(const DNSName& name, bool subtree = false);
+ size_t size();
void preRemoval(const NegCacheEntry& entry)
{
member<NegCacheEntry, DNSName, &NegCacheEntry::d_name>>>>
negcache_t;
- // Required for the cachecleaner
- typedef negcache_t::nth_index<1>::type negcache_sequence_t;
+ struct MapCombo
+ {
+ MapCombo() {}
+ MapCombo(const MapCombo &) = delete;
+ MapCombo & operator=(const MapCombo &) = delete;
+ negcache_t d_map;
+ std::mutex mutex;
+ std::atomic<uint64_t> d_entriesCount{0};
+ uint64_t d_contended_count{0};
+ uint64_t d_acquired_count{0};
+ bool d_cachecachevalid{false}; // XXX
+ };
+
+ vector<MapCombo> d_maps;
+
+ MapCombo& getMap(const DNSName &qname)
+ {
+ return d_maps[qname.hash() % d_maps.size()];
+ }
+public:
+ struct lock {
+ lock(MapCombo& map) : m(map.mutex)
+ {
+ if (!m.try_lock()) {
+ m.lock();
+ map.d_contended_count++;
+ }
+ map.d_acquired_count++;
+ }
+ ~lock() {
+ m.unlock();
+ }
+ private:
+ std::mutex &m;
+ };
- // Stores the negative cache entries
- negcache_t d_negcache;
};
BOOST_AUTO_TEST_CASE(test_dumpToFile)
{
- NegCache cache;
+ NegCache cache(1);
vector<string> expected;
expected.push_back("www1.powerdns.com. 600 IN TYPE0 VIA powerdns.com. ; (Indeterminate)\n");
expected.push_back("powerdns.com. 600 IN SOA ns1. hostmaster. 1 2 3 4 5 ; (Indeterminate)\n");
GlobalStateHolder<SuffixMatchNode> g_dontThrottleNames;
GlobalStateHolder<NetmaskGroup> g_dontThrottleNetmasks;
std::unique_ptr<MemRecursorCache> s_RC{nullptr};
+std::unique_ptr<NegCache> s_negcache{nullptr};
unsigned int g_numThreads = 1;
bool g_lowercaseOutgoing = false;
vector<DNSRecord> nsset;
if (!s_RC)
s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
+ if (!s_negcache)
+ s_negcache = std::unique_ptr<NegCache>(new NegCache());
DNSRecord arr, aaaarr, nsrr;
nsrr.d_name = g_rootdnsname;
}
s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
+ s_negcache = std::unique_ptr<NegCache>(new NegCache());
SyncRes::s_maxqperq = 50;
SyncRes::s_maxnsaddressqperq = 10;
sr->setLogMode(debug == false ? SyncRes::LogNone : SyncRes::Log);
SyncRes::setDomainMap(std::make_shared<SyncRes::domainmap_t>());
- SyncRes::clearNegCache();
+ s_negcache->clear();
}
void setDNSSECValidation(std::unique_ptr<SyncRes>& sr, const DNSSECMode& mode)
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
/* one for target1 and one for the entire TLD */
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 2U);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_REQUIRE_EQUAL(ret.size(), 1U);
BOOST_CHECK_LE(ret[0].d_ttl, SyncRes::s_maxnegttl);
/* one for target1 and one for the entire TLD */
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 2U);
/* we should have sent only one query */
BOOST_CHECK_EQUAL(queriesCount, 1U);
/* even with root-nx-trust on and a NX answer from the root,
we should not have cached the entire TLD this time. */
- BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_REQUIRE(ret[0].d_type == QType::A);
BOOST_CHECK(getRR<ARecordContent>(ret[0])->getCA() == ComboAddress("192.0.2.2"));
- BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 3U);
}
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
/* one for target1 */
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(ret.size(), 1U);
/* one for target1 */
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
/* we should have sent three queries */
BOOST_CHECK_EQUAL(queriesCount, 3U);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 2U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 2U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 2U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 2U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
// Now test without RFC 8020 to see the cache and query count grow
SyncRes::s_hardenNXD = SyncRes::HardenNXD::No;
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 2U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
// New query
ret.clear();
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 3U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 2U);
ret.clear();
res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 4U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 3U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 3U);
ret.clear();
res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 5U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 4U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 4U);
// reset
SyncRes::s_hardenNXD = SyncRes::HardenNXD::DNSSEC;
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
BOOST_CHECK_EQUAL(ret.size(), 6U);
BOOST_CHECK_EQUAL(queriesCount, 9U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
BOOST_CHECK_EQUAL(ret.size(), 6U);
BOOST_CHECK_EQUAL(queriesCount, 9U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
BOOST_CHECK_EQUAL(ret.size(), 6U);
BOOST_CHECK_EQUAL(queriesCount, 9U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
BOOST_CHECK_EQUAL(ret.size(), 6U);
BOOST_CHECK_EQUAL(queriesCount, 9U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
// Now test without RFC 8020 to see the cache and query count grow
SyncRes::s_hardenNXD = SyncRes::HardenNXD::No;
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
BOOST_CHECK_EQUAL(ret.size(), 6U);
BOOST_CHECK_EQUAL(queriesCount, 9U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
// New query
ret.clear();
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
BOOST_CHECK_EQUAL(ret.size(), 6U);
BOOST_CHECK_EQUAL(queriesCount, 11U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 2U);
ret.clear();
res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
BOOST_CHECK_EQUAL(ret.size(), 6U);
BOOST_CHECK_EQUAL(queriesCount, 13U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 3U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 3U);
ret.clear();
res = sr->beginResolve(target4, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
BOOST_CHECK_EQUAL(ret.size(), 6U);
BOOST_CHECK_EQUAL(queriesCount, 15U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 4U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 4U);
// reset
SyncRes::s_hardenNXD = SyncRes::HardenNXD::DNSSEC;
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 2U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 3U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target2, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 4U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 2U);
ret.clear();
res = sr->beginResolve(target3, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 4U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 2U);
}
BOOST_AUTO_TEST_CASE(test_rfc8020_nodata_bis)
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 2U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target1, QType(QType::A), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NoError);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 3U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 1U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
ret.clear();
res = sr->beginResolve(target2, QType(QType::TXT), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 4U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 2U);
ret.clear();
res = sr->beginResolve(target3, QType(QType::TXT), QClass::IN, ret);
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 4U);
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 2U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 2U);
}
BOOST_AUTO_TEST_CASE(test_skip_negcache_for_variable_response)
BOOST_CHECK_EQUAL(res, RCode::NXDomain);
BOOST_CHECK_EQUAL(ret.size(), 2U);
/* no negative cache entry because the response was variable */
- BOOST_CHECK_EQUAL(SyncRes::getNegCacheSize(), 0U);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 0U);
}
BOOST_AUTO_TEST_CASE(test_ecs_cache_limit_allowed)
/* === first without validation, then with (just-in-time validation) === */
/* clear the caches */
s_RC = std::unique_ptr<MemRecursorCache>(new MemRecursorCache());
- SyncRes::clearNegCache();
+ s_negcache = std::unique_ptr<NegCache>(new NegCache());
sr->setDNSSECValidationRequested(false);
primeHints();
/* check that the entry has not been negatively cached for longer than the RRSIG validity */
NegCache::NegCacheEntry ne;
- BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
- BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
+ BOOST_REQUIRE_EQUAL(s_negcache->get(target, QType(QType::A), sr->getNow(), ne), true);
BOOST_CHECK_EQUAL(ne.d_ttd, fixedNow + 1);
BOOST_CHECK_EQUAL(ne.d_validationState, vState::Secure);
BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
/* check that the entry has been negatively cached but not longer than s_maxbogusttl */
NegCache::NegCacheEntry ne;
- BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
- BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
+ BOOST_REQUIRE_EQUAL(s_negcache->get(target, QType(QType::A), sr->getNow(), ne), true);
BOOST_CHECK_EQUAL(ne.d_ttd, fixedNow + SyncRes::s_maxbogusttl);
BOOST_CHECK_EQUAL(ne.d_validationState, vState::Bogus);
BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 1U);
/* check that the entry has been negatively cached */
NegCache::NegCacheEntry ne;
- BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
- BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
+ BOOST_REQUIRE_EQUAL(s_negcache->get(target, QType(QType::A), sr->getNow(), ne), true);
BOOST_CHECK_EQUAL(ne.d_validationState, vState::Indeterminate);
BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1U);
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Secure);
BOOST_REQUIRE_EQUAL(ret.size(), 4U);
BOOST_CHECK_EQUAL(queriesCount, 4U);
- BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
- BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
+ BOOST_REQUIRE_EQUAL(s_negcache->get(target, QType(QType::A), sr->getNow(), ne), true);
BOOST_CHECK_EQUAL(ne.d_validationState, vState::Secure);
BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 1U);
/* check that the entry has not been negatively cached */
NegCache::NegCacheEntry ne;
- BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
- BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
+ BOOST_REQUIRE_EQUAL(s_negcache->get(target, QType(QType::A), sr->getNow(), ne), true);
BOOST_CHECK_EQUAL(ne.d_validationState, vState::Indeterminate);
BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0U);
BOOST_CHECK_EQUAL(sr->getValidationState(), vState::Insecure);
BOOST_REQUIRE_EQUAL(ret.size(), 1U);
BOOST_CHECK_EQUAL(queriesCount, 1U);
- BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
+ BOOST_REQUIRE_EQUAL(s_negcache->get(target, QType(QType::A), sr->getNow(), ne), true);
BOOST_CHECK_EQUAL(ne.d_validationState, vState::Insecure);
BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 0U);
}
BOOST_CHECK_EQUAL(queriesCount, 1U);
NegCache::NegCacheEntry ne;
- BOOST_CHECK_EQUAL(SyncRes::t_sstorage.negcache.size(), 1U);
- BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
+ BOOST_CHECK_EQUAL(s_negcache->size(), 1U);
+ BOOST_REQUIRE_EQUAL(s_negcache->get(target, QType(QType::A), sr->getNow(), ne), true);
BOOST_CHECK_EQUAL(ne.d_validationState, vState::Indeterminate);
BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1U);
BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
}
BOOST_CHECK_EQUAL(queriesCount, 4U);
- BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
+ BOOST_REQUIRE_EQUAL(s_negcache->get(target, QType(QType::A), sr->getNow(), ne), true);
BOOST_CHECK_EQUAL(ne.d_validationState, vState::Bogus);
BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1U);
BOOST_CHECK_EQUAL(record.d_ttl, SyncRes::s_maxbogusttl);
}
BOOST_CHECK_EQUAL(queriesCount, 4U);
- BOOST_REQUIRE_EQUAL(SyncRes::t_sstorage.negcache.get(target, QType(QType::A), sr->getNow(), ne), true);
+ BOOST_REQUIRE_EQUAL(s_negcache->get(target, QType(QType::A), sr->getNow(), ne), true);
BOOST_CHECK_EQUAL(ne.d_validationState, vState::Bogus);
BOOST_CHECK_EQUAL(ne.authoritySOA.records.size(), 1U);
BOOST_CHECK_EQUAL(ne.authoritySOA.signatures.size(), 1U);
}
if (state != vState::Indeterminate) {
/* validation succeeded, let's update the cache entry so we don't have to validate again */
- boost::optional<uint32_t> capTTD = boost::none;
+ boost::optional<time_t> capTTD = boost::none;
if (state == vState::Bogus) {
capTTD = d_now.tv_sec + s_maxbogusttl;
}
- t_sstorage.negcache.updateValidationStatus(ne.d_name, ne.d_qtype, state, capTTD);
+ s_negcache->updateValidationStatus(ne.d_name, ne.d_qtype, state, capTTD);
}
}
NegCache::NegCacheEntry ne;
if(s_rootNXTrust &&
- t_sstorage.negcache.getRootNXTrust(qname, d_now, ne) &&
+ s_negcache->getRootNXTrust(qname, d_now, ne) &&
ne.d_auth.isRoot() &&
!(wasForwardedOrAuthZone && !authname.isRoot())) { // when forwarding, the root may only neg-cache if it was forwarded to.
sttl = ne.d_ttd - d_now.tv_sec;
res = RCode::NXDomain;
giveNegative = true;
cachedState = ne.d_validationState;
- } else if (t_sstorage.negcache.get(qname, qtype, d_now, ne)) {
+ } else if (s_negcache->get(qname, qtype, d_now, ne)) {
/* If we are looking for a DS, discard NXD if auth == qname
and ask for a specific denial instead */
if (qtype != QType::DS || ne.d_qtype.getCode() || ne.d_auth != qname ||
- t_sstorage.negcache.get(qname, qtype, d_now, ne, true))
+ s_negcache->get(qname, qtype, d_now, ne, true))
{
res = RCode::NXDomain;
sttl = ne.d_ttd - d_now.tv_sec;
negCacheName.prependRawLabel(labels.back());
labels.pop_back();
while(!labels.empty()) {
- if (t_sstorage.negcache.get(negCacheName, QType(0), d_now, ne, true)) {
+ if (s_negcache->get(negCacheName, QType(0), d_now, ne, true)) {
if (ne.d_validationState == vState::Indeterminate && validationEnabled()) {
// LOG(prefix << negCacheName << " negatively cached and vState::Indeterminate, trying to validate NXDOMAIN" << endl);
// ...
We have a regression test making sure we do exactly that.
*/
if(!wasVariable() && newtarget.empty()) {
- t_sstorage.negcache.add(ne);
+ s_negcache->add(ne);
if(s_rootNXTrust && ne.d_auth.isRoot() && auth.isRoot() && lwr.d_aabit) {
ne.d_name = ne.d_name.getLastLabel();
- t_sstorage.negcache.add(ne);
+ s_negcache->add(ne);
}
}
LOG(prefix<<qname<<": got negative indication of DS record for '"<<newauth<<"'"<<endl);
if(!wasVariable()) {
- t_sstorage.negcache.add(ne);
+ s_negcache->add(ne);
}
if (qname == newauth && qtype == QType::DS) {
if(!wasVariable()) {
if(qtype.getCode()) { // prevents us from blacking out a whole domain
- t_sstorage.negcache.add(ne);
+ s_negcache->add(ne);
}
}
cont_t d_cont;
};
+extern std::unique_ptr<NegCache> s_negcache;
+
class SyncRes : public boost::noncopyable
{
public:
};
struct ThreadLocalStorage {
- NegCache negcache;
nsspeeds_t nsSpeeds;
throttle_t throttle;
ednsstatus_t ednsstatus;
{
return t_sstorage.fails.value(server);
}
-
- static void clearNegCache()
- {
- t_sstorage.negcache.clear();
- }
-
- static uint64_t getNegCacheSize()
- {
- return t_sstorage.negcache.size();
- }
-
- static void pruneNegCache(unsigned int maxEntries)
- {
- t_sstorage.negcache.prune(maxEntries);
- }
-
- static uint64_t wipeNegCache(const DNSName& name, bool subtree = false)
- {
- return t_sstorage.negcache.wipe(name, subtree);
- }
-
static void setDomainMap(std::shared_ptr<domainmap_t> newMap)
{
t_sstorage.domainmap = newMap;
}
-
static const std::shared_ptr<domainmap_t> getDomainMap()
{
return t_sstorage.domainmap;