Browse Source

[1574] 1st step of NSEC3 load support: revise the internal zone data structure
so that it can hold both normal name tree and NSEC3 space. a simple test case
was added.

JINMEI Tatuya 13 years ago
parent
commit
ef67582080
2 changed files with 78 additions and 31 deletions
  1. 67 31
      src/lib/datasrc/memory_datasrc.cc
  2. 11 0
      src/lib/datasrc/tests/memory_datasrc_unittest.cc

+ 67 - 31
src/lib/datasrc/memory_datasrc.cc

@@ -12,9 +12,12 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <functional>
 #include <map>
+#include <set>
 #include <cassert>
 #include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 
@@ -39,6 +42,7 @@ using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::data;
+using boost::scoped_ptr;
 
 namespace isc {
 namespace datasrc {
@@ -62,6 +66,27 @@ typedef boost::shared_ptr<Domain> DomainPtr;
 // The tree stores domains
 typedef RBTree<Domain> DomainTree;
 typedef RBNode<Domain> DomainNode;
+
+// Separate storage for NSEC3 RRs (and their RRSIGs)
+struct NameCompare : public binary_function<ConstRRsetPtr, ConstRRsetPtr, bool>
+{
+    bool operator()(const ConstRRsetPtr& n1, const ConstRRsetPtr& n2) const {
+        return (n1->getName().compare(n2->getName()).getOrder() < 0);
+    }
+};
+typedef set<ConstRRsetPtr, NameCompare> NSEC3Set;
+
+// Actual zone data: Essentially a set of zone's RRs.  This is defined as
+// a separate structure so that it'll be replaceable on reload.
+struct ZoneData {
+    ZoneData() : domains_(true) {}
+
+    // The main data (name + RRsets)
+    DomainTree domains_;
+
+    // The optional NSEC3 storage (TBD: should allocate it on demand)
+    NSEC3Set nsec3_set_;
+};
 }
 
 // Private data and hidden methods of InMemoryZoneFinder
@@ -69,10 +94,10 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
     // Constructor
     InMemoryZoneFinderImpl(const RRClass& zone_class, const Name& origin) :
         zone_class_(zone_class), origin_(origin), origin_data_(NULL),
-        domains_(true)
+        zone_data_(new ZoneData)
     {
         // We create the node for origin (it needs to exist anyway in future)
-        domains_.insert(origin, &origin_data_);
+        zone_data_->domains_.insert(origin, &origin_data_);
         DomainPtr origin_domain(new Domain);
         origin_data_->setData(origin_domain);
     }
@@ -85,7 +110,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
     string file_name_;
 
     // The actual zone data
-    DomainTree domains_;
+    scoped_ptr<ZoneData> zone_data_;
+    //DomainTree domains_;
 
     // Add the necessary magic for any wildcard contained in 'name'
     // (including itself) to be found in the zone.
@@ -236,11 +262,10 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
         }
     }
 
-    result::Result addRRsig(const ConstRRsetPtr sig_rrset,
-                            DomainTree& domains)
+    result::Result addRRsig(const ConstRRsetPtr sig_rrset, ZoneData& zone_data)
     {
         DomainNode* node = NULL;
-        if (domains.find(sig_rrset->getName(), &node) !=
+        if (zone_data.domains_.find(sig_rrset->getName(), &node) !=
             DomainTree::EXACTMATCH || node == NULL || !node->getData()) {
             isc_throw(AddError,
                       "RRSIG is being added, but no RR to be covered: "
@@ -296,7 +321,7 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
      * access is without the impl_-> and it will get inlined anyway.
      */
     // Implementation of InMemoryZoneFinder::add
-    result::Result add(const ConstRRsetPtr& rrset, DomainTree* domains) {
+    result::Result add(const ConstRRsetPtr& rrset, ZoneData& zone_data) {
         // Sanitize input.  This will cause an exception to be thrown
         // if the input RRset is empty.
         addValidation(rrset);
@@ -305,21 +330,28 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
         LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_ADD_RRSET).
             arg(rrset->getName()).arg(rrset->getType()).arg(origin_);
 
+        if (rrset->getType() == RRType::NSEC3()) {
+            // TBD: Duplicate check
+            zone_data.nsec3_set_.insert(rrset);
+            return (result::SUCCESS);
+        }
+
         // RRSIGs are special in various points, so we handle it in a
         // separate dedicated method.
         if (rrset->getType() == RRType::RRSIG()) {
-            return (addRRsig(rrset, *domains));
+            return (addRRsig(rrset, zone_data));
         }
 
         // Add wildcards possibly contained in the owner name to the domain
         // tree.
         // Note: this can throw an exception, breaking strong exception
         // guarantee.  (see also the note for contextCheck() below).
-        addWildcards(*domains, rrset->getName());
+        addWildcards(zone_data.domains_, rrset->getName());
 
         // Get the node
         DomainNode* node;
-        DomainTree::Result result = domains->insert(rrset->getName(), &node);
+        DomainTree::Result result = zone_data.domains_.insert(rrset->getName(),
+                                                              &node);
         // Just check it returns reasonable results
         assert((result == DomainTree::SUCCESS ||
                 result == DomainTree::ALREADYEXISTS) && node!= NULL);
@@ -366,18 +398,18 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
      * Same as above, but it checks the return value and if it already exists,
      * it throws.
      */
-    void addFromLoad(const ConstRRsetPtr& set, DomainTree* domains) {
-            switch (add(set, domains)) {
-                case result::EXIST:
-                    LOG_ERROR(logger, DATASRC_MEM_DUP_RRSET).
-                        arg(set->getName()).arg(set->getType());
-                    isc_throw(dns::MasterLoadError, "Duplicate rrset: " <<
-                        set->toText());
-                case result::SUCCESS:
-                    return;
-                default:
-                    assert(0);
-            }
+    void addFromLoad(const ConstRRsetPtr& set, ZoneData* zone_data) {
+        switch (add(set, *zone_data)) {
+        case result::EXIST:
+            LOG_ERROR(logger, DATASRC_MEM_DUP_RRSET).
+                arg(set->getName()).arg(set->getType());
+            isc_throw(dns::MasterLoadError, "Duplicate rrset: " <<
+                      set->toText());
+        case result::SUCCESS:
+            return;
+        default:
+            assert(0);
+        }
     }
 
     // Maintain intermediate data specific to the search context used in
@@ -499,7 +531,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
         FindState state(options);
         RBTreeNodeChain<Domain> node_path;
         bool rename(false);
-        switch (domains_.find(name, &node, node_path, cutCallback, &state)) {
+        switch (zone_data_->domains_.find(name, &node, node_path, cutCallback,
+                                          &state)) {
             case DomainTree::PARTIALMATCH:
                 /*
                  * In fact, we could use a single variable instead of
@@ -584,7 +617,8 @@ struct InMemoryZoneFinder::InMemoryZoneFinderImpl {
                     }
                     Name wildcard(Name("*").concatenate(
                         node_path.getAbsoluteName()));
-                    DomainTree::Result result(domains_.find(wildcard, &node));
+                    DomainTree::Result result =
+                        zone_data_->domains_.find(wildcard, &node);
                     /*
                      * Otherwise, why would the DOMAINFLAG_WILD be there if
                      * there was no wildcard under it?
@@ -719,7 +753,7 @@ InMemoryZoneFinder::findNSEC3(const Name&, bool) {
 
 result::Result
 InMemoryZoneFinder::add(const ConstRRsetPtr& rrset) {
-    return (impl_->add(rrset, &impl_->domains_));
+    return (impl_->add(rrset, *impl_->zone_data_));
 }
 
 
@@ -727,13 +761,14 @@ void
 InMemoryZoneFinder::load(const string& filename) {
     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_LOAD).arg(getOrigin()).
         arg(filename);
-    // Load it into a temporary tree
-    DomainTree tmp;
+    // Load it into temporary zone data
+    scoped_ptr<ZoneData> tmp(new ZoneData);
     masterLoad(filename.c_str(), getOrigin(), getClass(),
-        boost::bind(&InMemoryZoneFinderImpl::addFromLoad, impl_, _1, &tmp));
+               boost::bind(&InMemoryZoneFinderImpl::addFromLoad, impl_,
+                           _1, tmp.get()));
     // If it went well, put it inside
     impl_->file_name_ = filename;
-    tmp.swap(impl_->domains_);
+    tmp.swap(impl_->zone_data_);
     // And let the old data die with tmp
 }
 
@@ -924,8 +959,9 @@ InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
         isc_throw(Unexpected, "The zone at " + name.toText() +
                   " is not InMemoryZoneFinder");
     }
-    return (ZoneIteratorPtr(new MemoryIterator(zone->impl_->domains_, name,
-                                               separate_rrs)));
+    return (ZoneIteratorPtr(new MemoryIterator(
+                                zone->impl_->zone_data_->domains_, name,
+                                separate_rrs)));
 }
 
 ZoneUpdaterPtr

+ 11 - 0
src/lib/datasrc/tests/memory_datasrc_unittest.cc

@@ -1307,4 +1307,15 @@ TEST_F(InMemoryZoneFinderTest, addbadRRsig) {
     EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_a_txt)),
                  InMemoryZoneFinder::AddError);
 }
+
+TEST_F(InMemoryZoneFinderTest, addNSEC3) {
+    zone_finder_.add(textToRRset(
+                         "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org. "
+                         "300 IN NSEC3 1 1 12 aabbccdd "
+                         "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG"));
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              zone_finder_.find(
+                  Name("0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM.example.org"),
+                  RRType::NSEC3()).code);
+}
 }