Also AXFR a zone from a master with a lower serial.
+.. _setting-domain-cache-ttl:
+
+``domain-cache-ttl``
+--------------------
+
+- Integer
+- Default: 0
+
+Seconds to cache a list of all known domains. A value of 0 will disable the cache.
+
+If your backends do not respond to unknown domains, it is suggested to enable :ref:`setting-consistent-backends` and set this option to `60`.
+
.. _setting-cache-ttl:
``cache-ttl``
#include "pdns/misc.hh"
#include "pdns/dynlistener.hh"
#include "pdns/lock.hh"
+#include "pdns/auth-domaincache.hh"
+
+extern AuthDomainCache g_domainCache;
/*
All instances of this backend share one s_state, which is indexed by zone name and zone id.
safePutBBDomainInfo(bbd);
+ g_domainCache.add(domainname, bbd.d_id); // make new domain visible
+
g_log << Logger::Warning << "Zone " << domainname << " loaded" << endl;
return "Loaded zone " + domainname.toLogString() + " from " + filename;
}
});
}
-bool LMDBBackend::createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& masters, const string& account)
+bool LMDBBackend::createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& masters, const string& account, int* zoneId)
{
DomainInfo di;
- auto txn = d_tdomains->getRWTransaction();
- if (txn.get<0>(domain, di)) {
- throw DBException("Domain '" + domain.toLogString() + "' exists already");
- }
+ {
+ auto txn = d_tdomains->getRWTransaction();
+ if (txn.get<0>(domain, di)) {
+ throw DBException("Domain '" + domain.toLogString() + "' exists already");
+ }
+
+ di.zone = domain;
+ di.kind = kind;
+ di.masters = masters;
+ di.account = account;
- di.zone = domain;
- di.kind = kind;
- di.masters = masters;
- di.account = account;
+ txn.put(di);
+ txn.commit();
+ }
- txn.put(di);
- txn.commit();
+ if (zoneId != nullptr) {
+ auto txn = d_tdomains->getROTransaction();
+ *zoneId = txn.get<0>(domain, di);
+ }
return true;
}
bool list(const DNSName& target, int id, bool include_disabled) override;
bool getDomainInfo(const DNSName& domain, DomainInfo& di, bool getserial = true) override;
- bool createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& masters, const string& account) override;
+ bool createDomain(const DNSName& domain, const DomainInfo::DomainKind kind, const vector<ComboAddress>& masters, const string& account, int* zoneId) override;
bool startTransaction(const DNSName& domain, int domain_id = -1) override;
bool commitTransaction() override;
libtestremotebackend_la_SOURCES = \
../../pdns/arguments.hh ../../pdns/arguments.cc \
+ ../../pdns/auth-domaincache.cc ../../pdns/auth-domaincache.hh \
../../pdns/auth-packetcache.cc ../../pdns/auth-packetcache.hh \
../../pdns/auth-querycache.cc ../../pdns/auth-querycache.hh \
../../pdns/base32.cc \
#include "pdns/arguments.hh"
#include "pdns/json.hh"
#include "pdns/statbag.hh"
+#include "pdns/auth-domaincache.hh"
#include "pdns/auth-packetcache.hh"
#include "pdns/auth-querycache.hh"
StatBag S;
+AuthDomainCache g_domainCache;
AuthPacketCache PC;
AuthQueryCache QC;
ArgvMap& arg()
#include "pdns/arguments.hh"
#include "pdns/json.hh"
#include "pdns/statbag.hh"
+#include "pdns/auth-domaincache.hh"
#include "pdns/auth-packetcache.hh"
#include "pdns/auth-querycache.hh"
StatBag S;
+AuthDomainCache g_domainCache;
AuthPacketCache PC;
AuthQueryCache QC;
ArgvMap& arg()
#include "pdns/dnsrecords.hh"
#include "pdns/json.hh"
#include "pdns/statbag.hh"
+#include "pdns/auth-domaincache.hh"
#include "pdns/auth-packetcache.hh"
#include "pdns/auth-querycache.hh"
StatBag S;
+AuthDomainCache g_domainCache;
AuthPacketCache PC;
AuthQueryCache QC;
ArgvMap& arg()
#include "pdns/arguments.hh"
#include "pdns/json.hh"
#include "pdns/statbag.hh"
+#include "pdns/auth-domaincache.hh"
#include "pdns/auth-packetcache.hh"
#include "pdns/auth-querycache.hh"
StatBag S;
+AuthDomainCache g_domainCache;
AuthPacketCache PC;
AuthQueryCache QC;
ArgvMap& arg()
#include "pdns/dnsrecords.hh"
#include "pdns/json.hh"
#include "pdns/statbag.hh"
+#include "pdns/auth-domaincache.hh"
#include "pdns/auth-packetcache.hh"
#include "pdns/auth-querycache.hh"
StatBag S;
+AuthDomainCache g_domainCache;
AuthPacketCache PC;
AuthQueryCache QC;
ArgvMap& arg()
#include "pdns/dnsrecords.hh"
#include "pdns/json.hh"
#include "pdns/statbag.hh"
+#include "pdns/auth-domaincache.hh"
#include "pdns/auth-packetcache.hh"
#include "pdns/auth-querycache.hh"
StatBag S;
+AuthDomainCache g_domainCache;
AuthPacketCache PC;
AuthQueryCache QC;
ArgvMap& arg()
ascii.hh \
auth-caches.cc auth-caches.hh \
auth-carbon.cc \
+ auth-domaincache.cc auth-domaincache.hh \
auth-packetcache.cc auth-packetcache.hh \
auth-querycache.cc auth-querycache.hh \
axfr-retriever.cc axfr-retriever.hh \
pdnsutil_SOURCES = \
arguments.cc \
auth-caches.cc auth-caches.hh \
+ auth-domaincache.cc auth-domaincache.hh \
auth-packetcache.cc auth-packetcache.hh \
auth-querycache.cc auth-querycache.hh \
backends/gsql/gsqlbackend.cc backends/gsql/gsqlbackend.hh \
testrunner_SOURCES = \
arguments.cc \
auth-caches.cc auth-caches.hh \
+ auth-domaincache.cc auth-domaincache.hh \
auth-packetcache.cc auth-packetcache.hh \
auth-querycache.cc auth-querycache.hh \
base32.cc \
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "auth-domaincache.hh"
+#include "logger.hh"
+#include "statbag.hh"
+#include "arguments.hh"
+#include "cachecleaner.hh"
+extern StatBag S;
+
+AuthDomainCache::AuthDomainCache(size_t mapsCount): d_maps(mapsCount)
+{
+ S.declare("domain-cache-hit", "Number of hits on the domain cache");
+ S.declare("domain-cache-miss", "Number of misses on the domain cache");
+ S.declare("domain-cache-size", "Number of entries in the domain cache", StatType::gauge);
+
+ d_statnumhit=S.getPointer("domain-cache-hit");
+ d_statnummiss=S.getPointer("domain-cache-miss");
+ d_statnumentries=S.getPointer("domain-cache-size");
+
+ d_ttl = 0;
+}
+
+AuthDomainCache::~AuthDomainCache()
+{
+ try {
+ vector<WriteLock> locks;
+ for(auto& mc : d_maps) {
+ locks.push_back(WriteLock(mc.d_mut));
+ }
+ locks.clear();
+ }
+ catch(...) {
+ }
+}
+
+bool AuthDomainCache::getEntry(const DNSName &domain, int& zoneId)
+{
+ auto& mc = getMap(domain);
+ bool found = false;
+ {
+ ReadLock rl(mc.d_mut);
+ auto iter = mc.d_map.find(domain);
+ if (iter != mc.d_map.end()) {
+ found = true;
+ zoneId = iter->second.zoneId;
+ }
+ }
+
+ if (found) {
+ (*d_statnumhit)++;
+ } else {
+ (*d_statnummiss)++;
+ }
+ return found;
+}
+
+bool AuthDomainCache::isEnabled() const
+{
+ return d_ttl > 0;
+}
+
+void AuthDomainCache::clear()
+{
+ purgeLockedCollectionsVector(d_maps);
+}
+
+void AuthDomainCache::replace(const vector<tuple<DNSName, int>> &domain_indices)
+{
+ if(!d_ttl)
+ return;
+
+ size_t count = domain_indices.size();
+ vector<MapCombo> newMaps(d_maps.size());
+
+ // build new maps
+ for(const tuple<DNSName, int>& tup: domain_indices) {
+ const DNSName& domain = tup.get<0>();
+ CacheValue val;
+ val.zoneId = tup.get<1>();
+ auto& mc = newMaps[getMapIndex(domain)];
+ mc.d_map.emplace(domain, val);
+ }
+
+ for(size_t mapIndex = 0; mapIndex < d_maps.size(); mapIndex++)
+ {
+ auto& mc = d_maps[mapIndex];
+ WriteLock l(mc.d_mut);
+ mc.d_map = newMaps[mapIndex].d_map;
+ }
+
+ d_statnumentries->store(count);
+}
+
+void AuthDomainCache::add(const DNSName& domain, const int zoneId)
+{
+ if(!d_ttl)
+ return;
+
+ CacheValue val;
+ val.zoneId = zoneId;
+
+ int mapIndex = getMapIndex(domain);
+ {
+ auto& mc = d_maps[mapIndex];
+ WriteLock l(mc.d_mut);
+ mc.d_map.emplace(domain, val);
+ }
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <string>
+#include <map>
+#include "dns.hh"
+
+#include <unordered_map>
+
+#include "dns.hh"
+#include "dnspacket.hh"
+#include "lock.hh"
+
+class AuthDomainCache : public boost::noncopyable
+{
+public:
+ AuthDomainCache(size_t mapsCount=1024);
+ ~AuthDomainCache();
+
+ void replace(const vector<tuple<DNSName, int>> &domains);
+ void add(const DNSName& domain, const int zoneId);
+
+ bool getEntry(const DNSName &domain, int &zoneId);
+
+ size_t size() { return *d_statnumentries; } //!< number of entries in the cache
+
+ uint32_t getTTL() const {
+ return d_ttl;
+ }
+
+ void setTTL(uint32_t ttl) {
+ d_ttl = ttl;
+ }
+
+ bool isEnabled() const;
+
+ void clear();
+
+private:
+ struct CacheValue
+ {
+ int zoneId{-1};
+ };
+
+ typedef std::unordered_map<DNSName, CacheValue, std::hash<DNSName>> cmap_t;
+
+ struct MapCombo
+ {
+ MapCombo() { }
+ ~MapCombo() { }
+ MapCombo(const MapCombo &) = delete;
+ MapCombo & operator=(const MapCombo &) = delete;
+
+ ReadWriteLock d_mut;
+ cmap_t d_map;
+ };
+
+ vector<MapCombo> d_maps;
+ size_t getMapIndex(const DNSName& domain)
+ {
+ return domain.hash() % d_maps.size();
+ }
+ MapCombo& getMap(const DNSName& qname)
+ {
+ return d_maps[getMapIndex(qname)];
+ }
+
+ AtomicCounter d_ops{0};
+ AtomicCounter *d_statnumhit;
+ AtomicCounter *d_statnummiss;
+ AtomicCounter *d_statnumentries;
+
+ time_t d_ttl;
+};
return false;
}
-bool GSQLBackend::createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account)
+bool GSQLBackend::createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account, int* zoneId)
{
vector<string> masters_s;
masters_s.reserve(masters.size());
bind("account", account)->
execute()->
reset();
+
+ if (zoneId != nullptr) {
+ // XXX: needs its own stmt as godbc has a table name in it
+ d_GetLastInsertedKeyIdQuery_stmt->execute();
+ if (!d_GetLastInsertedKeyIdQuery_stmt->hasNextRow()) {
+ return false;
+ }
+ SSqlStatement::row_t row;
+ d_GetLastInsertedKeyIdQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-last-inserted-key-id-query", row, 1);
+ *zoneId = std::stoi(row[0]);
+ d_GetLastInsertedKeyIdQuery_stmt->reset();
+ }
+ return true;
}
catch(SSqlException &e) {
throw PDNSException("Database error trying to insert new domain '"+domain.toLogString()+"': "+ e.txtReason());
masters = tmp;
}
}
- createDomain(domain, DomainInfo::Slave, masters, account);
+ createDomain(domain, DomainInfo::Slave, masters, account, nullptr);
}
catch(SSqlException &e) {
throw PDNSException("Database error trying to insert new slave domain '"+domain.toLogString()+"': "+ e.txtReason());
bool feedRecord(const DNSResourceRecord &r, const DNSName &ordername, bool ordernameIsNSEC3=false) override;
bool feedEnts(int domain_id, map<DNSName,bool>& nonterm) override;
bool feedEnts3(int domain_id, const DNSName &domain, map<DNSName,bool> &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow) override;
- bool createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account) override;
+ bool createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account, int* zoneId=nullptr) override;
bool createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account) override;
bool deleteDomain(const DNSName &domain) override;
bool superMasterAdd(const string &ip, const string &nameserver, const string &account) override;
StatBag S; //!< Statistics are gathered across PDNS via the StatBag class S
AuthPacketCache PC; //!< This is the main PacketCache, shared across all threads
AuthQueryCache QC;
+AuthDomainCache g_domainCache;
std::unique_ptr<DNSProxy> DP{nullptr};
std::unique_ptr<DynListener> dl{nullptr};
CommunicatorClass Communicator;
::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
::arg().set("negquery-cache-ttl","Seconds to store negative query results in the QueryCache")="60";
::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
+ ::arg().set("domain-cache-ttl","Seconds to cache list of known domains")="0";
::arg().set("server-id", "Returned when queried for 'id.server' TXT or NSID, defaults to hostname - disabled or custom")="";
::arg().set("default-soa-content","Default SOA content")="a.misconfigured.dns.server.invalid hostmaster.@ 0 10800 3600 604800 3600";
::arg().set("default-soa-edit","Default SOA-EDIT value")="";
sd_notify(0, "READY=1");
#endif
+ const uint32_t secpollInterval = 1800;
+ uint32_t secpollSince = 0;
+ uint32_t domainCacheUpdateSince = 0;
for(;;) {
- sleep(1800);
- try {
- doSecPoll(false);
+ const uint32_t slept = g_domainCache.getTTL() == 0 ? secpollInterval : std::min(secpollInterval, g_domainCache.getTTL());
+ sleep(slept); // if any signals arrive, we might run more often than expected.
+
+ domainCacheUpdateSince += slept;
+ if (domainCacheUpdateSince >= g_domainCache.getTTL()) {
+ domainCacheUpdateSince = 0;
+ UeberBackend B;
+ B.updateDomainCache();
+ }
+
+ secpollSince += slept;
+ if (secpollSince >= secpollInterval) {
+ secpollSince = 0;
+ try {
+ doSecPoll(false);
+ }
+ catch(...){}
}
- catch(...){}
}
g_log<<Logger::Error<<"Mainthread exiting - should never happen"<<endl;
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#pragma once
+#include "auth-domaincache.hh"
#include "auth-packetcache.hh"
#include "auth-querycache.hh"
#include "utility.hh"
extern StatBag S; //!< Statistics are gathered across PDNS via the StatBag class S
extern AuthPacketCache PC; //!< This is the main PacketCache, shared across all threads
extern AuthQueryCache QC;
+extern AuthDomainCache g_domainCache;
extern std::unique_ptr<DNSProxy> DP;
extern std::unique_ptr<DynListener> dl;
extern CommunicatorClass Communicator;
}
//! called by PowerDNS to create a new domain
- virtual bool createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account)
+ virtual bool createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account, int* zoneId = nullptr)
{
return false;
}
#include "dnsbackend.hh"
#include "ueberbackend.hh"
#include "arguments.hh"
+#include "auth-domaincache.hh"
#include "auth-packetcache.hh"
#include "auth-querycache.hh"
#include "zoneparser-tng.hh"
StatBag S;
AuthPacketCache PC;
AuthQueryCache QC;
+AuthDomainCache g_domainCache;
namespace po = boost::program_options;
po::variables_map g_vm;
}
}
+ g_domainCache.setTTL(::arg().asNum("domain-cache-ttl"));
+ {
+ UeberBackend B;
+ B.updateDomainCache();
+ }
+
UeberBackend::go();
N=std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception
g_udpReceivers.push_back(N);
#include <boost/multi_index/key_extractors.hpp>
#include "arguments.hh"
+#include "auth-domaincache.hh"
#include "auth-querycache.hh"
#include "ueberbackend.hh"
struct UeberBackendSetupArgFixture {
UeberBackendSetupArgFixture() {
+ extern AuthDomainCache g_domainCache;
extern AuthQueryCache QC;
::arg().set("query-cache-ttl")="0";
::arg().set("negquery-cache-ttl")="0";
::arg().set("consistent-backends")="no";
QC.cleanup();
+ ::arg().set("domain-cache-ttl")="0";
+ g_domainCache.clear();
BackendMakers().clear();
SimpleBackend::s_zones.clear();
SimpleBackend::s_metadata.clear();
static void testWithoutThenWithCache(std::function<void(UeberBackend& ub)> func)
{
+ extern AuthDomainCache g_domainCache;
extern AuthQueryCache QC;
{
::arg().set("query-cache-ttl")="0";
::arg().set("negquery-cache-ttl")="0";
QC.cleanup();
+ ::arg().set("domain-cache-ttl")="0";
+ g_domainCache.clear();
UeberBackend ub;
func(ub);
::arg().set("query-cache-ttl")="20";
::arg().set("negquery-cache-ttl")="60";
QC.cleanup();
+ ::arg().set("domain-cache-ttl")="60";
+ g_domainCache.clear();
UeberBackend ub;
+ ub.updateDomainCache();
/* a first time to fill the cache */
func(ub);
/* a second time to make sure every call has been tried with the cache filled */
#endif
#include <boost/test/unit_test.hpp>
#include "arguments.hh"
+#include "auth-domaincache.hh"
#include "auth-packetcache.hh"
#include "auth-querycache.hh"
#include "statbag.hh"
StatBag S;
+AuthDomainCache g_domainCache;
AuthPacketCache PC;
AuthQueryCache QC;
#include <boost/archive/binary_oarchive.hpp>
#include "auth-querycache.hh"
+#include "auth-domaincache.hh"
#include "utility.hh"
#include "logger.hh"
#include "statbag.hh"
+extern AuthDomainCache g_domainCache;
extern StatBag S;
vector<UeberBackend *>UeberBackend::instances;
bool UeberBackend::createDomain(const DNSName &domain, const DomainInfo::DomainKind kind, const vector<ComboAddress> &masters, const string &account)
{
+ bool success = false;
+ int zoneId;
for(DNSBackend* mydb : backends) {
- if(mydb->createDomain(domain, kind, masters, account)) {
- return true;
+ if(mydb->createDomain(domain, kind, masters, account, &zoneId)) {
+ success = true;
+ break;
}
}
- return false;
+ if (success) {
+ g_domainCache.add(domain, zoneId); // make new domain visible
+ }
+ return success;
}
bool UeberBackend::doesDNSSEC()
}
}
+void UeberBackend::updateDomainCache() {
+ if (!g_domainCache.isEnabled()) {
+ return;
+ }
+
+ vector<tuple<DNSName, int>> domain_indices;
+
+ for (vector<DNSBackend*>::iterator i = backends.begin(); i != backends.end(); ++i )
+ {
+ vector<DomainInfo> domains;
+ (*i)->getAllDomains(&domains, false);
+ for(const auto& di: domains) {
+ domain_indices.push_back({di.zone, (int)di.id}); // this cast should not be necessary
+ }
+ }
+ g_domainCache.replace(domain_indices);
+}
+
void UeberBackend::rediscover(string *status)
{
-
for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
{
string tmpstr;
if(status)
*status+=tmpstr + (i!=backends.begin() ? "\n" : "");
}
+
+ updateDomainCache();
}
// of them has a more specific zone but don't bother asking this specific
// backend again for b.c.example.com., c.example.com. and example.com.
// If a backend has no match it may respond with an empty qname.
-
bool found = false;
int cstat;
DNSName shorter(target);
vector<pair<size_t, SOAData> > bestmatch (backends.size(), make_pair(target.wirelength()+1, SOAData()));
do {
+ int zoneId{-1};
+ if(cachedOk && g_domainCache.isEnabled()) {
+ if (g_domainCache.getEntry(shorter, zoneId)) {
+ // Zone exists in domain cache, directly lookup SOA.
+ // XXX: this code path and the cache lookup below should be merged; but that needs the code path below to also use ANY.
+ // Or it should just also use lookup().
+ DNSZoneRecord zr;
+ lookup(QType(QType::SOA), shorter, zoneId, nullptr);
+ if (!get(zr)) {
+ throw PDNSException("Backend returned no SOA for existing domain '"+shorter.toLogString()+"'");
+ }
+ sd->qname = zr.dr.d_name;
+ fillSOAData(zr, *sd);
+ // leave database handle in a consistent state
+ while (get(zr))
+ ;
+ goto found;
+ }
+ // domain does not exist, try again with shorter name
+ continue;
+ }
d_question.qtype = QType::SOA;
d_question.qname = shorter;
- d_question.zoneId = -1;
+ d_question.zoneId = zoneId;
// Check cache
if(cachedOk && (d_cache_ttl || d_negcache_ttl)) {
-
cstat = cacheHas(d_question,d_answers);
if(cstat == 1 && !d_answers.empty() && d_cache_ttl) {
DLOG(g_log<<Logger::Error<<"add pos cache entry: "<<sd->qname<<endl);
d_question.qtype = QType::SOA;
d_question.qname = sd->qname;
- d_question.zoneId = -1;
+ d_question.zoneId = zoneId;
DNSZoneRecord rr;
rr.dr.d_name = sd->qname;
/** Determines if we are authoritative for a zone, and at what level */
bool getAuth(const DNSName &target, const QType &qtype, SOAData* sd, bool cachedOk=true);
-
/** Load SOA info from backends, ignoring the cache.*/
bool getSOAUncached(const DNSName &domain, SOAData &sd);
bool get(DNSZoneRecord &r);
bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result);
bool searchComments(const string &pattern, int maxResults, vector<Comment>& result);
+ void updateDomainCache();
+
bool inTransaction();
private:
handle d_handle;
int cacheHas(const Question &q, vector<DNSZoneRecord> &rrs);
void addNegCache(const Question &q);
void addCache(const Question &q, vector<DNSZoneRecord>&& rrs);
-
};
--query-logging --dnsupdate=yes \
--expand-alias=yes --outgoing-axfr-expand-alias=yes \
--resolver=$RESOLVERIP \
+ --domain-cache-ttl=0 \
--cache-ttl=$cachettl --dname-processing $lua_prequery &
skipreasons="nodnssec noent nodyndns nometa noaxfr"
cleandig ns1.addzone.com A
cleandig ns1.test.com A
$PDNSCONTROL --config-name=bind --socket-dir=. --no-config bind-add-zone addzone.com ${PWD}/zones/addzone.com >/dev/null 2>&1
-$PDNSCONTROL --config-name=bind --socket-dir=. --no-config purge addzone.com
+# output of purge changes if domain-cache-ttl is set
+$PDNSCONTROL --config-name=bind --socket-dir=. --no-config purge addzone.com >/dev/null
sleep 1
$PDNSCONTROL --config-name=bind --socket-dir=. --no-config bind-add-zone addzone.com ${PWD}/zones/addzone.com
sleep 1
0 ns1.test.com. IN A 3600 1.1.1.1
Rcode: 0 (No Error), RD: 0, QR: 1, TC: 0, AA: 1, opcode: 0
Reply to question for qname='ns1.test.com.', qtype=A
-1
Already loaded
0 ns1.addzone.com. IN A 3600 1.1.1.5
Rcode: 0 (No Error), RD: 0, QR: 1, TC: 0, AA: 1, opcode: 0