Skip to content

Instantly share code, notes, and snippets.

@Habbie
Created April 26, 2013 11:42
Show Gist options
  • Select an option

  • Save Habbie/5466734 to your computer and use it in GitHub Desktop.

Select an option

Save Habbie/5466734 to your computer and use it in GitHub Desktop.
Index: pdns/rec_channel_rec.cc
===================================================================
--- pdns/rec_channel_rec.cc (Revision 2623)
+++ pdns/rec_channel_rec.cc (Arbeitskopie)
@@ -455,6 +455,8 @@
addGetStat("noping-outqueries", &g_stats.noPingOutQueries);
addGetStat("noedns-outqueries", &g_stats.noEdnsOutQueries);
+ addGetStat("prefetch-queries", &g_stats.prefetched);
+
addGetStat("uptime", calculateUptime);
#ifndef WIN32
Index: pdns/recpacketcache.cc
===================================================================
--- pdns/recpacketcache.cc (Revision 2623)
+++ pdns/recpacketcache.cc (Arbeitskopie)
@@ -13,7 +13,7 @@
}
bool RecursorPacketCache::getResponsePacket(const std::string& queryPacket, time_t now,
- std::string* responsePacket, uint32_t* age)
+ std::string* responsePacket, uint32_t* age, unsigned int prefetchRatio)
{
struct Entry e;
e.d_packet=queryPacket;
@@ -24,8 +24,12 @@
d_misses++;
return false;
}
-
- if((uint32_t)now < iter->d_ttd) { // it is fresh!
+
+ uint32_t origTTL = iter->d_ttd - iter->d_creation;
+ uint32_t ratioTTL = origTTL/100*(100-prefetchRatio);
+ if(origTTL>0 && ratioTTL<1) ratioTTL=1;
+
+ if((uint32_t)now < iter->d_creation + ratioTTL) { // it is fresh!
// cerr<<"Fresh for another "<<iter->d_ttd - now<<" seconds!"<<endl;
*age = now - iter->d_creation;
uint16_t id;
Index: pdns/syncres.hh
===================================================================
--- pdns/syncres.hh (Revision 2623)
+++ pdns/syncres.hh (Arbeitskopie)
@@ -28,6 +28,7 @@
string d_name;
QType d_qtype;
string d_qname;
+ uint32_t d_authttl;
uint32_t d_ttd;
uint32_t getTTD() const
{
@@ -479,6 +480,7 @@
uint64_t noPingOutQueries, noEdnsOutQueries;
uint64_t packetCacheHits;
uint64_t noPacketError;
+ uint64_t prefetched;
time_t startupTime;
unsigned int maxMThreadStackUsage;
};
Index: pdns/recursor_cache.hh
===================================================================
--- pdns/recursor_cache.hh (Revision 2623)
+++ pdns/recursor_cache.hh (Arbeitskopie)
@@ -50,6 +50,8 @@
string d_string;
+ uint32_t d_authttl;
+
bool operator<(const StoredRecord& rhs) const
{
return d_string < rhs.d_string;
Index: pdns/pdns_recursor.cc
===================================================================
--- pdns/pdns_recursor.cc (Revision 2623)
+++ pdns/pdns_recursor.cc (Arbeitskopie)
@@ -74,6 +74,7 @@
__thread FDMultiplexer* t_fdm;
__thread unsigned int t_id;
unsigned int g_maxTCPPerClient;
+unsigned int g_prefetchRatio;
unsigned int g_networkTimeoutMsec;
bool g_logCommonErrors;
__thread shared_ptr<PowerDNSLua>* t_pdl;
@@ -498,6 +499,7 @@
}
vector<DNSResourceRecord> ret;
+ vector<DNSResourceRecord> prefetch;
vector<uint8_t> packet;
DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass);
@@ -559,6 +561,10 @@
for(vector<DNSResourceRecord>::const_iterator i=ret.begin(); i!=ret.end(); ++i) {
pw.startRecord(i->qname, i->qtype.getCode(), i->ttl, i->qclass, (DNSPacketWriter::Place)i->d_place);
minTTL = min(minTTL, i->ttl);
+ if(!sr.d_outqueries && g_prefetchRatio && i->d_place==DNSResourceRecord::ANSWER) {
+ if(i->ttl<i->authttl*g_prefetchRatio/100)
+ prefetch.push_back(*i);
+ }
if(i->qtype.getCode() == QType::A) { // blast out A record w/o doing whole dnswriter thing
uint32_t ip=0;
IpToU32(i->content, &ip);
@@ -648,6 +654,19 @@
if(newLat < 1000000) // outliers of several minutes exist..
g_stats.avgLatencyUsec=(uint64_t)((1-0.0001)*g_stats.avgLatencyUsec + 0.0001*newLat);
+ if(prefetch.size() && !variableAnswer) {
+ for(vector<DNSResourceRecord>::const_iterator i=prefetch.begin(); i!=prefetch.end(); ++i) {
+ t_RC->doAgeCache(g_now.tv_sec, i->qname, i->qtype.getCode(), 0);
+ }
+ vector<DNSResourceRecord> ret;
+ int res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret);
+ if(res == RCode::NoError) {
+ g_stats.prefetched++;
+ if(!g_quiet)
+ L<<Logger::Warning<<"prefetched: qname="<<dc->d_mdp.d_qname<<" qtype="<<DNSRecordContent::NumberToType(dc->d_mdp.d_qtype)<<endl;
+ }
+ }
+
delete dc;
dc=0;
}
@@ -820,7 +839,7 @@
string response;
try {
uint32_t age;
- if(!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(question, g_now.tv_sec, &response, &age)) {
+ if(!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(question, g_now.tv_sec, &response, &age, g_prefetchRatio)) {
if(!g_quiet)
L<<Logger::Error<<t_id<< " question answered from packet cache from "<<fromaddr.toString()<<endl;
@@ -1720,6 +1739,7 @@
g_initialDomainMap = parseAuthAndForwards();
+ g_prefetchRatio=min(::arg().asNum("prefetch-ratio"), 90);
g_logCommonErrors=::arg().mustDo("log-common-errors");
@@ -2014,6 +2034,7 @@
::arg().set("serve-rfc1918", "If we should be authoritative for RFC 1918 private IP space")="";
::arg().set("auth-can-lower-ttl", "If we follow RFC 2181 to the letter, an authoritative server can lower the TTL of NS records")="off";
::arg().set("lua-dns-script", "Filename containing an optional 'lua' script that will be used to modify dns answers")="";
+ ::arg().set("prefetch-ratio", "Prefetch RR if request within <number> percent of TTL. 0=off, maximum is 90")="10";
::arg().setSwitch( "ignore-rd-bit", "Assume each packet requires recursion, for compatibility" )= "off";
::arg().setSwitch( "disable-edns-ping", "Disable EDNSPing" )= "no";
::arg().setSwitch( "disable-edns", "Disable EDNS" )= "";
Index: pdns/dns.hh
===================================================================
--- pdns/dns.hh (Revision 2623)
+++ pdns/dns.hh (Arbeitskopie)
@@ -80,6 +80,7 @@
string content; //!< what this record points to. Example: 10.1.2.3
uint16_t priority; //!< For qtypes that support a priority or preference (MX, SRV)
uint32_t ttl; //!< Time To Live of this record
+ uint32_t authttl; //!< Authoritative Time To Live of this record
int domain_id; //!< If a backend implements this, the domain_id of the zone this record is in
time_t last_modified; //!< For autocalculating SOA serial numbers - the backend needs to fill this in
enum Place {QUESTION=0, ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; //!< Type describing the positioning of a DNSResourceRecord within, say, a DNSPacket
@@ -98,6 +99,7 @@
ar & content;
ar & priority;
ar & ttl;
+ ar & authttl;
ar & domain_id;
ar & last_modified;
ar & d_place;
Index: pdns/syncres.cc
===================================================================
--- pdns/syncres.cc (Revision 2623)
+++ pdns/syncres.cc (Arbeitskopie)
@@ -90,6 +90,7 @@
rr.qtype=qtype;
rr.qclass=1;
rr.ttl=86400;
+ rr.authttl=86400;
if(qtype.getCode()==QType::PTR)
rr.content="localhost.";
else
@@ -107,6 +108,7 @@
rr.qtype=qtype;
rr.qclass=qclass;
rr.ttl=86400;
+ rr.authttl=86400;
if(pdns_iequals(qname,"version.bind.") || pdns_iequals(qname,"version.pdns."))
rr.content="\""+::arg()["version-string"]+"\"";
else
@@ -991,6 +993,9 @@
DNSResourceRecord rr=*i;
rr.d_place=DNSResourceRecord::ANSWER;
+ rr.authttl = rr.ttl;
+ i->authttl = rr.authttl;
+
rr.ttl += d_now.tv_sec;
if(rr.qtype.getCode() == QType::NS) // people fiddle with the case
Index: pdns/recursor_cache.cc
===================================================================
--- pdns/recursor_cache.cc (Revision 2623)
+++ pdns/recursor_cache.cc (Arbeitskopie)
@@ -132,6 +132,7 @@
ttd=k->d_ttd;
if(res) {
DNSResourceRecord rr=String2DNSRR(qname, QType(i->d_qtype), k->d_string, ttd);
+ rr.authttl=k->d_authttl;
res->insert(rr);
}
}
@@ -235,6 +236,7 @@
// cerr<<"\tHave "<<content.size()<<" records to store\n";
for(set<DNSResourceRecord>::const_iterator i=content.begin(); i != content.end(); ++i) {
// cerr<<"To store: "<<i->content<<endl;
+ dr.d_authttl=i->authttl;
dr.d_ttd=i->ttl;
dr.d_string=DNSRR2String(*i);
@@ -246,6 +248,7 @@
if(range.first != range.second) {
// cerr<<"\t\tMay need to modify TTL of stored record\n";
for(vector<StoredRecord>::iterator j=range.first ; j!=range.second; ++j) {
+ j->d_authttl=i->authttl;
/* see http://mailman.powerdns.com/pipermail/pdns-users/2006-May/003413.html */
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
//~ cerr<<"\t\tNot doing so, trying to raise TTL NS\n";
@@ -299,24 +302,36 @@
bool MemRecursorCache::doAgeCache(time_t now, const string& name, uint16_t qtype, int32_t newTTL)
{
cache_t::iterator iter = d_cache.find(tie(name, qtype));
- if(iter == d_cache.end())
+ uint32_t maxTTD=std::numeric_limits<uint32_t>::min();
+ if(iter == d_cache.end()) {
return false;
+ }
- int32_t ttl = iter->getTTD() - now;
- if(ttl < 0)
+ CacheEntry ce = *iter;
+
+ if(ce.d_records.size()==1) {
+ maxTTD=ce.d_records.begin()->d_ttd;
+ }
+ else { // find the LATEST ttd
+ for(vector<StoredRecord>::const_iterator i=ce.d_records.begin(); i != ce.d_records.end(); ++i)
+ maxTTD=max(maxTTD, i->d_ttd);
+ }
+
+ int32_t maxTTL = maxTTD - now;
+
+ if(maxTTL < 0)
return false; // would be dead anyhow
- if(ttl > newTTL) {
+ if(maxTTL > newTTL) {
d_cachecachevalid=false;
- ttl = newTTL;
- uint32_t newTTD = now + ttl;
-
- CacheEntry ce = *iter;
+ uint32_t newTTD = now + newTTL;
+
for(vector<StoredRecord>::iterator j = ce.d_records.begin() ; j != ce.d_records.end(); ++j) {
- j->d_ttd = newTTD;
+ if(j->d_ttd>newTTD) // do never renew expired or older TTLs
+ j->d_ttd = newTTD;
}
-
+
d_cache.replace(iter, ce);
return true;
}
Index: pdns/recpacketcache.hh
===================================================================
--- pdns/recpacketcache.hh (Revision 2623)
+++ pdns/recpacketcache.hh (Arbeitskopie)
@@ -19,7 +19,7 @@
{
public:
RecursorPacketCache();
- bool getResponsePacket(const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age);
+ bool getResponsePacket(const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, unsigned int prefetchRatio);
void insertResponsePacket(const std::string& responsePacket, time_t now, uint32_t ttd);
void doPruneTo(unsigned int maxSize=250000);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment