Browse Source

[2441] Update in-memory data source so it can load RRs in any order

The ZoneDataLoader can still be simplified to remove the vectors
in it (as the RdataSet now merges for us). This will be done
in a future commit.

* In some tests, the RdataSet list sequence changed (as there's no
  order enforced for this data). Tests were adjusted for it.
* Some test data was adjusted to add missing NS records.
* Some tests now pass and don't throw exceptions as duplicate
  records for a type are now accepted.
Mukund Sivaraman 12 years ago
parent
commit
28ebeea1c4

+ 10 - 26
src/lib/datasrc/memory/zone_data_loader.cc

@@ -77,8 +77,7 @@ public:
     void flushNodeRRsets();
     void flushNodeRRsets();
 
 
 private:
 private:
-    typedef std::map<isc::dns::RRType, isc::dns::ConstRRsetPtr> NodeRRsets;
+    typedef std::vector<isc::dns::ConstRRsetPtr> NodeRRsets;
-    typedef NodeRRsets::value_type NodeRRsetsVal;
 
 
     // A helper to identify the covered type of an RRSIG.
     // A helper to identify the covered type of an RRSIG.
     const isc::dns::Name& getCurrentName() const;
     const isc::dns::Name& getCurrentName() const;
@@ -103,13 +102,9 @@ ZoneDataLoader::addFromLoad(const ConstRRsetPtr& rrset) {
     // once, so we check the "duplicate" here.
     // once, so we check the "duplicate" here.
     const bool is_rrsig = rrset->getType() == RRType::RRSIG();
     const bool is_rrsig = rrset->getType() == RRType::RRSIG();
     NodeRRsets& node_rrsets = is_rrsig ? node_rrsigsets_ : node_rrsets_;
     NodeRRsets& node_rrsets = is_rrsig ? node_rrsigsets_ : node_rrsets_;
-    const RRType& rrtype = is_rrsig ? getCoveredType(rrset) : rrset->getType();
+
-    if (!node_rrsets.insert(NodeRRsetsVal(rrtype, rrset)).second) {
+    // Store this RRset until it can be added to the zone.
-        isc_throw(ZoneDataUpdater::AddError,
+    node_rrsets.insert(node_rrsets.begin(), rrset);
-                  "Duplicate add of the same type of"
-                  << (is_rrsig ? " RRSIG" : "") << " RRset: "
-                  << rrset->getName() << "/" << rrtype);
-    }
 
 
     if (rrset->getRRsig()) {
     if (rrset->getRRsig()) {
         addFromLoad(rrset->getRRsig());
         addFromLoad(rrset->getRRsig());
@@ -118,23 +113,12 @@ ZoneDataLoader::addFromLoad(const ConstRRsetPtr& rrset) {
 
 
 void
 void
 ZoneDataLoader::flushNodeRRsets() {
 ZoneDataLoader::flushNodeRRsets() {
-    BOOST_FOREACH(NodeRRsetsVal val, node_rrsets_) {
+    BOOST_FOREACH(ConstRRsetPtr rrset, node_rrsets_) {
-        // Identify the corresponding RRSIG for the RRset, if any.  If
+        updater_.add(rrset, ConstRRsetPtr());
-        // found add both the RRset and its RRSIG at once.
-        ConstRRsetPtr sig_rrset;
-        NodeRRsets::iterator sig_it = node_rrsigsets_.find(val.first);
-        if (sig_it != node_rrsigsets_.end()) {
-            sig_rrset = sig_it->second;
-            node_rrsigsets_.erase(sig_it);
-        }
-        updater_.add(val.second, sig_rrset);
     }
     }
 
 
-    // Normally rrsigsets map should be empty at this point, but it's still
+    BOOST_FOREACH(ConstRRsetPtr rrset, node_rrsigsets_) {
-    // possible that an RRSIG that don't has covered RRset is added; they
+        updater_.add(ConstRRsetPtr(), rrset);
-    // still remain in the map.  We add them to the zone separately.
-    BOOST_FOREACH(NodeRRsetsVal val, node_rrsigsets_) {
-        updater_.add(ConstRRsetPtr(), val.second);
     }
     }
 
 
     node_rrsets_.clear();
     node_rrsets_.clear();
@@ -144,10 +128,10 @@ ZoneDataLoader::flushNodeRRsets() {
 const Name&
 const Name&
 ZoneDataLoader::getCurrentName() const {
 ZoneDataLoader::getCurrentName() const {
     if (!node_rrsets_.empty()) {
     if (!node_rrsets_.empty()) {
-        return (node_rrsets_.begin()->second->getName());
+        return (node_rrsets_.front()->getName());
     }
     }
     assert(!node_rrsigsets_.empty());
     assert(!node_rrsigsets_.empty());
-    return (node_rrsigsets_.begin()->second->getName());
+    return (node_rrsigsets_.front()->getName());
 }
 }
 
 
 void
 void

+ 33 - 11
src/lib/datasrc/memory/zone_data_updater.cc

@@ -270,8 +270,12 @@ ZoneDataUpdater::addNSEC3(const Name& name, const ConstRRsetPtr rrset,
     ZoneNode* node;
     ZoneNode* node;
     nsec3_data->insertName(mem_sgmt_, name, &node);
     nsec3_data->insertName(mem_sgmt_, name, &node);
 
 
-    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, rrset, rrsig);
+    // Create a new RdataSet, merging any existing existing NSEC3 data
-    RdataSet* old_rdataset = node->setData(rdataset);
+    // for this name.
+    RdataSet* old_rdataset = node->getData();
+    RdataSet* rdataset = RdataSet::create(mem_sgmt_, encoder_, rrset, rrsig,
+                                          old_rdataset);
+    old_rdataset = node->setData(rdataset);
     if (old_rdataset != NULL) {
     if (old_rdataset != NULL) {
         RdataSet::destroy(mem_sgmt_, old_rdataset, rrclass_);
         RdataSet::destroy(mem_sgmt_, old_rdataset, rrclass_);
     }
     }
@@ -298,16 +302,34 @@ ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
             contextCheck(*rrset, rdataset_head);
             contextCheck(*rrset, rdataset_head);
         }
         }
 
 
-        if (RdataSet::find(rdataset_head, rrtype, true) != NULL) {
+        // Create a new RdataSet, merging any existing data for this
-            isc_throw(AddError,
+        // type.
-                      "RRset of the type already exists: "
+        RdataSet* old_rdataset = RdataSet::find(rdataset_head, rrtype, true);
-                      << name << " (type: " << rrtype << ")");
-        }
-
         RdataSet* rdataset_new = RdataSet::create(mem_sgmt_, encoder_,
         RdataSet* rdataset_new = RdataSet::create(mem_sgmt_, encoder_,
-                                                  rrset, rrsig);
+                                                  rrset, rrsig, old_rdataset);
-        rdataset_new->next = rdataset_head;
+        if (old_rdataset == NULL) {
-        node->setData(rdataset_new);
+            // There is no existing RdataSet. Prepend the new RdataSet
+            // to the list.
+            rdataset_new->next = rdataset_head;
+            node->setData(rdataset_new);
+        } else {
+            // Replace the old RdataSet in the list with the newly
+            // created one, and destroy the old one.
+            for (RdataSet* cur = rdataset_head, *prev = NULL;
+                 cur != NULL;
+                 prev = cur, cur = cur->getNext()) {
+                if (cur == old_rdataset) {
+                    rdataset_new->next = cur->getNext();
+                    if (prev == NULL) {
+                        node->setData(rdataset_new);
+                    } else {
+                        prev->next = rdataset_new;
+                    }
+                    break;
+                }
+            }
+            RdataSet::destroy(mem_sgmt_, old_rdataset, rrclass_);
+        }
 
 
         // Ok, we just put it in.
         // Ok, we just put it in.
 
 

+ 43 - 40
src/lib/datasrc/tests/memory/memory_client_unittest.cc

@@ -74,6 +74,7 @@ const char* rrset_data[] = {
 const char* rrset_data_separated[] = {
 const char* rrset_data_separated[] = {
     "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
     "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
     "68 3600 300 3600000 3600",
     "68 3600 300 3600000 3600",
+    "example.org. 3600 IN NS ns1.example.org.",
     "a.example.org. 3600 IN A 192.168.0.1", // these two belong to the same
     "a.example.org. 3600 IN A 192.168.0.1", // these two belong to the same
     "a.example.org. 3600 IN A 192.168.0.2", // RRset, but are separated.
     "a.example.org. 3600 IN A 192.168.0.2", // RRset, but are separated.
     NULL
     NULL
@@ -83,6 +84,7 @@ const char* rrset_data_separated[] = {
 const char* rrset_data_sigseparated[] = {
 const char* rrset_data_sigseparated[] = {
     "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
     "example.org. 3600 IN SOA ns1.example.org. bugs.x.w.example.org. "
     "68 3600 300 3600000 3600",
     "68 3600 300 3600000 3600",
+    "example.org. 3600 IN NS ns1.example.org.",
     "a.example.org. 3600 IN A 192.168.0.1",
     "a.example.org. 3600 IN A 192.168.0.1",
     "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
     "a.example.org. 3600 IN RRSIG A 5 3 3600 20150420235959 20051021000000 "
     "40430 example.org. FAKEFAKE",
     "40430 example.org. FAKEFAKE",
@@ -254,20 +256,20 @@ TEST_F(MemoryClientTest, loadFromIterator) {
     // First we have the SOA
     // First we have the SOA
     ConstRRsetPtr rrset(iterator->getNextRRset());
     ConstRRsetPtr rrset(iterator->getNextRRset());
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::SOA(), rrset->getType());
+    EXPECT_EQ(RRType::NS(), rrset->getType());
 
 
     // RRType::NS() RRset
     // RRType::NS() RRset
     rrset = iterator->getNextRRset();
     rrset = iterator->getNextRRset();
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::NS(), rrset->getType());
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
 
 
-    // RRType::MX() RRset
+    // RRType::A() RRset
     rrset = iterator->getNextRRset();
     rrset = iterator->getNextRRset();
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
     EXPECT_EQ(RRType::MX(), rrset->getType());
     EXPECT_EQ(RRType::MX(), rrset->getType());
     EXPECT_EQ(1, rrset->getRRsigDataCount()); // this RRset is signed
     EXPECT_EQ(1, rrset->getRRsigDataCount()); // this RRset is signed
 
 
-    // RRType::A() RRset
+    // RRType::MX() RRset
     rrset = iterator->getNextRRset();
     rrset = iterator->getNextRRset();
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
     EXPECT_EQ(RRType::A(), rrset->getType());
     EXPECT_EQ(RRType::A(), rrset->getType());
@@ -279,24 +281,22 @@ TEST_F(MemoryClientTest, loadFromIterator) {
     // Iterating past the end should result in an exception
     // Iterating past the end should result in an exception
     EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
     EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
 
 
-    // Loading the zone with an iterator separating RRs of the same RRset
+    // Loading the zone with an iterator separating RRs of the same
-    // will fail because the resulting sequence doesn't meet assumptions of
+    // RRset should not fail. It is acceptable to load RRs of the same
-    // the (current) in-memory implementation.
+    // type again.
-    EXPECT_THROW(client_->load(Name("example.org"),
+    client_->load(Name("example.org"),
-                               *MockIterator::makeIterator(
+                  *MockIterator::makeIterator(
-                                   rrset_data_separated)),
+                      rrset_data_separated));
-                 ZoneDataUpdater::AddError);
 
 
     // Similar to the previous case, but with separated RRSIGs.
     // Similar to the previous case, but with separated RRSIGs.
-    EXPECT_THROW(client_->load(Name("example.org"),
+    client_->load(Name("example.org"),
-                               *MockIterator::makeIterator(
+                  *MockIterator::makeIterator(
-                                   rrset_data_sigseparated)),
+                      rrset_data_sigseparated));
-                 ZoneDataUpdater::AddError);
 
 
     // Emulating bogus iterator implementation that passes empty RRSIGs.
     // Emulating bogus iterator implementation that passes empty RRSIGs.
     EXPECT_THROW(client_->load(Name("example.org"),
     EXPECT_THROW(client_->load(Name("example.org"),
                                *MockIterator::makeIterator(rrset_data, true)),
                                *MockIterator::makeIterator(rrset_data, true)),
-                 isc::Unexpected);
+                 ZoneDataUpdater::AddError);
 }
 }
 
 
 TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
 TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
@@ -380,11 +380,11 @@ TEST_F(MemoryClientTest, loadReloadZone) {
 
 
     const RdataSet* set = node->getData();
     const RdataSet* set = node->getData();
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::SOA(), set->type);
+    EXPECT_EQ(RRType::NS(), set->type);
 
 
     set = set->getNext();
     set = set->getNext();
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::NS(), set->type);
+    EXPECT_EQ(RRType::SOA(), set->type);
 
 
     set = set->getNext();
     set = set->getNext();
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
@@ -409,11 +409,11 @@ TEST_F(MemoryClientTest, loadReloadZone) {
 
 
     set = node->getData();
     set = node->getData();
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::SOA(), set->type);
+    EXPECT_EQ(RRType::NS(), set->type);
 
 
     set = set->getNext();
     set = set->getNext();
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::NS(), set->type);
+    EXPECT_EQ(RRType::SOA(), set->type);
 
 
     set = set->getNext();
     set = set->getNext();
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
@@ -439,15 +439,18 @@ TEST_F(MemoryClientTest, loadReloadZone) {
 }
 }
 
 
 TEST_F(MemoryClientTest, loadDuplicateType) {
 TEST_F(MemoryClientTest, loadDuplicateType) {
-    // This should not result in any exceptions:
+    // This should not result in any exceptions (multiple records of the
+    // same name, type are present, one after another in sequence).
     client_->load(Name("example.org"),
     client_->load(Name("example.org"),
                   TEST_DATA_DIR "/example.org-duplicate-type.zone");
                   TEST_DATA_DIR "/example.org-duplicate-type.zone");
 
 
-    // This should throw:
+    // This should not result in any exceptions (multiple records of the
-    EXPECT_THROW(client_->load(Name("example.org"),
+    // same name, type are present, but not one after another in
-                               TEST_DATA_DIR
+    // sequence).
-                               "/example.org-duplicate-type-bad.zone"),
+    client_->load(Name("example.org"),
-                 ZoneDataUpdater::AddError);
+                  TEST_DATA_DIR
+                  "/example.org-duplicate-type-bad.zone");
+
     // Teardown checks for memory segment leaks
     // Teardown checks for memory segment leaks
 }
 }
 
 
@@ -649,15 +652,15 @@ TEST_F(MemoryClientTest, getIterator) {
     client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
     client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
 
 
-    // First we have the SOA
+    // First we have the NS
     ConstRRsetPtr rrset(iterator->getNextRRset());
     ConstRRsetPtr rrset(iterator->getNextRRset());
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::SOA(), rrset->getType());
+    EXPECT_EQ(RRType::NS(), rrset->getType());
 
 
-    // Then the NS
+    // Then the SOA
     rrset = iterator->getNextRRset();
     rrset = iterator->getNextRRset();
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::NS(), rrset->getType());
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
 
 
     // There's nothing else in this iterator
     // There's nothing else in this iterator
     EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
     EXPECT_EQ(ConstRRsetPtr(), iterator->getNextRRset());
@@ -673,15 +676,15 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
     // separate_rrs = false
     // separate_rrs = false
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
 
 
-    // First we have the SOA
+    // First we have the NS
     ConstRRsetPtr rrset(iterator->getNextRRset());
     ConstRRsetPtr rrset(iterator->getNextRRset());
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::SOA(), rrset->getType());
+    EXPECT_EQ(RRType::NS(), rrset->getType());
 
 
-    // Then, the NS
+    // Then, the SOA
     rrset = iterator->getNextRRset();
     rrset = iterator->getNextRRset();
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::NS(), rrset->getType());
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
 
 
     // Only one RRType::A() RRset
     // Only one RRType::A() RRset
     rrset = iterator->getNextRRset();
     rrset = iterator->getNextRRset();
@@ -694,15 +697,15 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
     // separate_rrs = true
     // separate_rrs = true
     ZoneIteratorPtr iterator2(client_->getIterator(Name("example.org"), true));
     ZoneIteratorPtr iterator2(client_->getIterator(Name("example.org"), true));
 
 
-    // First we have the SOA
+    // First we have the NS
     rrset = iterator2->getNextRRset();
     rrset = iterator2->getNextRRset();
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::SOA(), rrset->getType());
+    EXPECT_EQ(RRType::NS(), rrset->getType());
 
 
-    // Then, the NS
+    // Then, the SOA
     rrset = iterator2->getNextRRset();
     rrset = iterator2->getNextRRset();
     EXPECT_TRUE(rrset);
     EXPECT_TRUE(rrset);
-    EXPECT_EQ(RRType::NS(), rrset->getType());
+    EXPECT_EQ(RRType::SOA(), rrset->getType());
 
 
     // First RRType::A() RRset
     // First RRType::A() RRset
     rrset = iterator2->getNextRRset();
     rrset = iterator2->getNextRRset();
@@ -777,12 +780,12 @@ TEST_F(MemoryClientTest, findZoneData) {
 
 
     const RdataSet* set = node->getData();
     const RdataSet* set = node->getData();
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::SOA(), set->type);
+    EXPECT_EQ(RRType::NS(), set->type);
 
 
     /* Check NS */
     /* Check NS */
     set = set->getNext();
     set = set->getNext();
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
     EXPECT_NE(static_cast<const RdataSet*>(NULL), set);
-    EXPECT_EQ(RRType::NS(), set->type);
+    EXPECT_EQ(RRType::SOA(), set->type);
 
 
     set = set->getNext();
     set = set->getNext();
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);
     EXPECT_EQ(static_cast<const RdataSet*>(NULL), set);

+ 3 - 1
src/lib/datasrc/tests/memory/testdata/example.org-duplicate-type-bad.zone

@@ -1,4 +1,6 @@
-example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 77 3600 300 3600000 3600
+example.org. 3600 IN SOA	ns1.example.org. bugs.x.w.example.org. 78 3600 300 3600000 3600
+example.org.			      3600 IN NS	ns1.example.org.
+example.org.			      3600 IN NS	ns2.example.org.
 ns1.example.org.		      3600 IN A	 	192.168.0.1
 ns1.example.org.		      3600 IN A	 	192.168.0.1
 ns1.example.org.		      3600 IN AAAA 	::1
 ns1.example.org.		      3600 IN AAAA 	::1
 ns1.example.org.		      3600 IN A	 	192.168.0.2
 ns1.example.org.		      3600 IN A	 	192.168.0.2

+ 4 - 6
src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc

@@ -111,12 +111,10 @@ TEST_F(ZoneDataUpdaterTest, rrsigOnly) {
     EXPECT_EQ(0, rdset->getRdataCount());
     EXPECT_EQ(0, rdset->getRdataCount());
     EXPECT_EQ(1, rdset->getSigRdataCount());
     EXPECT_EQ(1, rdset->getSigRdataCount());
 
 
-    // The RRSIG covering A prohibits an actual A RRset from being added.
+    // The RRSIG covering A must not prohibit an actual A RRset from
-    // This should be loosened in future version, but we check the current
+    // being added later.
-    // behavior.
+    updater_->add(textToRRset("www.example.org. 3600 IN A 192.0.2.1"),
-    EXPECT_THROW(updater_->add(
+                  ConstRRsetPtr());
-                     textToRRset("www.example.org. 3600 IN A 192.0.2.1"),
-                     ConstRRsetPtr()), ZoneDataUpdater::AddError);
 
 
     // The special "wildcarding" node mark should be added for the RRSIG-only
     // The special "wildcarding" node mark should be added for the RRSIG-only
     // case, too.
     // case, too.