Parcourir la source

sync with trunk

git-svn-id: svn://bind10.isc.org/svn/bind10/branches/trac411@3598 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya il y a 14 ans
Parent
commit
26c6fdf210

+ 12 - 0
ChangeLog

@@ -1,3 +1,15 @@
+  118.	[func]		jinmei
+	src/lib/dns: changed the interface of AbstractRRset::getRdataIterator()
+	so that the internal cursor would point to the first RDATA
+	automatically.  This will be a more intuitive and less error prone
+	behavior.  This is a backward compatible change. (Trac #410, r3595)
+
+  117.  [func]		jinmei
+	src/lib/datasrc: added new zone and zone table classes for the
+	support of in memory data source.  This is an intermediate step to
+	the bigger feature, and is not yet actually usable in practice.
+	(Trac #399, svn r3590)
+
   116.	[bug]		jerry
   116.	[bug]		jerry
 	src/bin/xfrout: Xfrout and Auth will communicate by long tcp
 	src/bin/xfrout: Xfrout and Auth will communicate by long tcp
 	connection, Auth needs to make a new connection only on the first
 	connection, Auth needs to make a new connection only on the first

+ 1 - 1
src/bin/host/host.cc

@@ -131,7 +131,7 @@ host_lookup(const char* const name, const char* const type) {
                       }
                       }
 
 
                       RdataIteratorPtr rit = (*it)->getRdataIterator();
                       RdataIteratorPtr rit = (*it)->getRdataIterator();
-                      for (rit->first(); !rit->isLast(); rit->next()) {
+                      for (; !rit->isLast(); rit->next()) {
                           // instead of using my name, maybe use returned label?
                           // instead of using my name, maybe use returned label?
                           cout << name << " has address " <<
                           cout << name << " has address " <<
                               (*rit).getCurrent().toText() << endl;
                               (*rit).getCurrent().toText() << endl;

+ 1 - 0
src/lib/datasrc/Makefile.am

@@ -15,3 +15,4 @@ libdatasrc_la_SOURCES += static_datasrc.h static_datasrc.cc
 libdatasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
 libdatasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
 libdatasrc_la_SOURCES += query.h query.cc
 libdatasrc_la_SOURCES += query.h query.cc
 libdatasrc_la_SOURCES += cache.h cache.cc
 libdatasrc_la_SOURCES += cache.h cache.cc
+libdatasrc_la_SOURCES += zonetable.h zonetable.cc

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

@@ -170,9 +170,9 @@ public:
     /// then promoted to the head of the LRU queue.  (NOTE: Because
     /// then promoted to the head of the LRU queue.  (NOTE: Because
     /// of this, "retrieve" cannot be implemented as a const method.)
     /// of this, "retrieve" cannot be implemented as a const method.)
     ///
     ///
-    /// \param name The query name
-    /// \param rrclass The query class
-    /// \param rrtype The query type
+    /// \param qname The query name
+    /// \param qclass The query class
+    /// \param qtype The query type
     /// \param rrset Returns the RRset found, if any, to the caller
     /// \param rrset Returns the RRset found, if any, to the caller
     /// \param flags Returns the flags, if any, to the caller
     /// \param flags Returns the flags, if any, to the caller
     ///
     ///

+ 1 - 4
src/lib/datasrc/data_source.cc

@@ -95,7 +95,7 @@ getAdditional(Query& q, ConstRRsetPtr rrset) {
     }
     }
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    for (it->first(); !it->isLast(); it->next()) {
+    for (; !it->isLast(); it->next()) {
         const Rdata& rd(it->getCurrent());
         const Rdata& rd(it->getCurrent());
         if (rrset->getType() == RRType::NS()) {
         if (rrset->getType() == RRType::NS()) {
             const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
             const generic::NS& ns = dynamic_cast<const generic::NS&>(rd);
@@ -123,7 +123,6 @@ synthesizeCname(QueryTaskPtr task, RRsetPtr rrset, RRsetList& target) {
 
 
     // More than one DNAME RR in the RRset is illegal, so we only have
     // More than one DNAME RR in the RRset is illegal, so we only have
     // to process the first one.
     // to process the first one.
-    it->first();
     if (it->isLast()) {
     if (it->isLast()) {
         return;
         return;
     }
     }
@@ -152,7 +151,6 @@ chaseCname(Query& q, QueryTaskPtr task, RRsetPtr rrset) {
 
 
     // More than one CNAME RR in the RRset is illegal, so we only have
     // More than one CNAME RR in the RRset is illegal, so we only have
     // to process the first one.
     // to process the first one.
-    it->first();
     if (it->isLast()) {
     if (it->isLast()) {
         return;
         return;
     }
     }
@@ -660,7 +658,6 @@ getNsec3Param(Query& q, ZoneInfo& zoneinfo) {
     // XXX: currently only one NSEC3 chain per zone is supported;
     // XXX: currently only one NSEC3 chain per zone is supported;
     // we will need to revisit this.
     // we will need to revisit this.
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     if (it->isLast()) {
     if (it->isLast()) {
         return (ConstNsec3ParamPtr());
         return (ConstNsec3ParamPtr());
     }
     }

+ 1 - 0
src/lib/datasrc/tests/Makefile.am

@@ -24,6 +24,7 @@ run_unittests_SOURCES += static_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += cache_unittest.cc
 run_unittests_SOURCES += cache_unittest.cc
 run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
 run_unittests_SOURCES += test_datasrc.h test_datasrc.cc
+run_unittests_SOURCES += zonetable_unittest.cc
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 run_unittests_LDADD = $(GTEST_LDADD)
 run_unittests_LDADD = $(GTEST_LDADD)

+ 0 - 34
src/lib/datasrc/tests/datasrc_unittest.cc

@@ -124,7 +124,6 @@ DataSrcTest::QueryCommon(const RRClass& qclass) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -138,7 +137,6 @@ DataSrcTest::QueryCommon(const RRClass& qclass) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -154,7 +152,6 @@ DataSrcTest::QueryCommon(const RRClass& qclass) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -193,7 +190,6 @@ TEST_F(DataSrcTest, NSQuery) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -216,7 +212,6 @@ TEST_F(DataSrcTest, DuplicateQuery) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -237,7 +232,6 @@ TEST_F(DataSrcTest, DuplicateQuery) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -334,7 +328,6 @@ TEST_F(DataSrcTest, Wildcard) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.2", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.2", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -353,7 +346,6 @@ TEST_F(DataSrcTest, Wildcard) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -369,7 +361,6 @@ TEST_F(DataSrcTest, Wildcard) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -406,7 +397,6 @@ TEST_F(DataSrcTest, WildcardCname) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("www.example.com.", it->getCurrent().toText());
     EXPECT_EQ("www.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -419,7 +409,6 @@ TEST_F(DataSrcTest, WildcardCname) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -438,7 +427,6 @@ TEST_F(DataSrcTest, WildcardCname) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -454,7 +442,6 @@ TEST_F(DataSrcTest, WildcardCname) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -474,7 +461,6 @@ TEST_F(DataSrcTest, WildcardCnameNodata) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("www.example.com.", it->getCurrent().toText());
     EXPECT_EQ("www.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -506,7 +492,6 @@ TEST_F(DataSrcTest, WildcardCnameNxdomain) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("spork.example.com.", it->getCurrent().toText());
     EXPECT_EQ("spork.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -544,7 +529,6 @@ TEST_F(DataSrcTest, AuthDelegation) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.2", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.2", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -556,7 +540,6 @@ TEST_F(DataSrcTest, AuthDelegation) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -572,7 +555,6 @@ TEST_F(DataSrcTest, AuthDelegation) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -591,7 +573,6 @@ TEST_F(DataSrcTest, Dname) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("sql1.example.com.", it->getCurrent().toText());
     EXPECT_EQ("sql1.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -605,7 +586,6 @@ TEST_F(DataSrcTest, Dname) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -621,7 +601,6 @@ TEST_F(DataSrcTest, Dname) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -649,7 +628,6 @@ TEST_F(DataSrcTest, Cname) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("cnametest.flame.org.", it->getCurrent().toText());
     EXPECT_EQ("cnametest.flame.org.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -668,7 +646,6 @@ TEST_F(DataSrcTest, CnameInt) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("www.example.com.", it->getCurrent().toText());
     EXPECT_EQ("www.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -695,7 +672,6 @@ TEST_F(DataSrcTest, CnameExt) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("www.sql1.example.com.", it->getCurrent().toText());
     EXPECT_EQ("www.sql1.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -720,7 +696,6 @@ TEST_F(DataSrcTest, Delegation) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("ns1.subzone.example.com.", it->getCurrent().toText());
     EXPECT_EQ("ns1.subzone.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_FALSE(it->isLast());
     EXPECT_FALSE(it->isLast());
@@ -732,7 +707,6 @@ TEST_F(DataSrcTest, Delegation) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -751,7 +725,6 @@ TEST_F(DataSrcTest, NSDelegation) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("ns1.subzone.example.com.", it->getCurrent().toText());
     EXPECT_EQ("ns1.subzone.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_FALSE(it->isLast());
     EXPECT_FALSE(it->isLast());
@@ -763,7 +736,6 @@ TEST_F(DataSrcTest, NSDelegation) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -795,7 +767,6 @@ TEST_F(DataSrcTest, NSECZonecut) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -817,7 +788,6 @@ TEST_F(DataSrcTest, DNAMEZonecut) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("ns1.subzone.example.com.", it->getCurrent().toText());
     EXPECT_EQ("ns1.subzone.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_FALSE(it->isLast());
     EXPECT_FALSE(it->isLast());
@@ -829,7 +799,6 @@ TEST_F(DataSrcTest, DNAMEZonecut) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
@@ -854,7 +823,6 @@ TEST_F(DataSrcTest, DS) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns01.example.com.", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
     EXPECT_EQ("dns02.example.com.", it->getCurrent().toText());
@@ -890,7 +858,6 @@ TEST_F(DataSrcTest, NSECZonecutOfNonsecureZone) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ(createRdata(RRType::NS(), RRClass::IN(),
     EXPECT_EQ(createRdata(RRType::NS(), RRClass::IN(),
                           "ns.sub.example.org.")->toText(),
                           "ns.sub.example.org.")->toText(),
               it->getCurrent().toText());
               it->getCurrent().toText());
@@ -904,7 +871,6 @@ TEST_F(DataSrcTest, NSECZonecutOfNonsecureZone) {
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
     EXPECT_EQ(RRClass::IN(), rrset->getClass());
 
 
     it = rrset->getRdataIterator();
     it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ(createRdata(RRType::A(), RRClass::IN(), "192.0.2.101")->toText(),
     EXPECT_EQ(createRdata(RRType::A(), RRClass::IN(), "192.0.2.101")->toText(),
               it->getCurrent().toText());
               it->getCurrent().toText());
     it->next();
     it->next();

+ 0 - 1
src/lib/datasrc/tests/sqlite3_unittest.cc

@@ -244,7 +244,6 @@ checkRRset(RRsetPtr rrset, const Name& expected_name,
     EXPECT_EQ(expected_rrttl, rrset->getTTL());
     EXPECT_EQ(expected_rrttl, rrset->getTTL());
 
 
     RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
     RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
-    rdata_iterator->first();
     vector<string>::const_iterator data_it = expected_data.begin();
     vector<string>::const_iterator data_it = expected_data.begin();
     for (; data_it != expected_data.end(); ++data_it) {
     for (; data_it != expected_data.end(); ++data_it) {
         EXPECT_FALSE(rdata_iterator->isLast());
         EXPECT_FALSE(rdata_iterator->isLast());

+ 0 - 1
src/lib/datasrc/tests/static_unittest.cc

@@ -109,7 +109,6 @@ checkRRset(ConstRRsetPtr rrset, const Name& expected_name,
     EXPECT_EQ(rrttl, rrset->getTTL());
     EXPECT_EQ(rrttl, rrset->getTTL());
 
 
     RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
     RdataIteratorPtr rdata_iterator = rrset->getRdataIterator();
-    rdata_iterator->first();
     vector<string>::const_iterator data_it = expected_data.begin();
     vector<string>::const_iterator data_it = expected_data.begin();
     for (; data_it != expected_data.end(); ++data_it) {
     for (; data_it != expected_data.end(); ++data_it) {
         EXPECT_FALSE(rdata_iterator->isLast());
         EXPECT_FALSE(rdata_iterator->isLast());

+ 1 - 1
src/lib/datasrc/tests/test_datasrc.cc

@@ -408,7 +408,7 @@ copyRRset(RRsetPtr const source) {
     RRsetPtr rrset = RRsetPtr(new RRset(source->getName(), source->getClass(),
     RRsetPtr rrset = RRsetPtr(new RRset(source->getName(), source->getClass(),
                                         source->getType(), source->getTTL()));
                                         source->getType(), source->getTTL()));
     RdataIteratorPtr it = source->getRdataIterator();
     RdataIteratorPtr it = source->getRdataIterator();
-    for (it->first(); !it->isLast(); it->next()) {
+    for (; !it->isLast(); it->next()) {
         rrset->addRdata(it->getCurrent());
         rrset->addRdata(it->getCurrent());
     }
     }
     if (source->getRRsig()) {
     if (source->getRRsig()) {

+ 104 - 0
src/lib/datasrc/tests/zonetable_unittest.cc

@@ -0,0 +1,104 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <exceptions/exceptions.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <datasrc/zonetable.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::dns;
+using namespace isc::datasrc;
+
+namespace {
+TEST(ZoneTest, init) {
+    Zone zone(RRClass::IN(), Name("example.com"));
+    EXPECT_EQ(Name("example.com"), zone.getOrigin());
+    EXPECT_EQ(RRClass::IN(), zone.getClass());
+
+    Zone ch_zone(RRClass::CH(), Name("example"));
+    EXPECT_EQ(Name("example"), ch_zone.getOrigin());
+    EXPECT_EQ(RRClass::CH(), ch_zone.getClass());
+}
+
+class ZoneTableTest : public ::testing::Test {
+protected:
+    ZoneTableTest() : zone1(new Zone(RRClass::IN(), Name("example.com"))),
+                      zone2(new Zone(RRClass::IN(), Name("example.net"))),
+                      zone3(new Zone(RRClass::IN(), Name("example")))
+    {}
+    ZoneTable zone_table;
+    ZonePtr zone1, zone2, zone3;
+};
+
+TEST_F(ZoneTableTest, add) {
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone1));
+    EXPECT_EQ(ZoneTable::EXIST, zone_table.add(zone1));
+    // names are compared in a case insensitive manner.
+    EXPECT_EQ(ZoneTable::EXIST, zone_table.add(
+                  ZonePtr(new Zone(RRClass::IN(), Name("EXAMPLE.COM")))));
+
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone2));
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone3));
+
+    // Zone table is indexed only by name.  Duplicate origin name with
+    // different zone class isn't allowed.
+    EXPECT_EQ(ZoneTable::EXIST, zone_table.add(
+                  ZonePtr(new Zone(RRClass::CH(), Name("example.com")))));
+
+    /// Bogus zone (NULL)
+    EXPECT_THROW(zone_table.add(ZonePtr()), isc::InvalidParameter);
+}
+
+TEST_F(ZoneTableTest, remove) {
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone1));
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone2));
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone3));
+
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.remove(Name("example.net")));
+    EXPECT_EQ(ZoneTable::NOTFOUND, zone_table.remove(Name("example.net")));
+}
+
+TEST_F(ZoneTableTest, find) {
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone1));
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone2));
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone3));
+
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.find(Name("example.com")).code);
+    EXPECT_EQ(Name("example.com"),
+              zone_table.find(Name("example.com")).zone->getOrigin());
+
+    EXPECT_EQ(ZoneTable::NOTFOUND,
+              zone_table.find(Name("example.org")).code);
+    EXPECT_EQ(static_cast<const Zone*>(NULL),
+              zone_table.find(Name("example.org")).zone);
+
+    // there's no exact match.  the result should be the longest match,
+    // and the code should be PARTIALMATCH.
+    EXPECT_EQ(ZoneTable::PARTIALMATCH,
+              zone_table.find(Name("www.example.com")).code);
+    EXPECT_EQ(Name("example.com"),
+              zone_table.find(Name("www.example.com")).zone->getOrigin());
+
+    // make sure the partial match is indeed the longest match by adding
+    // a zone with a shorter origin and query again.
+    ZonePtr zone_com(new Zone(RRClass::IN(), Name("com")));
+    EXPECT_EQ(ZoneTable::SUCCESS, zone_table.add(zone_com));
+    EXPECT_EQ(Name("example.com"),
+              zone_table.find(Name("www.example.com")).zone->getOrigin());
+}
+}

+ 110 - 0
src/lib/datasrc/zonetable.cc

@@ -0,0 +1,110 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// Note: map and utility (for 'pair') are for temporary workaround.
+// we'll soon replace them with built-in intelligent backend structure. 
+#include <map>
+#include <utility>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <datasrc/zonetable.h>
+
+using namespace std;
+using namespace isc::dns;
+
+namespace isc {
+namespace datasrc {
+
+struct Zone::ZoneImpl {
+    ZoneImpl(const RRClass& zone_class, const Name& origin) :
+        zone_class_(zone_class), origin_(origin)
+    {}
+    RRClass zone_class_;
+    Name origin_;
+};
+
+Zone::Zone(const RRClass& zone_class, const Name& origin) : impl_(NULL) {
+    impl_ = new ZoneImpl(zone_class, origin);
+}
+
+Zone::~Zone() {
+    delete impl_;
+}
+
+const Name&
+Zone::getOrigin() const {
+    return (impl_->origin_);
+}
+
+const RRClass&
+Zone::getClass() const {
+    return (impl_->zone_class_);
+}
+
+// This is a temporary, inefficient implementation using std::map and handmade
+// iteration to realize longest match.
+
+struct ZoneTable::ZoneTableImpl {
+    typedef map<Name, ZonePtr> ZoneMap;
+    typedef pair<Name, ZonePtr> NameAndZone;
+    ZoneMap zones;
+};
+
+ZoneTable::ZoneTable() : impl_(new ZoneTableImpl)
+{}
+
+ZoneTable::~ZoneTable() {
+    delete impl_;
+}
+
+ZoneTable::Result
+ZoneTable::add(ZonePtr zone) {
+    if (!zone) {
+        isc_throw(InvalidParameter,
+                  "Null pointer is passed to ZoneTable::add()");
+    }
+
+    if (impl_->zones.insert(
+            ZoneTableImpl::NameAndZone(zone->getOrigin(), zone)).second
+        == true) {
+        return (SUCCESS);
+    } else {
+        return (EXIST);
+    }
+}
+
+ZoneTable::Result
+ZoneTable::remove(const Name& origin) {
+    return (impl_->zones.erase(origin) == 1 ? SUCCESS : NOTFOUND);
+}
+
+ZoneTable::FindResult
+ZoneTable::find(const Name& name) const {
+    // Inefficient internal loop to find a longest match.
+    // This will be replaced with a single call to more intelligent backend.
+    for (int i = 0; i < name.getLabelCount(); ++i) {
+        Name matchname(name.split(i));
+        ZoneTableImpl::ZoneMap::const_iterator found =
+            impl_->zones.find(matchname);
+        if (found != impl_->zones.end()) {
+            return (FindResult(i == 0 ? SUCCESS : PARTIALMATCH,
+                               (*found).second.get()));
+        }
+    }
+    return (FindResult(NOTFOUND, NULL));
+}
+} // end of namespace datasrc
+} // end of namespace isc

+ 248 - 0
src/lib/datasrc/zonetable.h

@@ -0,0 +1,248 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __ZONETABLE_H
+#define __ZONETABLE_H 1
+
+#include <boost/shared_ptr.hpp>
+
+namespace isc {
+namespace dns {
+class Name;
+class RRClass;
+};
+
+namespace datasrc {
+
+/// \brief A single authoritative zone
+///
+/// The \c Zone class represents a DNS zone as part of %data source.
+///
+/// At the moment this is provided mainly for making the \c ZoneTable class
+/// testable, and only provides a minimal set of features.
+/// This is why this class is defined in the same header file, but it may
+/// have to move to a separate header file when we understand what is
+/// necessary for this class for actual operation.
+/// Likewise, it will have more features.  For example, it will maintain
+/// information about the location of a zone file, whether it's loaded in
+/// memory, etc.
+class Zone {
+    ///
+    /// \name Constructors and Destructor.
+    ///
+    /// \b Note:
+    /// The copy constructor and the assignment operator are intentionally
+    /// defined as private, making this class non copyable.
+    //@{
+private:
+    Zone(const Zone& source);
+    Zone& operator=(const Zone& source);
+public:
+    /// \brief Constructor from zone parameters.
+    ///
+    /// This constructor internally involves resource allocation, and if
+    /// it fails, a corresponding standard exception will be thrown.
+    /// It never throws an exception otherwise.
+    ///
+    /// \param rrclass The RR class of the zone.
+    /// \param origin The origin name of the zone.
+    Zone(const isc::dns::RRClass& rrclass, const isc::dns::Name& origin);
+
+    /// The destructor.
+    ~Zone();
+    //@}
+
+    ///
+    /// \name Getter Methods
+    ///
+    /// These methods never throw an exception.
+    //@{
+    /// \brief Return the origin name of the zone.
+    const isc::dns::Name& getOrigin() const;
+
+    /// \brief Return the RR class of the zone.
+    const isc::dns::RRClass& getClass() const;
+    //@}
+
+private:
+    struct ZoneImpl;
+    ZoneImpl* impl_;
+};
+
+/// \brief A pointer-like type pointing to a \c Zone object.
+typedef boost::shared_ptr<Zone> ZonePtr;
+
+/// \brief A pointer-like type pointing to a \c Zone object.
+typedef boost::shared_ptr<const Zone> ConstZonePtr;
+
+/// \brief A set of authoritative zones.
+///
+/// The \c ZoneTable class represents a set of zones of the same RR class
+/// and provides a basic interface to help DNS lookup processing.
+/// For a given domain name, its \c find() method searches the set for a zone
+/// that gives a longest match against that name.
+///
+/// The set of zones are assumed to be of the same RR class, but the
+/// \c ZoneTable class does not enforce the assumption through its interface.
+/// For example, the \c add() method does not check if the new zone
+/// is of the same RR class as that of the others already in the table.
+/// It is caller's responsibility to ensure this assumption.
+///
+/// <b>Notes to developer:</b>
+///
+/// The add() method takes a (Boost) shared pointer because it would be
+/// inconvenient to require the caller to maintain the ownership of zones,
+/// while it wouldn't be safe to delete unnecessary zones inside the zone
+/// table.
+///
+/// On the other hand, the find() method returns a bare pointer, rather than
+/// the shared pointer, in order to minimize the dependency on Boost
+/// definitions in our public interfaces.  This means the caller can only
+/// refer to the returned object (via the pointer) for a short period.
+///  It should be okay for simple lookup purposes, but if we see the need
+/// for keeping a \c Zone object for a longer period of context, we may
+/// have to revisit this decision.
+///
+/// Currently, \c FindResult::zone is immutable for safety.
+/// In future versions we may want to make it changeable.  For example,
+/// we may want to allow configuration update on an existing zone.
+///
+/// In BIND 9's "zt" module, the equivalent of \c find() has an "option"
+/// parameter.  The only defined option is the one to specify the "no exact"
+/// mode, and the only purpose of that mode is to prefer a second longest match
+/// even if there is an exact match in order to deal with type DS query.
+/// This trick may help enhance performance, but it also seems to make the
+/// implementation complicated for a very limited, minor case.  So, for now,
+/// we don't introduce the special mode, and, since it was the only reason to
+/// have search options in BIND 9, our initial implementation doesn't provide
+/// a switch for options.
+class ZoneTable {
+public:
+    /// Result codes of various public methods of \c ZoneTable.
+    ///
+    /// The detailed semantics may differ in different methods.
+    /// See the description of specific methods for more details.
+    enum Result {
+        SUCCESS,  ///< The operation is successful.
+        EXIST,    ///< A zone is already stored in \c ZoneTable.
+        NOTFOUND, ///< The specified zone is not found in \c ZoneTable.
+        PARTIALMATCH ///< \c Only a partial match is found in \c find(). 
+    };
+
+    /// \brief A helper structure to represent the search result of
+    /// <code>ZoneTable::find()</code>.
+    ///
+    /// This is a straightforward pair of the result code and a pointer
+    /// to the found zone to represent the result of \c find().
+    /// We use this in order to avoid overloading the return value for both
+    /// the result code ("success" or "not found") and the found object,
+    /// i.e., avoid using \c NULL to mean "not found", etc.
+    ///
+    /// This is a simple value class with no internal state, so for
+    /// convenience we allow the applications to refer to the members
+    /// directly.
+    ///
+    /// See the description of \c find() for the semantics of the member
+    /// variables.
+    struct FindResult {
+        FindResult(Result param_code, const Zone* param_zone) :
+            code(param_code), zone(param_zone)
+        {}
+        const Result code;
+        const Zone* const zone;
+    };
+
+    ///
+    /// \name Constructors and Destructor.
+    ///
+    /// \b Note:
+    /// The copy constructor and the assignment operator are intentionally
+    /// defined as private, making this class non copyable.
+    //@{
+private:
+    ZoneTable(const ZoneTable& source);
+    ZoneTable& operator=(const ZoneTable& source);
+
+public:
+    /// Default constructor.
+    ///
+    /// This constructor internally involves resource allocation, and if
+    /// it fails, a corresponding standard exception will be thrown.
+    /// It never throws an exception otherwise.
+    ZoneTable();
+
+    /// The destructor.
+    ~ZoneTable();
+    //@}
+
+    /// Add a \c Zone to the \c ZoneTable.
+    ///
+    /// \c zone must not be associated with a NULL pointer; otherwise
+    /// an exception of class \c InvalidParameter will be thrown.
+    /// If internal resource allocation fails, a corresponding standard
+    /// exception will be thrown.
+    /// This method never throws an exception otherwise.
+    ///
+    /// \param zone A \c Zone object to be added.
+    /// \return \c SUCCESS If the zone is successfully added to the zone table.
+    /// \return \c EXIST The zone table already stores a zone that has the
+    /// same origin.
+    Result add(ZonePtr zone);
+
+    /// Remove a \c Zone of the given origin name from the \c ZoneTable.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \param origin The origin name of the zone to be removed.
+    /// \return \c SUCCESS If the zone is successfully removed from the
+    /// zone table.
+    /// \return \c NOTFOUND The zone table does not store the zone that matches
+    /// \c origin.
+    Result remove(const isc::dns::Name& origin);
+
+    /// Find a \c Zone that best matches the given name in the \c ZoneTable.
+    ///
+    /// It searches the internal storage for a \c Zone that gives the
+    /// longest match against \c name, and returns the result in the
+    /// form of a \c FindResult object as follows:
+    /// - \c code: The result code of the operation.
+    ///   - \c SUCCESS: A zone that gives an exact match is found
+    ///   - \c PARTIALMATCH: A zone whose origin is a super domain of
+    ///     \c name is found (but there is no exact match)
+    ///   - \c NOTFOUND: For all other cases.
+    /// - \c zone: A pointer to the found \c Zone object if one is found;
+    /// otherwise \c NULL.
+    ///
+    /// The pointer returned in the \c FindResult object is only valid until
+    /// the corresponding zone is removed from the zone table.
+    /// The caller must ensure that the zone is held in the zone table while
+    /// it needs to refer to it.
+    ///
+    /// This method never throws an exception.
+    ///
+    /// \param name A domain name for which the search is performed.
+    /// \return A \c FindResult object enclosing the search result (see above).
+    FindResult find(const isc::dns::Name& name) const;
+
+private:
+    struct ZoneTableImpl;
+    ZoneTableImpl* impl_;
+};
+}
+}
+#endif  // __ZONETABLE_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 1 - 1
src/lib/dns/python/rrset_python.cc

@@ -355,7 +355,7 @@ RRset_getRdata(s_RRset* self) {
 
 
     RdataIteratorPtr it = self->rrset->getRdataIterator();
     RdataIteratorPtr it = self->rrset->getRdataIterator();
 
 
-    for (it->first(); !it->isLast(); it->next()) {
+    for (; !it->isLast(); it->next()) {
         s_Rdata *rds = static_cast<s_Rdata*>(rdata_type.tp_alloc(&rdata_type, 0));
         s_Rdata *rds = static_cast<s_Rdata*>(rdata_type.tp_alloc(&rdata_type, 0));
         if (rds != NULL) {
         if (rds != NULL) {
             // hmz them iterators/shared_ptrs and private constructors
             // hmz them iterators/shared_ptrs and private constructors

+ 2 - 3
src/lib/dns/rrset.cc

@@ -44,7 +44,6 @@ AbstractRRset::toText() const {
     string s;
     string s;
     RdataIteratorPtr it = getRdataIterator();
     RdataIteratorPtr it = getRdataIterator();
 
 
-    it->first();
     if (it->isLast()) {
     if (it->isLast()) {
         isc_throw(EmptyRRset, "ToText() is attempted for an empty RRset");
         isc_throw(EmptyRRset, "ToText() is attempted for an empty RRset");
     }
     }
@@ -66,7 +65,6 @@ rrsetToWire(const AbstractRRset& rrset, T& output, const size_t limit) {
     unsigned int n = 0;
     unsigned int n = 0;
     RdataIteratorPtr it = rrset.getRdataIterator();
     RdataIteratorPtr it = rrset.getRdataIterator();
 
 
-    it->first();
     if (it->isLast()) {
     if (it->isLast()) {
         isc_throw(EmptyRRset, "ToWire() is attempted for an empty RRset");
         isc_throw(EmptyRRset, "ToWire() is attempted for an empty RRset");
     }
     }
@@ -224,7 +222,8 @@ private:
     BasicRdataIterator() {}
     BasicRdataIterator() {}
 public:
 public:
     BasicRdataIterator(const std::vector<rdata::ConstRdataPtr>& datavector) :
     BasicRdataIterator(const std::vector<rdata::ConstRdataPtr>& datavector) :
-        datavector_(&datavector) {}
+        datavector_(&datavector), it_(datavector_->begin())
+    {}
     ~BasicRdataIterator() {}
     ~BasicRdataIterator() {}
     virtual void first() { it_ = datavector_->begin(); }
     virtual void first() { it_ = datavector_->begin(); }
     virtual void next() { ++it_; }
     virtual void next() { ++it_; }

+ 17 - 13
src/lib/dns/rrset.h

@@ -148,7 +148,7 @@ typedef boost::shared_ptr<RdataIterator> RdataIteratorPtr;
 ///      "sort" and "search(find)" method?
 ///      "sort" and "search(find)" method?
 ///   - what about comparing two RRsets of the same type?  If we need this,
 ///   - what about comparing two RRsets of the same type?  If we need this,
 ///     should it compare rdata's as a set or as a list (i.e. compare
 ///     should it compare rdata's as a set or as a list (i.e. compare
-///     each %rdata one by one or as a whole)?  c.f. NLnet Labs' ldns
+///     each rdata one by one or as a whole)?  c.f. NLnet Labs' ldns
 ///     (http://www.nlnetlabs.nl/projects/ldns/doc/index.html)
 ///     (http://www.nlnetlabs.nl/projects/ldns/doc/index.html)
 ///     has \c ldns_rr_list_compare(), which takes the latter approach
 ///     has \c ldns_rr_list_compare(), which takes the latter approach
 ///     (seemingly assuming the caller sorts the lists beforehand).
 ///     (seemingly assuming the caller sorts the lists beforehand).
@@ -357,7 +357,7 @@ public:
     /// \endcode
     /// \endcode
     ///
     ///
     /// This method is more strictly typed than the pointer version:
     /// This method is more strictly typed than the pointer version:
-    /// If \c %rdata does not refer to the appropriate derived
+    /// If \c rdata does not refer to the appropriate derived
     /// \c Rdata class
     /// \c Rdata class
     /// for the \c RRType for this \c RRset, it throws an exception of class
     /// for the \c RRType for this \c RRset, it throws an exception of class
     /// \c std::bad_cast.
     /// \c std::bad_cast.
@@ -385,6 +385,10 @@ public:
     /// \brief Return an iterator to go through all RDATA stored in the
     /// \brief Return an iterator to go through all RDATA stored in the
     /// \c RRset.
     /// \c RRset.
     ///
     ///
+    /// The rdata cursor of the returned iterator will point to the first
+    /// RDATA, that is, it effectively calls \c RdataIterator::first()
+    /// internally.
+    ///
     /// Using the design pattern terminology, \c getRdataIterator()
     /// Using the design pattern terminology, \c getRdataIterator()
     /// is an example of a <em>factory method</em>.
     /// is an example of a <em>factory method</em>.
     ///
     ///
@@ -417,10 +421,10 @@ public:
 /// The RDATA objects stored in the \c RRset are considered to form
 /// The RDATA objects stored in the \c RRset are considered to form
 /// a unidirectional list from the \c RdataIterator point of view (while
 /// a unidirectional list from the \c RdataIterator point of view (while
 /// the actual implementation in the derived \c RRset may not use a list).
 /// the actual implementation in the derived \c RRset may not use a list).
-/// We call this unidirectional list the <em>%rdata list</em>.
+/// We call this unidirectional list the <em>rdata list</em>.
 ///
 ///
 /// An \c RdataIterator object internally (and conceptually) holds a
 /// An \c RdataIterator object internally (and conceptually) holds a
-/// <em>%rdata cursor</em>, which points to a specific item of the %rdata list.
+/// <em>rdata cursor</em>, which points to a specific item of the rdata list.
 ///
 ///
 /// Note about design choice: as is clear from the interface, \c RdataIterator
 /// Note about design choice: as is clear from the interface, \c RdataIterator
 /// is not compatible with the standard iterator classes.
 /// is not compatible with the standard iterator classes.
@@ -458,29 +462,29 @@ private:
     //@}
     //@}
 
 
 public:
 public:
-    /// \brief Move the %rdata cursor to the first RDATA in the %rdata list
+    /// \brief Move the rdata cursor to the first RDATA in the rdata list
     /// (if any).
     /// (if any).
     ///
     ///
     /// This method can safely be called multiple times, even after moving
     /// This method can safely be called multiple times, even after moving
-    /// the %rdata cursor forward by the \c next() method.
+    /// the rdata cursor forward by the \c next() method.
     ///
     ///
     /// This method should never throw an exception.
     /// This method should never throw an exception.
     virtual void first() = 0;
     virtual void first() = 0;
 
 
-    /// \brief Move the %rdata cursor to the next RDATA in the %rdata list
+    /// \brief Move the rdata cursor to the next RDATA in the rdata list
     /// (if any).
     /// (if any).
     ///
     ///
     /// This method should never throw an exception.
     /// This method should never throw an exception.
     virtual void next() = 0;
     virtual void next() = 0;
 
 
-    /// \brief Return the current \c Rdata corresponding to the %rdata cursor.
+    /// \brief Return the current \c Rdata corresponding to the rdata cursor.
     ///
     ///
     /// \return A reference to an \c rdata::::Rdata object corresponding
     /// \return A reference to an \c rdata::::Rdata object corresponding
-    /// to the %rdata cursor.
+    /// to the rdata cursor.
     virtual const rdata::Rdata& getCurrent() const = 0;
     virtual const rdata::Rdata& getCurrent() const = 0;
 
 
-    /// \brief Return true iff the %rdata cursor has reached the end of the
-    /// %rdata list.
+    /// \brief Return true iff the rdata cursor has reached the end of the
+    /// rdata list.
     ///
     ///
     /// Once this method returns \c true, the behavior of any subsequent
     /// Once this method returns \c true, the behavior of any subsequent
     /// call to \c next() or \c getCurrent() is undefined.
     /// call to \c next() or \c getCurrent() is undefined.
@@ -489,8 +493,8 @@ public:
     ///
     ///
     /// This method should never throw an exception.
     /// This method should never throw an exception.
     ///
     ///
-    /// \return \c true if the %rdata cursor has reached the end of the
-    /// %rdata list; otherwise \c false.
+    /// \return \c true if the rdata cursor has reached the end of the
+    /// rdata list; otherwise \c false.
     virtual bool isLast() const = 0;
     virtual bool isLast() const = 0;
 };
 };
 
 

+ 0 - 1
src/lib/dns/tests/message_unittest.cc

@@ -293,7 +293,6 @@ TEST_F(MessageTest, fromWire) {
     // TTL should be 3600, even though that of the 2nd RR is 7200
     // TTL should be 3600, even though that of the 2nd RR is 7200
     EXPECT_EQ(RRTTL(3600), rrset->getTTL());
     EXPECT_EQ(RRTTL(3600), rrset->getTTL());
     RdataIteratorPtr it = rrset->getRdataIterator();
     RdataIteratorPtr it = rrset->getRdataIterator();
-    it->first();
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     it->next();
     it->next();
     EXPECT_EQ("192.0.2.2", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.2", it->getCurrent().toText());

+ 1 - 3
src/lib/dns/tests/rrset_unittest.cc

@@ -117,8 +117,7 @@ void
 addRdataTestCommon(const RRset& rrset) {
 addRdataTestCommon(const RRset& rrset) {
     EXPECT_EQ(2, rrset.getRdataCount());
     EXPECT_EQ(2, rrset.getRdataCount());
 
 
-    RdataIteratorPtr it = rrset.getRdataIterator();
-    it->first();
+    RdataIteratorPtr it = rrset.getRdataIterator(); // cursor is set to the 1st
     EXPECT_FALSE(it->isLast());
     EXPECT_FALSE(it->isLast());
     EXPECT_EQ(0, it->getCurrent().compare(in::A("192.0.2.1")));
     EXPECT_EQ(0, it->getCurrent().compare(in::A("192.0.2.1")));
     it->next();
     it->next();
@@ -156,7 +155,6 @@ TEST_F(RRsetTest, addRdataPtr) {
 TEST_F(RRsetTest, iterator) {
 TEST_F(RRsetTest, iterator) {
     // Iterator for an empty RRset.
     // Iterator for an empty RRset.
     RdataIteratorPtr it = rrset_a_empty.getRdataIterator();
     RdataIteratorPtr it = rrset_a_empty.getRdataIterator();
-    it->first();
     EXPECT_TRUE(it->isLast());
     EXPECT_TRUE(it->isLast());
 
 
     // Normal case (already tested, but do it again just in case)
     // Normal case (already tested, but do it again just in case)

+ 0 - 1
src/lib/dns/tests/rrsetlist_unittest.cc

@@ -150,7 +150,6 @@ TEST_F(RRsetListTest, checkData) {
 
 
     RdataIteratorPtr it =
     RdataIteratorPtr it =
         list.findRRset(RRType::A(), RRClass::IN())->getRdataIterator();
         list.findRRset(RRType::A(), RRClass::IN())->getRdataIterator();
-    it->first();
     EXPECT_FALSE(it->isLast());
     EXPECT_FALSE(it->isLast());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
     EXPECT_EQ("192.0.2.1", it->getCurrent().toText());
 }
 }

+ 2 - 2
src/lib/exceptions/exceptions.h

@@ -40,7 +40,7 @@ public:
     /// file line number.
     /// file line number.
     ///
     ///
     /// @param file the file name where the exception was thrown.
     /// @param file the file name where the exception was thrown.
-    /// @param line the line in @ref file where the exception was thrown.
+    /// @param line the line in \a file where the exception was thrown.
     /// @param what a description (type) of the exception.
     /// @param what a description (type) of the exception.
     Exception(const char* file, size_t line, const char* what) :
     Exception(const char* file, size_t line, const char* what) :
         file_(file), line_(line), what_(what) {}
         file_(file), line_(line), what_(what) {}
@@ -49,7 +49,7 @@ public:
     /// file line number.
     /// file line number.
     ///
     ///
     /// @param file the file name where the exception was thrown.
     /// @param file the file name where the exception was thrown.
-    /// @param line the line in @ref file where the exception was thrown.
+    /// @param line the line in \a file where the exception was thrown.
     /// @param what a description (type) of the exception.
     /// @param what a description (type) of the exception.
     Exception(const char* file, size_t line, const std::string& what) :
     Exception(const char* file, size_t line, const std::string& what) :
         file_(file), line_(line), what_(what) {}
         file_(file), line_(line), what_(what) {}