4
4
#include <boost/shared_ptr.hpp>
5
5
#include "dnsrecords.hh"
7
8
using namespace boost;
11
#ifdef GCC_SKIP_LOCKING
12
#include <bits/atomicity.h>
13
// 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
__attribute__ ((__unused__))
18
__exchange_and_add(volatile _Atomic_word* __mem, int __val)
20
register _Atomic_word __result=*__mem;
26
__attribute__ ((__unused__))
27
__atomic_add(volatile _Atomic_word* __mem, int __val)
9
34
DNSResourceRecord String2DNSRR(const string& qname, const QType& qt, const string& serial, uint32_t ttd)
11
36
shared_ptr<DNSRecordContent> regen=DNSRecordContent::unserialize(qname,qt.getCode(), serial);
32
59
unsigned int MemRecursorCache::size()
34
return d_cache.size();
62
for(cache_t::const_iterator i=d_cache.begin(); i!=d_cache.end(); ++i) {
63
ret+=i->d_name.size();
68
unsigned int MemRecursorCache::bytes()
72
for(cache_t::const_iterator i=d_cache.begin(); i!=d_cache.end(); ++i) {
73
ret+=i->d_name.length();
74
for(vector<StoredRecord>::const_iterator j=i->d_records.begin(); j!= i->d_records.end(); ++j)
37
81
int MemRecursorCache::get(time_t now, const string &qname, const QType& qt, set<DNSResourceRecord>* res)
39
83
unsigned int ttd=0;
40
cache_t::const_iterator j=d_cache.find(toLowerCanonic(qname)+"|"+qt.getName());
84
uint16_t code=qt.getCode();
85
string key(toLowerCanonic(qname)); key.append(1,'|'); key.append((char*)&code, ((char*)&code)+2);
86
cache_t::const_iterator j=d_cache.find(key);
41
87
// cerr<<"looking up "<< toLowerCanonic(qname)+"|"+qt.getName() << endl;
45
if(j!=d_cache.end() && j->first==toLowerCanonic(qname)+"|"+qt.getName() && j->second.begin()->d_ttd>(unsigned int)now) {
91
if(j!=d_cache.end() && j->d_records.begin()->d_ttd>(unsigned int)now) {
47
for(set<StoredRecord>::const_iterator k=j->second.begin(); k != j->second.end(); ++k) {
93
for(vector<StoredRecord>::const_iterator k=j->d_records.begin(); k != j->d_records.end(); ++k) {
48
94
DNSResourceRecord rr=String2DNSRR(qname, qt, k->d_string, ttd=k->d_ttd);
49
95
// cerr<<"Returning '"<<rr.content<<"'\n";
107
/* the code below is rather tricky - it basically replaces the stuff cached for qname by content, but it is special
108
cased for when inserting identical records with only differing ttls, in which case the entry is not
109
touched, but only given a new ttd */
61
110
void MemRecursorCache::replace(const string &qname, const QType& qt, const set<DNSResourceRecord>& content)
63
set<StoredRecord>& stored=d_cache[toLowerCanonic(qname)+"|"+qt.getName()];
112
int code=qt.getCode();
113
string key(toLowerCanonic(qname)); key.append(1,'|'); key.append((char*)&code, ((char*)&code)+2);
114
cache_t::iterator stored=d_cache.find(key);
117
if(stored == d_cache.end()) {
118
stored=d_cache.insert(CacheEntry(key,vector<StoredRecord>())).first;
122
pair<vector<StoredRecord>::iterator, vector<StoredRecord>::iterator> range;
125
CacheEntry ce=*stored;
65
127
for(set<DNSResourceRecord>::const_iterator i=content.begin(); i != content.end(); ++i) {
68
129
dr.d_string=DNSRR2String(*i);
70
//cerr<<"Storing: "<< toLowerCanonic(qname)+"|"+qt.getName() << " <=> '"<<i->content<<"', ttd="<<i->ttl<<endl;
74
void MemRecursorCache::doPrune(void)
76
unsigned int names=0, records=0;
78
for(cache_t::iterator j=d_cache.begin();j!=d_cache.end();){
79
for(set<StoredRecord>::iterator k=j->second.begin();k!=j->second.end();)
80
if((unsigned int)k->d_ttd < (unsigned int) now) {
88
if(j->second.empty()) { // everything is gone
132
ce.d_records.push_back(dr);
134
range=equal_range(ce.d_records.begin(), ce.d_records.end(), dr);
136
if(range.first != range.second) {
137
for(vector<StoredRecord>::iterator j=range.first ; j!=range.second; ++j)
141
ce.d_records.push_back(dr);
142
sort(ce.d_records.begin(), ce.d_records.end());
147
sort(ce.d_records.begin(), ce.d_records.end());
150
if(ce.d_records.capacity() != ce.d_records.size())
151
vector<StoredRecord>(ce.d_records).swap(ce.d_records);
153
d_cache.replace(stored, ce);
158
void MemRecursorCache::doPrune(void)
160
unsigned int names=0;
161
uint32_t now=(uint32_t)time(0);
163
// cout<<"Going to prune!\n";
165
typedef cache_t::nth_index<1>::type cache_by_ttd_t;
166
cache_by_ttd_t& ttdindex=d_cache.get<1>();
168
uint32_t looked(0), quickZonk(0), fullZonk(0), partialZonk(0), noZonk(0);
171
cache_by_ttd_t::iterator j;
172
for(j=ttdindex.begin();j!=ttdindex.end();){
173
if(j->getTTD() > now) {
174
// cout<<"Done pruning, this record ("<<j->d_name<<") only needs to get killed in "<< j->getTTD() - now <<" seconds, rest will be later\n";
179
// cout<<"Looking at '"<<j->d_name<<"', "<<now - j->getTTD()<<" seconds overdue!\n";
181
if(j->d_records.size()==1) {
182
// ttdindex.erase(j++);
190
size_t before=ce.d_records.size();
191
ce.d_records.erase(remove_if(ce.d_records.begin(), ce.d_records.end(), p), ce.d_records.end());
193
if(ce.d_records.empty()) { // everything is gone
194
// cout<<"Zonked it entirely!\n";
195
// ttdindex.erase(j++);
200
if(ce.d_records.size()!=before) {
201
// cout<<"Zonked partially, putting back, new TTD: "<< ce.getTTD() - now<<endl;;
202
cache_by_ttd_t::iterator here=j++;
203
ttdindex.replace(here, ce);
214
// cout<<"Walk took "<< dt.udiff()<<"usec\n";
216
ttdindex.erase(ttdindex.begin(), j);
217
// cout<<"Erase took "<< dt.udiff()<<" usec, looked: "<<looked<<", quick: "<<quickZonk<<", full: ";
218
// cout<<fullZonk<<", partial: "<<partialZonk<<", no: "<<noZonk<<"\n";
219
// cache_t(d_cache).swap(d_cache);