BIND 10 master, updated. 61a7a86532aac5a0b84cadee0330f0eb20762ba6 Merge branch 'master' into trac2435

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Jan 16 10:25:56 UTC 2013


The branch, master has been updated
       via  61a7a86532aac5a0b84cadee0330f0eb20762ba6 (commit)
       via  09c47d4fef3388cd1aa2aa7db402da67c4968d3f (commit)
       via  48892724360a9c706de8c2ffaa5099dc1da211ea (commit)
       via  2b05b3926ac85363b1063a12c9ac8d0ac9cda3de (commit)
       via  0c28935d20983b280976f0a62e4b32de735b29a8 (commit)
       via  568655c55d104fcee40289810dd4431188a989f1 (commit)
       via  f2f653c6f29d56c00fdb09af6ba54bd1ab36f31f (commit)
       via  8bd08bf2531ad91b4d3f4ef4b8f304c2dfc9c249 (commit)
       via  caf2b100bf61d75cd98935bb59b6b39a718289a9 (commit)
       via  75d921323cf83bf67ec24d28927ee472b517fa88 (commit)
       via  2f7f7b1e0fb86c93c17b04489ab7e836a59fe622 (commit)
       via  9bc254508724e55db2ce9624a0a9322f4d3d9f31 (commit)
       via  00980e1e05152e7b44968438dc846ea41f43c113 (commit)
       via  355fb4b538030ec31101edd4b8ea6e2ae2d90e65 (commit)
       via  34724a6251f8d624c2c69d06fc1ddb9c21f201f0 (commit)
       via  5200f31617133fc3700b802a7299efbc3a980ec5 (commit)
       via  ecfc245797cd10313557991c778e686fa1f19b37 (commit)
       via  79cfa55b6202c07cbba0b0db6532ca2dff9e2a9c (commit)
       via  a9a2f80671f01894e3c2909e8a185c8fb7396977 (commit)
       via  4d277fcbe264e299596a2ddc15243c87565f6127 (commit)
       via  137cfc9037a103e5c5ec814a798dbc56db6ae835 (commit)
       via  3ea93cc724f87d47c024f895650853f284daf9a1 (commit)
       via  5e3bc4cf78dddd89f3a9e4670336b7d46bbb124e (commit)
       via  c16bfe0dc892c2bd34e88daa12120202bcf9e3eb (commit)
       via  6c0febf6e8ca20b9d585d5b5577ee2989464fad0 (commit)
       via  716eeec4d6fc5d5db9a8dba8b242fd541380a92f (commit)
       via  a69acbd2f9dde5eb533b95ef0d538495e733dcd2 (commit)
       via  173f076fb4c6d687de433786e0cf1ffd53fb95b2 (commit)
       via  88639855c40c5a935126bb44d49883e4f452740b (commit)
       via  70cb4d4886e27554e9a9e8751089ba8bd4678701 (commit)
      from  f9169a71cb277c3733a8ff7d0fea87762196762d (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 61a7a86532aac5a0b84cadee0330f0eb20762ba6
Merge: 09c47d4 f9169a7
Author: Mukund Sivaraman <muks at isc.org>
Date:   Wed Jan 16 15:45:56 2013 +0530

    Merge branch 'master' into trac2435
    
    Conflicts:
    	src/lib/datasrc/tests/database_unittest.cc

-----------------------------------------------------------------------

Summary of changes:
 src/lib/datasrc/Makefile.am                        |    1 +
 src/lib/datasrc/database.cc                        |   62 ++++++
 src/lib/datasrc/rrset_collection_base.cc           |   71 +++++++
 src/lib/datasrc/rrset_collection_base.h            |  126 ++++++++++++
 src/lib/datasrc/tests/database_unittest.cc         |  209 ++++++++++++++++++++
 .../datasrc/tests/master_loader_callbacks_test.cc  |    3 +
 src/lib/datasrc/tests/zone_loader_unittest.cc      |    3 +
 src/lib/datasrc/zone.h                             |   35 ++++
 src/lib/dns/rrset_collection_base.h                |   30 +++
 9 files changed, 540 insertions(+)
 create mode 100644 src/lib/datasrc/rrset_collection_base.cc
 create mode 100644 src/lib/datasrc/rrset_collection_base.h

-----------------------------------------------------------------------
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index a4edd4e..dc1007a 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -38,6 +38,7 @@ libb10_datasrc_la_SOURCES += client_list.h client_list.cc
 libb10_datasrc_la_SOURCES += memory_datasrc.h memory_datasrc.cc
 libb10_datasrc_la_SOURCES += master_loader_callbacks.h
 libb10_datasrc_la_SOURCES += master_loader_callbacks.cc
+libb10_datasrc_la_SOURCES += rrset_collection_base.h rrset_collection_base.cc
 libb10_datasrc_la_SOURCES += zone_loader.h zone_loader.cc
 nodist_libb10_datasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
 libb10_datasrc_la_LDFLAGS = -no-undefined -version-info 1:0:1
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index b5117e0..0b010a4 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -19,6 +19,7 @@
 #include <datasrc/database.h>
 #include <datasrc/data_source.h>
 #include <datasrc/iterator.h>
+#include <datasrc/rrset_collection_base.h>
 
 #include <exceptions/exceptions.h>
 #include <dns/name.h>
@@ -1384,6 +1385,36 @@ DatabaseClient::getIterator(const isc::dns::Name& name,
     return (iterator);
 }
 
+/// \brief datasrc implementation of RRsetCollectionBase.
+class RRsetCollection : public isc::datasrc::RRsetCollectionBase {
+public:
+    /// \brief Constructor.
+    RRsetCollection(ZoneUpdater& updater, const isc::dns::RRClass& rrclass) :
+        isc::datasrc::RRsetCollectionBase(updater, rrclass)
+    {}
+
+    /// \brief Destructor
+    virtual ~RRsetCollection() {}
+
+    /// \brief A wrapper around \c disable() so that it can be used as a
+    /// public method. \c disable() is protected.
+    void disableWrapper() {
+        disable();
+    }
+
+protected:
+    // TODO: RRsetCollectionBase::Iter is not implemented and the
+    // following two methods just throw.
+
+    virtual RRsetCollectionBase::IterPtr getBeginning() {
+        isc_throw(NotImplemented, "This method is not implemented.");
+    }
+
+    virtual RRsetCollectionBase::IterPtr getEnd() {
+        isc_throw(NotImplemented, "This method is not implemented.");
+    }
+};
+
 //
 // Zone updater using some database system as the underlying data source.
 //
@@ -1423,6 +1454,15 @@ public:
 
     virtual ZoneFinder& getFinder() { return (*finder_); }
 
+    virtual isc::datasrc::RRsetCollectionBase& getRRsetCollection() {
+        if (!rrset_collection_) {
+            // This is only assigned the first time and remains for the
+            // lifetime of the DatabaseUpdater.
+            rrset_collection_.reset(new RRsetCollection(*this, zone_class_));
+        }
+        return (*rrset_collection_);
+    }
+
     virtual void addRRset(const AbstractRRset& rrset);
     virtual void deleteRRset(const AbstractRRset& rrset);
     virtual void commit();
@@ -1447,6 +1487,7 @@ private:
     DiffPhase diff_phase_;
     Serial serial_;
     boost::scoped_ptr<DatabaseClient::Finder> finder_;
+    boost::shared_ptr<isc::datasrc::RRsetCollection> rrset_collection_;
 
     // This is a set of validation checks commonly used for addRRset() and
     // deleteRRset to minimize duplicate code logic and to make the main
@@ -1577,6 +1618,14 @@ isNSEC3KindType(RRType rrtype, const Rdata& rdata) {
 
 void
 DatabaseUpdater::addRRset(const AbstractRRset& rrset) {
+    if (rrset_collection_) {
+        isc_throw(InvalidOperation,
+                  "Cannot add RRset after an RRsetCollection has been "
+                  "requested for ZoneUpdater for "
+                  << zone_name_ << "/" << zone_class_ << " on "
+                  << db_name_);
+    }
+
     validateAddOrDelete("add", rrset, DELETE, ADD);
 
     // It's guaranteed rrset has at least one RDATA at this point.
@@ -1627,6 +1676,14 @@ DatabaseUpdater::addRRset(const AbstractRRset& rrset) {
 
 void
 DatabaseUpdater::deleteRRset(const AbstractRRset& rrset) {
+    if (rrset_collection_) {
+        isc_throw(InvalidOperation,
+                  "Cannot delete RRset after an RRsetCollection has been "
+                  "requested for ZoneUpdater for "
+                  << zone_name_ << "/" << zone_class_ << " on "
+                  << db_name_);
+    }
+
     // If this is the first operation, pretend we are starting a new delete
     // sequence after adds.  This will simplify the validation below.
     if (diff_phase_ == NOT_STARTED) {
@@ -1681,6 +1738,11 @@ DatabaseUpdater::commit() {
     accessor_->commit();
     committed_ = true; // make sure the destructor won't trigger rollback
 
+    // Disable the RRsetCollection if it exists.
+    if (rrset_collection_) {
+        rrset_collection_->disableWrapper();
+    }
+
     // We release the accessor immediately after commit is completed so that
     // we don't hold the possible internal resource any longer.
     accessor_.reset();
diff --git a/src/lib/datasrc/rrset_collection_base.cc b/src/lib/datasrc/rrset_collection_base.cc
new file mode 100644
index 0000000..b19f62e
--- /dev/null
+++ b/src/lib/datasrc/rrset_collection_base.cc
@@ -0,0 +1,71 @@
+// Copyright (C) 2013  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 <datasrc/rrset_collection_base.h>
+#include <datasrc/zone_loader.h>
+#include <exceptions/exceptions.h>
+
+using namespace isc;
+using namespace isc::dns;
+
+namespace isc {
+namespace datasrc {
+
+ConstRRsetPtr
+isc::datasrc::RRsetCollectionBase::find(const isc::dns::Name& name,
+                                        const isc::dns::RRClass& rrclass,
+                                        const isc::dns::RRType& rrtype) const
+{
+    if (isDisabled()) {
+        isc_throw(RRsetCollectionError, "This RRsetCollection is disabled.");
+    }
+
+    if (rrclass != rrclass_) {
+        // We could throw an exception here, but RRsetCollection is
+        // expected to support an arbitrary collection of RRsets, and it
+        // can be queried just as arbitrarily. So we just return nothing
+        // here.
+        return (ConstRRsetPtr());
+    }
+
+    ZoneFinder& finder = updater_.getFinder();
+    try {
+        ZoneFinderContextPtr result =
+            finder.find(name, rrtype,
+                        ZoneFinder::NO_WILDCARD | ZoneFinder::FIND_GLUE_OK);
+        // We return the result rrset only if the result code is
+        // SUCCESS. We return empty if CNAME, DNAME, DELEGATION,
+        // etc. are returned by the ZoneFinder.
+        //
+        // Note that in the case that the queried type itself is CNAME
+        // or DNAME, then the finder will return SUCCESS.
+        if (result->code == ZoneFinder::SUCCESS) {
+            return (result->rrset);
+        } else {
+            return (ConstRRsetPtr());
+        }
+    } catch (const OutOfZone&) {
+        // As RRsetCollection is an arbitrary set of RRsets, in case the
+        // searched name is out of zone, we return nothing instead of
+        // propagating the exception.
+        return (ConstRRsetPtr());
+    } catch (const DataSourceError& e) {
+        isc_throw(RRsetCollectionError,
+                  "ZoneFinder threw a DataSourceError: "
+                      << e.getMessage().c_str());
+    }
+}
+
+} // end of namespace datasrc
+} // end of namespace isc
diff --git a/src/lib/datasrc/rrset_collection_base.h b/src/lib/datasrc/rrset_collection_base.h
new file mode 100644
index 0000000..c02df9a
--- /dev/null
+++ b/src/lib/datasrc/rrset_collection_base.h
@@ -0,0 +1,126 @@
+// Copyright (C) 2013  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 RRSET_COLLECTION_DATASRC_H
+#define RRSET_COLLECTION_DATASRC_H 1
+
+#include <dns/rrset_collection_base.h>
+#include <dns/rrclass.h>
+#include <datasrc/zone.h>
+
+namespace isc {
+namespace datasrc {
+
+/// \brief A forward declaration
+class ZoneUpdater;
+
+/// \brief datasrc derivation of \c isc::dns::RRsetCollectionBase.
+///
+/// This is an abstract class that adds datasrc related detail to
+/// \c isc::dns::RRsetCollectionBase. Derived classes need to complete
+/// the implementation (add iterator support, etc.) before using it.
+class RRsetCollectionBase : public isc::dns::RRsetCollectionBase {
+public:
+    /// \brief Constructor.
+    ///
+    /// No reference (count via \c shared_ptr) to the \c ZoneUpdater is
+    /// acquired. The RRsetCollection must not be used after its
+    /// \c ZoneUpdater has been destroyed.
+    ///
+    /// \param updater The ZoneUpdater to wrap around.
+    /// \param rrclass The RRClass of the records in the zone.
+    RRsetCollectionBase(ZoneUpdater& updater,
+                        const isc::dns::RRClass& rrclass) :
+        updater_(updater),
+        rrclass_(rrclass),
+        disabled_(false)
+    {}
+
+    /// \brief Destructor
+    virtual ~RRsetCollectionBase() {}
+
+    /// \brief Find a matching RRset in the collection.
+    ///
+    /// Returns the RRset in the collection that exactly matches the
+    /// given \c name, \c rrclass and \c rrtype.  If no matching RRset
+    /// is found, \c NULL is returned.
+    ///
+    /// Note that not all records added through the updater may
+    /// necessarily be found by this method, such as RRs subject to
+    /// DNAME substitution.
+    ///
+    /// \throw isc::dns::RRsetCollectionError if \c find() results in
+    /// some underlying datasrc error, or if \c disable() was called.
+    ///
+    /// \param name The name of the RRset to search for.
+    /// \param rrclass The class of the RRset to search for.
+    /// \param rrtype The type of the RRset to search for.
+    /// \returns The RRset if found, \c NULL otherwise.
+    virtual isc::dns::ConstRRsetPtr find(const isc::dns::Name& name,
+                                         const isc::dns::RRClass& rrclass,
+                                         const isc::dns::RRType& rrtype) const;
+
+protected:
+    /// \brief Disable the RRsetCollection.
+    ///
+    /// After calling this method, calling operations such as find() or
+    /// using the iterator would result in an \c
+    /// isc::dns::RRsetCollectionError. This method is typically called
+    /// in the \c commit() implementations of some \c ZoneUpdaters.
+    void disable() {
+        disabled_ = true;
+    }
+
+    /// \brief Return if the RRsetCollection is disabled.
+    bool isDisabled() const {
+        return (disabled_);
+    }
+
+    /// \brief See \c isc::dns::RRsetCollectionBase::getBeginning() for
+    /// documentation.
+    ///
+    /// \throw isc::dns::RRsetCollectionError if using the iterator
+    /// results in some underlying datasrc error, or if \c disable() was
+    /// called.
+    virtual IterPtr getBeginning() = 0;
+
+    /// \brief See \c isc::dns::RRsetCollectionBase::getEnd() for
+    /// documentation.
+    ///
+    /// \throw isc::dns::RRsetCollectionError if using the iterator
+    /// results in some underlying datasrc error, or if \c disable() was
+    /// called.
+    virtual IterPtr getEnd() = 0;
+
+private:
+    ZoneUpdater& updater_;
+    isc::dns::RRClass rrclass_;
+    bool disabled_;
+};
+
+/// \brief A pointer-like type pointing to an
+/// \c isc::datasrc::RRsetCollectionBase object.
+///
+/// This type is used to handle RRsetCollections in a polymorphic manner
+/// in libdatasrc.
+typedef boost::shared_ptr<isc::datasrc::RRsetCollectionBase> RRsetCollectionPtr;
+
+} // end of namespace datasrc
+} // end of namespace isc
+
+#endif  // RRSET_COLLECTION_DATASRC_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index 3a97cb5..9f5ade4 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -2221,6 +2221,12 @@ TYPED_TEST(DatabaseClientTest, findDelegation) {
                this->rrttl_, ZoneFinder::DNAME, this->expected_rdatas_,
                this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
                isc::dns::Name("dname.example.org."));
+    // below.dname.example.org. has an A record
+    doFindTest(*finder, isc::dns::Name("below.dname.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::DNAME(),
+               this->rrttl_, ZoneFinder::DNAME, this->expected_rdatas_,
+               this->expected_sig_rdatas_, ZoneFinder::RESULT_DEFAULT,
+               isc::dns::Name("dname.example.org."));
     doFindTest(*finder, isc::dns::Name("really.deep.below.dname.example.org."),
                isc::dns::RRType::AAAA(), isc::dns::RRType::DNAME(),
                this->rrttl_, ZoneFinder::DNAME, this->expected_rdatas_,
@@ -4223,4 +4229,207 @@ TYPED_TEST(DatabaseClientTest, deleteZoneRollbackOnNotFind) {
     EXPECT_TRUE(this->client_->deleteZone(this->zname_));
 }
 
+TYPED_TEST_CASE(RRsetCollectionTest, TestAccessorTypes);
+
+// This test fixture is templated so that we can share (most of) the test
+// cases with different types of data sources.  Note that in test cases
+// we need to use 'this' to refer to member variables of the test class.
+template <typename ACCESSOR_TYPE>
+class RRsetCollectionTest : public DatabaseClientTest<ACCESSOR_TYPE> {
+public:
+    RRsetCollectionTest() :
+        DatabaseClientTest<ACCESSOR_TYPE>(),
+        updater(this->client_->getUpdater(this->zname_, false)),
+        collection(updater->getRRsetCollection())
+    {}
+
+    ZoneUpdaterPtr updater;
+    isc::datasrc::RRsetCollectionBase& collection;
+};
+
+TYPED_TEST(RRsetCollectionTest, find) {
+    // Test the find() that returns ConstRRsetPtr
+    ConstRRsetPtr rrset = this->collection.find(Name("www.example.org."),
+                                                RRClass::IN(), RRType::A());
+    ASSERT_TRUE(rrset);
+    EXPECT_EQ(RRType::A(), rrset->getType());
+    EXPECT_EQ(RRTTL(3600), rrset->getTTL());
+    EXPECT_EQ(RRClass("IN"), rrset->getClass());
+    EXPECT_EQ(Name("www.example.org"), rrset->getName());
+
+    // foo.example.org doesn't exist
+    rrset = this->collection.find(Name("foo.example.org"), this->qclass_,
+                                  RRType::A());
+    EXPECT_FALSE(rrset);
+
+    // www.example.org exists, but not with MX
+    rrset = this->collection.find(Name("www.example.org"), this->qclass_,
+                                  RRType::MX());
+    EXPECT_FALSE(rrset);
+
+    // www.example.org exists, with AAAA
+    rrset = this->collection.find(Name("www.example.org"), this->qclass_,
+                                  RRType::AAAA());
+    EXPECT_TRUE(rrset);
+
+    // www.example.org with AAAA does not exist in RRClass::CH()
+    rrset = this->collection.find(Name("www.example.org"), RRClass::CH(),
+                                  RRType::AAAA());
+    EXPECT_FALSE(rrset);
+
+    // Out-of-zone find()s must not throw.
+    rrset = this->collection.find(Name("www.example.com"), this->qclass_,
+                                  RRType::A());
+    EXPECT_FALSE(rrset);
+
+    // "cname.example.org." with type CNAME should return the CNAME RRset
+    rrset = this->collection.find(Name("cname.example.org"), this->qclass_,
+                                  RRType::CNAME());
+    ASSERT_TRUE(rrset);
+    EXPECT_EQ(RRType::CNAME(), rrset->getType());
+    EXPECT_EQ(Name("cname.example.org"), rrset->getName());
+
+    // "cname.example.org." with type A should return nothing
+    rrset = this->collection.find(Name("cname.example.org"), this->qclass_,
+                                  RRType::A());
+    EXPECT_FALSE(rrset);
+
+    // "dname.example.org." with type DNAME should return the DNAME RRset
+    rrset = this->collection.find(Name("dname.example.org"), this->qclass_,
+                                  RRType::DNAME());
+    ASSERT_TRUE(rrset);
+    EXPECT_EQ(RRType::DNAME(), rrset->getType());
+    EXPECT_EQ(Name("dname.example.org"), rrset->getName());
+
+    // "below.dname.example.org." with type AAAA should return nothing
+    rrset = this->collection.find(Name("below.dname.example.org"),
+                                  this->qclass_, RRType::AAAA());
+    EXPECT_FALSE(rrset);
+
+    // "below.dname.example.org." with type A does not return the record
+    // (see top of file). See \c isc::datasrc::RRsetCollectionBase::find()
+    // documentation for details.
+    rrset = this->collection.find(Name("below.dname.example.org"),
+                                  this->qclass_, RRType::A());
+    EXPECT_FALSE(rrset);
+
+    // With the FIND_GLUE_OK option passed to ZoneFinder's find(),
+    // searching for "delegation.example.org." with type NS should
+    // return the NS record. Without FIND_GLUE_OK, ZoneFinder's find()
+    // would return DELEGATION and the find() below would return
+    // nothing.
+    rrset = this->collection.find(Name("delegation.example.org"),
+                                  this->qclass_, RRType::NS());
+    ASSERT_TRUE(rrset);
+    EXPECT_EQ(RRType::NS(), rrset->getType());
+    EXPECT_EQ(Name("delegation.example.org"), rrset->getName());
+
+    // With the NO_WILDCARD option passed to ZoneFinder's find(),
+    // searching for some "foo.wildcard.example.org." would make
+    // ZoneFinder's find() return NXDOMAIN, and the find() below should
+    // return nothing.
+    rrset = this->collection.find(Name("foo.wild.example.org"),
+                                  this->qclass_, RRType::A());
+    EXPECT_FALSE(rrset);
+
+    // Searching directly for "*.wild.example.org." should return the
+    // record.
+    rrset = this->collection.find(Name("*.wild.example.org"),
+                                  this->qclass_, RRType::A());
+    ASSERT_TRUE(rrset);
+    EXPECT_EQ(RRType::A(), rrset->getType());
+    EXPECT_EQ(Name("*.wild.example.org"), rrset->getName());
+}
+
+TYPED_TEST(RRsetCollectionTest, iteratorTest) {
+    // Iterators are currently not implemented.
+    EXPECT_THROW(this->collection.begin(), isc::NotImplemented);
+    EXPECT_THROW(this->collection.end(), isc::NotImplemented);
+}
+
+typedef RRsetCollectionTest<MockAccessor> MockRRsetCollectionTest;
+
+TEST_F(MockRRsetCollectionTest, findError) {
+    // A test using the MockAccessor for checking that FindError is
+    // thrown properly if a find attempt using ZoneFinder results in a
+    // DataSourceError.
+    //
+    // The "dsexception.example.org." name is rigged by the MockAccessor
+    // to throw a DataSourceError.
+    EXPECT_THROW({
+        this->collection.find(Name("dsexception.example.org"), this->qclass_,
+                              RRType::A());
+    }, RRsetCollectionError);
+}
+
+TYPED_TEST_CASE(RRsetCollectionAndUpdaterTest, TestAccessorTypes);
+
+// This test fixture is templated so that we can share (most of) the test
+// cases with different types of data sources.  Note that in test cases
+// we need to use 'this' to refer to member variables of the test class.
+template <typename ACCESSOR_TYPE>
+class RRsetCollectionAndUpdaterTest : public DatabaseClientTest<ACCESSOR_TYPE> {
+public:
+    RRsetCollectionAndUpdaterTest() :
+        DatabaseClientTest<ACCESSOR_TYPE>(),
+        updater_(this->client_->getUpdater(this->zname_, false))
+    {}
+
+    ZoneUpdaterPtr updater_;
+};
+
+// Test that using addRRset() or deleteRRset() on the ZoneUpdater throws
+// after an RRsetCollection is created.
+TYPED_TEST(RRsetCollectionAndUpdaterTest, updateThrows) {
+    // 1. Addition test
+
+    // addRRset() must not throw.
+    this->updater_->addRRset(*this->rrset_);
+
+    // Now setup a new updater and call getRRsetCollection() on it.
+    this->updater_.reset();
+    this->updater_ = this->client_->getUpdater(this->zname_, false);
+    (void) this->updater_->getRRsetCollection();
+
+    // addRRset() must throw isc::InvalidOperation here.
+    EXPECT_THROW(this->updater_->addRRset(*this->rrset_),
+                 isc::InvalidOperation);
+
+    // 2. Deletion test
+
+    // deleteRRset() must not throw.
+    this->updater_.reset();
+    this->updater_ = this->client_->getUpdater(this->zname_, false);
+    this->updater_->addRRset(*this->rrset_);
+    this->updater_->deleteRRset(*this->rrset_);
+
+    // Now setup a new updater and call getRRsetCollection() on it.
+    this->updater_.reset();
+    this->updater_ = this->client_->getUpdater(this->zname_, false);
+    this->updater_->addRRset(*this->rrset_);
+    (void) this->updater_->getRRsetCollection();
+
+    // deleteRRset() must throw isc::InvalidOperation here.
+    EXPECT_THROW(this->updater_->deleteRRset(*this->rrset_),
+                 isc::InvalidOperation);
+}
+
+// Test that using an RRsetCollection after calling commit() on the
+// ZoneUpdater throws, as the RRsetCollection is disabled.
+TYPED_TEST(RRsetCollectionAndUpdaterTest, useAfterCommitThrows) {
+     isc::datasrc::RRsetCollectionBase& collection =
+         this->updater_->getRRsetCollection();
+
+     // find() must not throw here.
+     collection.find(Name("foo.wild.example.org"), this->qclass_, RRType::A());
+
+     this->updater_->commit();
+
+     // find() must throw RRsetCollectionError here, as the
+     // RRsetCollection is disabled.
+     EXPECT_THROW(collection.find(Name("foo.wild.example.org"),
+                                  this->qclass_, RRType::A()),
+                  RRsetCollectionError);
+}
+
 }
diff --git a/src/lib/datasrc/tests/master_loader_callbacks_test.cc b/src/lib/datasrc/tests/master_loader_callbacks_test.cc
index 19ec4d2..dc44461 100644
--- a/src/lib/datasrc/tests/master_loader_callbacks_test.cc
+++ b/src/lib/datasrc/tests/master_loader_callbacks_test.cc
@@ -65,6 +65,9 @@ public:
     virtual ZoneFinder& getFinder() {
         isc_throw(isc::NotImplemented, "Not to be called in this test");
     }
+    virtual isc::datasrc::RRsetCollectionBase& getRRsetCollection() {
+        isc_throw(isc::NotImplemented, "Not to be called in this test");
+    }
     virtual void deleteRRset(const isc::dns::AbstractRRset&) {
         isc_throw(isc::NotImplemented, "Not to be called in this test");
     }
diff --git a/src/lib/datasrc/tests/zone_loader_unittest.cc b/src/lib/datasrc/tests/zone_loader_unittest.cc
index b19a843..943ea2f 100644
--- a/src/lib/datasrc/tests/zone_loader_unittest.cc
+++ b/src/lib/datasrc/tests/zone_loader_unittest.cc
@@ -89,6 +89,9 @@ public:
     virtual ZoneFinder& getFinder() {
         return (finder_);
     }
+    virtual isc::datasrc::RRsetCollectionBase& getRRsetCollection() {
+        isc_throw(isc::NotImplemented, "Method not used in tests");
+    }
     virtual void addRRset(const isc::dns::AbstractRRset& rrset) {
         if (client_->commit_called_) {
             isc_throw(DataSourceError, "Add after commit");
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index 0d7438d..01d6a83 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -21,6 +21,7 @@
 
 #include <datasrc/exceptions.h>
 #include <datasrc/result.h>
+#include <datasrc/rrset_collection_base.h>
 
 #include <utility>
 #include <vector>
@@ -740,6 +741,9 @@ typedef boost::shared_ptr<ZoneFinder::Context> ZoneFinderContextPtr;
 /// \c ZoneFinder::Context object.
 typedef boost::shared_ptr<ZoneFinder::Context> ConstZoneFinderContextPtr;
 
+/// \brief A forward declaration
+class RRsetCollectionBase;
+
 /// The base class to make updates to a single zone.
 ///
 /// On construction, each derived class object will start a "transaction"
@@ -802,6 +806,29 @@ public:
     /// \return A reference to a \c ZoneFinder for the updated zone
     virtual ZoneFinder& getFinder() = 0;
 
+    /// Return an RRsetCollection for the updater.
+    ///
+    /// This method returns an \c RRsetCollection for the updater,
+    /// implementing the \c isc::datasrc::RRsetCollectionBase
+    /// interface. Typically, the returned \c RRsetCollection is a
+    /// singleton for its \c ZoneUpdater. The returned RRsetCollection
+    /// object must not be used after its corresponding \c ZoneUpdater
+    /// has been destroyed. The returned RRsetCollection object may be
+    /// used to search RRsets from the ZoneUpdater. The actual
+    /// \c RRsetCollection returned has a behavior dependent on the
+    /// \c ZoneUpdater implementation.
+    ///
+    /// The behavior of the RRsetCollection is similar to the behavior
+    /// of the \c Zonefinder returned by \c getFinder().
+    /// Implementations of \c ZoneUpdater may not allow adding or
+    /// deleting RRsets after \c getRRsetCollection() is called.
+    /// Implementations of \c ZoneUpdater may disable a previously
+    /// returned \c RRsetCollection after \c commit() is called. If an
+    /// \c RRsetCollection is disabled, using methods such as \c find()
+    /// and using its iterator would cause an exception to be
+    /// thrown. See \c isc::datasrc::RRsetCollectionBase for details.
+    virtual isc::datasrc::RRsetCollectionBase& getRRsetCollection() = 0;
+
     /// Add an RRset to a zone via the updater
     ///
     /// This may be revisited in a future version, but right now the intended
@@ -849,6 +876,10 @@ public:
     /// calls after \c commit() the implementation must throw a
     /// \c DataSourceError exception.
     ///
+    /// Implementations of \c ZoneUpdater may not allow adding or
+    /// deleting RRsets after \c getRRsetCollection() is called. In this
+    /// case, implementations throw an \c InvalidOperation exception.
+    ///
     /// If journaling was requested when getting this updater, it will reject
     /// to add the RRset if the squence doesn't look like and IXFR (see
     /// DataSourceClient::getUpdater). In such case isc::BadValue is thrown.
@@ -920,6 +951,10 @@ public:
     /// calls after \c commit() the implementation must throw a
     /// \c DataSourceError exception.
     ///
+    /// Implementations of \c ZoneUpdater may not allow adding or
+    /// deleting RRsets after \c getRRsetCollection() is called. In this
+    /// case, implementations throw an \c InvalidOperation exception.
+    ///
     /// If journaling was requested when getting this updater, it will reject
     /// to add the RRset if the squence doesn't look like and IXFR (see
     /// DataSourceClient::getUpdater). In such case isc::BadValue is thrown.
diff --git a/src/lib/dns/rrset_collection_base.h b/src/lib/dns/rrset_collection_base.h
index 35a1a9a..5ae172a 100644
--- a/src/lib/dns/rrset_collection_base.h
+++ b/src/lib/dns/rrset_collection_base.h
@@ -25,6 +25,19 @@
 namespace isc {
 namespace dns {
 
+/// \brief Error during RRsetCollectionBase find() operation
+///
+/// This exception is thrown when an calling implementation of
+/// \c RRsetCollectionBase::find() results in an error which is not due
+/// to unmatched data, but because of some other underlying error
+/// condition.
+class RRsetCollectionError : public Exception {
+public:
+    RRsetCollectionError(const char* file, size_t line, const char* what) :
+        Exception(file, line, what)
+    {}
+};
+
 /// \brief Generic class to represent a set of RRsets.
 ///
 /// This is a generic container and the stored set of RRsets does not
@@ -44,6 +57,17 @@ public:
     /// given \c name, \c rrclass and \c rrtype.  If no matching RRset
     /// is found, \c NULL is returned.
     ///
+    /// This method's implementations currently are not specified to
+    /// handle \c RRTypes such as RRSIG and NSEC3. RRSIGs are attached
+    /// to their corresponding \c RRset and it is not straightforward to
+    /// search for them. Searching for RRSIGs will return \c false
+    /// always. Support for RRSIGs may be added in the future.
+    ///
+    /// Non-concrete types such as ANY and AXFR are unsupported and will
+    /// return \c false always.
+    ///
+    /// \throw RRsetCollectionError if find() results in some
+    /// implementation-specific error.
     /// \param name The name of the RRset to search for.
     /// \param rrtype The type of the RRset to search for.
     /// \param rrclass The class of the RRset to search for.
@@ -96,10 +120,16 @@ protected:
 
     /// \brief Returns an \c IterPtr wrapping an Iter pointing to the
     /// beginning of the collection.
+    ///
+    /// \throw isc::dns::RRsetCollectionError if using the iterator
+    /// results in some underlying datasrc error.
     virtual IterPtr getBeginning() = 0;
 
     /// \brief Returns an \c IterPtr wrapping an Iter pointing past the
     /// end of the collection.
+    ///
+    /// \throw isc::dns::RRsetCollectionError if using the iterator
+    /// results in some underlying datasrc error.
     virtual IterPtr getEnd() = 0;
 
 public:



More information about the bind10-changes mailing list