Browse Source

[2420] extend RdataSet::find() to control whether to match sig-only RdataSets.

and use it in zone data updater to preserve the previous behavior.
JINMEI Tatuya 12 years ago
parent
commit
d805ae680f

+ 19 - 6
src/lib/datasrc/memory/rdataset.h

@@ -205,6 +205,11 @@ public:
     /// if not found in the entire list, it returns NULL.  The head pointer
     /// can be NULL, in which case this function will simply return NULL.
     ///
+    /// By default, this method ignores an RdataSet that only contains an
+    /// RRSIG (i.e., missing the covered RdataSet); if the optional
+    /// sigonly_ok parameter is explicitly set to true, it matches such
+    /// RdataSet and returns it if found.
+    ///
     /// \note This function is defined as a (static) class method to
     /// clarify its an operation for \c RdataSet objects and to make the
     /// name shorter.  But its implementation does not depend on private
@@ -215,10 +220,14 @@ public:
     /// \param rdata_head A pointer to \c RdataSet from which the search
     /// starts.  It can be NULL.
     /// \param type The RRType of \c RdataSet to find.
+    /// \param sigonly_ok Whether it should find an RdataSet that only has
+    /// RRSIG
     /// \return A pointer to the found \c RdataSet or NULL if none found.
     static const RdataSet*
-    find(const RdataSet* rdataset_head, const dns::RRType& type) {
-        return (find<const RdataSet>(rdataset_head, type));
+    find(const RdataSet* rdataset_head, const dns::RRType& type,
+         bool sigonly_ok = false)
+    {
+        return (find<const RdataSet>(rdataset_head, type, sigonly_ok));
     }
 
     /// \brief Find \c RdataSet of given RR type from a list (non const
@@ -227,8 +236,10 @@ public:
     /// This is similar to the const version, except it takes and returns non
     /// const pointers.
     static RdataSet*
-    find(RdataSet* rdataset_head, const dns::RRType& type) {
-        return (find<RdataSet>(rdataset_head, type));
+    find(RdataSet* rdataset_head, const dns::RRType& type,
+         bool sigonly_ok = false)
+    {
+        return (find<RdataSet>(rdataset_head, type, sigonly_ok));
     }
 
     typedef boost::interprocess::offset_ptr<RdataSet> RdataSetPtr;
@@ -347,12 +358,14 @@ private:
     // Shared by both mutable and immutable versions of find()
     template <typename RdataSetType>
     static RdataSetType*
-    find(RdataSetType* rdataset_head, const dns::RRType& type) {
+    find(RdataSetType* rdataset_head, const dns::RRType& type, bool sigonly_ok)
+    {
         for (RdataSetType* rdataset = rdataset_head;
              rdataset != NULL;
              rdataset = rdataset->getNext()) // use getNext() for efficiency
         {
-            if (rdataset->type == type) {
+            if (rdataset->type == type &&
+                (rdataset->getRdataCount() > 0 || sigonly_ok)) {
                 return (rdataset);
             }
         }

+ 1 - 1
src/lib/datasrc/memory/zone_data_updater.cc

@@ -294,7 +294,7 @@ ZoneDataUpdater::addRdataSet(const Name& name, const RRType& rrtype,
             contextCheck(*rrset, rdataset_head);
         }
 
-        if (RdataSet::find(rdataset_head, rrtype) != NULL) {
+        if (RdataSet::find(rdataset_head, rrtype, true) != NULL) {
             isc_throw(AddError,
                       "RRset of the type already exists: "
                       << name << " (type: " << rrtype << ")");

+ 56 - 0
src/lib/datasrc/tests/memory/rdataset_unittest.cc

@@ -40,6 +40,7 @@ using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::datasrc::memory;
 using namespace isc::testutils;
+using isc::datasrc::memory::detail::SegmentObjectHolder;
 using boost::lexical_cast;
 
 namespace {
@@ -135,6 +136,61 @@ TEST_F(RdataSetTest, getNext) {
     RdataSet::destroy(mem_sgmt_, rdataset, RRClass::IN());
 }
 
+TEST_F(RdataSetTest, find) {
+    // Create some RdataSets and make a chain of them.
+    SegmentObjectHolder<RdataSet, RRClass> holder1(
+        mem_sgmt_,
+        RdataSet::create(mem_sgmt_, encoder_, a_rrset_, ConstRRsetPtr()),
+        RRClass::IN());
+    ConstRRsetPtr aaaa_rrset =
+        textToRRset("www.example.com. 1076895760 IN AAAA 2001:db8::1");
+    SegmentObjectHolder<RdataSet, RRClass> holder2(
+        mem_sgmt_,
+        RdataSet::create(mem_sgmt_, encoder_, aaaa_rrset, ConstRRsetPtr()),
+        RRClass::IN());
+    ConstRRsetPtr sigonly_rrset =
+        textToRRset("www.example.com. 1076895760 IN RRSIG "
+                    "TXT 5 2 3600 20120814220826 20120715220826 "
+                    "1234 example.com. FAKE");
+    SegmentObjectHolder<RdataSet, RRClass> holder3(
+        mem_sgmt_,
+        RdataSet::create(mem_sgmt_, encoder_, ConstRRsetPtr(), sigonly_rrset),
+        RRClass::IN());
+
+    RdataSet* rdataset_a = holder1.get();
+    RdataSet* rdataset_aaaa = holder2.get();
+    RdataSet* rdataset_sigonly = holder3.get();
+    RdataSet* rdataset_null = NULL;
+    rdataset_a->next = rdataset_aaaa;
+    rdataset_aaaa->next = rdataset_sigonly;
+
+    // If a non-RRSIG part of rdataset exists for the given type, it will be
+    // returned regardless of the value of sigonly_ok.  If it's RRSIG-only
+    // rdataset, it returns non NULL iff sigonly_ok is explicitly set to true.
+    EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a, RRType::AAAA()));
+    EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a, RRType::AAAA(), true));
+    EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a, RRType::AAAA(), false));
+
+    EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a, RRType::TXT()));
+    EXPECT_EQ(rdataset_sigonly, RdataSet::find(rdataset_a, RRType::TXT(),
+                                               true));
+    EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a, RRType::TXT(), false));
+
+    // Same tests for the const version of find().
+    const RdataSet* rdataset_a_const = holder1.get();
+    EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a_const, RRType::AAAA()));
+    EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a_const, RRType::AAAA(),
+                                            true));
+    EXPECT_EQ(rdataset_aaaa, RdataSet::find(rdataset_a_const, RRType::AAAA(),
+                                            false));
+
+    EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a_const, RRType::TXT()));
+    EXPECT_EQ(rdataset_sigonly, RdataSet::find(rdataset_a_const, RRType::TXT(),
+                                               true));
+    EXPECT_EQ(rdataset_null, RdataSet::find(rdataset_a_const, RRType::TXT(),
+                                            false));
+}
+
 // A helper function to create an RRset containing the given number of
 // unique RDATAs.
 ConstRRsetPtr

+ 1 - 1
src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc

@@ -94,7 +94,7 @@ TEST_F(ZoneDataUpdaterTest, rrisgOnly) {
     ZoneNode* node = getNode(mem_sgmt_, Name("www.example.org"), zone_data_);
     const RdataSet* rdset = node->getData();
     ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
-    rdset = RdataSet::find(rdset, RRType::A());
+    rdset = RdataSet::find(rdset, RRType::A(), true);
     ASSERT_NE(static_cast<RdataSet*>(NULL), rdset);
     EXPECT_EQ(0, rdset->getRdataCount());
     EXPECT_EQ(1, rdset->getSigRdataCount());