Browse Source

[2098] supported isSameKind.

JINMEI Tatuya 12 years ago
parent
commit
a599678940

+ 61 - 0
src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc

@@ -463,4 +463,65 @@ TEST_F(TreeNodeRRsetTest, toText) {
                               false),
                 ConstRRsetPtr(), ConstRRsetPtr());
 }
+
+TEST_F(TreeNodeRRsetTest, isSameKind) {
+    const TreeNodeRRset rrset(rrclass_, www_node_, a_rdataset_, true);
+
+    // Same name (node), same type (rdataset) => same kind
+    EXPECT_TRUE(rrset.isSameKind(TreeNodeRRset(rrclass_, www_node_,
+                                               a_rdataset_, true)));
+
+    // Same name (node), different type (rdataset) => not same kind
+    EXPECT_FALSE(rrset.isSameKind(TreeNodeRRset(rrclass_, www_node_,
+                                                aaaa_rdataset_, true)));
+
+    // Different name, different type => not same kind
+    EXPECT_FALSE(rrset.isSameKind(TreeNodeRRset(rrclass_, origin_node_,
+                                                ns_rdataset_, true)));
+
+    // Different name, same type => not same kind.
+    // Note: this shouldn't happen in our in-memory data source implementation,
+    // but API doesn't prohibit it.
+    EXPECT_FALSE(rrset.isSameKind(TreeNodeRRset(rrclass_, origin_node_,
+                                                a_rdataset_, true)));
+
+    // Wildcard and expanded RRset
+    const TreeNodeRRset wildcard_rrset(rrclass_, wildcard_node_,
+                                       wildcard_rdataset_, true);
+    const TreeNodeRRset match_rrset(match_name_, rrclass_, wildcard_node_,
+                                    wildcard_rdataset_, true);
+    EXPECT_FALSE(wildcard_rrset.isSameKind(match_rrset));
+    EXPECT_FALSE(match_rrset.isSameKind(wildcard_rrset));
+
+    // Both are wildcard expanded, and have different names
+    const TreeNodeRRset match2_rrset(Name("match2.example.com"), rrclass_,
+                                     wildcard_node_, wildcard_rdataset_, true);
+    EXPECT_FALSE(match_rrset.isSameKind(match2_rrset));
+    EXPECT_FALSE(match2_rrset.isSameKind(match_rrset));
+
+    // Pathological case.  "badwild" is constructed as if expanded due to
+    // a wildcard, but has the same owner name of the wildcard itself.
+    // Technically, they should be considered of the same kind, but this
+    // implementation considers they are not.  But this case shouldn't happen
+    // as long as the RRsets are only constructed inside the in-memory
+    // zone finder implementation.
+    const TreeNodeRRset badwild_rrset(wildcard_name_, rrclass_, wildcard_node_,
+                                      wildcard_rdataset_, true);
+    EXPECT_FALSE(wildcard_rrset.isSameKind(badwild_rrset));
+    EXPECT_EQ(wildcard_rrset.toText(), badwild_rrset.toText());
+
+    // Pathological case:  Same name, same type, but different class.
+    // This case should be impossible because if the RRsets share the same
+    // tree node, they must belong to the same RR class.  This case is
+    // a caller's bug, and the isSameKind() implementation returns the
+    // "wrong" (= true) answer.
+    EXPECT_TRUE(rrset.isSameKind(TreeNodeRRset(RRClass::CH(), www_node_,
+                                               a_rdataset_, true)));
+
+    // Same kind of different RRset class
+    EXPECT_TRUE(rrset.isSameKind(*a_rrset_));
+
+    // Different kind of different RRset class
+    EXPECT_FALSE(rrset.isSameKind(*aaaa_rrset_));
+}
 }

+ 44 - 4
src/lib/datasrc/memory/treenode_rrset.cc

@@ -40,7 +40,8 @@ namespace isc {
 namespace datasrc {
 namespace memory {
 
-TreeNodeRRset::TreeNodeRRset(const dns::Name& realname, dns::RRClass rrclass,
+TreeNodeRRset::TreeNodeRRset(const dns::Name& realname,
+                             const dns::RRClass& rrclass,
                              const ZoneNode* node, const RdataSet* rdataset,
                              bool dnssec_ok) :
     node_(node), rdataset_(rdataset),
@@ -329,10 +330,49 @@ TreeNodeRRset::removeRRsig() {
     isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
 }
 
-// needed
 bool
-TreeNodeRRset::isSameKind(const AbstractRRset& /*other*/) const {
-    isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
+TreeNodeRRset::isSameKind(const AbstractRRset& abs_other) const {
+    const TreeNodeRRset* other =
+        dynamic_cast<const TreeNodeRRset*>(&abs_other);
+    if (other != NULL) {
+        // If type is different, they are not the same kind
+        if (rdataset_ != other->rdataset_) {
+            return (false);
+        }
+        // Same for the owner name (note: in practice this method would be
+        // called for rrsets at different nodes, so we check that condition
+        // first).  Note also that based on the basic assumption of the
+        // ZoneTree, if the nodes are different their RR classes must be
+        // different.
+        if (node_ != other->node_ || !hasSameRealName(*other)) {
+            return (false);
+        }
+        return (true);
+    }
+    return (AbstractRRset::isSameKind(abs_other));
+}
+
+bool
+TreeNodeRRset::hasSameRealName(const TreeNodeRRset& other) const {
+    // If one is constructed with a "real name" and the other isn't
+    // *we consider* them different.
+    if ((realname_buf_ == NULL && other.realname_buf_ != NULL) ||
+        (realname_buf_ != NULL && other.realname_buf_ == NULL)) {
+        return (false);
+    }
+
+    // If both are constructed with a "real name", we compare their names
+    // (as label sequences) explicitly.
+    if (realname_buf_ != NULL && other.realname_buf_ != NULL) {
+        uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+        uint8_t other_labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+        if (!getOwnerLabels(labels_buf).equals(
+                other.getOwnerLabels(other_labels_buf))) {
+            return (false);
+        }
+    }
+
+    return (true);
 }
 
 } // namespace memory

+ 25 - 4
src/lib/datasrc/memory/treenode_rrset.h

@@ -37,14 +37,14 @@ namespace memory {
 
 class TreeNodeRRset : public dns::AbstractRRset {
 public:
-    TreeNodeRRset(dns::RRClass rrclass, const ZoneNode* node,
+    TreeNodeRRset(const dns::RRClass& rrclass, const ZoneNode* node,
                   const RdataSet* rdataset, bool dnssec_ok) :
         node_(node), rdataset_(rdataset),
         rrsig_count_(rdataset_->getSigRdataCount()), rrclass_(rrclass),
         dnssec_ok_(dnssec_ok), name_(NULL), realname_buf_(NULL)
     {}
 
-    TreeNodeRRset(const dns::Name& realname, dns::RRClass rrclass,
+    TreeNodeRRset(const dns::Name& realname, const dns::RRClass& rrclass,
                   const ZoneNode* node, const RdataSet* rdataset,
                   bool dnssec_ok);
 
@@ -94,8 +94,24 @@ public:
     virtual void addRRsig(const dns::RRsetPtr& sigs);
     virtual void removeRRsig();
 
-    // needed
-    virtual bool isSameKind(const dns::AbstractRRset& other) const;
+    /// \brief Specialized version of \c isSameKind() for \c TreeNodeRRset.
+    ///
+    /// As a kind of optimization, this implementation exploits the assumption
+    /// of how \c TreeNodeRRset objects are created: They must be always
+    /// created inside the in-memory data source finder implementation,
+    /// and they are constructed with the \c realname parameter if and only
+    /// if the corresponding query name is subject to wildcard substitution.
+    ///
+    /// So, if the given RRset is of \c TreeNodeRRset, and one and only one of
+    /// of them has \c realname, they are considered to have different names.
+    ///
+    /// Also, this implementation does not compare RR classes explicitly;
+    /// if two \c TreeNodeRRset objects belong to different RR classes,
+    /// they should belong to different zone trees (according to the assumption
+    /// of how the zone data are built), and therefore they cannot be at
+    /// same zone node.  So it's sufficient to compare the (address of the)
+    /// node; if they are different they cannot be of the same kind.
+    virtual bool isSameKind(const dns::AbstractRRset& abs_other) const;
 
 private:
     dns::RdataIteratorPtr getSigRdataIterator() const;
@@ -110,6 +126,11 @@ private:
         return (node_->getAbsoluteLabels(labels_buf));
     }
 
+    // A helper for isSameKind() to check if 'this' and 'other' has
+    // the same "real" name in case at least either is constructed with
+    // a real name.
+    bool hasSameRealName(const TreeNodeRRset& other) const;
+
     const ZoneNode* node_;
     const RdataSet* rdataset_;
     const size_t rrsig_count_;