]> granicus.if.org Git - pdns/commitdiff
implement packetcache pruning, hardcoded at 250k entries right now
authorBert Hubert <bert.hubert@netherlabs.nl>
Wed, 20 Jan 2010 19:51:45 +0000 (19:51 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Wed, 20 Jan 2010 19:51:45 +0000 (19:51 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1502 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/pdns_recursor.cc
pdns/recpacketcache.cc
pdns/recpacketcache.hh

index afaf0f9c8fc43260a73a51c6e3ddbcd51cb075ff..83c9d0f4edb13648e5471df8a43abcc8d6d90603 100644 (file)
@@ -1046,6 +1046,7 @@ try
     DTime dt;
     dt.setTimeval(now);
     t_RC->doPrune(); // this function is local to a thread, so fine anyhow
+    t_packetCache->doPruneTo();
     
     typedef SyncRes::negcache_t::nth_index<1>::type negcache_by_ttd_index_t;
     negcache_by_ttd_index_t& ttdindex=boost::multi_index::get<1>(SyncRes::t_sstorage->negcache); 
index 0393bda9b8f4597a8b1e2d7b1c1baaafe2b5c15b..11d1f4a3accaf658c70de8ec297d5bb1e6c2ef3f 100644 (file)
@@ -15,14 +15,28 @@ bool RecursorPacketCache::getResponsePacket(const std::string& queryPacket, time
   struct Entry e;
   e.d_packet=queryPacket;
   
+  
   packetCache_t::const_iterator iter = d_packetCache.find(e);
-  if(iter != d_packetCache.end() && (uint32_t)now < iter->d_ttd) {
+  
+  if(iter == d_packetCache.end()) {
+    d_misses++;
+    return false;
+  }
+  typedef packetCache_t::nth_index<1>::type sequence_t;
+  sequence_t& sidx=d_packetCache.get<1>();
+  sequence_t::iterator si=d_packetCache.project<1>(iter);
+    
+  if((uint32_t)now < iter->d_ttd) { // it is fresh!
     uint16_t id = ((struct dnsheader*)queryPacket.c_str())->id;
     *responsePacket = iter->d_packet;
     ((struct dnsheader*)responsePacket->c_str())->id=id;
     d_hits++;
+
+    sidx.relocate(sidx.end(), si); // put it at the end of the delete queue
+
     return true;
   }
+  sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue
   d_misses++;
   return false;
 }
@@ -33,9 +47,10 @@ void RecursorPacketCache::insertResponsePacket(const std::string& responsePacket
   e.d_packet = responsePacket;
   e.d_ttd = now+ttl;
   packetCache_t::iterator iter = d_packetCache.find(e);
+  
   if(iter != d_packetCache.end()) {
     iter->d_packet = responsePacket;
-    iter->d_ttd = now +ttl;
+    iter->d_ttd = now + ttl;
   }
   else 
     d_packetCache.insert(e);
@@ -45,3 +60,60 @@ uint64_t RecursorPacketCache::size()
 {
   return d_packetCache.size();
 }
+
+// this code is almost a copy of the one in recursor_cache.cc
+void RecursorPacketCache::doPruneTo(unsigned int maxCached)
+{
+  uint32_t now=(uint32_t)time(0);
+  unsigned int toTrim=0;
+  
+  unsigned int cacheSize=d_packetCache.size();
+
+  if(maxCached && cacheSize > maxCached) {
+    toTrim = cacheSize - maxCached;
+  }
+
+//  cout<<"Need to trim "<<toTrim<<" from cache to meet target!\n";
+
+  typedef packetCache_t::nth_index<1>::type sequence_t;
+  sequence_t& sidx=d_packetCache.get<1>();
+
+  unsigned int tried=0, lookAt, erased=0;
+
+  // two modes - if toTrim is 0, just look through 10000 records and nuke everything that is expired
+  // otherwise, scan first 5*toTrim records, and stop once we've nuked enough
+  if(toTrim)
+    lookAt=5*toTrim;
+  else
+    lookAt=cacheSize/10;
+
+
+  sequence_t::iterator iter=sidx.begin(), eiter;
+  for(; iter != sidx.end() && tried < lookAt ; ++tried) {
+    if(iter->d_ttd < now) { 
+      sidx.erase(iter++);
+      erased++;
+    }
+    else
+      ++iter;
+
+    if(toTrim && erased > toTrim)
+      break;
+  }
+
+  //cout<<"erased "<<erased<<" records based on ttd\n";
+  
+  if(erased >= toTrim) // done
+    return;
+
+
+  toTrim -= erased;
+
+  //if(toTrim)
+    // cout<<"Still have "<<toTrim - erased<<" entries left to erase to meet target\n"; 
+
+  eiter=iter=sidx.begin();
+  std::advance(eiter, toTrim); 
+  sidx.erase(iter, eiter);      // just lob it off from the beginning
+}
+
index aca00de7e6f86218ea79f59039afe2acc0399c90..320f84e44083386a455f4e66bfa2a04d923dbc40 100644 (file)
@@ -6,13 +6,22 @@
 #include "dns.hh"
 #include "namespaces.hh"
 #include <iostream>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
 
+
+using namespace ::boost::multi_index;
+
+//! Stores whole packets, ready for lobbing back at the client. Not threadsafe.
 class RecursorPacketCache
 {
 public:
   RecursorPacketCache();
   bool getResponsePacket(const std::string& queryPacket, time_t now, std::string* responsePacket);
   void insertResponsePacket(const std::string& responsePacket, time_t now, uint32_t ttd);
+  void doPruneTo(unsigned int maxSize=250000);
   
   void prune();
   uint64_t d_hits, d_misses;
@@ -27,8 +36,18 @@ private:
 
     inline bool operator<(const struct Entry& rhs) const;
   };
-  typedef std::set<struct Entry> packetCache_t;
-  packetCache_t d_packetCache;
+  
+  typedef multi_index_container<
+    Entry,
+    indexed_by  <
+                  ordered_unique<identity<Entry> >, 
+                  sequenced<> 
+               >
+  > packetCache_t;
+  
+   packetCache_t d_packetCache;
 };
 
 // needs to take into account: qname, qtype, opcode, rd, qdcount, EDNS size