Browse Source

iterate over RRs

chenzhengzhang 14 years ago
parent
commit
66ace85fab

+ 38 - 0
src/lib/datasrc/memory_datasrc.cc

@@ -19,6 +19,7 @@
 
 #include <dns/name.h>
 #include <dns/rrclass.h>
+#include <dns/rrsetlist.h>
 #include <dns/masterload.h>
 
 #include <datasrc/memory_datasrc.h>
@@ -185,6 +186,7 @@ struct MemoryZone::MemoryZoneImpl {
         return (false);
     }
 
+
     // Implementation of MemoryZone::find
     FindResult find(const Name& name, RRType type,
                     const FindOptions options) const
@@ -222,6 +224,16 @@ struct MemoryZone::MemoryZoneImpl {
             }
         }
 
+        // handle type any query
+        const bool is_any_query = (type == RRType::ANY());
+        if (is_any_query){
+            if (node->getData()->empty()) {
+                return (FindResult(NXRRSET, ConstRRsetPtr()));
+            } else {
+                return (FindResult(SUCCESS, ConstRRsetPtr()));
+            }
+        }
+
         found = node->getData()->find(type);
         if (found != node->getData()->end()) {
             // Good, it is here
@@ -235,6 +247,26 @@ struct MemoryZone::MemoryZoneImpl {
             return (FindResult(NXRRSET, ConstRRsetPtr()));
         }
     }
+
+    // Implementation of MemoryZone::findAny
+    FindResult findAny(const Name& name, RRsetList& target) const
+    {
+        FindResult result(find(name, RRType::ANY(), FIND_DEFAULT));
+        if (result.code == SUCCESS) {
+            DomainNode* node(NULL);
+            FindState state(FIND_DEFAULT);
+            domains_.find(name, &node, zonecutCallback, &state);
+            assert(!node->getData()->empty());
+
+            Domain::const_iterator it;
+            for (it = node->getData()->begin();
+                 it != node->getData()->end(); it++)
+            {
+                target.addRRset(boost::const_pointer_cast<RRset>(it->second));
+            }
+        }
+        return (result);
+    }
 };
 
 MemoryZone::MemoryZone(const RRClass& zone_class, const Name& origin) :
@@ -263,6 +295,12 @@ MemoryZone::find(const Name& name, const RRType& type,
     return (impl_->find(name, type, options));
 }
 
+Zone::FindResult
+MemoryZone::findAny(const Name& name, RRsetList& target) const
+{
+    return (impl_->findAny(name, target));
+}
+
 result::Result
 MemoryZone::add(const ConstRRsetPtr& rrset) {
     return (impl_->add(rrset, &impl_->domains_));

+ 19 - 1
src/lib/datasrc/memory_datasrc.h

@@ -22,6 +22,7 @@
 namespace isc {
 namespace dns {
 class Name;
+class RRsetList;
 };
 
 namespace datasrc {
@@ -61,12 +62,29 @@ public:
     ///
     /// See documentation in \c Zone.
     ///
-    /// It returns NULL pointer in case of NXDOMAIN and NXRRSET
+    /// It returns NULL pointer in case of NXDOMAIN and NXRRSET,
+    /// and also SUCCESS for TYPE_ANY query.
     /// (the base class documentation does not seem to require that).
     virtual FindResult find(const isc::dns::Name& name,
                             const isc::dns::RRType& type,
                             const FindOptions options = FIND_DEFAULT) const;
 
+    /// \brief Iterate over RRs with the same owner name in the zone.
+    ///
+    /// It gets all RRsets under the domain name.
+    ///
+    /// It throws DuplicateRRset exception if there are duplicate rrsets under
+    /// the same domain. This method involve internal resource allocation,
+    /// especially for constructing the FindResult, and may throw an exception
+    /// if it fails. It should not throw other types of exceptions.
+    ///
+    /// \param name The domain name to be searched for.
+    /// \param target  Insert RRs under the domain name into it.
+    /// \return A \c FindResult object enclosing the search result, it returns
+    /// NULL in case of NXDOMAIN, NXRRSET and SUCCESS.
+    FindResult findAny(const isc::dns::Name& name,
+                       isc::dns::RRsetList& target) const;
+
     /// \brief Inserts an rrset into the zone.
     ///
     /// It puts another RRset into the zone.

+ 3 - 3
src/lib/datasrc/static_datasrc.h

@@ -76,9 +76,9 @@ public:
                             isc::dns::Name& target,
                             const isc::dns::Name* zonename) const;
 
-   Result findCoveringNSEC3(const isc::dns::Name& zonename,
-                            std::string& hash,
-                            isc::dns::RRsetList& target) const;
+    Result findCoveringNSEC3(const isc::dns::Name& zonename,
+                             std::string& hash,
+                             isc::dns::RRsetList& target) const;
 
     Result init();
     Result init(isc::data::ConstElementPtr config);

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

@@ -16,6 +16,7 @@
 
 #include <dns/name.h>
 #include <dns/rrclass.h>
+#include <dns/rrsetlist.h>
 #include <dns/rrttl.h>
 #include <dns/masterload.h>
 
@@ -229,6 +230,41 @@ public:
                 }
             });
     }
+
+    /**
+     * \brief Test one TYPE_ANY find query to the zone.
+     *
+     * Asks a query to the zone and checks it does not throw and returns
+     * expected results. It returns nothing, it just signals failures
+     * to GTEST.
+     *
+     * \param name The name to ask for.
+     * \param result The expected code of the result.
+     * \param check_answer Should a check against equality of the answer be
+     *     done?
+     * \param answer The expected rrset, if any should be returned.
+     * \param zone Check different MemoryZone object than zone_ (if NULL,
+     *     uses zone_)
+     */
+    void findAnyTest(const Name& name, Zone::Result result,
+                     RRsetList& target, bool check_answer = true,
+                     const ConstRRsetPtr& answer = ConstRRsetPtr(),
+                     MemoryZone *zone = NULL)
+    {
+        if (!zone) {
+            zone = &zone_;
+        }
+        // The whole block is inside, because we need to check the result and
+        // we can't assign to FindResult
+        EXPECT_NO_THROW({
+                Zone::FindResult find_result(zone->findAny(name, target));
+                // Check it returns correct answers
+                EXPECT_EQ(result, find_result.code);
+                if (check_answer) {
+                    EXPECT_EQ(answer, find_result.rrset);
+                }
+            });
+    }
 };
 
 /**
@@ -292,6 +328,62 @@ TEST_F(MemoryZoneTest, delegationNS) {
              Zone::DELEGATION, true, rr_child_ns_); // note: !rr_grandchild_ns_
 }
 
+TEST_F(MemoryZoneTest, any) {
+    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
+    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
+    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
+
+    findTest(Name("example.org"), RRType::ANY(), Zone::SUCCESS,
+             true, ConstRRsetPtr());
+    findTest(Name("child.example.org"), RRType::ANY(), Zone::DELEGATION,
+             true, rr_child_ns_);
+    findTest(Name("example.com"), RRType::ANY(), Zone::NXDOMAIN,
+             true, ConstRRsetPtr());
+}
+
+TEST_F(MemoryZoneTest, findAny) {
+    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_a_)));
+    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_ns_)));
+    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_glue_)));
+
+    // origin
+    RRsetList origin_rrsets;
+    findAnyTest(origin_, Zone::SUCCESS, origin_rrsets,
+                true, ConstRRsetPtr());
+    EXPECT_EQ(2, origin_rrsets.size());
+    EXPECT_EQ(rr_a_, origin_rrsets.findRRset(RRType::A(), RRClass::IN()));
+    EXPECT_EQ(rr_ns_, origin_rrsets.findRRset(RRType::NS(), RRClass::IN()));
+
+    // out zone name
+    RRsetList out_rrsets;
+    findAnyTest(Name("example.com"), Zone::NXDOMAIN, out_rrsets,
+                true, ConstRRsetPtr());
+    EXPECT_EQ(0, out_rrsets.size());
+
+    RRsetList glue_child_rrsets;
+    findAnyTest(child_glue_name_, Zone::SUCCESS, glue_child_rrsets,
+                true, ConstRRsetPtr());
+    EXPECT_EQ(1, glue_child_rrsets.size());
+
+    // TODO: test NXRRSET case after rbtree non-terminal logic has
+    // been implemented
+
+    // add zone cut
+    EXPECT_NO_THROW(EXPECT_EQ(SUCCESS, zone_.add(rr_child_ns_)));
+
+    // zone cut
+    RRsetList child_rrsets;
+    findAnyTest(child_ns_name_, Zone::DELEGATION, child_rrsets,
+                true, rr_child_ns_);
+    EXPECT_EQ(0, child_rrsets.size());
+
+    // glue for this zone cut
+    RRsetList new_glue_child_rrsets;
+    findAnyTest(child_glue_name_, Zone::DELEGATION, new_glue_child_rrsets,
+                true, rr_child_ns_);
+    EXPECT_EQ(0, new_glue_child_rrsets.size());
+}
+
 TEST_F(MemoryZoneTest, glue) {
     // install zone data:
     // a zone cut
@@ -459,4 +551,5 @@ TEST_F(MemoryZoneTest, getFileName) {
     EXPECT_EQ(TEST_DATA_DIR "/root.zone", zone_.getFileName());
     EXPECT_TRUE(rootzone.getFileName().empty());
 }
+
 }