From: Bert Hubert Date: Mon, 13 Mar 2006 19:40:12 +0000 (+0000) Subject: move to multi_index_container to speed up prunes X-Git-Tag: pdns-2.9.20~8 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=ca0b5def6013adc2ececb14462e76712259ab244;p=pdns move to multi_index_container to speed up prunes git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@580 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- diff --git a/pdns/recursor_cache.cc b/pdns/recursor_cache.cc index d6a89a001..69ae27445 100644 --- a/pdns/recursor_cache.cc +++ b/pdns/recursor_cache.cc @@ -7,7 +7,7 @@ using namespace std; using namespace boost; #include "config.h" - +#define GCC_SKIP_LOCKING #ifdef GCC_SKIP_LOCKING #include // 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::const_iterator j=i->second.begin(); j!= i->second.end(); ++j) + ret+=i->d_name.length(); + for(vector::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::const_iterator k=j->second.begin(); k != j->second.end(); ++k) { + for(vector::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 '"<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())).first; + stored=d_cache.insert(CacheEntry(key,vector())).first; isNew=true; } pair::iterator, vector::iterator> range; StoredRecord dr; + CacheEntry ce=*stored; + for(set::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::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(stored->second).swap(stored->second); + + if(ce.d_records.capacity() != ce.d_records.size()) + vector(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 ("<d_name<<") only needs to get killed in "<< j->getTTD() - now <<" seconds, rest will be later\n"; + break; + } + else + ; +// cout<<"Looking at '"<d_name<<"', "<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< #include #include #include "dns.hh" #include "qtype.hh" #include #include +#undef L +#include +#include +#include +#include + +#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 > cache_t; + // typedef __gnu_cxx::hash_map > cache_t; + struct CacheEntry + { + CacheEntry(const string& name, const vector& records) : d_name(name), d_records(records) + {} + string d_name; + typedef vector records_t; + records_t d_records; + uint32_t getTTD() const + { + uint32_t earliest=numeric_limits::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 >, + ordered_non_unique > + > + > cache_t; + private: cache_t d_cache;