]> granicus.if.org Git - pdns/commitdiff
move to multi_index_container to speed up prunes
authorBert Hubert <bert.hubert@netherlabs.nl>
Mon, 13 Mar 2006 19:40:12 +0000 (19:40 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Mon, 13 Mar 2006 19:40:12 +0000 (19:40 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@580 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/recursor_cache.cc
pdns/recursor_cache.hh

index d6a89a001a340015566755c811db2f2a579269a7..69ae274459f3a6bd0318ec5f7569bab44d426748 100644 (file)
@@ -7,7 +7,7 @@ using namespace std;
 using namespace boost;
 
 #include "config.h"
-
+#define GCC_SKIP_LOCKING
 #ifdef GCC_SKIP_LOCKING
 #include <bits/atomicity.h>
 // This code is ugly but does speedup the recursor tremendously on multi-processor systems, and even has a large effect (20, 30%) on uniprocessor 
@@ -60,7 +60,7 @@ unsigned int MemRecursorCache::size()
 {
   unsigned int ret=0;
   for(cache_t::const_iterator i=d_cache.begin(); i!=d_cache.end(); ++i) {
-    ret+=i->second.size();
+    ret+=i->d_name.size();
   }
   return ret;
 }
@@ -70,8 +70,8 @@ unsigned int MemRecursorCache::bytes()
   unsigned int ret=0;
 
   for(cache_t::const_iterator i=d_cache.begin(); i!=d_cache.end(); ++i) {
-    ret+=i->first.length();
-    for(vector<StoredRecord>::const_iterator j=i->second.begin(); j!= i->second.end(); ++j)
+    ret+=i->d_name.length();
+    for(vector<StoredRecord>::const_iterator j=i->d_records.begin(); j!= i->d_records.end(); ++j)
       ret+=j->size();
   }
   return ret;
@@ -88,9 +88,9 @@ int MemRecursorCache::get(time_t now, const string &qname, const QType& qt, set<
   if(res)
     res->clear();
 
-  if(j!=d_cache.end() && j->second.begin()->d_ttd>(unsigned int)now) {
+  if(j!=d_cache.end() && j->d_records.begin()->d_ttd>(unsigned int)now) {
     if(res) {
-      for(vector<StoredRecord>::const_iterator k=j->second.begin(); k != j->second.end(); ++k) {
+      for(vector<StoredRecord>::const_iterator k=j->d_records.begin(); k != j->d_records.end(); ++k) {
        DNSResourceRecord rr=String2DNSRR(qname, qt,  k->d_string, ttd=k->d_ttd); 
        //      cerr<<"Returning '"<<rr.content<<"'\n";
        res->insert(rr);
@@ -112,58 +112,109 @@ void MemRecursorCache::replace(const string &qname, const QType& qt,  const set<
   int code=qt.getCode();
   string key(toLowerCanonic(qname)); key.append(1,'|'); key.append((char*)&code, ((char*)&code)+2);
   cache_t::iterator stored=d_cache.find(key);
+  
   bool isNew=false;
   if(stored == d_cache.end()) {
-    stored=d_cache.insert(make_pair(key,vector<StoredRecord>())).first;
+    stored=d_cache.insert(CacheEntry(key,vector<StoredRecord>())).first;
     isNew=true;
   }
 
   pair<vector<StoredRecord>::iterator, vector<StoredRecord>::iterator> range;
 
   StoredRecord dr;
+  CacheEntry ce=*stored;
+
   for(set<DNSResourceRecord>::const_iterator i=content.begin(); i != content.end(); ++i) {
     dr.d_ttd=i->ttl;
     dr.d_string=DNSRR2String(*i);
     
     if(isNew) 
-      stored->second.push_back(dr);
+      ce.d_records.push_back(dr);
     else {
-      range=equal_range(stored->second.begin(), stored->second.end(), dr);
+      range=equal_range(ce.d_records.begin(), ce.d_records.end(), dr);
       
       if(range.first != range.second) {
        for(vector<StoredRecord>::iterator j=range.first ; j!=range.second; ++j)
          j->d_ttd=i->ttl;
       }
       else {
-       stored->second.push_back(dr);
-       sort(stored->second.begin(), stored->second.end());
+       ce.d_records.push_back(dr);
+       sort(ce.d_records.begin(), ce.d_records.end());
       }
     }
   }
   if(isNew) {
-    sort(stored->second.begin(), stored->second.end());
+    sort(ce.d_records.begin(), ce.d_records.end());
   }
-  if(stored->second.capacity() != stored->second.size())
-    vector<StoredRecord>(stored->second).swap(stored->second);
+
+  if(ce.d_records.capacity() != ce.d_records.size())
+    vector<StoredRecord>(ce.d_records).swap(ce.d_records);
+
+  d_cache.replace(stored, ce);
 }
   
 
 void MemRecursorCache::doPrune(void)
 {
   unsigned int names=0;
-  time_t now=time(0);
-  for(cache_t::iterator j=d_cache.begin();j!=d_cache.end();){
+  uint32_t now=(uint32_t)time(0);
+
+//  cout<<"Going to prune!\n";
+
+  typedef cache_t::nth_index<1>::type cache_by_ttd_t;
+  cache_by_ttd_t& ttdindex=d_cache.get<1>();
+
+  uint32_t looked(0), quickZonk(0), fullZonk(0), partialZonk(0), noZonk(0);
+  DTime dt;
+  dt.set(); 
+  cache_by_ttd_t::iterator j;
+  for(j=ttdindex.begin();j!=ttdindex.end();){
+    if(j->getTTD() > now) {
+//      cout<<"Done pruning, this record ("<<j->d_name<<") only needs to get killed in "<< j->getTTD() - now <<" seconds, rest will be later\n";
+      break;
+    }
+    else 
+       ;
+//      cout<<"Looking at '"<<j->d_name<<"', "<<now - j->getTTD()<<" seconds overdue!\n";
+    looked++;
+    if(j->d_records.size()==1) {
+//      ttdindex.erase(j++);
+      j++;
+      quickZonk++;
+      continue;
+    }
     predicate p(now);
-    j->second.erase(remove_if(j->second.begin(), j->second.end(), p), j->second.end());
+    CacheEntry ce=*j;
 
-    if(j->second.empty()) { // everything is gone
-      d_cache.erase(j++);
-      names++;
+    size_t before=ce.d_records.size();
+    ce.d_records.erase(remove_if(ce.d_records.begin(), ce.d_records.end(), p), ce.d_records.end());
+
+    if(ce.d_records.empty()) { // everything is gone
+//      cout<<"Zonked it entirely!\n";
+//      ttdindex.erase(j++);
+      j++;
+      fullZonk++;
     }
     else {
-      ++j;
+      if(ce.d_records.size()!=before) {
+//     cout<<"Zonked partially, putting back, new TTD: "<< ce.getTTD() - now<<endl;;
+       cache_by_ttd_t::iterator here=j++;
+       ttdindex.replace(here, ce);
+        partialZonk++;
+      }
+      else {
+       ++j;
+        noZonk++;
+       break;
+      }
     }
   }
+  
+//  cout<<"Walk took "<< dt.udiff()<<"usec\n";
+  dt.set();
+  ttdindex.erase(ttdindex.begin(), j);
+//  cout<<"Erase took "<< dt.udiff()<<" usec, looked: "<<looked<<", quick: "<<quickZonk<<", full: ";
+//  cout<<fullZonk<<", partial: "<<partialZonk<<", no: "<<noZonk<<"\n";
   //  cache_t(d_cache).swap(d_cache);
 }
 
index d222987270f40b99ab32a90e87400eebc6339cd2..34d95681a76897276cee8dea8f54f8ab5634496f 100644 (file)
@@ -1,12 +1,20 @@
 #ifndef RECURSOR_CACHE_HH
 #define RECURSOR_CACHE_HH
-#include <ext/hash_map>
 #include <string>
 #include <set>
 #include "dns.hh"
 #include "qtype.hh"
 #include <iostream>
 #include <boost/utility.hpp>
+#undef L
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+
+#define L theL()
+using namespace boost;
+using namespace ::boost::multi_index;
 
 namespace __gnu_cxx {
   template<>
@@ -34,8 +42,9 @@ private:
   struct StoredRecord
   {
     mutable uint32_t d_ttd;
-    //optString<> d_string;
+
     string d_string;
+
     bool operator<(const StoredRecord& rhs) const
     {
       return d_string < rhs.d_string;
@@ -55,12 +64,36 @@ private:
     
     bool operator()(const StoredRecord& sr) const
     {
-      return sr.d_ttd < d_limit;
+      return sr.d_ttd <= d_limit;
     }
     time_t d_limit;
   };
 
-  typedef __gnu_cxx::hash_map<string, vector<StoredRecord> > cache_t;
+  //   typedef __gnu_cxx::hash_map<string, vector<StoredRecord> > cache_t;
+  struct CacheEntry
+  {
+    CacheEntry(const string& name, const vector<StoredRecord>& records) : d_name(name), d_records(records)
+    {}
+    string d_name;
+    typedef vector<StoredRecord> records_t;
+    records_t d_records;
+    uint32_t getTTD() const
+    {
+      uint32_t earliest=numeric_limits<uint32_t>::max();
+      for(records_t::const_iterator i=d_records.begin(); i != d_records.end(); ++i)
+       earliest=min(earliest, i->d_ttd);
+      return earliest;
+    }
+  };
+
+  typedef multi_index_container<
+    CacheEntry,
+    indexed_by <
+                hashed_unique<member<CacheEntry,string,&CacheEntry::d_name> >,
+                ordered_non_unique<const_mem_fun<CacheEntry,uint32_t,&CacheEntry::getTTD> >
+               >
+  > cache_t;
+
 
 private:
   cache_t d_cache;