Browse Source

[2098] supportd rdata iterator

JINMEI Tatuya 12 years ago
parent
commit
823275807b

+ 50 - 3
src/lib/datasrc/memory/tests/treenode_rrset_unittest.cc

@@ -24,6 +24,11 @@
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
+#include <string>
+#include <vector>
+
+using std::vector;
+using std::string;
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::dns::rdata;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc::memory;
@@ -39,7 +44,8 @@ protected:
         rrclass_(RRClass::IN()),
         rrclass_(RRClass::IN()),
         origin_name_("example.com"), www_name_("www.example.com"),
         origin_name_("example.com"), www_name_("www.example.com"),
         ns_rrset_(textToRRset("example.com. 3600 IN NS ns.example.com.")),
         ns_rrset_(textToRRset("example.com. 3600 IN NS ns.example.com.")),
-        a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1")),
+        a_rrset_(textToRRset("www.example.com. 3600 IN A 192.0.2.1\n"
+                             "www.example.com. 3600 IN A 192.0.2.2")),
         dname_rrset_(textToRRset("example.com. 3600 IN DNAME d.example.org.")),
         dname_rrset_(textToRRset("example.com. 3600 IN DNAME d.example.org.")),
         rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG "
         rrsig_rrset_(textToRRset("www.example.com. 3600 IN RRSIG "
                                  "A 5 2 3600 20120814220826 20120715220826 "
                                  "A 5 2 3600 20120814220826 20120715220826 "
@@ -90,14 +96,14 @@ TEST_F(TreeNodeRRsetTest, create) {
     EXPECT_EQ(RRClass::IN(), rrset1.getClass());
     EXPECT_EQ(RRClass::IN(), rrset1.getClass());
     EXPECT_EQ(RRType::A(), rrset1.getType());
     EXPECT_EQ(RRType::A(), rrset1.getType());
     EXPECT_EQ(www_name_, rrset1.getName());
     EXPECT_EQ(www_name_, rrset1.getName());
-    EXPECT_EQ(1, rrset1.getRdataCount());
+    EXPECT_EQ(2, rrset1.getRdataCount());
     EXPECT_EQ(1, rrset1.getRRsigDataCount());
     EXPECT_EQ(1, rrset1.getRRsigDataCount());
 
 
     const TreeNodeRRset rrset2(RRClass::IN(), www_node_, a_rdataset_, false);
     const TreeNodeRRset rrset2(RRClass::IN(), www_node_, a_rdataset_, false);
     EXPECT_EQ(RRClass::IN(), rrset2.getClass());
     EXPECT_EQ(RRClass::IN(), rrset2.getClass());
     EXPECT_EQ(RRType::A(), rrset2.getType());
     EXPECT_EQ(RRType::A(), rrset2.getType());
     EXPECT_EQ(www_name_, rrset2.getName());
     EXPECT_EQ(www_name_, rrset2.getName());
-    EXPECT_EQ(1, rrset2.getRdataCount());
+    EXPECT_EQ(2, rrset2.getRdataCount());
     EXPECT_EQ(0, rrset2.getRRsigDataCount());
     EXPECT_EQ(0, rrset2.getRRsigDataCount());
 }
 }
 
 
@@ -167,4 +173,45 @@ TEST_F(TreeNodeRRsetTest, toWire) {
                       Name("example.org"), dname_rrset_, ConstRRsetPtr(),
                       Name("example.org"), dname_rrset_, ConstRRsetPtr(),
                       false);
                       false);
 }
 }
+
+void
+checkRdataIterator(const vector<string>& expected, RdataIteratorPtr rit) {
+    
+    for (vector<string>::const_iterator it = expected.begin();
+         it != expected.end();
+         ++it)
+    {
+        ASSERT_FALSE(rit->isLast());
+        EXPECT_EQ(*it, rit->getCurrent().toText());
+        rit->next();
+    }
+    // We should have reached the end of RDATA
+    EXPECT_TRUE(rit->isLast());
+
+    // move to the first RDATA again, and check the value.
+    rit->first();
+    EXPECT_EQ(expected[0], rit->getCurrent().toText());
+}
+
+TEST_F(TreeNodeRRsetTest, getRdataIterator) {
+    // This RRset should have 2 A RDATAs
+    vector<string> expected;
+    expected.push_back("192.0.2.1");
+    expected.push_back("192.0.2.2");
+    checkRdataIterator(expected,
+                       TreeNodeRRset(rrclass_, www_node_, a_rdataset_, true).
+                       getRdataIterator());
+
+    // The iterator shouldn't work different with or without RRSIG
+    checkRdataIterator(expected,
+                       TreeNodeRRset(rrclass_, www_node_, a_rdataset_, false).
+                       getRdataIterator());
+
+    // This RRset should have 1 NS RDATA (containing name field)
+    expected.clear();
+    expected.push_back("ns.example.com.");
+    checkRdataIterator(expected,
+                       TreeNodeRRset(rrclass_, origin_node_, ns_rdataset_,
+                                     false).getRdataIterator());
+}
 }
 }

+ 59 - 2
src/lib/datasrc/memory/treenode_rrset.cc

@@ -31,6 +31,7 @@
 
 
 #include <cassert>
 #include <cassert>
 #include <string>
 #include <string>
+#include <vector>
 
 
 using namespace isc::dns;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::dns::rdata;
@@ -158,11 +159,67 @@ TreeNodeRRset::addRdata(const rdata::Rdata&) {
     isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
     isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
 }
 }
 
 
+namespace {
+// In this namespace we define a set of helper stuff to implement the
+// RdataIterator for the TreeNodeRRset.  We should eventually optimize
+// the code so that performance sensitive path won't require the iterator,
+// so, at the moment, the implementation is straightforward, but less
+// efficient one: It builds a vector of Rdata objects on construction,
+// and its getCurrent() returns the stored data.
+
+class TreeNodeRdataIterator : public RdataIterator {
+public:
+    TreeNodeRdataIterator(const std::vector<ConstRdataPtr>& rdata_list) :
+        rdata_list_(rdata_list), rdata_it_(rdata_list_.begin())
+    {}
+    virtual void first() { rdata_it_ = rdata_list_.begin(); }
+    virtual void next() {
+        ++rdata_it_;
+    }
+    virtual const rdata::Rdata& getCurrent() const {
+        return (**rdata_it_);
+    }
+    virtual bool isLast() const { return (rdata_it_ == rdata_list_.end()); }
+private:
+    const std::vector<ConstRdataPtr> rdata_list_;
+    std::vector<ConstRdataPtr>::const_iterator rdata_it_;
+};
+
+void
+renderNameToBuffer(const LabelSequence& name_labels, RdataNameAttributes,
+                   util::OutputBuffer* buffer)
+{
+    size_t data_len;
+    const uint8_t *data = name_labels.getData(&data_len);
+    buffer->writeData(data, data_len);
+}
+
+void
+renderDataToBuffer(const void* data, size_t data_len,
+                   util::OutputBuffer* buffer)
+{
+    buffer->writeData(data, data_len);
+}
+}
 
 
-// needed
 RdataIteratorPtr
 RdataIteratorPtr
 TreeNodeRRset::getRdataIterator() const {
 TreeNodeRRset::getRdataIterator() const {
-    isc_throw(Unexpected, "unexpected method called on TreeNodeRRset");
+    util::OutputBuffer buffer(0);
+    RdataReader reader(rrclass_, rdataset_->type, rdataset_->getDataBuf(),
+                       rdataset_->getRdataCount(), rrsig_count_,
+                       boost::bind(renderNameToBuffer, _1, _2, &buffer),
+                       boost::bind(renderDataToBuffer, _1, _2, &buffer));
+
+    std::vector<ConstRdataPtr> rdata_list;
+    for (size_t i = 0; i < rdataset_->getRdataCount(); ++i) {
+        buffer.clear();
+        const bool rendered = reader.iterateRdata();
+        assert(rendered == true);
+        util::InputBuffer ib(buffer.getData(), buffer.getLength());
+        rdata_list.push_back(createRdata(rdataset_->type, rrclass_,
+                                         ib, ib.getLength()));
+    }
+    return (RdataIteratorPtr(new TreeNodeRdataIterator(rdata_list)));
 }
 }
 
 
 RRsetPtr
 RRsetPtr