#define PDNS_CACHECLEANER_HH
// this function can clean any cache that has a getTTD() method on its entries, and a 'sequence' index as its second index
+// the ritual is that the oldest entries are in *front* of the sequence collection, so on a hit, move an item to the end
+// on a miss, move it to the beginning
template <typename T> void pruneCollection(T& collection, unsigned int maxCached)
{
uint32_t now=(uint32_t)time(0);
sidx.erase(iter, eiter); // just lob it off from the beginning
}
+
+template <typename T> void moveCacheItemToFrontOrBack(T& collection, typename T::iterator& iter, bool front)
+{
+ typedef typename T::template nth_index<1>::type sequence_t;
+ sequence_t& sidx=collection.get<1>();
+ typename sequence_t::iterator si=collection.project<1>(iter);
+ if(front)
+ sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue
+ else
+ sidx.relocate(sidx.end(), si); // back
+}
+
+template <typename T> void moveCacheItemToFront(T& collection, typename T::iterator& iter)
+{
+ moveCacheItemToFrontOrBack(collection, iter, true);
+}
+
+template <typename T> void moveCacheItemToBack(T& collection, typename T::iterator& iter)
+{
+ moveCacheItemToFrontOrBack(collection, iter, false);
+}
+
#endif
d_misses++;
return false;
}
- typedef packetCache_t::nth_index<1>::type sequence_t;
- sequence_t& sidx=d_packetCache.get<1>();
- sequence_t::iterator si=d_packetCache.project<1>(iter);
if((uint32_t)now < iter->d_ttd) { // it is fresh!
// cerr<<"Fresh for another "<<iter->d_ttd - now<<" seconds!"<<endl;
*responsePacket = iter->d_packet;
((struct dnsheader*)responsePacket->c_str())->id=id;
d_hits++;
-
- sidx.relocate(sidx.end(), si); // put it at the end of the delete queue
+ moveCacheItemToBack(d_packetCache, iter);
return true;
}
- sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue
+ moveCacheItemToFront(d_packetCache, iter);
d_misses++;
return false;
}
for(cache_t::const_iterator i=d_cachecache.first; i != d_cachecache.second; ++i)
if(i->d_qtype == qt.getCode() || qt.getCode()==QType::ANY ||
(qt.getCode()==QType::ADDR && (i->d_qtype == QType::A || i->d_qtype == QType::AAAA) )
- ) {
- typedef cache_t::nth_index<1>::type sequence_t;
- sequence_t& sidx=d_cache.get<1>();
- sequence_t::iterator si=d_cache.project<1>(i);
-
+ ) {
for(vector<StoredRecord>::const_iterator k=i->d_records.begin(); k != i->d_records.end(); ++k) {
if(k->d_ttd < 1000000000 || k->d_ttd > (uint32_t) now) { // FIXME what does the 100000000 number mean?
ttd=k->d_ttd;
}
if(res) {
if(res->empty())
- sidx.relocate(sidx.begin(), si);
+ moveCacheItemToFront(d_cache, i);
else
- sidx.relocate(sidx.end(), si);
+ moveCacheItemToBack(d_cache, i);
}
if(qt.getCode()!=QType::ANY && qt.getCode()!=QType::ADDR) // normally if we have a hit, we are done
break;
#include "dnsparser.hh"
#include "dns_random.hh"
#include "lock.hh"
+#include "cachecleaner.hh"
__thread SyncRes::StaticStorage* t_sstorage;
return res<0 ? RCode::ServFail : res;
}
+#if 0
// for testing purpoises
static bool ipv6First(const ComboAddress& a, const ComboAddress& b)
{
return !(a.sin4.sin_family < a.sin4.sin_family);
}
+#endif
/** This function explicitly goes out for A addresses, but if configured to use IPv6 as well, will also return any IPv6 addresses in the cache
Additionally, it will return the 'best' address up front, and the rest shufled
giveNegative=true;
sqname=ni->d_qname;
sqt=QType::SOA;
+ moveCacheItemToBack(t_sstorage->negcache, ni);
break;
}
else {
- LOG<<prefix<<qname<<": Entire record '"<<qname<<"' was negatively cached, but entry expired"<<endl;
+ LOG<<prefix<<qname<<": Entire record '"<<qname<<"' or type was negatively cached, but entry expired"<<endl;
+ moveCacheItemToFront(t_sstorage->negcache, ni);
}
}
}