}
template <typename S, typename C, typename T>
-uint64_t pruneMutexCollectionsVector(C& container, std::vector<T>& maps, uint64_t maxCached, uint64_t cacheSize)
+uint64_t pruneMutexCollectionsVector(time_t now, C& container, std::vector<T>& maps, uint64_t maxCached, uint64_t cacheSize)
{
- const time_t now = time(nullptr);
uint64_t totErased = 0;
uint64_t toTrim = 0;
uint64_t lookAt = 0;
*
* \param maxEntries The maximum number of entries that may exist in the cache.
*/
-void NegCache::prune(size_t maxEntries)
+void NegCache::prune(time_t now, size_t maxEntries)
{
size_t cacheSize = size();
- pruneMutexCollectionsVector<SequenceTag>(*this, d_maps, maxEntries, cacheSize);
+ pruneMutexCollectionsVector<SequenceTag>(now, *this, d_maps, maxEntries, cacheSize);
}
/*!
bool getRootNXTrust(const DNSName& qname, const struct timeval& now, NegCacheEntry& ne, bool serveStale, bool refresh);
size_t count(const DNSName& qname);
size_t count(const DNSName& qname, QType qtype);
- void prune(size_t maxEntries);
+ void prune(time_t now, size_t maxEntries);
void clear();
size_t doDump(int fd, size_t maxCacheEntries, time_t now = time(nullptr));
size_t wipe(const DNSName& name, bool subtree = false);
else if (info.isHandler()) {
if (g_packetCache) {
static PeriodicTask packetCacheTask{"packetCacheTask", 5};
- packetCacheTask.runIfDue(now, []() {
- g_packetCache->doPruneTo(g_maxPacketCacheEntries);
+ packetCacheTask.runIfDue(now, [now]() {
+ g_packetCache->doPruneTo(now.tv_sec, g_maxPacketCacheEntries);
});
}
static PeriodicTask recordCachePruneTask{"RecordCachePruneTask", 5};
- recordCachePruneTask.runIfDue(now, []() {
- g_recCache->doPrune(g_maxCacheEntries);
+ recordCachePruneTask.runIfDue(now, [now]() {
+ g_recCache->doPrune(now.tv_sec, g_maxCacheEntries);
});
static PeriodicTask negCachePruneTask{"NegCachePrunteTask", 5};
- negCachePruneTask.runIfDue(now, []() {
- g_negCache->prune(g_maxCacheEntries / 8);
+ negCachePruneTask.runIfDue(now, [now]() {
+ g_negCache->prune(now.tv_sec, g_maxCacheEntries / 8);
});
static PeriodicTask aggrNSECPruneTask{"AggrNSECPruneTask", 5};
assert(map.getEntriesCount() == shard->d_map.size()); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay): clib implementation
}
-void RecursorPacketCache::doPruneTo(size_t maxSize)
+void RecursorPacketCache::doPruneTo(time_t now, size_t maxSize)
{
size_t cacheSize = size();
- pruneMutexCollectionsVector<SequencedTag>(*this, d_maps, maxSize, cacheSize);
+ pruneMutexCollectionsVector<SequencedTag>(now, *this, d_maps, maxSize, cacheSize);
}
uint64_t RecursorPacketCache::doDump(int file)
bool getResponsePacket(unsigned int tag, const std::string& queryPacket, DNSName& qname, uint16_t* qtype, uint16_t* qclass, time_t now, std::string* responsePacket, uint32_t* age, vState* valState, uint32_t* qhash, OptPBData* pbdata, bool tcp);
void insertResponsePacket(unsigned int tag, uint32_t qhash, std::string&& query, const DNSName& qname, uint16_t qtype, uint16_t qclass, std::string&& responsePacket, time_t now, uint32_t ttl, const vState& valState, OptPBData&& pbdata, bool tcp);
- void doPruneTo(size_t maxSize);
+ void doPruneTo(time_t now, size_t maxSize);
uint64_t doDump(int file);
uint64_t doWipePacketCache(const DNSName& name, uint16_t qtype = 0xffff, bool subtree = false);
uint16_t MemRecursorCache::s_maxServedStaleExtensions;
+void MemRecursorCache::resetStaticsForTests()
+{
+ s_maxServedStaleExtensions = 0;
+ SyncRes::s_refresh_ttlperc = 0;
+ SyncRes::s_locked_ttlperc = 0;
+ SyncRes::s_minimumTTL = 0;
+}
+
MemRecursorCache::MemRecursorCache(size_t mapsCount) :
d_maps(mapsCount == 0 ? 1 : mapsCount)
{
return count;
}
-void MemRecursorCache::doPrune(size_t keep)
+void MemRecursorCache::doPrune(time_t now, size_t keep)
{
size_t cacheSize = size();
- pruneMutexCollectionsVector<SequencedTag>(*this, d_maps, keep, cacheSize);
+ pruneMutexCollectionsVector<SequencedTag>(now, *this, d_maps, keep, cacheSize);
}
namespace boost
void replace(time_t, const DNSName& qname, const QType qt, const vector<DNSRecord>& content, const vector<shared_ptr<const RRSIGRecordContent>>& signatures, const std::vector<std::shared_ptr<DNSRecord>>& authorityRecs, bool auth, const DNSName& authZone, boost::optional<Netmask> ednsmask = boost::none, const OptTag& routingTag = boost::none, vState state = vState::Indeterminate, boost::optional<ComboAddress> from = boost::none, bool refresh = false, time_t ttl_time = time(nullptr));
- void doPrune(size_t keep);
+ void doPrune(time_t now, size_t keep);
uint64_t doDump(int fd, size_t maxCacheEntries);
size_t doWipeCache(const DNSName& name, bool sub, QType qtype = 0xffff);
pdns::stat_t cacheHits{0}, cacheMisses{0};
+ static void resetStaticsForTests();
+
private:
struct CacheEntry
{
BOOST_CHECK_EQUAL(cache.size(), 400U);
- cache.prune(100);
+ cache.prune(now.tv_sec, 100);
BOOST_CHECK_EQUAL(cache.size(), 100U);
}
BOOST_CHECK_EQUAL(cache.size(), 400U);
- cache.prune(100);
+ cache.prune(now.tv_sec, 100);
BOOST_CHECK_EQUAL(cache.size(), 100U);
}
/* power2 has been inserted more recently, so it should be
removed last */
- cache.prune(1);
+ cache.prune(now.tv_sec, 1);
BOOST_CHECK_EQUAL(cache.size(), 1U);
NegCache::NegCacheEntry got;
/* power2 has been updated more recently, so it should be
removed last */
- cache.prune(1);
+ cache.prune(now.tv_sec, 1);
BOOST_CHECK_EQUAL(cache.size(), 1U);
got = NegCache::NegCacheEntry();
string qpacket((const char*)&packet[0], packet.size());
pw.startRecord(qname, QType::A, ttd);
- BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag, qpacket, time(nullptr), &fpacket, &age, &qhash), false);
- BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &qhash), false);
+ time_t now = time(nullptr);
+ BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag, qpacket, now, &fpacket, &age, &qhash), false);
+ BOOST_CHECK_EQUAL(rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, now, &fpacket, &age, &qhash), false);
ARecordContent ar("127.0.0.1");
ar.toPacket(pw);
pw.commit();
string rpacket((const char*)&packet[0], packet.size());
- rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), time(0), ttd, vState::Indeterminate, boost::none, false);
+ rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, boost::none, false);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
- rpc.doPruneTo(0);
+ rpc.doPruneTo(now, 0);
BOOST_CHECK_EQUAL(rpc.size(), 0U);
- rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), time(0), ttd, vState::Indeterminate, boost::none, false);
+ rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, boost::none, false);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
rpc.doWipePacketCache(qname);
BOOST_CHECK_EQUAL(rpc.size(), 0U);
- rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), time(0), ttd, vState::Indeterminate, boost::none, false);
+ rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), now, ttd, vState::Indeterminate, boost::none, false);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
uint32_t qhash2 = 0;
- bool found = rpc.getResponsePacket(tag, qpacket, time(nullptr), &fpacket, &age, &qhash2);
+ bool found = rpc.getResponsePacket(tag, qpacket, now, &fpacket, &age, &qhash2);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK_EQUAL(qhash, qhash2);
BOOST_CHECK_EQUAL(fpacket, rpacket);
- found = rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &qhash2);
+ found = rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, now, &fpacket, &age, &qhash2);
BOOST_CHECK_EQUAL(found, true);
BOOST_CHECK_EQUAL(qhash, qhash2);
BOOST_CHECK_EQUAL(fpacket, rpacket);
pw2.getHeader()->id = dns_random_uint16();
qpacket.assign((const char*)&packet[0], packet.size());
- found = rpc.getResponsePacket(tag, qpacket, time(nullptr), &fpacket, &age, &qhash);
+ found = rpc.getResponsePacket(tag, qpacket, now, &fpacket, &age, &qhash);
BOOST_CHECK_EQUAL(found, false);
- found = rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, time(nullptr), &fpacket, &age, &qhash);
+ found = rpc.getResponsePacket(tag, qpacket, qname, QType::A, QClass::IN, now, &fpacket, &age, &qhash);
BOOST_CHECK_EQUAL(found, false);
rpc.doWipePacketCache(DNSName("com"), 0xffff, true);
rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), future, ttd, vState::Indeterminate, boost::none, false);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
- rpc.doPruneTo(0);
+ rpc.doPruneTo(time(nullptr), 0);
BOOST_CHECK_EQUAL(rpc.size(), 0U);
rpc.insertResponsePacket(tag, qhash, string(qpacket), qname, QType::A, QClass::IN, string(rpacket), future, ttd, vState::Indeterminate, boost::none, false);
BOOST_CHECK_EQUAL(rpc.size(), 1U);
BOOST_CHECK_EQUAL(rpc.size(), 2U);
/* remove all responses from the cache */
- rpc.doPruneTo(0);
+ rpc.doPruneTo(time(nullptr), 0);
BOOST_CHECK_EQUAL(rpc.size(), 0U);
/* reinsert both */
BOOST_CHECK_EQUAL(rpc.size(), 2U);
/* remove all responses from the cache */
- rpc.doPruneTo(0);
+ rpc.doPruneTo(time(nullptr), 0);
BOOST_CHECK_EQUAL(rpc.size(), 0U);
/* reinsert both */
static void simple(time_t now)
{
+ MemRecursorCache::resetStaticsForTests();
MemRecursorCache MRC;
std::vector<DNSRecord> records;
BOOST_AUTO_TEST_CASE(test_RecursorCacheGhost)
{
+ MemRecursorCache::resetStaticsForTests();
MemRecursorCache MRC;
std::vector<DNSRecord> records;
{
// Test #12140: as QM does a best NS lookup and then uses it, incoming infra records should update
// cache, otherwise they might expire in-between.
+ MemRecursorCache::resetStaticsForTests();
MemRecursorCache MRC;
std::vector<DNSRecord> records;
BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries)
{
+ MemRecursorCache::resetStaticsForTests();
MemRecursorCache MRC(1);
std::vector<DNSRecord> records;
/* we ask that 10 entries remain in the cache, this is larger than
the cache size (2), so 1 entry will be looked at as the code
rounds up the 10% of entries per shard to look at */
- MRC.doPrune(10);
+ MRC.doPrune(now, 10);
BOOST_CHECK_EQUAL(MRC.size(), 1U);
/* the remaining entry should be power2, but to get it
/* we ask that 10 entries remain in the cache, this is larger than
the cache size (2), so 1 entry will be looked at as the code
rounds up the 10% of entries per shard to look at */
- MRC.doPrune(10);
+ MRC.doPrune(now, 10);
BOOST_CHECK_EQUAL(MRC.size(), 1U);
/* the remaining entry should be power1, but to get it
BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries)
{
+ MemRecursorCache::resetStaticsForTests();
MemRecursorCache MRC(1);
std::vector<DNSRecord> records;
/* the one for power2 having been inserted
more recently should be removed last */
/* we ask that only entry remains in the cache */
- MRC.doPrune(1);
+ MRC.doPrune(now, 1);
BOOST_CHECK_EQUAL(MRC.size(), 1U);
/* the remaining entry should be power2 */
to the back of the expunge queue, so power2 should be at the front
and should this time be removed first */
/* we ask that only entry remains in the cache */
- MRC.doPrune(1);
+ MRC.doPrune(now, 1);
BOOST_CHECK_EQUAL(MRC.size(), 1U);
/* the remaining entry should be power1 */
/* the entry for power1 should have been moved to the back of the expunge queue
due to the hit, so power2 should be at the front and should this time be removed first */
/* we ask that only entry remains in the cache */
- MRC.doPrune(1);
+ MRC.doPrune(now, 1);
BOOST_CHECK_EQUAL(MRC.size(), 1U);
/* the remaining entry should be power1 */
/* check that power2 is gone */
BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), MemRecursorCache::None, &retrieved, who, boost::none, nullptr), -1);
- MRC.doPrune(0);
+ MRC.doPrune(now, 0);
BOOST_CHECK_EQUAL(MRC.size(), 0U);
/* add a lot of netmask-specific entries */
/* remove a bit less than half of them */
size_t keep = 129;
- MRC.doPrune(keep);
+ MRC.doPrune(now, keep);
BOOST_CHECK_EQUAL(MRC.size(), keep);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U);
BOOST_CHECK_EQUAL(found, keep);
/* remove the rest */
- MRC.doPrune(0);
+ MRC.doPrune(now, 0);
BOOST_CHECK_EQUAL(MRC.size(), 0U);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
}
BOOST_AUTO_TEST_CASE(test_RecursorCacheECSIndex)
{
+ MemRecursorCache::resetStaticsForTests();
MemRecursorCache MRC(1);
const DNSName power("powerdns.com.");
BOOST_CHECK_EQUAL(getRR<ARecordContent>(retrieved.at(0))->getCA().toString(), dr1Content.toString());
/* wipe everything */
- MRC.doPrune(0);
+ MRC.doPrune(now, 0);
BOOST_CHECK_EQUAL(MRC.size(), 0U);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
BOOST_CHECK_EQUAL(getRR<ARecordContent>(retrieved.at(0))->getCA().toString(), dr1Content.toString());
/* wipe everything */
- MRC.doPrune(0);
+ MRC.doPrune(now, 0);
BOOST_CHECK_EQUAL(MRC.size(), 0U);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
BOOST_CHECK_EQUAL(MRC.size(), 2U);
/* wipe everything */
- MRC.doPrune(0);
+ MRC.doPrune(now, 0);
BOOST_CHECK_EQUAL(MRC.size(), 0U);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 1U);
/* wipe everything */
- MRC.doPrune(0);
+ MRC.doPrune(now, 0);
BOOST_CHECK_EQUAL(MRC.size(), 0U);
BOOST_CHECK_EQUAL(MRC.ecsIndexSize(), 0U);
}
BOOST_AUTO_TEST_CASE(test_RecursorCache_Wipe)
{
+ MemRecursorCache::resetStaticsForTests();
MemRecursorCache MRC;
const DNSName power("powerdns.com.");
BOOST_AUTO_TEST_CASE(test_RecursorCacheTagged)
{
+ MemRecursorCache::resetStaticsForTests();
MemRecursorCache MRC;
const DNSName authZone(".");