From: bert hubert Date: Wed, 12 Mar 2014 16:05:57 +0000 (+0100) Subject: it is a ip X-Git-Tag: rec-3.6.0-rc1~138^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f08339e316f3feb444f7bb02734b4354ea0bd8e2;p=thirdparty%2Fpdns.git it is a ip --- diff --git a/modules/bindbackend/bindbackend2.cc b/modules/bindbackend/bindbackend2.cc index 460ef6898f..8624d7160e 100644 --- a/modules/bindbackend/bindbackend2.cc +++ b/modules/bindbackend/bindbackend2.cc @@ -58,8 +58,7 @@ on start of query, we find the best zone to answer from */ -// this map contains BB2DomainInfo structs, each of which contains a *pointer* to domain data -shared_ptr Bind2Backend::s_state; +Bind2Backend::state_t Bind2Backend::s_state; /* the model is that all our state hides in s_state. This State instance consists of the id_zone_map, which contains all our zone information, indexed by id. Then there is the name_id_map, which allows us to map a query to a zone id. @@ -82,9 +81,7 @@ shared_ptr Bind2Backend::s_state; int Bind2Backend::s_first=1; bool Bind2Backend::s_ignore_broken_records=false; -pthread_mutex_t Bind2Backend::s_startup_lock=PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t Bind2Backend::s_state_lock=PTHREAD_MUTEX_INITIALIZER; -pthread_mutex_t Bind2Backend::s_state_swap_lock=PTHREAD_MUTEX_INITIALIZER; +pthread_rwlock_t Bind2Backend::s_state_lock; pthread_mutex_t Bind2Backend::s_supermaster_config_lock=PTHREAD_MUTEX_INITIALIZER; string Bind2Backend::s_binddirectory; /* when a query comes in, we find the most appropriate zone and answer from that */ @@ -140,24 +137,19 @@ void BB2DomainInfo::setCtime() void Bind2Backend::setNotified(uint32_t id, uint32_t serial) { - Lock l(&s_state_lock); - s_state->id_zone_map[id].d_lastnotified=serial; + BB2DomainInfo bbd; + safeGetBBDomainInfo(id, &bbd); + bbd.d_lastnotified = serial; + safePutBBDomainInfo(id, bbd); } void Bind2Backend::setFresh(uint32_t domain_id) { - Lock l(&s_state_lock); - s_state->id_zone_map[domain_id].d_lastcheck=time(0); -} - -shared_ptr Bind2Backend::getState() -{ - shared_ptr ret; - { - Lock l(&s_state_swap_lock); - ret = s_state; // is only read from + BB2DomainInfo bbd; + if(safeGetBBDomainInfo(domain_id, &bbd)) { + bbd.d_lastcheck=time(0); + safePutBBDomainInfo(domain_id, bbd); } - return ret; } bool Bind2Backend::startTransaction(const string &qname, int id) @@ -170,23 +162,34 @@ bool Bind2Backend::startTransaction(const string &qname, int id) if(id == 0) { throw DBException("domain_id 0 is invalid for this backend."); } - shared_ptr state = getState(); - const BB2DomainInfo &bbd=state->id_zone_map[d_transaction_id=id]; - - d_transaction_tmpname=bbd.d_filename+"."+itoa(random()); - d_of=new ofstream(d_transaction_tmpname.c_str()); - if(!*d_of) { - throw DBException("Unable to open temporary zonefile '"+d_transaction_tmpname+"': "+stringerror()); - unlink(d_transaction_tmpname.c_str()); - delete d_of; - d_of=0; + d_transaction_id=id; + BB2DomainInfo bbd; + if(safeGetBBDomainInfo(id, &bbd)) { + d_transaction_tmpname=bbd.d_filename+"."+itoa(random()); + d_of=new ofstream(d_transaction_tmpname.c_str()); + if(!*d_of) { + throw DBException("Unable to open temporary zonefile '"+d_transaction_tmpname+"': "+stringerror()); + unlink(d_transaction_tmpname.c_str()); + delete d_of; + d_of=0; + } + + *d_of<<"; Written by PowerDNS, don't edit!"< state = getState(); - // this might fail if s_state was cycled during the AXFR - if(rename(d_transaction_tmpname.c_str(), state->id_zone_map[d_transaction_id].d_filename.c_str())<0) - throw DBException("Unable to commit (rename to: '" + state->id_zone_map[d_transaction_id].d_filename+"') AXFRed zone: "+stringerror()); - - queueReload(&state->id_zone_map[d_transaction_id]); + BB2DomainInfo bbd; + if(safeGetBBDomainInfo(d_transaction_id, &bbd)) { + if(rename(d_transaction_tmpname.c_str(), bbd.d_filename.c_str())<0) + throw DBException("Unable to commit (rename to: '" + bbd.d_filename+"') AXFRed zone: "+stringerror()); + queueReload(&bbd); + } d_transaction_id=0; @@ -227,8 +230,10 @@ bool Bind2Backend::feedRecord(const DNSResourceRecord &r, string *ordername) { string qname=r.qname; - const shared_ptr state = getState(); - string domain = state->id_zone_map[d_transaction_id].d_name; + BB2DomainInfo bbd; + safeGetBBDomainInfo(d_transaction_id, &bbd); + + string domain = bbd.d_name; if(!stripDomainSuffix(&qname,domain)) throw DBException("out-of-zone data '"+qname+"' during AXFR of zone '"+domain+"'"); @@ -263,48 +268,52 @@ bool Bind2Backend::feedRecord(const DNSResourceRecord &r, string *ordername) void Bind2Backend::getUpdatedMasters(vector *changedDomains) { SOAData soadata; - shared_ptr state = getState(); + ReadLock rl(&s_state_lock); - for(id_zone_map_t::const_iterator i = state->id_zone_map.begin(); i != state->id_zone_map.end() ; ++i) { - if(!i->second.d_masters.empty() && this->alsoNotify.empty() && i->second.d_also_notify.empty()) + for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { + if(!i->d_masters.empty() && this->alsoNotify.empty() && i->d_also_notify.empty()) continue; soadata.serial=0; try { - this->getSOA(i->second.d_name, soadata); // we might not *have* a SOA yet, but this might trigger a load of it + this->getSOA(i->d_name, soadata); // we might not *have* a SOA yet, but this might trigger a load of it } catch(...){} DomainInfo di; - di.id=i->first; + di.id=i->d_id; di.serial=soadata.serial; - di.zone=i->second.d_name; - di.last_check=i->second.d_lastcheck; + di.zone=i->d_name; + di.last_check=i->d_lastcheck; di.backend=this; di.kind=DomainInfo::Master; - if(!i->second.d_lastnotified) { // don't do notification storm on startup - Lock l(&s_state_lock); - s_state->id_zone_map[i->first].d_lastnotified=soadata.serial; + if(!i->d_lastnotified) { // don't do notification storm on startup + // what if i->first is new?? + BB2DomainInfo bbd; + if(safeGetBBDomainInfo(i->d_id, &bbd)) { + bbd.d_lastnotified=soadata.serial; + safePutBBDomainInfo(i->d_id, bbd); + } } else - if(soadata.serial!=i->second.d_lastnotified) + if(soadata.serial != i->d_lastnotified) changedDomains->push_back(di); } } -void Bind2Backend::getAllDomains(vector *domains, bool include_disabled) { +void Bind2Backend::getAllDomains(vector *domains, bool include_disabled) +{ + ReadLock rl(&s_state_lock); SOAData soadata; - shared_ptr state = getState(); - - for(id_zone_map_t::const_iterator i = state->id_zone_map.begin(); i != state->id_zone_map.end() ; ++i) { + for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { soadata.db=(DNSBackend *)-1; // makes getSOA() skip the cache. - this->getSOA(i->second.d_name, soadata); + this->getSOA(i->d_name, soadata); DomainInfo di; - di.id=i->first; + di.id=i->d_id; di.serial=soadata.serial; - di.zone=i->second.d_name; - di.last_check=i->second.d_lastcheck; + di.zone=i->d_name; + di.last_check=i->d_lastcheck; di.backend=this; - di.kind=i->second.d_masters.empty() ? DomainInfo::Master : DomainInfo::Slave; //TODO: what about Native? + di.kind=i->d_masters.empty() ? DomainInfo::Master : DomainInfo::Slave; //TODO: what about Native? domains->push_back(di); } @@ -313,15 +322,15 @@ void Bind2Backend::getAllDomains(vector *domains, bool include_disab void Bind2Backend::getUnfreshSlaveInfos(vector *unfreshDomains) { - shared_ptr state = getState(); - for(id_zone_map_t::const_iterator i = state->id_zone_map.begin(); i != state->id_zone_map.end() ; ++i) { - if(i->second.d_masters.empty()) + ReadLock rl(&s_state_lock); + for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { + if(i->d_masters.empty()) continue; DomainInfo sd; - sd.id=i->first; - sd.zone=i->second.d_name; - sd.masters=i->second.d_masters; - sd.last_check=i->second.d_lastcheck; + sd.id=i->d_id; + sd.zone=i->d_name; + sd.masters=i->d_masters; + sd.last_check=i->d_lastcheck; sd.backend=this; sd.kind=DomainInfo::Slave; SOAData soadata; @@ -329,7 +338,7 @@ void Bind2Backend::getUnfreshSlaveInfos(vector *unfreshDomains) soadata.serial=0; soadata.db=(DNSBackend *)-1; // not sure if this is useful, inhibits any caches that might be around try { - getSOA(i->second.d_name,soadata); // we might not *have* a SOA yet + getSOA(i->d_name,soadata); // we might not *have* a SOA yet } catch(...){} sd.serial=soadata.serial; @@ -340,21 +349,21 @@ void Bind2Backend::getUnfreshSlaveInfos(vector *unfreshDomains) bool Bind2Backend::getDomainInfo(const string &domain, DomainInfo &di) { - shared_ptr state = getState(); - for(id_zone_map_t::const_iterator i = state->id_zone_map.begin(); i != state->id_zone_map.end() ; ++i) { // why is this a linear scan?? - if(pdns_iequals(i->second.d_name,domain)) { - di.id=i->first; + ReadLock rl(&s_state_lock); + for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { + if(pdns_iequals(i->d_name,domain)) { + di.id=i->d_id; di.zone=domain; - di.masters=i->second.d_masters; - di.last_check=i->second.d_lastcheck; + di.masters=i->d_masters; + di.last_check=i->d_lastcheck; di.backend=this; - di.kind=i->second.d_masters.empty() ? DomainInfo::Master : DomainInfo::Slave; + di.kind=i->d_masters.empty() ? DomainInfo::Master : DomainInfo::Slave; di.serial=0; try { SOAData sd; sd.serial=0; - getSOA(i->second.d_name,sd); // we might not *have* a SOA yet + getSOA(i->d_name,sd); // we might not *have* a SOA yet di.serial=sd.serial; } catch(...){} @@ -367,14 +376,14 @@ bool Bind2Backend::getDomainInfo(const string &domain, DomainInfo &di) void Bind2Backend::alsoNotifies(const string &domain, set *ips) { - shared_ptr state = getState(); + ReadLock rl(&s_state_lock); // combine global list with local list for(set::iterator i = this->alsoNotify.begin(); i != this->alsoNotify.end(); i++) { (*ips).insert(*i); } - for(id_zone_map_t::const_iterator i = state->id_zone_map.begin(); i != state->id_zone_map.end() ; ++i) { - if(i->second.d_name==domain) { - for(set::iterator it = i->second.d_also_notify.begin(); it != i->second.d_also_notify.end(); it++) { + for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { + if(pdns_iequals(i->d_name,domain)) { + for(set::iterator it = i->d_also_notify.begin(); it != i->d_also_notify.end(); it++) { (*ips).insert(*it); } return; @@ -398,12 +407,14 @@ static string canonic(string ret) return ret; } -void Bind2Backend::parseZoneFile(shared_ptr staging, BB2DomainInfo *bbd) +void Bind2Backend::parseZoneFile(BB2DomainInfo *bbd) { NSEC3PARAMRecordContent ns3pr; bool nsec3zone=getNSEC3PARAM(bbd->d_name, &ns3pr); ZoneParserTNG zpt(bbd->d_filename, bbd->d_name, s_binddirectory); + bbd->d_records.getWRITABLE().reset(); + DNSResourceRecord rr; string hashed; while(zpt.get(rr)) { // FIXME this code is duplicate @@ -416,11 +427,11 @@ void Bind2Backend::parseZoneFile(shared_ptr staging, BB2DomainInfo *bbd) else hashed=""; } - insert(staging, bbd->d_id, rr.qname, rr.qtype, rr.content, rr.ttl, rr.priority, hashed); + insert(*bbd, rr.qname, rr.qtype, rr.content, rr.ttl, rr.priority, hashed); } - fixupAuth(staging->id_zone_map[bbd->d_id].d_records); - doEmptyNonTerminals(staging, bbd->d_id, nsec3zone, ns3pr); + fixupAuth(bbd->d_records.getWRITABLE()); + doEmptyNonTerminals(*bbd, nsec3zone, ns3pr); bbd->setCtime(); bbd->d_loaded=true; @@ -428,15 +439,11 @@ void Bind2Backend::parseZoneFile(shared_ptr staging, BB2DomainInfo *bbd) } /** THIS IS AN INTERNAL FUNCTION! It does moadnsparser prio impedance matching - This function adds a record to a domain with a certain id. Much of the complication is due to the efforts to benefit from std::string reference counting copy on write semantics */ -void Bind2Backend::insert(shared_ptr stage, int id, const string &qnameu, const QType &qtype, const string &content, int ttl, int prio, const std::string& hashed, bool *auth) +void Bind2Backend::insert(BB2DomainInfo& bb2, const string &qnameu, const QType &qtype, const string &content, int ttl, int prio, const std::string& hashed, bool *auth) { - BB2DomainInfo bb2 = stage->id_zone_map[id]; Bind2DNSRecord bdr; - - recordstorage_t& records=*bb2.d_records; - + shared_ptr records = bb2.d_records.getWRITABLE(); bdr.qname=canonic(qnameu); //cerr << "qname = " << bdr.qname << ", d_name = " << bb2.d_name << endl; if(bb2.d_name.empty()) @@ -455,9 +462,8 @@ void Bind2Backend::insert(shared_ptr stage, int id, const string &qnameu, bdr.qname.swap(bdr.qname); - - if(!records.empty() && bdr.qname==boost::prior(records.end())->qname) - bdr.qname=boost::prior(records.end())->qname; + if(!records->empty() && bdr.qname==boost::prior(records->end())->qname) + bdr.qname=boost::prior(records->end())->qname; // cerr<<"Before reverse: '"< stage, int id, const string &qnameu, bdr.ttl=ttl; bdr.priority=prio; - records.insert(bdr); + records->insert(bdr); } string Bind2Backend::DLReloadNowHandler(const vector&parts, Utility::pid_t ppid) { - shared_ptr state = getState(); ostringstream ret; for(vector::const_iterator i=parts.begin()+1;iname_id_map.count(*i)) { - BB2DomainInfo& bbd=state->id_zone_map[state->name_id_map[*i]]; + BB2DomainInfo bbd; + if(safeGetBBDomainInfo(*i, &bbd)) { Bind2Backend bb2; bb2.queueReload(&bbd); ret<< *i << ": "<< (bbd.d_loaded ? "": "[rejected]") <<"\t"<&parts, Utility::pid string Bind2Backend::DLDomStatusHandler(const vector&parts, Utility::pid_t ppid) { ostringstream ret; - shared_ptr state = getState(); if(parts.size() > 1) { for(vector::const_iterator i=parts.begin()+1;iname_id_map.count(*i)) { - BB2DomainInfo& bbd=state->id_zone_map[state->name_id_map[*i]]; // XXX s_name_id_map needs trick as well + BB2DomainInfo bbd; + if(safeGetBBDomainInfo(*i, &bbd)) { ret<< *i << ": "<< (bbd.d_loaded ? "": "[rejected]") <<"\t"<id_zone_map.begin(); i!=state->id_zone_map.end(); ++i) - ret<< i->second.d_name << ": "<< (i->second.d_loaded ? "": "[rejected]") <<"\t"<second.d_status<<"\n"; + else { + ReadLock rl(&s_state_lock); + for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { + ret<< i->d_name << ": "<< (i->d_loaded ? "": "[rejected]") <<"\t"<d_status<<"\n"; + } + } if(ret.str().empty()) ret<<"no domains passed"; @@ -539,13 +547,13 @@ string Bind2Backend::DLDomStatusHandler(const vector&parts, Utility::pid string Bind2Backend::DLListRejectsHandler(const vector&parts, Utility::pid_t ppid) { - shared_ptr state = getState(); - + ReadLock rl(&s_state_lock); ostringstream ret; - for(id_zone_map_t::iterator j = state->id_zone_map.begin(); j != state->id_zone_map.end(); ++j) - if(!j->second.d_loaded) - ret<second.d_name<<"\t"<second.d_status<d_loaded) + ret<d_name<<"\t"<d_status<&parts, Utility::pid string domainname = canonic(parts[1]); const string &filename = parts[2]; - - if(getState()->name_id_map.count(domainname)) + BB2DomainInfo bbd; + if(safeGetBBDomainInfo(domainname, &bbd)) return "Already loaded"; - // Interference with loadConfig() and createSlaveDomain(), use locking - Lock l(&s_state_lock); - Bind2Backend bb2; - BB2DomainInfo& bbd = bb2.createDomainEntry(domainname, filename); + bb2.createDomainEntry(domainname, filename); bbd.d_filename=filename; bbd.d_checknow=true; bbd.d_loaded=true; bbd.d_lastcheck=0; bbd.d_status="parsing into memory"; - - s_state->name_id_map[bbd.d_name]=bbd.d_id; + + /// XXX ALL WRONG SUPPLANT L<(new State); if(loadZones) { loadConfig(); s_first=0; @@ -617,9 +621,10 @@ void Bind2Backend::rediscover(string *status) void Bind2Backend::reload() { - Lock l(&s_state_lock); - for(id_zone_map_t::iterator i = s_state->id_zone_map.begin(); i != s_state->id_zone_map.end(); ++i) - i->second.d_checknow=true; + WriteLock rwl(&s_state_lock); + for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) { + i->d_checknow=true; + } } void Bind2Backend::fixupAuth(shared_ptr records) @@ -651,10 +656,9 @@ void Bind2Backend::fixupAuth(shared_ptr records) } } -void Bind2Backend::doEmptyNonTerminals(shared_ptr stage, int id, bool nsec3zone, NSEC3PARAMRecordContent ns3pr) +void Bind2Backend::doEmptyNonTerminals(BB2DomainInfo& bbd, bool nsec3zone, NSEC3PARAMRecordContent ns3pr) { - BB2DomainInfo bb2 = stage->id_zone_map[id]; - + shared_ptr records = bbd.d_records.getWRITABLE(); bool auth, doent=true; set qnames; map nonterm; @@ -662,10 +666,10 @@ void Bind2Backend::doEmptyNonTerminals(shared_ptr stage, int id, bool nse uint32_t maxent = ::arg().asNum("max-ent-entries"); - BOOST_FOREACH(const Bind2DNSRecord& bdr, *bb2.d_records) + BOOST_FOREACH(const Bind2DNSRecord& bdr, *records) qnames.insert(labelReverse(bdr.qname)); - BOOST_FOREACH(const Bind2DNSRecord& bdr, *bb2.d_records) { + BOOST_FOREACH(const Bind2DNSRecord& bdr, *records) { shorter=labelReverse(bdr.qname); if (!bdr.auth && bdr.qtype == QType::NS) @@ -679,7 +683,7 @@ void Bind2Backend::doEmptyNonTerminals(shared_ptr stage, int id, bool nse { if(!(maxent)) { - L< stage, int id, bool nse pair nt; BOOST_FOREACH(nt, nonterm) { - rr.qname=nt.first+"."+bb2.d_name+"."; + rr.qname=nt.first+"."+bbd.d_name+"."; if(nsec3zone) hashed=toBase32Hex(hashQNameWithSalt(ns3pr.d_iterations, ns3pr.d_salt, rr.qname)); - insert(stage, id, rr.qname, rr.qtype, rr.content, rr.ttl, rr.priority, hashed, &nt.second); + insert(bbd, rr.qname, rr.qtype, rr.content, rr.ttl, rr.priority, hashed, &nt.second); } } void Bind2Backend::loadConfig(string* status) { - // Interference with createDomainEntry() - Lock l(&s_state_lock); - static int domain_id=1; - shared_ptr staging = shared_ptr(new State); - if(!getArg("config").empty()) { BindParser BP; try { @@ -761,44 +760,31 @@ void Bind2Backend::loadConfig(string* status) continue; } - BB2DomainInfo* bbd=0; - - if(!s_state->name_id_map.count(i->name)) { // is it fully new? - bbd=&staging->id_zone_map[domain_id]; - bbd->d_id=domain_id++; - - // this isn't necessary, we do this on the actual load - // bbd->d_records=shared_ptr (new recordstorage_t); + BB2DomainInfo bbd; - bbd->setCheckInterval(getArgAsNum("check-interval")); - bbd->d_lastnotified=0; - bbd->d_loaded=false; - } - else { // no, we knew about it already - staging->id_zone_map[s_state->name_id_map[i->name]] = s_state->id_zone_map[s_state->name_id_map[i->name]]; // these should all be read-only on s_state - bbd = &staging->id_zone_map[s_state->name_id_map[i->name]]; + if(!safeGetBBDomainInfo(i->name, &bbd)) { + bbd.d_id=domain_id++; + bbd.setCheckInterval(getArgAsNum("check-interval")); + bbd.d_lastnotified=0; + bbd.d_loaded=false; } - staging->name_id_map[i->name]=bbd->d_id; // fill out name -> id map - // overwrite what we knew about the domain - bbd->d_name=toLower(canonic(i->name)); + bbd.d_name=toLower(canonic(i->name)); - bool filenameChanged = (bbd->d_filename!=i->filename); - bbd->d_filename=i->filename; - bbd->d_masters=i->masters; - bbd->d_also_notify=i->alsoNotify; + bool filenameChanged = (bbd.d_filename!=i->filename); + bbd.d_filename=i->filename; + bbd.d_masters=i->masters; + bbd.d_also_notify=i->alsoNotify; - if(filenameChanged || !bbd->d_loaded || !bbd->current()) { + if(filenameChanged || !bbd.d_loaded || !bbd.current()) { L<name<<"' from file '"<filename<<"'"<d_records=shared_ptr (new recordstorage_t()); + bbd.d_records=shared_ptr (new recordstorage_t()); - parseZoneFile(staging, bbd); - - // s_stage->id_zone_map[bbd->d_id].d_records->swap(*s_staging_zone_map[bbd->d_id].d_records); + parseZoneFile(&bbd); } catch(PDNSException &ae) { ostringstream msg; @@ -806,7 +792,8 @@ void Bind2Backend::loadConfig(string* status) if(status) *status+=msg.str(); - staging->id_zone_map[bbd->d_id].d_status=msg.str(); + bbd.d_status=msg.str(); + L<id_zone_map[bbd->d_id].d_status=msg.str(); + bbd.d_status=msg.str(); L< *>&tmp=d_zone_id_map[bbd.d_id]; // shrink trick - vector *>(tmp).swap(tmp); - */ } // figure out which domains were new and which vanished int remdomains=0; set oldnames, newnames; - for(id_zone_map_t::const_iterator j=s_state->id_zone_map.begin();j != s_state->id_zone_map.end();++j) { +#if 0 + for(state_t::const_iterator j=state.get()->id_zone_map.begin();j != s_state.get()->id_zone_map.end();++j) { oldnames.insert(j->second.d_name); } for(id_zone_map_t::const_iterator j=staging->id_zone_map.begin(); j!= staging->id_zone_map.end(); ++j) { newnames.insert(j->second.d_name); } - +#endif vector diff; + set_difference(oldnames.begin(), oldnames.end(), newnames.begin(), newnames.end(), back_inserter(diff)); remdomains=diff.size(); -#if 0 - // remove domains from the *name* map, delete their pointer - for(vector::const_iterator k=diff.begin();k!=diff.end(); ++k) { - L<name_id_map.erase(*k); - } - - // now remove from the s_state->id_zone_map - for(id_zone_map_t::iterator j=s_state->id_zone_map.begin();j!=s_state->id_zone_map.end();++j) { // O(N*M) - for(vector::const_iterator k=diff.begin();k!=diff.end();++k) - if(j->second.d_name==*k) { - L<second.d_name<<"' from memory"<second.d_loaded=false; - nukeZoneRecords(&j->second); - - break; - } - } -#endif - // count number of entirely new domains vector diff2; set_difference(newnames.begin(), newnames.end(), oldnames.begin(), oldnames.end(), back_inserter(diff2)); newdomains=diff2.size(); - Lock l(&s_state_swap_lock); - s_state.swap(staging); + // NOW DO MAGIC STUFF SO THINGS WORK - // report ostringstream msg; msg<<" Done parsing domains, "<d_loaded=0; // block further access - bbd->d_records = shared_ptr (new recordstorage_t); -} - void Bind2Backend::queueReload(BB2DomainInfo *bbd) { - Lock l(&s_state_lock); - - shared_ptr staging(new State); - - // we reload *now* for the time being - try { - // nukeZoneRecords(bbd); // ? do we need this? - staging->id_zone_map[bbd->d_id]=s_state->id_zone_map[bbd->d_id]; + BB2DomainInfo bbold; + safeGetBBDomainInfo(bbd->d_id, &bbold); shared_ptr newrecords(new recordstorage_t); - staging->id_zone_map[bbd->d_id].d_records=newrecords; - - parseZoneFile(staging, &staging->id_zone_map[bbd->d_id]); - staging->id_zone_map[bbd->d_id].setCtime(); - - s_state->id_zone_map[bbd->d_id]=staging->id_zone_map[bbd->d_id]; // move over - - // bbd can still be in use in another thread so update it as well - // but dont update ctime and status on that copy - bbd->d_loaded=true; - bbd->d_checknow=false; + parseZoneFile(&bbold); + safePutBBDomainInfo(bbd->d_id, bbold); L<d_name<<"' ("<d_filename<<") reloaded"<upper_bound(domain); + shared_ptr records = bbd.d_records.get(); + recordstorage_t::const_iterator iter = records->upper_bound(domain); if (before.empty()){ //cout<<"starting before for: '"<upper_bound(domain); + iter = records->upper_bound(domain); - while(iter == bbd.d_records->end() || (iter->qname) > domain || (!(iter->auth) && (!(iter->qtype == QType::NS))) || (!(iter->qtype))) + while(iter == records->end() || (iter->qname) > domain || (!(iter->auth) && (!(iter->qtype == QType::NS))) || (!(iter->qtype))) iter--; before=iter->qname; @@ -946,9 +887,9 @@ bool Bind2Backend::findBeforeAndAfterUnhashed(BB2DomainInfo& bbd, const std::str } //cerr<<"Now after"<upper_bound(domain); + iter = records->upper_bound(domain); - if(iter == bbd.d_records->end()) { + if(iter == records->end()) { //cerr<<"\tFound the end, begin storage: '"<begin()->qname<<"', '"<auth) && (!(iter->qtype == QType::NS))) || (!(iter->qtype))) { iter++; - if(iter == bbd.d_records->end()) + if(iter == records->end()) { after.clear(); break; @@ -973,10 +914,12 @@ bool Bind2Backend::findBeforeAndAfterUnhashed(BB2DomainInfo& bbd, const std::str bool Bind2Backend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after) { - shared_ptr state = s_state; - BB2DomainInfo& bbd = state->id_zone_map[id]; + + BB2DomainInfo bbd; + safeGetBBDomainInfo(id, &bbd); + NSEC3PARAMRecordContent ns3pr; - string auth=state->id_zone_map[id].d_name; + string auth=bbd.d_name; if(!getNSEC3PARAM(auth, &ns3pr)) { //cerr<<"in bind2backend::getBeforeAndAfterAbsolute: no nsec3 for "<::type records_by_hashindex_t; - records_by_hashindex_t& hashindex=boost::multi_index::get(*bbd.d_records); + records_by_hashindex_t& hashindex=boost::multi_index::get(*bbd.d_records.get()); // BOOST_FOREACH(const Bind2DNSRecord& bdr, hashindex) { // cerr<<"Hash: "< state = s_state; + shared_ptr state = s_state.get(); name_id_map_t::const_iterator iditer; do { @@ -1105,8 +1048,8 @@ void Bind2Backend::lookup(const QType &qtype, const string &qname, DNSPacket *pk d_handle.qtype=qtype; d_handle.domain=qname.substr(qname.size()-domain.length()); - - BB2DomainInfo& bbd = state->id_zone_map[iditer->second]; + BB2DomainInfo bbd; + safeGetBBDomainInfo(iditer->second, &bbd); if(!bbd.d_loaded) { d_handle.reset(); throw DBException("Zone for '"+bbd.d_name+"' in '"+bbd.d_filename+"' temporarily not available (file missing, or master dead)"); // fsck @@ -1118,7 +1061,7 @@ void Bind2Backend::lookup(const QType &qtype, const string &qname, DNSPacket *pk throw DBException("Zone for '"+bbd.d_name+"' in '"+bbd.d_filename+"' being reloaded"); // if we don't throw here, we crash for some reason } - d_handle.d_records = bbd.d_records; // give it a reference counted copy + d_handle.d_records = bbd.d_records.get(); if(d_handle.d_records->empty()) DLOG(L<<"Query with no results"< state = s_state; + shared_ptr state = s_state.get(); if(!state->id_zone_map.count(id)) return false; d_handle.reset(); DLOG(L<<"Bind2Backend constructing handle for list of "<id_zone_map[id].d_records; // give it a copy, which will stay around + d_handle.d_records=state->id_zone_map[id].d_records.get(); // give it a copy, which will stay around d_handle.d_qname_iter= d_handle.d_records->begin(); d_handle.d_qname_end=d_handle.d_records->end(); // iter now points to a vector of pointers to vector @@ -1263,7 +1206,7 @@ bool Bind2Backend::handle::get_list(DNSResourceRecord &r) // this function really is too slow bool Bind2Backend::isMaster(const string &name, const string &ip) { - shared_ptr state = getState(); + shared_ptr state = s_state.get(); for(id_zone_map_t::iterator j=state->id_zone_map.begin(); j!=state->id_zone_map.end();++j) { if(j->second.d_name==name) { for(vector::const_iterator iter = j->second.d_masters.begin(); iter != j->second.d_masters.end(); ++iter) @@ -1316,12 +1259,12 @@ BB2DomainInfo &Bind2Backend::createDomainEntry(const string &domain, const strin int newid=1; // Find a free zone id nr. - if (!s_state->id_zone_map.empty()) { - id_zone_map_t::reverse_iterator i = s_state->id_zone_map.rbegin(); + if (!s_state.get()->id_zone_map.empty()) { + id_zone_map_t::reverse_iterator i = s_state.get()->id_zone_map.rbegin(); newid = i->second.d_id + 1; } - BB2DomainInfo &bbd = s_state->id_zone_map[newid]; + BB2DomainInfo &bbd = s_state.get()->id_zone_map[newid]; bbd.d_id = newid; bbd.d_records = shared_ptr(new recordstorage_t); @@ -1334,7 +1277,6 @@ BB2DomainInfo &Bind2Backend::createDomainEntry(const string &domain, const strin bool Bind2Backend::createSlaveDomain(const string &ip, const string &domain, const string &nameserver, const string &account) { - string filename = getArg("supermaster-destdir")+'/'+domain; L << Logger::Warning << d_logprefix @@ -1361,13 +1303,13 @@ bool Bind2Backend::createSlaveDomain(const string &ip, const string &domain, con } // Interference with loadConfig() and DLAddDomainHandler(), use locking - Lock l(&s_state_lock); + Lock l(&s_state.d_lock); BB2DomainInfo &bbd = createDomainEntry(canonic(domain), filename); bbd.d_masters.push_back(ip); - s_state->name_id_map[bbd.d_name] = bbd.d_id; + s_state.get()->name_id_map[bbd.d_name] = bbd.d_id; return true; } diff --git a/modules/bindbackend/bindbackend2.hh b/modules/bindbackend/bindbackend2.hh index 713b3e426b..51ae43bff3 100644 --- a/modules/bindbackend/bindbackend2.hh +++ b/modules/bindbackend/bindbackend2.hh @@ -36,6 +36,7 @@ #include #include #include +#include "pdns/lock.hh" #include "pdns/misc.hh" #include "pdns/dnsbackend.hh" @@ -90,6 +91,55 @@ typedef multi_index_container< > > recordstorage_t; +template +class LookButDontTouch // : public boost::noncopyable +{ +public: + LookButDontTouch() + { + pthread_mutex_init(&d_lock, 0); + pthread_mutex_init(&d_swaplock, 0); + } + LookButDontTouch(shared_ptr records) : d_records(records) + { + pthread_mutex_init(&d_lock, 0); + pthread_mutex_init(&d_swaplock, 0); + } + + shared_ptr get() + { + shared_ptr ret; + { + Lock l(&d_lock); + ret = d_records; + } + return ret; + } + + shared_ptr getWRITABLE() + { + shared_ptr ret; + { + Lock l(&d_lock); + ret = d_records; + } + return ret; + } + + + void swap(shared_ptr records) + { + Lock l(&d_lock); + Lock l2(&d_swaplock); + d_records.swap(records); + } + pthread_mutex_t d_lock; + pthread_mutex_t d_swaplock; +private: + shared_ptr d_records; +}; + + /** Class which describes all metadata of a domain for storage by the Bind2Backend, and also contains a pointer to a vector of Bind2DNSRecord's */ class BB2DomainInfo { @@ -113,7 +163,7 @@ public: uint32_t d_lastnotified; //!< Last serial number we notified our slaves of - shared_ptr d_records; //!< the actual records belonging to this domain + LookButDontTouch d_records; //!< the actual records belonging to this domain private: time_t getCtime(); time_t d_checkinterval; @@ -167,17 +217,15 @@ public: // end of DNSSEC - typedef map name_id_map_t; - typedef map id_zone_map_t; + typedef multi_index_container < BB2DomainInfo , + indexed_by < ordered_unique >, + ordered_unique, CIStringCompare > + > > state_t; + static state_t s_state; + static pthread_rwlock_t s_state_lock; - struct State : public boost::noncopyable - { - name_id_map_t name_id_map; //!< convert a name to a domain id - id_zone_map_t id_zone_map; - }; - - void parseZoneFile(shared_ptr staging, BB2DomainInfo *bbd); - static void insert(shared_ptr stage, int id, const string &qname, const QType &qtype, const string &content, int ttl=300, int prio=25, const std::string& hashed=string(), bool *auth=0); + void parseZoneFile(BB2DomainInfo *bbd); + static void insert(BB2DomainInfo& bbd, const string &qname, const QType &qtype, const string &content, int ttl=300, int prio=25, const std::string& hashed=string(), bool *auth=0); void rediscover(string *status=0); bool isMaster(const string &name, const string &ip); @@ -190,6 +238,10 @@ public: private: void setupDNSSEC(); + static bool safeGetBBDomainInfo(int id, BB2DomainInfo* bbd); + static bool safePutBBDomainInfo(int id, const BB2DomainInfo& bbd); + static bool safeGetBBDomainInfo(const std::string& name, BB2DomainInfo* bbd); + bool GetBBDomainInfo(int id, BB2DomainInfo** bbd); shared_ptr d_dnssecdb; bool getNSEC3PARAM(const std::string& zname, NSEC3PARAMRecordContent* ns3p); class handle @@ -200,9 +252,8 @@ private: handle(); - shared_ptr d_records; + shared_ptr d_records; recordstorage_t::const_iterator d_iter, d_end_iter; - recordstorage_t::const_iterator d_qname_iter; recordstorage_t::const_iterator d_qname_end; @@ -222,11 +273,6 @@ private: handle(const handle &); }; - - static shared_ptr s_state; - static pthread_mutex_t s_state_lock; //!< lock protecting ??? - static pthread_mutex_t s_state_swap_lock; - static shared_ptr getState(); static int s_first; //!< this is raised on construction to prevent multiple instances of us being generated static bool s_ignore_broken_records; @@ -251,7 +297,7 @@ private: static string DLReloadNowHandler(const vector&parts, Utility::pid_t ppid); static string DLAddDomainHandler(const vector&parts, Utility::pid_t ppid); static void fixupAuth(shared_ptr records); - static void doEmptyNonTerminals(shared_ptr stage, int id, bool nsec3zone, NSEC3PARAMRecordContent ns3pr); + static void doEmptyNonTerminals(BB2DomainInfo& bbd, bool nsec3zone, NSEC3PARAMRecordContent ns3pr); void loadConfig(string *status=0); static void nukeZoneRecords(BB2DomainInfo *bbd); };