after the check the domain is declared 'fresh', and will only be checked again
after '**refresh**' seconds have passed.
+When the freshness of a domain cannot be checked, e.g. because the master is offline, PowerDNS will retry the domain after [`slave-cycle-interval`](settings.md#slave-cycle-interval) seconds.
+Every time the domain fails it's freshness check, PowerDNS will hold back on checking the domain for `amount of failures * slave-cycle-interval` seconds, with a maximum of [`soa-retry-default`](settings.md#soa-retry-default) seconds between checks.
+With default settings, this means that PowerDNS will back off for 1, then 2, then 3 etc. minutes, to a maximum of 60 minutes between checks.
+
**Warning**: Slave support is OFF by default, turn it on by adding [`slave`](settings.md#slave) to the configuration.
**Note**: When running PowerDNS via the provided systemd service file, [`ProtectSystem`](http://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectSystem=) is set to `full`, this means PowerDNS is unable to write to e.g. `/etc` and `/home`, possibly being unable to write AXFR's zones.
bool d_masterschanged, d_slaveschanged;
bool d_preventSelfNotification;
+ // Used to keep some state on domains that failed their freshness checks.
+ // uint64_t == counter of the number of failures (increased by 1 every consecutive slave-cycle-interval that the domain fails)
+ // time_t == wait at least until this time before attempting a new check
+ map<DNSName, pair<uint64_t, time_t> > d_failedSlaveRefresh;
+
struct RemoveSentinel
{
explicit RemoveSentinel(const DNSName& dn, CommunicatorClass* cc) : d_dn(dn), d_cc(cc)
{
Lock l(&d_lock);
domains_by_name_t& nameindex=boost::multi_index::get<IDTag>(d_suckdomains);
+ time_t now = time(0);
for(DomainInfo& di : rdomains) {
+ const auto failed = d_failedSlaveRefresh.find(di.zone);
+ if (failed != d_failedSlaveRefresh.end() && now < failed->second.second )
+ // If the domain has failed before and the time before the next check has not expired, skip this domain
+ continue;
std::vector<std::string> localaddr;
SuckRequest sr;
sr.domain=di.zone;
L<<Logger::Warning<<"Received serial number updates for "<<ssr.d_freshness.size()<<" zone"<<addS(ssr.d_freshness.size())<<", had "<<ifl.getTimeouts()<<" timeout"<<addS(ifl.getTimeouts())<<endl;
typedef DomainNotificationInfo val_t;
+ time_t now = time(0);
for(val_t& val : sdomains) {
DomainInfo& di(val.di);
// might've come from the packethandler
continue;
}
- if(!ssr.d_freshness.count(di.id)) // what does this mean? XXX
+ if(!ssr.d_freshness.count(di.id)) { // If we don't have an answer for the domain
+ uint64_t newCount = 1;
+ const auto failedEntry = d_failedSlaveRefresh.find(di.zone);
+ if (failedEntry != d_failedSlaveRefresh.end())
+ newCount = d_failedSlaveRefresh[di.zone].first + 1;
+ time_t nextCheck = now + std::min(newCount * d_tickinterval, (uint64_t)::arg().asNum("soa-retry-default"));
+ d_failedSlaveRefresh[di.zone] = {newCount, nextCheck};
+ if (newCount == 1 || newCount % 10 == 0)
+ L<<Logger::Warning<<"Unable to retrieve SOA for "<<di.zone<<", this was the "<<(newCount == 1 ? "first" : std::to_string(newCount) + "th")<<" time."<<endl;
continue;
+ }
+
+ const auto wasFailedDomain = d_failedSlaveRefresh.find(di.zone);
+ if (wasFailedDomain != d_failedSlaveRefresh.end())
+ d_failedSlaveRefresh.erase(di.zone);
+
uint32_t theirserial = ssr.d_freshness[di.id].theirSerial, ourserial = di.serial;
if(rfc1982LessThan(theirserial, ourserial) && ourserial != 0) {