]> granicus.if.org Git - pdns/commitdiff
rec: Add unit tests for the cache removal queue (back/front)
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 27 Jun 2017 11:08:43 +0000 (13:08 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 27 Jun 2017 12:38:06 +0000 (14:38 +0200)
(cherry picked from commit 7e6f71937f0ac7678b81013da7538ca1e65d779a)

pdns/recursor_cache.cc
pdns/recursor_cache.hh
pdns/recursordist/test-recursorcache_cc.cc

index d64067d428992fc0c53da6c8e2d14f659b44f160..486d03ec994af3b2fc2ef3ed5eca1675bcdfbea7 100644 (file)
@@ -461,10 +461,15 @@ uint64_t MemRecursorCache::doDump(int fd)
   return count;
 }
 
-void MemRecursorCache::doPrune(void)
+void MemRecursorCache::doPrune(unsigned int keep)
 {
   d_cachecachevalid=false;
 
+  pruneCollection(*this, d_cache, keep);
+}
+
+void MemRecursorCache::doPrune(void)
+{
   unsigned int maxCached=::arg().asNum("max-cache-entries") / g_numThreads;
-  pruneCollection(*this, d_cache, maxCached);
+  doPrune(maxCached);
 }
index 1fb43745403d7554847fc10ae423e18f527e7595..cd79a75a045ca6c23d3b3b4f3b1be84a7d993a6d 100644 (file)
@@ -60,6 +60,7 @@ public:
   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(void);
+  void doPrune(unsigned int keep);
   uint64_t doDump(int fd);
 
   int doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff);
index ec95ee015fb226671d362324134176c917d80366..f3095d2d08d4a9ae11ea26d15f74b342383349e6 100644 (file)
@@ -264,4 +264,216 @@ BOOST_AUTO_TEST_CASE(test_RecursorCacheSimple) {
   }
 }
 
+BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingExpiredEntries) {
+  MemRecursorCache MRC;
+
+  std::vector<DNSRecord> records;
+  std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
+  std::vector<std::shared_ptr<DNSRecord>> authRecs;
+  BOOST_CHECK_EQUAL(MRC.size(), 0);
+  time_t now = time(nullptr);
+  DNSName power1("powerdns.com.");
+  DNSName power2("powerdns-1.com.");
+  time_t ttd = now - 30;
+  std::vector<DNSRecord> retrieved;
+  ComboAddress who("192.0.2.1");
+
+  /* entry for power, which expired 30s ago */
+  DNSRecord dr1;
+  ComboAddress dr1Content("2001:DB8::1");
+  dr1.d_name = power1;
+  dr1.d_type = QType::AAAA;
+  dr1.d_class = QClass::IN;
+  dr1.d_content = std::make_shared<AAAARecordContent>(dr1Content);
+  dr1.d_ttl = static_cast<uint32_t>(ttd);
+  dr1.d_place = DNSResourceRecord::ANSWER;
+
+  /* entry for power1, which expired 30 ago too */
+  DNSRecord dr2;
+  ComboAddress dr2Content("2001:DB8::2");
+  dr2.d_name = power2;
+  dr2.d_type = QType::AAAA;
+  dr2.d_class = QClass::IN;
+  dr2.d_content = std::make_shared<AAAARecordContent>(dr2Content);
+  dr2.d_ttl = static_cast<uint32_t>(ttd);
+  dr2.d_place = DNSResourceRecord::ANSWER;
+
+  /* insert both entries */
+  records.push_back(dr1);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  BOOST_CHECK_EQUAL(MRC.size(), 2);
+
+  /* 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);
+  BOOST_CHECK_EQUAL(MRC.size(), 1);
+
+  /* the remaining entry should be power2, but to get it
+     we need to go back in the past a bit */
+  BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), 1);
+  BOOST_REQUIRE_EQUAL(retrieved.size(), 1);
+  BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(retrieved.at(0))->getCA().toString(), dr2Content.toString());
+  /* check that power1 is gone */
+  BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), -1);
+
+  /* clear everything up */
+  MRC.doWipeCache(DNSName("."), true);
+  BOOST_CHECK_EQUAL(MRC.size(), 0);
+  records.clear();
+
+  /* insert both entries back */
+  records.push_back(dr1);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  BOOST_CHECK_EQUAL(MRC.size(), 2);
+
+  /* trigger a miss (expired) for power2 */
+  BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), -now);
+
+  /* power2 should have been moved to the front of the expunge
+     queue, and should this time be removed first */
+  /* we ask that only entry remains in the cache */
+  MRC.doPrune(1);
+  BOOST_CHECK_EQUAL(MRC.size(), 1);
+
+  /* the remaining entry should be power1, but to get it
+     we need to go back in the past a bit */
+  BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), 1);
+  BOOST_REQUIRE_EQUAL(retrieved.size(), 1);
+  BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(retrieved.at(0))->getCA().toString(), dr1Content.toString());
+  /* check that power2 is gone */
+  BOOST_CHECK_EQUAL(MRC.get(ttd - 1, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), -1);
+}
+
+BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries) {
+  MemRecursorCache MRC;
+
+  std::vector<DNSRecord> records;
+  std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
+  std::vector<std::shared_ptr<DNSRecord>> authRecs;
+  BOOST_CHECK_EQUAL(MRC.size(), 0);
+  time_t now = time(nullptr);
+  DNSName power1("powerdns.com.");
+  DNSName power2("powerdns-1.com.");
+  time_t ttd = now + 30;
+  std::vector<DNSRecord> retrieved;
+  ComboAddress who("192.0.2.1");
+
+  /* entry for power, which will expire in 30s */
+  DNSRecord dr1;
+  ComboAddress dr1Content("2001:DB8::1");
+  dr1.d_name = power1;
+  dr1.d_type = QType::AAAA;
+  dr1.d_class = QClass::IN;
+  dr1.d_content = std::make_shared<AAAARecordContent>(dr1Content);
+  dr1.d_ttl = static_cast<uint32_t>(ttd);
+  dr1.d_place = DNSResourceRecord::ANSWER;
+
+  /* entry for power1, which will expire in 30s too */
+  DNSRecord dr2;
+  ComboAddress dr2Content("2001:DB8::2");
+  dr2.d_name = power2;
+  dr2.d_type = QType::AAAA;
+  dr2.d_class = QClass::IN;
+  dr2.d_content = std::make_shared<AAAARecordContent>(dr2Content);
+  dr2.d_ttl = static_cast<uint32_t>(ttd);
+  dr2.d_place = DNSResourceRecord::ANSWER;
+
+  /* insert both entries */
+  records.push_back(dr1);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  BOOST_CHECK_EQUAL(MRC.size(), 2);
+
+  /* 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);
+  BOOST_CHECK_EQUAL(MRC.size(), 1);
+
+  /* the remaining entry should be power2 */
+  BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), ttd-now);
+  BOOST_REQUIRE_EQUAL(retrieved.size(), 1);
+  BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(retrieved.at(0))->getCA().toString(), dr2Content.toString());
+  /* check that power1 is gone */
+  BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), -1);
+
+  /* clear everything up */
+  MRC.doWipeCache(DNSName("."), true);
+  BOOST_CHECK_EQUAL(MRC.size(), 0);
+  records.clear();
+
+  /* insert both entries back */
+  records.push_back(dr1);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  BOOST_CHECK_EQUAL(MRC.size(), 2);
+
+  /* replace the entry for power1 */
+  records.push_back(dr1);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  BOOST_CHECK_EQUAL(MRC.size(), 2);
+
+  /* the replaced entry for power1 should have been moved
+     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);
+  BOOST_CHECK_EQUAL(MRC.size(), 1);
+
+  /* the remaining entry should be power1 */
+  BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), ttd-now);
+  BOOST_REQUIRE_EQUAL(retrieved.size(), 1);
+  BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(retrieved.at(0))->getCA().toString(), dr1Content.toString());
+  /* check that power2 is gone */
+  BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), -1);
+
+  /* clear everything up */
+  MRC.doWipeCache(DNSName("."), true);
+  BOOST_CHECK_EQUAL(MRC.size(), 0);
+  records.clear();
+
+  /* insert both entries back */
+  records.push_back(dr1);
+  MRC.replace(now, power1, QType(dr1.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, authRecs, true, boost::none);
+  records.clear();
+  BOOST_CHECK_EQUAL(MRC.size(), 2);
+
+  /* get a hit for power1 */
+  BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), ttd-now);
+  BOOST_REQUIRE_EQUAL(retrieved.size(), 1);
+  BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(retrieved.at(0))->getCA().toString(), dr1Content.toString());
+
+  /* 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);
+  BOOST_CHECK_EQUAL(MRC.size(), 1);
+
+  /* the remaining entry should be power1 */
+  BOOST_CHECK_EQUAL(MRC.get(now, power1, QType(dr1.d_type), false, &retrieved, who, nullptr), ttd-now);
+  BOOST_REQUIRE_EQUAL(retrieved.size(), 1);
+  BOOST_CHECK_EQUAL(getRR<AAAARecordContent>(retrieved.at(0))->getCA().toString(), dr1Content.toString());
+  /* check that power2 is gone */
+  BOOST_CHECK_EQUAL(MRC.get(now, power2, QType(dr2.d_type), false, &retrieved, who, nullptr), -1);
+}
+
 BOOST_AUTO_TEST_SUITE_END()