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::State> 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.
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 */
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::State> Bind2Backend::getState()
-{
- shared_ptr<State> 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)
if(id == 0) {
throw DBException("domain_id 0 is invalid for this backend.");
}
- shared_ptr<State> 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!"<<endl;
+ *d_of<<"; Zone '"+bbd.d_name+"' retrieved from master "<<endl<<"; at "<<nowTime()<<endl; // insert master info here again
+
+ return true;
}
-
- *d_of<<"; Written by PowerDNS, don't edit!"<<endl;
- *d_of<<"; Zone '"+bbd.d_name+"' retrieved from master "<<endl<<"; at "<<nowTime()<<endl; // insert master info here again
+ return false;
+}
- return true;
+bool Bind2Backend::safeGetBBDomainInfo(int id, BB2DomainInfo* bbd)
+{
+ ReadLock rl(&s_state_lock);
+ state_t::const_iterator iter = s_state.find(id);
+ if(iter == s_state.end())
+ return false;
+ *bbd=*iter;
}
bool Bind2Backend::commitTransaction()
return true;
delete d_of;
d_of=0;
- shared_ptr<State> 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;
{
string qname=r.qname;
- const shared_ptr<State> 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+"'");
void Bind2Backend::getUpdatedMasters(vector<DomainInfo> *changedDomains)
{
SOAData soadata;
- shared_ptr<State> 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<DomainInfo> *domains, bool include_disabled) {
+void Bind2Backend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled)
+{
+ ReadLock rl(&s_state_lock);
SOAData soadata;
- shared_ptr<State> 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);
}
void Bind2Backend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
{
- shared_ptr<State> 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;
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;
bool Bind2Backend::getDomainInfo(const string &domain, DomainInfo &di)
{
- shared_ptr<State> 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(...){}
void Bind2Backend::alsoNotifies(const string &domain, set<string> *ips)
{
- shared_ptr<State> state = getState();
+ ReadLock rl(&s_state_lock);
// combine global list with local list
for(set<string>::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<string>::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<string>::iterator it = i->d_also_notify.begin(); it != i->d_also_notify.end(); it++) {
(*ips).insert(*it);
}
return;
return ret;
}
-void Bind2Backend::parseZoneFile(shared_ptr<State> 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
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;
}
/** 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<State> 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<recordstorage_t> records = bb2.d_records.getWRITABLE();
bdr.qname=canonic(qnameu);
//cerr << "qname = " << bdr.qname << ", d_name = " << bb2.d_name << endl;
if(bb2.d_name.empty())
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: '"<<bdr.qname<<"', ";
bdr.qname=labelReverse(bdr.qname);
bdr.ttl=ttl;
bdr.priority=prio;
- records.insert(bdr);
+ records->insert(bdr);
}
string Bind2Backend::DLReloadNowHandler(const vector<string>&parts, Utility::pid_t ppid)
{
- shared_ptr<State> state = getState();
ostringstream ret;
for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) {
- if(state->name_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"<<bbd.d_status<<"\n";
+ // XXX supplant new bbd HOW?
}
else
ret<< *i << " no such domain\n";
string Bind2Backend::DLDomStatusHandler(const vector<string>&parts, Utility::pid_t ppid)
{
ostringstream ret;
- shared_ptr<State> state = getState();
if(parts.size() > 1) {
for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) {
- if(state->name_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"<<bbd.d_status<<"\n";
}
else
ret<< *i << " no such domain\n";
}
}
- else
- for(id_zone_map_t::iterator i=state->id_zone_map.begin(); i!=state->id_zone_map.end(); ++i)
- ret<< i->second.d_name << ": "<< (i->second.d_loaded ? "": "[rejected]") <<"\t"<<i->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"<<i->d_status<<"\n";
+ }
+ }
if(ret.str().empty())
ret<<"no domains passed";
string Bind2Backend::DLListRejectsHandler(const vector<string>&parts, Utility::pid_t ppid)
{
- shared_ptr<State> 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<<j->second.d_name<<"\t"<<j->second.d_status<<endl;
+ for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) {
+ if(!i->d_loaded)
+ ret<<i->d_name<<"\t"<<i->d_status<<endl;
+ }
return ret.str();
}
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<<Logger::Warning<<"Zone "<<domainname<< " loaded"<<endl;
return;
}
- s_state = shared_ptr<State>(new State);
if(loadZones) {
loadConfig();
s_first=0;
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<recordstorage_t> records)
}
}
-void Bind2Backend::doEmptyNonTerminals(shared_ptr<State> 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<recordstorage_t> records = bbd.d_records.getWRITABLE();
bool auth, doent=true;
set<string> qnames;
map<string, bool> nonterm;
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)
{
if(!(maxent))
{
- L<<Logger::Error<<"Zone '"<<bb2.d_name<<"' has too many empty non terminals."<<endl;
+ L<<Logger::Error<<"Zone '"<<bbd.d_name<<"' has too many empty non terminals."<<endl;
doent=false;
break;
}
pair<string, bool> 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<State> staging = shared_ptr<State>(new State);
-
if(!getArg("config").empty()) {
BindParser BP;
try {
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<recordstorage_t > (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<<Logger::Info<<d_logprefix<<" parsing '"<<i->name<<"' from file '"<<i->filename<<"'"<<endl;
try {
// we need to allocate a new vector so we don't kill the original, which is still in use!
- bbd->d_records=shared_ptr<recordstorage_t> (new recordstorage_t());
+ bbd.d_records=shared_ptr<recordstorage_t> (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;
if(status)
*status+=msg.str();
- staging->id_zone_map[bbd->d_id].d_status=msg.str();
+ bbd.d_status=msg.str();
+
L<<Logger::Warning<<d_logprefix<<msg.str()<<endl;
rejected++;
}
if(status)
*status+=msg.str();
- staging->id_zone_map[bbd->d_id].d_status=msg.str();
+ bbd.d_status=msg.str();
L<<Logger::Warning<<d_logprefix<<msg.str()<<endl;
rejected++;
}
}
- /*
- vector<vector<BBResourceRecord> *>&tmp=d_zone_id_map[bbd.d_id]; // shrink trick
- vector<vector<BBResourceRecord> *>(tmp).swap(tmp);
- */
}
// figure out which domains were new and which vanished
int remdomains=0;
set<string> 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<string> 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<string>::const_iterator k=diff.begin();k!=diff.end(); ++k) {
- L<<Logger::Error<<"Removing domain: "<<*k<<endl;
- s_state->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<string>::const_iterator k=diff.begin();k!=diff.end();++k)
- if(j->second.d_name==*k) {
- L<<Logger::Error<<"Removing records from zone '"<<j->second.d_name<<"' from memory"<<endl;
-
- j->second.d_loaded=false;
- nukeZoneRecords(&j->second);
-
- break;
- }
- }
-#endif
-
// count number of entirely new domains
vector<string> 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, "<<rejected<<" rejected, "<<newdomains<<" new, "<<remdomains<<" removed";
if(status)
}
}
-/** nuke all records from memory, keep bbd intact though. */
-void Bind2Backend::nukeZoneRecords(BB2DomainInfo *bbd)
-{
- bbd->d_loaded=0; // block further access
- bbd->d_records = shared_ptr<recordstorage_t > (new recordstorage_t);
-}
-
void Bind2Backend::queueReload(BB2DomainInfo *bbd)
{
- Lock l(&s_state_lock);
-
- shared_ptr<State> 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<recordstorage_t > 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<<Logger::Warning<<"Zone '"<<bbd->d_name<<"' ("<<bbd->d_filename<<") reloaded"<<endl;
}
catch(PDNSException &ae) {
{
string domain=toLower(qname);
- recordstorage_t::const_iterator iter = bbd.d_records->upper_bound(domain);
+ shared_ptr<const recordstorage_t> records = bbd.d_records.get();
+ recordstorage_t::const_iterator iter = records->upper_bound(domain);
if (before.empty()){
//cout<<"starting before for: '"<<domain<<"'"<<endl;
- iter = bbd.d_records->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;
}
//cerr<<"Now after"<<endl;
- iter = bbd.d_records->upper_bound(domain);
+ iter = records->upper_bound(domain);
- if(iter == bbd.d_records->end()) {
+ if(iter == records->end()) {
//cerr<<"\tFound the end, begin storage: '"<<bbd.d_records->begin()->qname<<"', '"<<bbd.d_name<<"'"<<endl;
after.clear(); // this does the right thing (i.e. point to apex, which is sure to have auth records)
} else {
while((!(iter->auth) && (!(iter->qtype == QType::NS))) || (!(iter->qtype)))
{
iter++;
- if(iter == bbd.d_records->end())
+ if(iter == records->end())
{
after.clear();
break;
bool Bind2Backend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, std::string& unhashed, std::string& before, std::string& after)
{
- shared_ptr<State> 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 "<<auth<<endl;
string lqname = toLower(qname);
// cerr<<"\nin bind2backend::getBeforeAndAfterAbsolute: nsec3 HASH for "<<auth<<", asked for: "<<lqname<< " (auth: "<<auth<<".)"<<endl;
typedef recordstorage_t::index<HashedTag>::type records_by_hashindex_t;
- records_by_hashindex_t& hashindex=boost::multi_index::get<HashedTag>(*bbd.d_records);
+ records_by_hashindex_t& hashindex=boost::multi_index::get<HashedTag>(*bbd.d_records.get());
// BOOST_FOREACH(const Bind2DNSRecord& bdr, hashindex) {
// cerr<<"Hash: "<<bdr.nsec3hash<<"\t"<< (lqname < bdr.nsec3hash) <<endl;
if(mustlog)
L<<Logger::Warning<<"Lookup for '"<<qtype.getName()<<"' of '"<<domain<<"'"<<endl;
- shared_ptr<State> state = s_state;
+ shared_ptr<const State> state = s_state.get();
name_id_map_t::const_iterator iditer;
do {
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
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"<<endl);
bool Bind2Backend::list(const string &target, int id, bool include_disabled)
{
- shared_ptr<State> state = s_state;
+ shared_ptr<const State> 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<<endl);
- d_handle.d_records=state->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<BBResourceRecords>
// this function really is too slow
bool Bind2Backend::isMaster(const string &name, const string &ip)
{
- shared_ptr<State> state = getState();
+ shared_ptr<const State> 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<string>::const_iterator iter = j->second.d_masters.begin(); iter != j->second.d_masters.end(); ++iter)
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<recordstorage_t >(new recordstorage_t);
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
}
// 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;
}