]> granicus.if.org Git - pdns/commitdiff
move recursor to 'hash_map'
authorBert Hubert <bert.hubert@netherlabs.nl>
Sat, 12 Nov 2005 15:17:49 +0000 (15:17 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Sat, 12 Nov 2005 15:17:49 +0000 (15:17 +0000)
remove optString 'optimization' which turned to make things worse
redo storage model of records

git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@548 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/dnspbench.cc
pdns/recursor_cache.cc
pdns/recursor_cache.hh

index 8fc69942a20f509455abf83a94d714dd75089981..441ef161a2f0f59f7f356116ae1a84cd8a40d54a 100644 (file)
@@ -5,14 +5,32 @@
 #include "dnsrecords.hh"
 #include "logger.hh"
 #include "statbag.hh"
+#include <set>
+#define BOOST_NO_MT
+
+#include <boost/pool/pool.hpp>
+#include <boost/pool/object_pool.hpp>
+
+#include <boost/pool/pool_alloc.hpp>
+using namespace boost;
 
 Logger L("dnspbench");
 StatBag S;
 
-
 int main(int argc, char** argv)
 try
 {
+  set<int, std::less<int>, boost::pool_allocator<int> > blah;
+
+  for(unsigned int n=0;n< 1000000;++n)
+    blah.insert(random());
+  cerr<<"Done inserting"<<endl;
+  string line;
+  getline(cin, line);
+  cerr<<"Done!"<<endl;
+
+  exit(0);
+
   dnsheader dnsheader;
   dnsheader.qdcount=htons(1);
   dnsheader.ancount=htons(1);
index c036a682c8ab3ce3982fd934458bdd4ca4e6d5bb..11422b34814e8e7b1cdd8fefe49a8cf724167b5b 100644 (file)
@@ -6,6 +6,32 @@
 using namespace std;
 using namespace boost;
 
+#include <bits/atomicity.h>
+
+#ifdef GCC_SKIP_LOGGING
+// This code is ugly but does speedup the recursor tremendously on multi-processor systems, and even has a large effect (20, 30%) on uniprocessor 
+namespace __gnu_cxx
+{
+  _Atomic_word
+  __attribute__ ((__unused__))
+  __exchange_and_add(volatile _Atomic_word* __mem, int __val)
+  {
+    register _Atomic_word __result;
+        __asm__ __volatile__ ("xadd{l} {%0,%1|%1,%0}"
+                          : "=r" (__result), "=m" (*__mem)
+                          : "0" (__val), "m" (*__mem));
+  }
+
+  void
+  __attribute__ ((__unused__))
+  __atomic_add(volatile _Atomic_word* __mem, int __val)
+  {
+    __asm__ __volatile__ ("add{l} {%1,%0|%0,%1}"
+                          : "=m" (*__mem) : "ir" (__val), "m" (*__mem));
+  }
+}
+#endif
+
 DNSResourceRecord String2DNSRR(const string& qname, const QType& qt, const string& serial, uint32_t ttd)
 {
   shared_ptr<DNSRecordContent> regen=DNSRecordContent::unserialize(qname,qt.getCode(), serial);
@@ -15,6 +41,8 @@ DNSResourceRecord String2DNSRR(const string& qname, const QType& qt, const strin
   rr.content=regen->getZoneRepresentation();
   rr.qtype=regen->d_qtype;
   //  cerr<<"Returning: '"<<rr.qname<<"' "<<rr.qtype.getName()<<"  "<<rr.ttl<<"  '"<<rr.content<<"'\n";
+  rr.content.reserve(0);
+  rr.qname.reserve(0);
   return rr;
 }
 
@@ -31,20 +59,39 @@ string DNSRR2String(const DNSResourceRecord& rr)
 
 unsigned int MemRecursorCache::size()
 {
-  return d_cache.size();
+  unsigned int ret=0;
+  for(cache_t::const_iterator i=d_cache.begin(); i!=d_cache.end(); ++i) {
+    ret+=i->second.size();
+  }
+  return ret;
+}
+
+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+=j->size();
+  }
+  return ret;
 }
 
+
 int MemRecursorCache::get(time_t now, const string &qname, const QType& qt, set<DNSResourceRecord>* res)
 {
   unsigned int ttd=0;
-  cache_t::const_iterator j=d_cache.find(toLowerCanonic(qname)+"|"+qt.getName());
+  uint16_t code=qt.getCode();
+  string key(toLowerCanonic(qname)); key.append(1,'|'); key.append((char*)&code, ((char*)&code)+2);
+  cache_t::const_iterator j=d_cache.find(key);
   //  cerr<<"looking up "<< toLowerCanonic(qname)+"|"+qt.getName() << endl;
   if(res)
     res->clear();
 
-  if(j!=d_cache.end() && j->first==toLowerCanonic(qname)+"|"+qt.getName() && j->second.begin()->d_ttd>(unsigned int)now) {
+  if(j!=d_cache.end() && j->second.begin()->d_ttd>(unsigned int)now) {
     if(res) {
-      for(set<StoredRecord>::const_iterator k=j->second.begin(); k != j->second.end(); ++k) {
+      for(vector<StoredRecord>::const_iterator k=j->second.begin(); k != j->second.end(); ++k) {
        DNSResourceRecord rr=String2DNSRR(qname, qt,  k->d_string, ttd=k->d_ttd); 
        //      cerr<<"Returning '"<<rr.content<<"'\n";
        res->insert(rr);
@@ -57,65 +104,59 @@ int MemRecursorCache::get(time_t now, const string &qname, const QType& qt, set<
   
   return -1;
 }
-  
 /* the code below is rather tricky - it basically replaces the stuff cached for qname by content, but it is special
    cased for when inserting identical records with only differing ttls, in which case the entry is not
    touched, but only given a new ttd */
 void MemRecursorCache::replace(const string &qname, const QType& qt,  const set<DNSResourceRecord>& content)
 {
-  set<StoredRecord>& stored=d_cache[toLowerCanonic(qname)+"|"+qt.getName()];
+  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;
+    isNew=true;
+  }
 
-  set<StoredRecord>::iterator k;
-  typedef vector<set<StoredRecord>::iterator> touched_t;
-  touched_t touched;
+  pair<vector<StoredRecord>::iterator, vector<StoredRecord>::iterator> range;
 
-  // walk through new content, encode it as new
   StoredRecord dr;
-
   for(set<DNSResourceRecord>::const_iterator i=content.begin(); i != content.end(); ++i) {
     dr.d_ttd=i->ttl;
     dr.d_string=DNSRR2String(*i);
-    k=stored.find(dr);
-    if(k!=stored.end()) {           // was it there already?
-      // cerr<<"updating record '"<<qname<<"' -> '"<<i->content<<"'\n";
-      k->d_ttd=i->ttl;              // update ttl
-      touched.push_back(k);         // note that this record is here to stay
-    }
+    
+    if(isNew) 
+      stored->second.push_back(dr);
     else {
-      //      cerr<<"inserting record '"<<qname<<"' -> '"<<i->content<<"'\n";
-      touched.push_back(stored.insert(dr).first);  // same thing
-    }
-  }
-  if(touched.size() != stored.size()) {
-    for(k=stored.begin(); k!=stored.end(); ) {                     // walk over the stored set of records
-      touched_t::const_iterator j;                                
-      for(j=touched.begin(); j!=touched.end() && *j != k ; ++j);   // walk over touched iterators
-      if(j==touched.end()) {                                       // this record was not there
-       //      DNSResourceRecord rr=String2DNSRR(qname, qt,  k->d_string, 0); 
-       //      cerr<<"removing from record '"<<qname<<"' '"<<rr.content<<"'\n";
-       //      k->d_string.prune();                                      
-       stored.erase(k++);                                         // cleanup
+      range=equal_range(stored->second.begin(), stored->second.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());
       }
-      else
-       ++k;
     }
   }
+  if(isNew) {
+    sort(stored->second.begin(), stored->second.end());
+  }
+  if(stored->second.capacity() != stored->second.size())
+    vector<StoredRecord>(stored->second).swap(stored->second);
 }
   
+
 void MemRecursorCache::doPrune(void)
 {
-  unsigned int names=0, records=0;
+  unsigned int names=0;
   time_t now=time(0);
   for(cache_t::iterator j=d_cache.begin();j!=d_cache.end();){
-    for(set<StoredRecord>::iterator k=j->second.begin();k!=j->second.end();) 
-      if((unsigned int)k->d_ttd < (unsigned int) now) {
-       //      k->d_string.prune();
-       j->second.erase(k++);
-       records++;
-      }
-      else
-       ++k;
-    
+    predicate p(now);
+    j->second.erase(remove_if(j->second.begin(), j->second.end(), p), j->second.end());
+
     if(j->second.empty()) { // everything is gone
       d_cache.erase(j++);
       names++;
@@ -124,5 +165,6 @@ void MemRecursorCache::doPrune(void)
       ++j;
     }
   }
+  //  cache_t(d_cache).swap(d_cache);
 }
 
index 5cb8070fd6844ba9052c43cdccd683e113439aa2..d222987270f40b99ab32a90e87400eebc6339cd2 100644 (file)
@@ -1,6 +1,6 @@
 #ifndef RECURSOR_CACHE_HH
 #define RECURSOR_CACHE_HH
-#include <map>
+#include <ext/hash_map>
 #include <string>
 #include <set>
 #include "dns.hh"
@@ -8,64 +8,23 @@
 #include <iostream>
 #include <boost/utility.hpp>
 
-template<int N=14>
-struct optString
-{
-  optString()
-  {
-    d_len=0;
-    *buf=0;
-  }
-
-  optString(const optString& rhs) : d_len(rhs.d_len)
-  {
-    memcpy(buf, rhs.buf, N);
-  }
-
-  optString(const string& str)
+namespace __gnu_cxx {
+  template<>
+  struct hash<string>
   {
-    if(str.size() < N-1) {
-      memcpy(buf, str.c_str(), str.size()+1);
-      d_len = str.size() + 1;
-    }
-    else {
-      new(buf) string(str);
-      d_len = 0;
+    size_t
+    operator()(const string& __s) const
+    { 
+      return __stl_hash_string(__s.c_str()); 
     }
-  }
-
-  operator string() const
-  {
-
-    if(d_len) {
-      return string(buf, buf + d_len - 1);
-    }
-    else {
-      return *((string*)buf);
-    }
-  }
-
-  void prune() const
-  {
-    //    cerr<<"did a prune!"<<endl;
-    if(!d_len)
-      ((string*)buf)->~string();
-  }
-
-  bool operator<(const optString& os) const
-  {
-    return (string)*this < (string) os;
-  }
-
-  char buf[N];
-  uint8_t d_len;
-} __attribute__((packed));
-
+  };
+}
 
 class MemRecursorCache : public boost::noncopyable //  : public RecursorCache
 {
 public:
   unsigned int size();
+  unsigned int bytes();
   int get(time_t, const string &qname, const QType& qt, set<DNSResourceRecord>* res);
   void replace(const string &qname, const QType& qt,  const set<DNSResourceRecord>& content);
   void doPrune(void);
@@ -75,15 +34,34 @@ private:
   struct StoredRecord
   {
     mutable uint32_t d_ttd;
-    //    optString<> d_string;
+    //optString<> d_string;
     string d_string;
     bool operator<(const StoredRecord& rhs) const
     {
       return d_string < rhs.d_string;
-      //      return make_pair(d_ttd, d_string) < make_pair(rhs.d_ttd, rhs.d_string);
+    }
+
+    unsigned int size() const
+    {
+      return 4+d_string.size();
     }
   };
-  typedef map<string, set<StoredRecord> > cache_t;
+
+  struct predicate
+  {
+    predicate(time_t limit) : d_limit(limit)
+    {
+    }
+    
+    bool operator()(const StoredRecord& sr) const
+    {
+      return sr.d_ttd < d_limit;
+    }
+    time_t d_limit;
+  };
+
+  typedef __gnu_cxx::hash_map<string, vector<StoredRecord> > cache_t;
+
 private:
   cache_t d_cache;
 };