]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: Add unit tests for the cache removal queue (back/front) 5416/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 21 Jun 2017 15:42:48 +0000 (17:42 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Wed, 21 Jun 2017 15:42:48 +0000 (17:42 +0200)
pdns/recursor_cache.cc
pdns/recursor_cache.hh
pdns/recursordist/test-recursorcache_cc.cc

index 7040e23ca9ecd03f10a50ce741a8e74ab1a4826e..113b88c744f2cfcb2ee14320e1c922f9a04644bb 100644 (file)
@@ -277,10 +277,15 @@ uint64_t MemRecursorCache::doDump(int fd)
   return count;
 }
 
-void MemRecursorCache::doPrune(void)
+void MemRecursorCache::doPrune(unsigned int keep)
 {
   d_cachecachevalid=false;
 
+  pruneCollection(d_cache, keep);
+}
+
+void MemRecursorCache::doPrune(void)
+{
   unsigned int maxCached=::arg().asNum("max-cache-entries") / g_numThreads;
-  pruneCollection(d_cache, maxCached);
+  doPrune(maxCached);
 }
index 0641ff53144a3cce4f2aa4bde757e5c5f7d44e89..30caffde4df35f39329dd97898a45d74cf7c25d7 100644 (file)
@@ -57,6 +57,7 @@ public:
 
   void replace(time_t, const DNSName &qname, const QType& qt,  const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, bool auth, boost::optional<Netmask> ednsmask=boost::none);
   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 1974bbea8ac317444d95d033e03d86012f068727..76cc071ff40da3bf26019921cdb30980df194d9a 100644 (file)
@@ -263,4 +263,214 @@ 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;
+  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, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, 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), &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), &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, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, 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), &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), &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), &retrieved, who, nullptr), -1);
+}
+
+BOOST_AUTO_TEST_CASE(test_RecursorCache_ExpungingValidEntries) {
+  MemRecursorCache MRC;
+
+  std::vector<DNSRecord> records;
+  std::vector<std::shared_ptr<RRSIGRecordContent>> signatures;
+  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, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, 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), &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), &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, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, 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, 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), &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), &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, true, boost::none);
+  records.clear();
+  records.push_back(dr2);
+  MRC.replace(now, power2, QType(dr2.d_type), records, signatures, 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), &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), &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), &retrieved, who, nullptr), -1);
+}
+
 BOOST_AUTO_TEST_SUITE_END()