BIND 10 trac2268, updated. b3d273056fa988f289ae4bf3f0a677808613b97b [2268] Sort oft-used RRTypes to be in front of RdataSet lists
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Oct 3 10:59:39 UTC 2012
The branch, trac2268 has been updated
via b3d273056fa988f289ae4bf3f0a677808613b97b (commit)
via b9250ecc03ef6854def286e388e9042fbd579971 (commit)
via 8de132995eade03f030a3a66c0f0bf4bc1b0726c (commit)
via 86fcb73a66e62bda72bf5d6aea7f1f852c7f5739 (commit)
via 61beda153425bfbd855c9bca9ff51fb0e99f2943 (commit)
via 038ba06b6e663343e93e63e0d77d3e3c1abf66bf (commit)
via b643e4ef3098a5671687031b2b1348ef60c780fa (commit)
via 371a652b90f43c0a2759b2be4d2fb6ef95d57ff0 (commit)
from 7eaa1760f3ed6cd57cf1b8458516fa3d457371d7 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit b3d273056fa988f289ae4bf3f0a677808613b97b
Author: Mukund Sivaraman <muks at isc.org>
Date: Wed Oct 3 16:20:48 2012 +0530
[2268] Sort oft-used RRTypes to be in front of RdataSet lists
commit b9250ecc03ef6854def286e388e9042fbd579971
Author: Mukund Sivaraman <muks at isc.org>
Date: Wed Oct 3 15:35:08 2012 +0530
[2268] Remove unused includes from InMemoryClient implementation
commit 8de132995eade03f030a3a66c0f0bf4bc1b0726c
Author: Mukund Sivaraman <muks at isc.org>
Date: Wed Oct 3 15:29:38 2012 +0530
[2268] Untabify code
commit 86fcb73a66e62bda72bf5d6aea7f1f852c7f5739
Author: Mukund Sivaraman <muks at isc.org>
Date: Wed Oct 3 15:28:16 2012 +0530
[2268] Remove pimpl from InMemoryClient
commit 61beda153425bfbd855c9bca9ff51fb0e99f2943
Author: Mukund Sivaraman <muks at isc.org>
Date: Wed Oct 3 15:04:51 2012 +0530
[2268] Remove unused member variables from InMemoryClient::Loader
commit 038ba06b6e663343e93e63e0d77d3e3c1abf66bf
Author: Mukund Sivaraman <muks at isc.org>
Date: Wed Oct 3 14:52:28 2012 +0530
[2268] Use the ZoneDataUpdater in test code too
commit b643e4ef3098a5671687031b2b1348ef60c780fa
Author: Mukund Sivaraman <muks at isc.org>
Date: Wed Oct 3 14:40:35 2012 +0530
[2268] Use ZoneDataUpdater in InMemoryClient
commit 371a652b90f43c0a2759b2be4d2fb6ef95d57ff0
Author: Mukund Sivaraman <muks at isc.org>
Date: Wed Oct 3 13:25:34 2012 +0530
[2268] Add ZoneDataUpdater class
-----------------------------------------------------------------------
Summary of changes:
src/lib/datasrc/memory/Makefile.am | 3 +-
src/lib/datasrc/memory/memory_client.cc | 497 ++------------------
src/lib/datasrc/memory/memory_client.h | 68 ++-
src/lib/datasrc/memory/zone_data_updater.cc | 406 ++++++++++++++++
src/lib/datasrc/memory/zone_data_updater.h | 132 ++++++
.../datasrc/tests/memory/memory_client_unittest.cc | 55 +--
.../datasrc/tests/memory/zone_finder_unittest.cc | 129 +----
7 files changed, 651 insertions(+), 639 deletions(-)
create mode 100644 src/lib/datasrc/memory/zone_data_updater.cc
create mode 100644 src/lib/datasrc/memory/zone_data_updater.h
-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index 3bdec0d..d46a907 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -16,10 +16,11 @@ libdatasrc_memory_la_SOURCES += treenode_rrset.h treenode_rrset.cc
libdatasrc_memory_la_SOURCES += rdata_serialization.h rdata_serialization.cc
libdatasrc_memory_la_SOURCES += zone_data.h zone_data.cc
libdatasrc_memory_la_SOURCES += segment_object_holder.h
-libdatasrc_memory_la_SOURCES += memory_client.h memory_client.cc
libdatasrc_memory_la_SOURCES += logger.h logger.cc
libdatasrc_memory_la_SOURCES += zone_table.h zone_table.cc
libdatasrc_memory_la_SOURCES += zone_finder.h zone_finder.cc
+libdatasrc_memory_la_SOURCES += zone_data_updater.h zone_data_updater.cc
+libdatasrc_memory_la_SOURCES += memory_client.h memory_client.cc
nodist_libdatasrc_memory_la_SOURCES = memory_messages.h memory_messages.cc
EXTRA_DIST = rdata_serialization_priv.cc
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index 5f6f510..008c131 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -17,12 +17,11 @@
#include <datasrc/memory/memory_client.h>
#include <datasrc/memory/logger.h>
#include <datasrc/memory/zone_data.h>
-#include <datasrc/memory/rdata_serialization.h>
#include <datasrc/memory/rdataset.h>
-#include <datasrc/memory/domaintree.h>
#include <datasrc/memory/segment_object_holder.h>
#include <datasrc/memory/treenode_rrset.h>
#include <datasrc/memory/zone_finder.h>
+#include <datasrc/memory/zone_data_updater.h>
#include <util/memory_segment_local.h>
@@ -31,15 +30,11 @@
#include <datasrc/result.h>
#include <dns/name.h>
-#include <dns/nsec3hash.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
#include <dns/rrsetlist.h>
#include <dns/masterload.h>
-#include <boost/function.hpp>
-#include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/noncopyable.hpp>
@@ -54,7 +49,6 @@ using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::datasrc::memory;
-using boost::scoped_ptr;
namespace isc {
namespace datasrc {
@@ -62,414 +56,12 @@ namespace memory {
using detail::SegmentObjectHolder;
-namespace {
-// Some type aliases
-typedef DomainTree<std::string> FileNameTree;
-typedef DomainTreeNode<std::string> FileNameNode;
-
-// A functor type used for loading.
-typedef boost::function<void(ConstRRsetPtr)> LoadCallback;
-
-} // end of anonymous namespace
-
-/// Implementation details for \c InMemoryClient hidden from the public
-/// interface.
-///
-/// For now, \c InMemoryClient only contains a \c ZoneTable object, which
-/// consists of (pointers to) \c InMemoryZoneFinder objects, we may add more
-/// member variables later for new features.
-class InMemoryClient::InMemoryClientImpl {
-private:
- // The deleter for the filenames stored in the tree.
- struct FileNameDeleter {
- FileNameDeleter() {}
- void operator()(std::string* filename) const {
- delete filename;
- }
- };
-
+class InMemoryClient::FileNameDeleter {
public:
- InMemoryClientImpl(util::MemorySegment& mem_sgmt, RRClass rrclass) :
- mem_sgmt_(mem_sgmt),
- rrclass_(rrclass),
- zone_count_(0),
- zone_table_(ZoneTable::create(mem_sgmt_, rrclass)),
- file_name_tree_(FileNameTree::create(mem_sgmt_, false))
- {}
- ~InMemoryClientImpl() {
- FileNameDeleter deleter;
- FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
-
- ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
- }
-
- util::MemorySegment& mem_sgmt_;
- const RRClass rrclass_;
- unsigned int zone_count_;
- ZoneTable* zone_table_;
- FileNameTree* file_name_tree_;
-
- // Common process for zone load.
- // rrset_installer is a functor that takes another functor as an argument,
- // and expected to call the latter for each RRset of the zone. How the
- // sequence of the RRsets is generated depends on the internal
- // details of the loader: either from a textual master file or from
- // another data source.
- // filename is the file name of the master file or empty if the zone is
- // loaded from another data source.
- result::Result load(const Name& zone_name, const string& filename,
- boost::function<void(LoadCallback)> rrset_installer);
-
- // Add the necessary magic for any wildcard contained in 'name'
- // (including itself) to be found in the zone.
- //
- // In order for wildcard matching to work correctly in the zone finder,
- // we must ensure that a node for the wildcarding level exists in the
- // backend ZoneTree.
- // E.g. if the wildcard name is "*.sub.example." then we must ensure
- // that "sub.example." exists and is marked as a wildcard level.
- // Note: the "wildcarding level" is for the parent name of the wildcard
- // name (such as "sub.example.").
- //
- // We also perform the same trick for empty wild card names possibly
- // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
- void addWildcards(const Name& zone_name, ZoneData& zone_data,
- const Name& name)
- {
- Name wname(name);
- const unsigned int labels(wname.getLabelCount());
- const unsigned int origin_labels(zone_name.getLabelCount());
- for (unsigned int l = labels;
- l > origin_labels;
- --l, wname = wname.split(1)) {
- if (wname.isWildcard()) {
- LOG_DEBUG(logger, DBG_TRACE_DATA,
- DATASRC_MEMORY_MEM_ADD_WILDCARD).arg(name);
-
- // Ensure a separate level exists for the "wildcarding" name,
- // and mark the node as "wild".
- ZoneNode* node;
- zone_data.insertName(mem_sgmt_, wname.split(1), &node);
- node->setFlag(ZoneData::WILDCARD_NODE);
-
- // Ensure a separate level exists for the wildcard name.
- // Note: for 'name' itself we do this later anyway, but the
- // overhead should be marginal because wildcard names should
- // be rare.
- zone_data.insertName(mem_sgmt_, wname, &node);
- }
- }
- }
-
- /*
- * Does some checks in context of the data that are already in the zone.
- * Currently checks for forbidden combinations of RRsets in the same
- * domain (CNAME+anything, DNAME+NS).
- *
- * If such condition is found, it throws AddError.
- */
- void contextCheck(const Name& zone_name, const AbstractRRset& rrset,
- const RdataSet* set) const
- {
- // Ensure CNAME and other type of RR don't coexist for the same
- // owner name except with NSEC, which is the only RR that can coexist
- // with CNAME (and also RRSIG, which is handled separately)
- if (rrset.getType() == RRType::CNAME()) {
- for (const RdataSet* sp = set; sp != NULL; sp = sp->getNext()) {
- if (sp->type != RRType::NSEC()) {
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_CNAME_TO_NONEMPTY).
- arg(rrset.getName());
- isc_throw(AddError, "CNAME can't be added with "
- << sp->type << " RRType for "
- << rrset.getName());
- }
- }
- } else if ((rrset.getType() != RRType::NSEC()) &&
- (RdataSet::find(set, RRType::CNAME()) != NULL)) {
- LOG_ERROR(logger,
- DATASRC_MEMORY_MEM_CNAME_COEXIST).arg(rrset.getName());
- isc_throw(AddError, "CNAME and " << rrset.getType() <<
- " can't coexist for " << rrset.getName());
- }
-
- /*
- * Similar with DNAME, but it must not coexist only with NS and only in
- * non-apex domains.
- * RFC 2672 section 3 mentions that it is implied from it and RFC 2181
- */
- if (rrset.getName() != zone_name &&
- // Adding DNAME, NS already there
- ((rrset.getType() == RRType::DNAME() &&
- RdataSet::find(set, RRType::NS()) != NULL) ||
- // Adding NS, DNAME already there
- (rrset.getType() == RRType::NS() &&
- RdataSet::find(set, RRType::DNAME()) != NULL)))
- {
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_DNAME_NS).arg(rrset.getName());
- isc_throw(AddError, "DNAME can't coexist with NS in non-apex "
- "domain " << rrset.getName());
- }
- }
-
- // Validate rrset before adding it to the zone. If something is wrong
- // it throws an exception. It doesn't modify the zone, and provides
- // the strong exception guarantee.
- void addValidation(const Name& zone_name, const ConstRRsetPtr rrset) {
- if (!rrset) {
- isc_throw(NullRRset, "The rrset provided is NULL");
- }
- if (rrset->getRdataCount() == 0) {
- isc_throw(AddError, "The rrset provided is empty: " <<
- rrset->getName() << "/" << rrset->getType());
- }
- // Check for singleton RRs. It should probably handled at a different
- // layer in future.
- if ((rrset->getType() == RRType::CNAME() ||
- rrset->getType() == RRType::DNAME()) &&
- rrset->getRdataCount() > 1)
- {
- // XXX: this is not only for CNAME or DNAME. We should generalize
- // this code for all other "singleton RR types" (such as SOA) in a
- // separate task.
- LOG_ERROR(logger,
- DATASRC_MEMORY_MEM_SINGLETON).arg(rrset->getName()).
- arg(rrset->getType());
- isc_throw(AddError, "multiple RRs of singleton type for "
- << rrset->getName());
- }
- // NSEC3/NSEC3PARAM is not a "singleton" per protocol, but this
- // implementation requests it be so at the moment.
- if ((rrset->getType() == RRType::NSEC3() ||
- rrset->getType() == RRType::NSEC3PARAM()) &&
- rrset->getRdataCount() > 1) {
- isc_throw(AddError, "Multiple NSEC3/NSEC3PARAM RDATA is given for "
- << rrset->getName() << " which isn't supported");
- }
-
- // For RRSIGs, check consistency of the type covered.
- // We know the RRset isn't empty, so the following check is safe.
- if (rrset->getType() == RRType::RRSIG()) {
- RdataIteratorPtr rit = rrset->getRdataIterator();
- const RRType covered = dynamic_cast<const generic::RRSIG&>(
- rit->getCurrent()).typeCovered();
- for (rit->next(); !rit->isLast(); rit->next()) {
- if (dynamic_cast<const generic::RRSIG&>(
- rit->getCurrent()).typeCovered() != covered) {
- isc_throw(AddError, "RRSIG contains mixed covered types: "
- << rrset->toText());
- }
- }
- }
-
- const NameComparisonResult compare =
- zone_name.compare(rrset->getName());
- if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
- compare.getRelation() != NameComparisonResult::EQUAL)
- {
- LOG_ERROR(logger,
- DATASRC_MEMORY_MEM_OUT_OF_ZONE).arg(rrset->getName()).
- arg(zone_name);
- isc_throw(OutOfZone, "The name " << rrset->getName() <<
- " is not contained in zone " << zone_name);
- }
+ FileNameDeleter() {}
- // Some RR types do not really work well with a wildcard.
- // Even though the protocol specifically doesn't completely ban such
- // usage, we refuse to load a zone containing such RR in order to
- // keep the lookup logic simpler and more predictable.
- // See RFC4592 and (for DNAME) RFC6672 for more technical background.
- // Note also that BIND 9 refuses NS at a wildcard, so in that sense
- // we simply provide compatible behavior.
- if (rrset->getName().isWildcard()) {
- if (rrset->getType() == RRType::NS()) {
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_NS).
- arg(rrset->getName());
- isc_throw(AddError, "Invalid NS owner name (wildcard): " <<
- rrset->getName());
- }
- if (rrset->getType() == RRType::DNAME()) {
- LOG_ERROR(logger, DATASRC_MEMORY_MEM_WILDCARD_DNAME).
- arg(rrset->getName());
- isc_throw(AddError, "Invalid DNAME owner name (wildcard): " <<
- rrset->getName());
- }
- }
-
- // Owner names of NSEC3 have special format as defined in RFC5155,
- // and cannot be a wildcard name or must be one label longer than
- // the zone origin. While the RFC doesn't prohibit other forms of
- // names, no sane zone would have such names for NSEC3.
- // BIND 9 also refuses NSEC3 at wildcard.
- if (rrset->getType() == RRType::NSEC3() &&
- (rrset->getName().isWildcard() ||
- rrset->getName().getLabelCount() !=
- zone_name.getLabelCount() + 1)) {
- LOG_ERROR(logger, DATASRC_MEMORY_BAD_NSEC3_NAME).
- arg(rrset->getName());
- isc_throw(AddError, "Invalid NSEC3 owner name: " <<
- rrset->getName());
- }
- }
-
- void addNSEC3(const ConstRRsetPtr rrset,
- const ConstRRsetPtr rrsig,
- ZoneData& zone_data)
- {
- // We know rrset has exactly one RDATA
- const generic::NSEC3& nsec3_rdata =
- dynamic_cast<const generic::NSEC3&>(
- rrset->getRdataIterator()->getCurrent());
-
- NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
- if (nsec3_data == NULL) {
- nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
- zone_data.setNSEC3Data(nsec3_data);
- zone_data.setSigned(true);
- } else {
- size_t salt_len = nsec3_data->getSaltLen();
- const uint8_t* salt_data = nsec3_data->getSaltData();
- const vector<uint8_t>& salt_data_2 = nsec3_rdata.getSalt();
-
- if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
- (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
- (salt_data_2.size() != salt_len)) {
- isc_throw(AddError,
- "NSEC3 with inconsistent parameters: " <<
- rrset->toText());
- }
- if ((salt_len > 0) &&
- (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
- isc_throw(AddError,
- "NSEC3 with inconsistent parameters: " <<
- rrset->toText());
- }
- }
-
- ZoneNode* node;
- nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
-
- RdataEncoder encoder;
- RdataSet* set = RdataSet::create(mem_sgmt_, encoder, rrset, rrsig);
- RdataSet* old_set = node->setData(set);
- if (old_set != NULL) {
- RdataSet::destroy(mem_sgmt_, rrclass_, old_set);
- }
- }
-
- void addRdataSet(const Name& zone_name, ZoneData& zone_data,
- const ConstRRsetPtr rrset, const ConstRRsetPtr rrsig)
- {
- if (rrset->getType() == RRType::NSEC3()) {
- addNSEC3(rrset, rrsig, zone_data);
- } else {
- ZoneNode* node;
- zone_data.insertName(mem_sgmt_, rrset->getName(), &node);
-
- RdataSet* rdataset_head = node->getData();
-
- // Checks related to the surrounding data.
- // Note: when the check fails and the exception is thrown,
- // it may break strong exception guarantee. At the moment
- // we prefer code simplicity and don't bother to introduce
- // complicated recovery code.
- contextCheck(zone_name, *rrset, rdataset_head);
-
- if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
- isc_throw(AddError,
- "RRset of the type already exists: "
- << rrset->getName() << " (type: "
- << rrset->getType() << ")");
- }
-
- RdataEncoder encoder;
- RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder, rrset,
- rrsig);
- rdataset->next = rdataset_head;
- node->setData(rdataset);
-
- // Ok, we just put it in
-
- // If this RRset creates a zone cut at this node, mark the
- // node indicating the need for callback in find().
- if (rrset->getType() == RRType::NS() &&
- rrset->getName() != zone_name) {
- node->setFlag(ZoneNode::FLAG_CALLBACK);
- // If it is DNAME, we have a callback as well here
- } else if (rrset->getType() == RRType::DNAME()) {
- node->setFlag(ZoneNode::FLAG_CALLBACK);
- }
-
- // If we've added NSEC3PARAM at zone origin, set up NSEC3
- // specific data or check consistency with already set up
- // parameters.
- if (rrset->getType() == RRType::NSEC3PARAM() &&
- rrset->getName() == zone_name) {
- // We know rrset has exactly one RDATA
- const generic::NSEC3PARAM& param =
- dynamic_cast<const generic::NSEC3PARAM&>
- (rrset->getRdataIterator()->getCurrent());
-
- NSEC3Data* nsec3_data = zone_data.getNSEC3Data();
- if (nsec3_data == NULL) {
- nsec3_data = NSEC3Data::create(mem_sgmt_, param);
- zone_data.setNSEC3Data(nsec3_data);
- zone_data.setSigned(true);
- } else {
- size_t salt_len = nsec3_data->getSaltLen();
- const uint8_t* salt_data = nsec3_data->getSaltData();
- const vector<uint8_t>& salt_data_2 = param.getSalt();
-
- if ((param.getHashalg() != nsec3_data->hashalg) ||
- (param.getIterations() != nsec3_data->iterations) ||
- (salt_data_2.size() != salt_len)) {
- isc_throw(AddError,
- "NSEC3PARAM with inconsistent parameters: "
- << rrset->toText());
- }
-
- if ((salt_len > 0) &&
- (std::memcmp(&salt_data_2[0],
- salt_data, salt_len) != 0)) {
- isc_throw(AddError,
- "NSEC3PARAM with inconsistent parameters: "
- << rrset->toText());
- }
- }
- } else if (rrset->getType() == RRType::NSEC()) {
- // If it is NSEC signed zone, we mark the zone as signed
- // (conceptually "signed" is a broader notion but our current
- // zone finder implementation regards "signed" as "NSEC
- // signed")
- zone_data.setSigned(true);
- }
- }
- }
-
- // Implementation of InMemoryClient::add()
- void add(const ConstRRsetPtr& rrset, const ConstRRsetPtr& sig_rrset,
- const Name& zone_name, ZoneData& zone_data)
- {
- // Sanitize input. This will cause an exception to be thrown
- // if the input RRset is empty.
- addValidation(zone_name, rrset);
- if (sig_rrset) {
- addValidation(zone_name, sig_rrset);
- }
-
- // OK, can add the RRset.
- LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEMORY_MEM_ADD_RRSET).
- arg(rrset->getName()).arg(rrset->getType()).arg(zone_name);
-
- // Add wildcards possibly contained in the owner name to the domain
- // tree. This can only happen for the normal (non-NSEC3) tree.
- // Note: this can throw an exception, breaking strong exception
- // guarantee. (see also the note for the call to contextCheck()
- // above).
- if (rrset->getType() != RRType::NSEC3()) {
- addWildcards(zone_name, zone_data, rrset->getName());
- }
-
- addRdataSet(zone_name, zone_data, rrset, sig_rrset);
+ void operator()(std::string* filename) const {
+ delete filename;
}
};
@@ -495,9 +87,9 @@ class InMemoryClient::Loader : boost::noncopyable {
typedef std::map<RRType, ConstRRsetPtr> NodeRRsets;
typedef NodeRRsets::value_type NodeRRsetsVal;
public:
- Loader(InMemoryClientImpl* client_impl, const Name& zone_name,
- ZoneData& zone_data) :
- client_impl_(client_impl), zone_name_(zone_name), zone_data_(zone_data)
+ Loader(util::MemorySegment& mem_sgmt, const RRClass rrclass,
+ const Name& zone_name, ZoneData& zone_data) :
+ updater_(mem_sgmt, rrclass, zone_name, zone_data)
{}
void addFromLoad(const ConstRRsetPtr& rrset) {
// If we see a new name, flush the temporary holders, adding the
@@ -515,7 +107,7 @@ public:
const RRType& rrtype = is_rrsig ?
getCoveredType(rrset) : rrset->getType();
if (!node_rrsets.insert(NodeRRsetsVal(rrtype, rrset)).second) {
- isc_throw(AddError,
+ isc_throw(ZoneDataUpdater::AddError,
"Duplicate add of the same type of"
<< (is_rrsig ? " RRSIG" : "") << " RRset: "
<< rrset->getName() << "/" << rrtype);
@@ -532,14 +124,15 @@ public:
sig_rrset = sig_it->second;
node_rrsigsets_.erase(sig_it);
}
- client_impl_->add(val.second, sig_rrset, zone_name_, zone_data_);
+ updater_.add(val.second, sig_rrset);
}
// Right now, we don't accept RRSIG without covered RRsets (this
// should eventually allowed, but to do so we'll need to update the
// finder).
if (!node_rrsigsets_.empty()) {
- isc_throw(AddError, "RRSIG is added without covered RRset for "
+ isc_throw(ZoneDataUpdater::AddError,
+ "RRSIG is added without covered RRset for "
<< getCurrentName());
}
@@ -570,23 +163,20 @@ private:
}
private:
- InMemoryClientImpl* client_impl_;
- const Name& zone_name_;
- ZoneData& zone_data_;
NodeRRsets node_rrsets_;
NodeRRsets node_rrsigsets_;
+ ZoneDataUpdater updater_;
};
result::Result
-InMemoryClient::InMemoryClientImpl::load(
- const Name& zone_name,
- const string& filename,
- boost::function<void(LoadCallback)> rrset_installer)
+InMemoryClient::load(const Name& zone_name,
+ const string& filename,
+ boost::function<void(LoadCallback)> rrset_installer)
{
SegmentObjectHolder<ZoneData, RRClass> holder(
mem_sgmt_, ZoneData::create(mem_sgmt_, zone_name), rrclass_);
- Loader loader(this, zone_name, *holder.get());
+ Loader loader(mem_sgmt_, rrclass_, zone_name, *holder.get());
rrset_installer(boost::bind(&Loader::addFromLoad, &loader, _1));
// Add any last RRsets that were left
loader.flushNodeRRsets();
@@ -605,7 +195,7 @@ InMemoryClient::InMemoryClientImpl::load(
// an SOA RR. This condition should be avoided, and hence load()
// should throw when an empty zone is loaded.
if (RdataSet::find(set, RRType::SOA()) == NULL) {
- isc_throw(EmptyZone,
+ isc_throw(ZoneDataUpdater::EmptyZone,
"Won't create an empty zone for: " << zone_name);
}
@@ -656,14 +246,16 @@ namespace {
// doesn't seem to do this conversion if we just pass 'callback'.
void
masterLoadWrapper(const char* const filename, const Name& origin,
- const RRClass& zone_class, LoadCallback callback)
+ const RRClass& zone_class,
+ InMemoryClient::LoadCallback callback)
{
masterLoad(filename, origin, zone_class, boost::bind(callback, _1));
}
-// The installer called from Impl::load() for the iterator version of load().
+// The installer called from load() for the iterator version of load().
void
-generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
+generateRRsetFromIterator(ZoneIterator* iterator,
+ InMemoryClient::LoadCallback callback) {
ConstRRsetPtr rrset;
while ((rrset = iterator->getNextRRset()) != NULL) {
callback(rrset);
@@ -673,21 +265,28 @@ generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
InMemoryClient::InMemoryClient(util::MemorySegment& mem_sgmt,
RRClass rrclass) :
- impl_(new InMemoryClientImpl(mem_sgmt, rrclass))
+ mem_sgmt_(mem_sgmt),
+ rrclass_(rrclass),
+ zone_count_(0),
+ zone_table_(ZoneTable::create(mem_sgmt_, rrclass)),
+ file_name_tree_(FileNameTree::create(mem_sgmt_, false))
{}
InMemoryClient::~InMemoryClient() {
- delete impl_;
+ FileNameDeleter deleter;
+ FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
+
+ ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
}
RRClass
InMemoryClient::getClass() const {
- return (impl_->rrclass_);
+ return (rrclass_);
}
unsigned int
InMemoryClient::getZoneCount() const {
- return (impl_->zone_count_);
+ return (zone_count_);
}
isc::datasrc::DataSourceClient::FindResult
@@ -695,7 +294,7 @@ InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
LOG_DEBUG(logger, DBG_TRACE_DATA,
DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
- ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
+ ZoneTable::FindResult result(zone_table_->findZone(zone_name));
ZoneFinderPtr finder;
if (result.code != result::NOTFOUND) {
@@ -707,7 +306,7 @@ InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
const ZoneData*
InMemoryClient::findZoneData(const isc::dns::Name& zone_name) {
- ZoneTable::FindResult result(impl_->zone_table_->findZone(zone_name));
+ ZoneTable::FindResult result(zone_table_->findZone(zone_name));
return (result.zone_data);
}
@@ -717,24 +316,23 @@ InMemoryClient::load(const isc::dns::Name& zone_name,
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD).arg(zone_name).
arg(filename);
- return (impl_->load(zone_name, filename,
- boost::bind(masterLoadWrapper, filename.c_str(),
- zone_name, getClass(), _1)));
+ return (load(zone_name, filename,
+ boost::bind(masterLoadWrapper, filename.c_str(),
+ zone_name, getClass(), _1)));
}
result::Result
InMemoryClient::load(const isc::dns::Name& zone_name,
ZoneIterator& iterator) {
- return (impl_->load(zone_name, string(),
- boost::bind(generateRRsetFromIterator,
- &iterator, _1)));
+ return (load(zone_name, string(),
+ boost::bind(generateRRsetFromIterator,
+ &iterator, _1)));
}
const std::string
InMemoryClient::getFileName(const isc::dns::Name& zone_name) const {
FileNameNode* node(NULL);
- FileNameTree::Result result = impl_->file_name_tree_->find(zone_name,
- &node);
+ FileNameTree::Result result = file_name_tree_->find(zone_name, &node);
if (result == FileNameTree::EXACTMATCH) {
return (*node->getData());
} else {
@@ -746,15 +344,16 @@ result::Result
InMemoryClient::add(const isc::dns::Name& zone_name,
const ConstRRsetPtr& rrset)
{
- const ZoneTable::FindResult result =
- impl_->zone_table_->findZone(zone_name);
+ const ZoneTable::FindResult result = zone_table_->findZone(zone_name);
if (result.code != result::SUCCESS) {
isc_throw(DataSourceError, "No such zone: " + zone_name.toText());
}
const ConstRRsetPtr sig_rrset =
rrset ? rrset->getRRsig() : ConstRRsetPtr();
- impl_->add(rrset, sig_rrset, zone_name, *result.zone_data);
+
+ ZoneDataUpdater updater(mem_sgmt_, rrclass_, zone_name, *result.zone_data);
+ updater.add(rrset, sig_rrset);
// add() doesn't allow duplicate add, so we always return SUCCESS.
return (result::SUCCESS);
@@ -874,7 +473,7 @@ public:
ZoneIteratorPtr
InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
- ZoneTable::FindResult result(impl_->zone_table_->findZone(name));
+ ZoneTable::FindResult result(zone_table_->findZone(name));
if (result.code != result::SUCCESS) {
isc_throw(DataSourceError, "No such zone: " + name.toText());
}
diff --git a/src/lib/datasrc/memory/memory_client.h b/src/lib/datasrc/memory/memory_client.h
index 330d62e..438e3fb 100644
--- a/src/lib/datasrc/memory/memory_client.h
+++ b/src/lib/datasrc/memory/memory_client.h
@@ -22,6 +22,8 @@
#include <datasrc/memory/zone_table.h>
#include <datasrc/memory/zone_data.h>
+#include <boost/function.hpp>
+
#include <string>
namespace isc {
@@ -168,40 +170,6 @@ public:
result::Result add(const isc::dns::Name& zone_name,
const isc::dns::ConstRRsetPtr& rrset);
- /// \brief RRset is NULL exception.
- ///
- /// This is thrown if the provided RRset parameter is NULL.
- struct NullRRset : public InvalidParameter {
- NullRRset(const char* file, size_t line, const char* what) :
- InvalidParameter(file, line, what)
- { }
- };
-
- /// \brief Zone is empty exception.
- ///
- /// This is thrown if we have an empty zone created as a result of
- /// load().
- struct EmptyZone : public InvalidParameter {
- EmptyZone(const char* file, size_t line, const char* what) :
- InvalidParameter(file, line, what)
- { }
- };
-
- /// \brief General failure exception for \c add().
- ///
- /// This is thrown against general error cases in adding an RRset
- /// to the zone.
- ///
- /// Note: this exception would cover cases for \c OutOfZone or
- /// \c NullRRset. We'll need to clarify and unify the granularity
- /// of exceptions eventually. For now, exceptions are added as
- /// developers see the need for it.
- struct AddError : public InvalidParameter {
- AddError(const char* file, size_t line, const char* what) :
- InvalidParameter(file, line, what)
- { }
- };
-
/// Returns a \c ZoneFinder result that best matches the given name.
///
/// This derived version of the method never throws an exception.
@@ -238,11 +206,35 @@ public:
getJournalReader(const isc::dns::Name& zone, uint32_t begin_serial,
uint32_t end_serial) const;
+ // A functor type used for loading.
+ typedef boost::function<void(isc::dns::ConstRRsetPtr)> LoadCallback;
+
private:
- // TODO: Do we still need the PImpl if nobody should manipulate this class
- // directly any more (it should be handled through DataSourceClient)?
- class InMemoryClientImpl;
- InMemoryClientImpl* impl_;
+ // Some type aliases
+ typedef DomainTree<std::string> FileNameTree;
+ typedef DomainTreeNode<std::string> FileNameNode;
+
+ // Common process for zone load.
+ // rrset_installer is a functor that takes another functor as an argument,
+ // and expected to call the latter for each RRset of the zone. How the
+ // sequence of the RRsets is generated depends on the internal
+ // details of the loader: either from a textual master file or from
+ // another data source.
+ // filename is the file name of the master file or empty if the zone is
+ // loaded from another data source.
+ result::Result load(const isc::dns::Name& zone_name,
+ const std::string& filename,
+ boost::function<void(LoadCallback)> rrset_installer);
+
+ util::MemorySegment& mem_sgmt_;
+ const isc::dns::RRClass rrclass_;
+ unsigned int zone_count_;
+ ZoneTable* zone_table_;
+ FileNameTree* file_name_tree_;
+
+ // A helper internal class used by the memory client, used for
+ // deleting filenames stored in an internal tree.
+ class FileNameDeleter;
// A helper internal class used by load(). It maintains some intermediate
// states while loading RRs of the zone.
diff --git a/src/lib/datasrc/memory/zone_data_updater.cc b/src/lib/datasrc/memory/zone_data_updater.cc
new file mode 100644
index 0000000..473a276
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_updater.cc
@@ -0,0 +1,406 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <datasrc/memory/zone_data_updater.h>
+#include <datasrc/zone.h>
+
+#include <dns/rdataclass.h>
+
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+namespace { // anonymous namespace
+
+// Returns a value-less than, or greater-than zero if 'a' is less-than
+// or greater-than 'b'. If they are equal, it returns 0. The comparison
+// function is such that often-used types such as A, AAAA, NS, SOA, MX,
+// etc. are less than other types. See the code for the ordering.
+int
+compareTypes(const RdataSet* a,
+ const RdataSet* b) {
+ // First RRType::A()
+ if (a->type == RRType::A()) {
+ return (-1);
+ } else if (b->type == RRType::A()) {
+ return (1);
+ }
+
+ // Then, RRType::AAAA(), etc.
+ if (a->type == RRType::AAAA()) {
+ return (-1);
+ } else if (b->type == RRType::AAAA()) {
+ return (1);
+ }
+
+ if (a->type == RRType::NS()) {
+ return (-1);
+ } else if (b->type == RRType::NS()) {
+ return (1);
+ }
+
+ if (a->type == RRType::SOA()) {
+ return (-1);
+ } else if (b->type == RRType::SOA()) {
+ return (1);
+ }
+
+ if (a->type == RRType::MX()) {
+ return (-1);
+ } else if (b->type == RRType::MX()) {
+ return (1);
+ }
+
+ // Everything else comes in front of the rest of the list, so that
+ // we can insert quickly.
+ return (-1);
+}
+
+} // end of anonymous namespace
+
+void
+ZoneDataUpdater::addWildcards(const Name& name) {
+ Name wname(name);
+ const unsigned int labels(wname.getLabelCount());
+ const unsigned int origin_labels(zone_name_.getLabelCount());
+ for (unsigned int l = labels;
+ l > origin_labels;
+ --l, wname = wname.split(1))
+ {
+ if (wname.isWildcard()) {
+ // Ensure a separate level exists for the "wildcarding"
+ // name, and mark the node as "wild".
+ ZoneNode* node;
+ zone_data_.insertName(mem_sgmt_, wname.split(1), &node);
+ node->setFlag(ZoneData::WILDCARD_NODE);
+
+ // Ensure a separate level exists for the wildcard name.
+ // Note: for 'name' itself we do this later anyway, but the
+ // overhead should be marginal because wildcard names should
+ // be rare.
+ zone_data_.insertName(mem_sgmt_, wname, &node);
+ }
+ }
+}
+
+void
+ZoneDataUpdater::contextCheck(const AbstractRRset& rrset,
+ const RdataSet* set) const {
+ // Ensure CNAME and other type of RR don't coexist for the same
+ // owner name except with NSEC, which is the only RR that can
+ // coexist with CNAME (and also RRSIG, which is handled separately)
+ if (rrset.getType() == RRType::CNAME()) {
+ for (const RdataSet* sp = set; sp != NULL; sp = sp->getNext()) {
+ if (sp->type != RRType::NSEC()) {
+ isc_throw(AddError,
+ "CNAME can't be added with " << sp->type
+ << " RRType for " << rrset.getName());
+ }
+ }
+ } else if ((rrset.getType() != RRType::NSEC()) &&
+ (RdataSet::find(set, RRType::CNAME()) != NULL))
+ {
+ isc_throw(AddError,
+ "CNAME and " << rrset.getType() <<
+ " can't coexist for " << rrset.getName());
+ }
+
+ // Similar with DNAME, but it must not coexist only with NS and only
+ // in non-apex domains. RFC 2672 section 3 mentions that it is
+ // implied from it and RFC 2181.
+ if (rrset.getName() != zone_name_ &&
+ // Adding DNAME, NS already there
+ ((rrset.getType() == RRType::DNAME() &&
+ RdataSet::find(set, RRType::NS()) != NULL) ||
+ // Adding NS, DNAME already there
+ (rrset.getType() == RRType::NS() &&
+ RdataSet::find(set, RRType::DNAME()) != NULL)))
+ {
+ isc_throw(AddError, "DNAME can't coexist with NS in non-apex domain: "
+ << rrset.getName());
+ }
+}
+
+void
+ZoneDataUpdater::validate(const isc::dns::ConstRRsetPtr rrset) const {
+ if (!rrset) {
+ isc_throw(NullRRset, "The rrset provided is NULL");
+ }
+
+ if (rrset->getRdataCount() == 0) {
+ isc_throw(AddError,
+ "The rrset provided is empty: "
+ << rrset->getName() << "/" << rrset->getType());
+ }
+
+ // Check for singleton RRs. It should probably handled at a different
+ // layer in future.
+ if ((rrset->getType() == RRType::CNAME() ||
+ rrset->getType() == RRType::DNAME()) &&
+ rrset->getRdataCount() > 1)
+ {
+ // XXX: this is not only for CNAME or DNAME. We should
+ // generalize this code for all other "singleton RR types" (such
+ // as SOA) in a separate task.
+ isc_throw(AddError, "multiple RRs of singleton type for "
+ << rrset->getName());
+ }
+
+ // NSEC3/NSEC3PARAM is not a "singleton" per protocol, but this
+ // implementation requests it be so at the moment.
+ if ((rrset->getType() == RRType::NSEC3() ||
+ rrset->getType() == RRType::NSEC3PARAM()) &&
+ (rrset->getRdataCount() > 1))
+ {
+ isc_throw(AddError, "Multiple NSEC3/NSEC3PARAM RDATA is given for "
+ << rrset->getName() << " which isn't supported");
+ }
+
+ // For RRSIGs, check consistency of the type covered. We know the
+ // RRset isn't empty, so the following check is safe.
+ if (rrset->getType() == RRType::RRSIG()) {
+ RdataIteratorPtr rit = rrset->getRdataIterator();
+ const RRType covered = dynamic_cast<const generic::RRSIG&>(
+ rit->getCurrent()).typeCovered();
+ for (rit->next(); !rit->isLast(); rit->next()) {
+ if (dynamic_cast<const generic::RRSIG&>(
+ rit->getCurrent()).typeCovered() != covered)
+ {
+ isc_throw(AddError, "RRSIG contains mixed covered types: "
+ << rrset->toText());
+ }
+ }
+ }
+
+ const NameComparisonResult compare = zone_name_.compare(rrset->getName());
+ if (compare.getRelation() != NameComparisonResult::SUPERDOMAIN &&
+ compare.getRelation() != NameComparisonResult::EQUAL)
+ {
+ isc_throw(OutOfZone,
+ "The name " << rrset->getName() <<
+ " is not contained in zone " << zone_name_);
+ }
+
+ // Some RR types do not really work well with a wildcard. Even
+ // though the protocol specifically doesn't completely ban such
+ // usage, we refuse to load a zone containing such RR in order to
+ // keep the lookup logic simpler and more predictable. See RFC4592
+ // and (for DNAME) RFC6672 for more technical background. Note also
+ // that BIND 9 refuses NS at a wildcard, so in that sense we simply
+ // provide compatible behavior.
+ if (rrset->getName().isWildcard()) {
+ if (rrset->getType() == RRType::NS()) {
+ isc_throw(AddError, "Invalid NS owner name (wildcard): "
+ << rrset->getName());
+ }
+
+ if (rrset->getType() == RRType::DNAME()) {
+ isc_throw(AddError, "Invalid DNAME owner name (wildcard): "
+ << rrset->getName());
+ }
+ }
+
+ // Owner names of NSEC3 have special format as defined in RFC5155,
+ // and cannot be a wildcard name or must be one label longer than
+ // the zone origin. While the RFC doesn't prohibit other forms of
+ // names, no sane zone would have such names for NSEC3. BIND 9 also
+ // refuses NSEC3 at wildcard.
+ if (rrset->getType() == RRType::NSEC3() &&
+ (rrset->getName().isWildcard() ||
+ rrset->getName().getLabelCount() !=
+ zone_name_.getLabelCount() + 1))
+ {
+ isc_throw(AddError, "Invalid NSEC3 owner name: " <<
+ rrset->getName() << "; zone: " << zone_name_);
+ }
+}
+
+void
+ZoneDataUpdater::addNSEC3(const ConstRRsetPtr rrset,
+ const ConstRRsetPtr rrsig) {
+ // We know rrset has exactly one RDATA
+ const generic::NSEC3& nsec3_rdata =
+ dynamic_cast<const generic::NSEC3&>(
+ rrset->getRdataIterator()->getCurrent());
+
+ NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+ if (nsec3_data == NULL) {
+ nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
+ zone_data_.setNSEC3Data(nsec3_data);
+ zone_data_.setSigned(true);
+ } else {
+ size_t salt_len = nsec3_data->getSaltLen();
+ const uint8_t* salt_data = nsec3_data->getSaltData();
+ const std::vector<uint8_t>& salt_data_2 = nsec3_rdata.getSalt();
+
+ if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
+ (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
+ (salt_data_2.size() != salt_len)) {
+ isc_throw(AddError,
+ "NSEC3 with inconsistent parameters: " <<
+ rrset->toText());
+ }
+
+ if ((salt_len > 0) &&
+ (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
+ isc_throw(AddError,
+ "NSEC3 with inconsistent parameters: " <<
+ rrset->toText());
+ }
+ }
+
+ ZoneNode* node;
+ nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
+
+ RdataSet* set = RdataSet::create(mem_sgmt_, encoder_, rrset, rrsig);
+ RdataSet* old_set = node->setData(set);
+ if (old_set != NULL) {
+ RdataSet::destroy(mem_sgmt_, rrclass_, old_set);
+ }
+}
+
+void
+ZoneDataUpdater::addRdataSet(const ConstRRsetPtr rrset,
+ const ConstRRsetPtr rrsig) {
+ if (rrset->getType() == RRType::NSEC3()) {
+ addNSEC3(rrset, rrsig);
+ } else {
+ ZoneNode* node;
+ zone_data_.insertName(mem_sgmt_, rrset->getName(), &node);
+
+ RdataSet* rdataset_head = node->getData();
+
+ // Checks related to the surrounding data. Note: when the check
+ // fails and the exception is thrown, it may break strong
+ // exception guarantee. At the moment we prefer code simplicity
+ // and don't bother to introduce complicated recovery code.
+ contextCheck(*rrset, rdataset_head);
+
+ if (RdataSet::find(rdataset_head, rrset->getType()) != NULL) {
+ isc_throw(AddError,
+ "RRset of the type already exists: "
+ << rrset->getName() << " (type: "
+ << rrset->getType() << ")");
+ }
+
+ RdataSet* rdataset_new = RdataSet::create(mem_sgmt_, encoder_,
+ rrset, rrsig);
+
+ // Insertion sort the new RdataSet into place in the list.
+ RdataSet* prev = NULL;
+ RdataSet* current = rdataset_head;
+ for (; current != NULL; current = current->getNext())
+ {
+ if (compareTypes(rdataset_new, current) < 0) {
+ break;
+ }
+
+ prev = current;
+ }
+
+ rdataset_new->next = current;
+ if (prev != NULL) {
+ prev->next = rdataset_new;
+ } else {
+ node->setData(rdataset_new);
+ }
+
+ // Ok, we just put it in.
+
+ // If this RRset creates a zone cut at this node, mark the node
+ // indicating the need for callback in find().
+ if (rrset->getType() == RRType::NS() &&
+ rrset->getName() != zone_name_) {
+ node->setFlag(ZoneNode::FLAG_CALLBACK);
+ // If it is DNAME, we have a callback as well here
+ } else if (rrset->getType() == RRType::DNAME()) {
+ node->setFlag(ZoneNode::FLAG_CALLBACK);
+ }
+
+ // If we've added NSEC3PARAM at zone origin, set up NSEC3
+ // specific data or check consistency with already set up
+ // parameters.
+ if (rrset->getType() == RRType::NSEC3PARAM() &&
+ rrset->getName() == zone_name_) {
+ // We know rrset has exactly one RDATA
+ const generic::NSEC3PARAM& param =
+ dynamic_cast<const generic::NSEC3PARAM&>(
+ rrset->getRdataIterator()->getCurrent());
+
+ NSEC3Data* nsec3_data = zone_data_.getNSEC3Data();
+ if (nsec3_data == NULL) {
+ nsec3_data = NSEC3Data::create(mem_sgmt_, param);
+ zone_data_.setNSEC3Data(nsec3_data);
+ zone_data_.setSigned(true);
+ } else {
+ size_t salt_len = nsec3_data->getSaltLen();
+ const uint8_t* salt_data = nsec3_data->getSaltData();
+ const std::vector<uint8_t>& salt_data_2 = param.getSalt();
+
+ if ((param.getHashalg() != nsec3_data->hashalg) ||
+ (param.getIterations() != nsec3_data->iterations) ||
+ (salt_data_2.size() != salt_len)) {
+ isc_throw(AddError,
+ "NSEC3PARAM with inconsistent parameters: "
+ << rrset->toText());
+ }
+
+ if ((salt_len > 0) &&
+ (std::memcmp(&salt_data_2[0],
+ salt_data, salt_len) != 0)) {
+ isc_throw(AddError,
+ "NSEC3PARAM with inconsistent parameters: "
+ << rrset->toText());
+ }
+ }
+ } else if (rrset->getType() == RRType::NSEC()) {
+ // If it is NSEC signed zone, we mark the zone as signed
+ // (conceptually "signed" is a broader notion but our
+ // current zone finder implementation regards "signed" as
+ // "NSEC signed")
+ zone_data_.setSigned(true);
+ }
+ }
+}
+
+void
+ZoneDataUpdater::add(const ConstRRsetPtr& rrset,
+ const ConstRRsetPtr& sig_rrset) {
+ // Validate input. This will cause an exception to be thrown if the
+ // input RRset is empty.
+ validate(rrset);
+ if (sig_rrset) {
+ validate(sig_rrset);
+ }
+
+ // OK, can add the RRset.
+
+ // Add wildcards possibly contained in the owner name to the domain
+ // tree. This can only happen for the normal (non-NSEC3) tree.
+ // Note: this can throw an exception, breaking strong exception
+ // guarantee. (see also the note for the call to contextCheck()
+ // above).
+ if (rrset->getType() != RRType::NSEC3()) {
+ addWildcards(rrset->getName());
+ }
+
+ addRdataSet(rrset, sig_rrset);
+}
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
diff --git a/src/lib/datasrc/memory/zone_data_updater.h b/src/lib/datasrc/memory/zone_data_updater.h
new file mode 100644
index 0000000..0b496c0
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_data_updater.h
@@ -0,0 +1,132 @@
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_ZONE_DATA_UPDATER_H
+#define DATASRC_ZONE_DATA_UPDATER_H 1
+
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/rdata_serialization.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrset.h>
+#include <util/memory_segment.h>
+
+#include <boost/noncopyable.hpp>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+class ZoneDataUpdater : boost::noncopyable {
+public:
+ ZoneDataUpdater(util::MemorySegment& mem_sgmt,
+ isc::dns::RRClass rrclass,
+ const isc::dns::Name& zone_name,
+ ZoneData& zone_data) :
+ mem_sgmt_(mem_sgmt),
+ rrclass_(rrclass),
+ zone_name_(zone_name),
+ zone_data_(zone_data)
+ {}
+
+ /// The destructor.
+ ~ZoneDataUpdater()
+ {}
+
+ //@}
+
+ /// This is thrown if the provided RRset parameter is NULL.
+ struct NullRRset : public InvalidParameter {
+ NullRRset(const char* file, size_t line, const char* what) :
+ InvalidParameter(file, line, what)
+ { }
+ };
+
+ /// \brief Zone is empty exception.
+ ///
+ /// This is thrown if we have an empty zone created as a result of
+ /// load().
+ struct EmptyZone : public InvalidParameter {
+ EmptyZone(const char* file, size_t line, const char* what) :
+ InvalidParameter(file, line, what)
+ { }
+ };
+
+ /// \brief General failure exception for \c add().
+ ///
+ /// This is thrown against general error cases in adding an RRset
+ /// to the zone.
+ ///
+ /// Note: this exception would cover cases for \c OutOfZone or
+ /// \c NullRRset. We'll need to clarify and unify the granularity
+ /// of exceptions eventually. For now, exceptions are added as
+ /// developers see the need for it.
+ struct AddError : public InvalidParameter {
+ AddError(const char* file, size_t line, const char* what) :
+ InvalidParameter(file, line, what)
+ { }
+ };
+
+ void add(const isc::dns::ConstRRsetPtr& rrset,
+ const isc::dns::ConstRRsetPtr& sig_rrset);
+
+private:
+ // Add the necessary magic for any wildcard contained in 'name'
+ // (including itself) to be found in the zone.
+ //
+ // In order for wildcard matching to work correctly in the zone finder,
+ // we must ensure that a node for the wildcarding level exists in the
+ // backend ZoneTree.
+ // E.g. if the wildcard name is "*.sub.example." then we must ensure
+ // that "sub.example." exists and is marked as a wildcard level.
+ // Note: the "wildcarding level" is for the parent name of the wildcard
+ // name (such as "sub.example.").
+ //
+ // We also perform the same trick for empty wild card names possibly
+ // contained in 'name' (e.g., '*.foo.example' in 'bar.*.foo.example').
+ void addWildcards(const isc::dns::Name& name);
+
+ // Does some checks in context of the data that are already in the
+ // zone. Currently checks for forbidden combinations of RRsets in
+ // the same domain (CNAME+anything, DNAME+NS). If such condition is
+ // found, it throws AddError.
+ void contextCheck(const isc::dns::AbstractRRset& rrset,
+ const RdataSet* set) const;
+
+ // Validate rrset before adding it to the zone. If something is wrong
+ // it throws an exception. It doesn't modify the zone, and provides
+ // the strong exception guarantee.
+ void validate(const isc::dns::ConstRRsetPtr rrset) const;
+
+ void addNSEC3(const isc::dns::ConstRRsetPtr rrset,
+ const isc::dns::ConstRRsetPtr rrsig);
+ void addRdataSet(const isc::dns::ConstRRsetPtr rrset,
+ const isc::dns::ConstRRsetPtr rrsig);
+
+ util::MemorySegment& mem_sgmt_;
+ const isc::dns::RRClass rrclass_;
+ const isc::dns::Name& zone_name_;
+ ZoneData& zone_data_;
+ RdataEncoder encoder_;
+};
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_ZONE_DATA_UPDATER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index 58979a4..80bc73f 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -30,6 +30,7 @@
#include <datasrc/data_source.h>
#include <datasrc/memory/zone_data.h>
#include <datasrc/memory/zone_table.h>
+#include <datasrc/memory/zone_data_updater.h>
#include <datasrc/memory/memory_client.h>
#include <testutils/dnsmessage_test.h>
@@ -188,7 +189,7 @@ TEST_F(MemoryClientTest, loadEmptyZoneFileThrows) {
EXPECT_THROW(client_->load(Name("."),
TEST_DATA_DIR "/empty.zone"),
- InMemoryClient::EmptyZone);
+ ZoneDataUpdater::EmptyZone);
EXPECT_EQ(0, client_->getZoneCount());
@@ -221,13 +222,13 @@ TEST_F(MemoryClientTest, loadFromIterator) {
// RRType::MX() RRset
rrset = iterator->getNextRRset();
EXPECT_TRUE(rrset);
- EXPECT_EQ(RRType::MX(), rrset->getType());
+ EXPECT_EQ(RRType::A(), rrset->getType());
EXPECT_EQ(1, rrset->getRRsigDataCount()); // this RRset is signed
// RRType::A() RRset
rrset = iterator->getNextRRset();
EXPECT_TRUE(rrset);
- EXPECT_EQ(RRType::A(), rrset->getType());
+ EXPECT_EQ(RRType::MX(), rrset->getType());
EXPECT_EQ(1, rrset->getRRsigDataCount()); // also signed
// There's nothing else in this iterator
@@ -242,13 +243,13 @@ TEST_F(MemoryClientTest, loadFromIterator) {
EXPECT_THROW(client_->load(Name("example.org"),
*MockIterator::makeIterator(
rrset_data_separated)),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Similar to the previous case, but with separated RRSIGs.
EXPECT_THROW(client_->load(Name("example.org"),
*MockIterator::makeIterator(
rrset_data_sigseparated)),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Emulating bogus iterator implementation that passes empty RRSIGs.
EXPECT_THROW(client_->load(Name("example.org"),
@@ -363,11 +364,11 @@ TEST_F(MemoryClientTest, loadReloadZone) {
set = node->getData();
EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
- EXPECT_EQ(RRType::AAAA(), set->type);
+ EXPECT_EQ(RRType::A(), set->type);
set = set->getNext();
EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
- EXPECT_EQ(RRType::A(), set->type);
+ EXPECT_EQ(RRType::AAAA(), set->type);
set = set->getNext();
EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
@@ -384,7 +385,7 @@ TEST_F(MemoryClientTest, loadDuplicateType) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-duplicate-type-bad.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -393,7 +394,7 @@ TEST_F(MemoryClientTest, loadMultipleCNAMEThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-multiple-cname.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -402,7 +403,7 @@ TEST_F(MemoryClientTest, loadMultipleDNAMEThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-multiple-dname.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -411,7 +412,7 @@ TEST_F(MemoryClientTest, loadMultipleNSEC3Throws) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-multiple-nsec3.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -420,7 +421,7 @@ TEST_F(MemoryClientTest, loadMultipleNSEC3PARAMThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-multiple-nsec3param.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -438,7 +439,7 @@ TEST_F(MemoryClientTest, loadWildcardNSThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-wildcard-ns.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -447,7 +448,7 @@ TEST_F(MemoryClientTest, loadWildcardDNAMEThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-wildcard-dname.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -456,7 +457,7 @@ TEST_F(MemoryClientTest, loadWildcardNSEC3Throws) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-wildcard-nsec3.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -465,7 +466,7 @@ TEST_F(MemoryClientTest, loadNSEC3WithFewerLabelsThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-nsec3-fewer-labels.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -474,7 +475,7 @@ TEST_F(MemoryClientTest, loadNSEC3WithMoreLabelsThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-nsec3-more-labels.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -483,12 +484,12 @@ TEST_F(MemoryClientTest, loadCNAMEAndNotNSECThrows) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-cname-and-not-nsec-1.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-cname-and-not-nsec-2.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -514,7 +515,7 @@ TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex1) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-dname-ns-nonapex-1.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -523,7 +524,7 @@ TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex2) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-dname-ns-nonapex-2.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -533,7 +534,7 @@ TEST_F(MemoryClientTest, loadRRSIGFollowsNothing) {
EXPECT_THROW(client_->load(Name("example.org"),
TEST_DATA_DIR
"/example.org-rrsig-follows-nothing.zone"),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -561,7 +562,7 @@ TEST_F(MemoryClientTest, loadRRSIGsRdataMixedCoveredTypes) {
rrset->addRRsig(rrsig);
EXPECT_THROW(client_->add(Name("example.org"), rrset),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -683,7 +684,7 @@ TEST_F(MemoryClientTest, addNullRRsetThrows) {
TEST_DATA_DIR "/example.org-rrsigs.zone");
EXPECT_THROW(client_->add(Name("example.org"), ConstRRsetPtr()),
- InMemoryClient::NullRRset);
+ ZoneDataUpdater::NullRRset);
// Teardown checks for memory segment leaks
}
@@ -695,7 +696,7 @@ TEST_F(MemoryClientTest, addEmptyRRsetThrows) {
RRsetPtr rrset_a(new RRset(Name("example.org"), RRClass::IN(), RRType::A(),
RRTTL(300)));
EXPECT_THROW(client_->add(Name("example.org"), rrset_a),
- InMemoryClient::AddError);
+ ZoneDataUpdater::AddError);
// Teardown checks for memory segment leaks
}
@@ -753,11 +754,11 @@ TEST_F(MemoryClientTest, findZoneData) {
set = node->getData();
EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
- EXPECT_EQ(RRType::AAAA(), set->type);
+ EXPECT_EQ(RRType::A(), set->type);
set = set->getNext();
EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
- EXPECT_EQ(RRType::A(), set->type);
+ EXPECT_EQ(RRType::AAAA(), set->type);
set = set->getNext();
EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index a536bf5..f950ccb 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -23,6 +23,7 @@
#include "../../tests/faked_nsec3.h"
#include <datasrc/memory/zone_finder.h>
+#include <datasrc/memory/zone_data_updater.h>
#include <datasrc/memory/rdata_serialization.h>
#include <datasrc/data_source.h>
#include <testutils/dnsmessage_test.h>
@@ -105,7 +106,8 @@ public:
class_(RRClass::IN()),
origin_("example.org"),
zone_data_(ZoneData::create(mem_sgmt_, origin_)),
- zone_finder_(*zone_data_, class_)
+ zone_finder_(*zone_data_, class_),
+ updater_(mem_sgmt_, class_, origin_, *zone_data_)
{
// Build test RRsets. Below, we construct an RRset for
// each textual RR(s) of zone_data, and assign it to the corresponding
@@ -190,130 +192,9 @@ public:
ZoneData::destroy(mem_sgmt_, zone_data_, RRClass::IN());
}
- // NSEC3-specific call for 'loading' data
- void addZoneDataNSEC3(const ConstRRsetPtr rrset) {
- assert(rrset->getType() == RRType::NSEC3());
-
- const generic::NSEC3& nsec3_rdata =
- dynamic_cast<const generic::NSEC3&>(
- rrset->getRdataIterator()->getCurrent());
-
- NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
- if (nsec3_data == NULL) {
- nsec3_data = NSEC3Data::create(mem_sgmt_, nsec3_rdata);
- zone_data_->setNSEC3Data(nsec3_data);
- } else {
- const size_t salt_len = nsec3_data->getSaltLen();
- const uint8_t* salt_data = nsec3_data->getSaltData();
- const vector<uint8_t>& salt_data_2 = nsec3_rdata.getSalt();
-
- if ((nsec3_rdata.getHashalg() != nsec3_data->hashalg) ||
- (nsec3_rdata.getIterations() != nsec3_data->iterations) ||
- (salt_data_2.size() != salt_len)) {
- isc_throw(isc::Unexpected,
- "NSEC3 with inconsistent parameters: " <<
- rrset->toText());
- }
-
- if ((salt_len > 0) &&
- (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0)) {
- isc_throw(isc::Unexpected,
- "NSEC3 with inconsistent parameters: " <<
- rrset->toText());
- }
- }
-
- ZoneNode* node;
- nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
-
- RdataSet* rdset = RdataSet::create(mem_sgmt_, encoder_,
- rrset, ConstRRsetPtr());
- RdataSet* old_rdset = node->setData(rdset);
- if (old_rdset != NULL) {
- RdataSet::destroy(mem_sgmt_, class_, old_rdset);
- }
- zone_data_->setSigned(true);
- }
-
// simplified version of 'loading' data
void addZoneData(const ConstRRsetPtr rrset) {
- ZoneNode* node = NULL;
-
- if (rrset->getType() == RRType::NSEC3()) {
- return (addZoneDataNSEC3(rrset));
- } else if (rrset->getType() == RRType::NSEC()) {
- zone_data_->setSigned(true);
- }
-
- zone_data_->insertName(mem_sgmt_, rrset->getName(), &node);
-
- if (rrset->getType() == RRType::NS() &&
- rrset->getName() != zone_data_->getOriginNode()->getName()) {
- node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
- } else if (rrset->getType() == RRType::DNAME()) {
- node->setFlag(DomainTreeNode<RdataSet>::FLAG_CALLBACK);
- }
-
- RdataSet* next_rds = node->getData();
- RdataSet* rdataset =
- RdataSet::create(mem_sgmt_, encoder_, rrset, rrset->getRRsig());
- rdataset->next = next_rds;
- node->setData(rdataset);
-
- // find wildcard nodes in name (go through all of them in case there
- // is a nonterminal one)
- // Note that this method is pretty much equal to the 'real' loader;
- // but less efficient
- Name name(rrset->getName());
- while (name.getLabelCount() > 1) {
- if (name.isWildcard()) {
- ZoneNode* wnode = NULL;
- // add Wild node
- zone_data_->insertName(mem_sgmt_, name.split(1), &wnode);
- wnode->setFlag(ZoneData::WILDCARD_NODE);
- // add wildcard name itself too
- zone_data_->insertName(mem_sgmt_, name, &wnode);
- }
- name = name.split(1);
- }
-
- // If we've added NSEC3PARAM at zone origin, set up NSEC3
- // specific data or check consistency with already set up
- // parameters.
- if (rrset->getType() == RRType::NSEC3PARAM() &&
- rrset->getName() == origin_) {
- // We know rrset has exactly one RDATA
- const generic::NSEC3PARAM& param =
- dynamic_cast<const generic::NSEC3PARAM&>
- (rrset->getRdataIterator()->getCurrent());
-
- NSEC3Data* nsec3_data = zone_data_->getNSEC3Data();
- if (nsec3_data == NULL) {
- nsec3_data = NSEC3Data::create(mem_sgmt_, param);
- zone_data_->setNSEC3Data(nsec3_data);
- zone_data_->setSigned(true);
- } else {
- size_t salt_len = nsec3_data->getSaltLen();
- const uint8_t* salt_data = nsec3_data->getSaltData();
- const vector<uint8_t>& salt_data_2 = param.getSalt();
-
- if ((param.getHashalg() != nsec3_data->hashalg) ||
- (param.getIterations() != nsec3_data->iterations) ||
- (salt_data_2.size() != salt_len)) {
- isc_throw(isc::Unexpected,
- "NSEC3PARAM with inconsistent parameters: "
- << rrset->toText());
- }
-
- if ((salt_len > 0) &&
- (std::memcmp(&salt_data_2[0],
- salt_data, salt_len) != 0)) {
- isc_throw(isc::Unexpected,
- "NSEC3PARAM with inconsistent parameters: "
- << rrset->toText());
- }
- }
- }
+ updater_.add(rrset, rrset->getRRsig());
}
// Some data to test with
@@ -323,7 +204,7 @@ public:
MemorySegmentTest mem_sgmt_;
memory::ZoneData* zone_data_;
memory::InMemoryZoneFinder zone_finder_;
- isc::datasrc::memory::RdataEncoder encoder_;
+ ZoneDataUpdater updater_;
// Placeholder for storing RRsets to be checked with rrsetsCheck()
vector<ConstRRsetPtr> actual_rrsets_;
More information about the bind10-changes
mailing list