Changeset 1374

Show
Ignore:
Timestamp:
07/28/09 22:33:20 (4 years ago)
Author:
ahu
Message:

clean up recursor cache and make it thread safe, plus change the core logic

Location:
trunk/pdns/pdns
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/pdns/pdns/recursor_cache.cc

    r1265 r1374  
    66#include "arguments.hh" 
    77#include "syncres.hh" 
     8#include "lock.hh" 
     9#include "recursor_cache.hh" 
    810 
    911using namespace std; 
     
    1214#include "config.h" 
    1315 
    14 #ifdef GCC_SKIP_LOCKING 
    15 #include <bits/atomicity.h> 
    16 // This code is ugly but does speedup the recursor tremendously on multi-processor systems, and even has a large effect (20, 30%) on uniprocessor  
    17 namespace __gnu_cxx 
    18 { 
    19   _Atomic_word 
    20   __attribute__ ((__unused__)) 
    21   __exchange_and_add(volatile _Atomic_word* __mem, int __val) 
    22   { 
    23     register _Atomic_word __result=*__mem; 
    24     *__mem+=__val; 
    25     return __result; 
    26   } 
    27  
    28   void 
    29   __attribute__ ((__unused__)) 
    30   __atomic_add(volatile _Atomic_word* __mem, int __val) 
    31   { 
    32     *__mem+=__val; 
    33   } 
    34 } 
    35 #endif 
    36  
     16pthread_rwlock_t MemRecursorCache::s_rwlock; 
    3717 
    3818DNSResourceRecord String2DNSRR(const string& qname, const QType& qt, const string& serial, uint32_t ttd) 
     
    8363} 
    8464 
     65// returns the RDATA for rr - might be compressed! 
    8566string DNSRR2String(const DNSResourceRecord& rr) 
    8667{ 
     
    126107int MemRecursorCache::getDirect(time_t now, const char* qname, const QType& qt, uint32_t ttd[10], char* data[10], uint16_t len[10]) 
    127108{ 
     109  ReadLock rl(&s_rwlock); 
     110 
    128111  if(!d_cachecachevalid || Utility::strcasecmp(d_cachedqname.c_str(), qname)) { 
    129112//    cerr<<"had cache cache miss for '"<<qname<<"'"<<endl; 
     
    187170int MemRecursorCache::get(time_t now, const string &qname, const QType& qt, set<DNSResourceRecord>* res) 
    188171{ 
     172  WriteLock wl(&s_rwlock); 
    189173  unsigned int ttd=0; 
    190174 
     
    215199         
    216200        for(vector<StoredRecord>::const_iterator k=i->d_records.begin(); k != i->d_records.end(); ++k) { 
    217           if(k->d_ttd < 1000000000 || k->d_ttd > (uint32_t) now) { 
     201          if(k->d_ttd < 1000000000 || k->d_ttd > (uint32_t) now) {  // FIXME what does the 100000000 number mean? 
    218202            ttd=k->d_ttd; 
    219203            if(res) { 
     
    238222  return -1; 
    239223} 
     224 
     225 
    240226  
    241227bool MemRecursorCache::attemptToRefreshNSTTL(const QType& qt, const set<DNSResourceRecord>& content, const CacheEntry& stored) 
    242228{ 
     229  //  WriteLock wl(&s_rwlock); (holds the lock already) 
    243230  if(!stored.d_auth) { 
    244231//    cerr<<"feel free to scribble non-auth data!"<<endl; 
     
    272259void MemRecursorCache::replace(time_t now, const string &qname, const QType& qt,  const set<DNSResourceRecord>& content, bool auth) 
    273260{ 
     261  WriteLock wl(&s_rwlock); 
    274262  d_cachecachevalid=false; 
    275263  tuple<string, uint16_t> key=make_tuple(qname, qt.getCode()); 
    276264  cache_t::iterator stored=d_cache.find(key); 
    277  
    278   //  cerr<<"storing "<< qname+"|"+qt.getName()<<" -> '"<<content.begin()->content<<"'\n"; 
    279265 
    280266  bool isNew=false; 
     
    283269    isNew=true; 
    284270  } 
    285    
    286271  pair<vector<StoredRecord>::iterator, vector<StoredRecord>::iterator> range; 
    287272 
     
    289274  CacheEntry ce=*stored; 
    290275 
    291   if(qt.getCode()==QType::SOA || qt.getCode()==QType::CNAME)  // you can only have one (1) each of these 
     276  //  cerr<<"storing "<< qname+"|"+qt.getName()<<" -> '"<<content.begin()->content<<"', isnew="<<isNew<<", auth="<<auth<<", ce.auth="<<ce.d_auth<<"\n"; 
     277 
     278  if(qt.getCode()==QType::SOA || qt.getCode()==QType::CNAME)  { // you can only have one (1) each of these 
     279    //    cerr<<"\tCleaning out existing store because of SOA and CNAME\n"; 
    292280    ce.d_records.clear(); 
    293  
    294   if(auth && !attemptToRefreshNSTTL(qt, content, ce) ) { 
    295     ce.d_records.clear(); // clear non-auth data 
    296     ce.d_auth = true; 
    297     isNew=true;           // data should be sorted again 
    298281  } 
    299282 
     
    304287        break; 
    305288    if(j != ce.d_records.end()) { // we still have valid data, ignore unauth data 
     289      //      cerr<<"\tStill hold valid auth data, and the new data is unauth, return\n"; 
    306290      return; 
    307291    } 
     
    310294    } 
    311295  } 
    312  
     296#if 0 
     297  if(auth && !attemptToRefreshNSTTL(qt, content, ce) ) { 
     298    cerr<<"\tGot auth data, and it was not refresh attempt of an NS record, nuking storage"<<endl; 
     299    ce.d_records.clear(); // clear non-auth data 
     300    ce.d_auth = true; 
     301    isNew=true;           // data should be sorted again 
     302  } 
     303#endif 
     304  //  cerr<<"\tHave "<<content.size()<<" records to store\n"; 
    313305  for(set<DNSResourceRecord>::const_iterator i=content.begin(); i != content.end(); ++i) { 
    314306    dr.d_ttd=i->ttl; 
     
    319311    else { 
    320312      range=equal_range(ce.d_records.begin(), ce.d_records.end(), dr); 
    321        
     313 
     314      if(range.first != range.second && (range.first != ce.d_records.begin() || range.second != ce.d_records.end())) { 
     315        //      cerr<<"\t\tIncomplete match! Must nuke"<<endl; 
     316        ce.d_records.clear(); 
     317        range.first = range.second = ce.d_records.begin(); 
     318      } 
     319 
    322320      if(range.first != range.second) { 
     321        //      cerr<<"\t\tMay need to modify TTL of stored record\n"; 
    323322        for(vector<StoredRecord>::iterator j=range.first ; j!=range.second; ++j) { 
    324323          /* see http://mailman.powerdns.com/pipermail/pdns-users/2006-May/003413.html */ 
    325           if(j->d_ttd > (unsigned int) now && i->ttl > j->d_ttd && qt.getCode()==QType::NS && auth) // don't allow auth servers to *raise* TTL of an NS record 
     324          if(j->d_ttd > (unsigned int) now && i->ttl > j->d_ttd && qt.getCode()==QType::NS && auth) { // don't allow auth servers to *raise* TTL of an NS recor 
     325            //      cerr<<"\t\tNot doing so, trying to raise TTL NS\n"; 
    326326            continue; 
    327           if(i->ttl > j->d_ttd || (auth && d_followRFC2181) ) // authoritative packets can override the TTL to be lower 
     327          } 
     328          if(i->ttl > j->d_ttd || (auth && d_followRFC2181) ) { // authoritative packets can override the TTL to be lower 
     329            //      cerr<<"\t\tUpdating the ttl, diff="<<j->d_ttd - i->ttl<<endl;; 
    328330            j->d_ttd=i->ttl; 
     331          } 
     332          else { 
     333            //      cerr<<"\t\tNOT updating the ttl, old= " <<j->d_ttd - now <<", new: "<<i->ttl - now <<endl; 
     334          } 
    329335        } 
    330336      } 
    331337      else { 
     338        //      cerr<<"\t\tThere was no exact copy of this record, so adding & sorting\n"; 
    332339        ce.d_records.push_back(dr); 
    333340        sort(ce.d_records.begin(), ce.d_records.end()); 
     
    337344 
    338345  if(isNew) { 
     346    //    cerr<<"\tSorting (because of isNew)\n"; 
    339347    sort(ce.d_records.begin(), ce.d_records.end()); 
    340348  } 
     
    348356int MemRecursorCache::doWipeCache(const string& name, uint16_t qtype) 
    349357{ 
     358  WriteLock wl(&s_rwlock); 
    350359  int count=0; 
    351360  d_cachecachevalid=false; 
     
    365374bool MemRecursorCache::doAgeCache(time_t now, const string& name, uint16_t qtype, int32_t newTTL) 
    366375{ 
     376  WriteLock wl(&s_rwlock); 
    367377  cache_t::iterator iter = d_cache.find(tie(name, qtype)); 
    368378  if(iter == d_cache.end())  
     
    393403void MemRecursorCache::doDumpAndClose(int fd) 
    394404{ 
     405  WriteLock wl(&s_rwlock); 
    395406  FILE* fp=fdopen(fd, "w"); 
    396407  if(!fp) { 
     
    424435void MemRecursorCache::doPrune(void) 
    425436{ 
     437  WriteLock wl(&s_rwlock); 
    426438  uint32_t now=(uint32_t)time(0); 
    427439  d_cachecachevalid=false; 
  • trunk/pdns/pdns/recursor_cache.hh

    r1265 r1374  
    77#include "misc.hh" 
    88#include <iostream> 
     9 
    910#include <boost/utility.hpp> 
    1011#undef L 
     
    2930public: 
    3031  MemRecursorCache() : d_followRFC2181(false), d_cachecachevalid(false) 
    31   {} 
     32  { 
     33    pthread_rwlock_init(&s_rwlock, 0); 
     34    //    cerr<<"ce: "<<sizeof(CacheEntry)<<", sr: "<<sizeof(struct StoredRecord)<<endl; 
     35  } 
    3236  unsigned int size(); 
    3337  unsigned int bytes(); 
     
    6367  }; 
    6468 
    65   struct predicate 
    66   { 
    67     predicate(uint32_t limit) : d_limit(limit) 
    68     { 
    69     } 
    70      
    71     bool operator()(const StoredRecord& sr) const 
    72     { 
    73       return sr.d_ttd <= d_limit; 
    74     } 
    75     uint32_t d_limit; 
    76   }; 
    77  
    78   //   typedef __gnu_cxx::hash_map<string, vector<StoredRecord> > cache_t; 
    7969  struct CacheEntry 
    8070  { 
    81     string d_qname; 
    82     uint16_t d_qtype; 
    83     bool d_auth; 
    84  
    8571    CacheEntry(const tuple<string, uint16_t>& key, const vector<StoredRecord>& records, bool auth) :  
    8672      d_qname(key.get<0>()), d_qtype(key.get<1>()), d_auth(auth), d_records(records) 
     
    8874 
    8975    typedef vector<StoredRecord> records_t; 
    90     records_t d_records; 
     76 
    9177    uint32_t getTTD() const 
    9278    { 
     
    9985      return earliest; 
    10086    } 
     87 
     88    string d_qname; 
     89    uint16_t d_qtype; 
     90    bool d_auth; 
     91    records_t d_records; 
    10192  }; 
    10293 
     
    122113  bool attemptToRefreshNSTTL(const QType& qt, const set<DNSResourceRecord>& content, const CacheEntry& stored); 
    123114 
     115  static pthread_rwlock_t s_rwlock; 
     116 
    124117}; 
    125118string DNSRR2String(const DNSResourceRecord& rr);