right now it's a naive copy. the test wouldn't even compile.
--- /dev/null
+// 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 <util/memory_segment_local.h>
+
+#include <dns/name.h>
+#include <dns/rrclass.h>
+
+#include <datasrc/zonetable.h>
+// We use InMemoryZone to put something into the table
+#include <datasrc/memory_datasrc.h>
+
+#include <gtest/gtest.h>
+
+using namespace isc::dns;
+using namespace isc::datasrc;
+
+namespace {
+TEST(ZoneTest, init) {
+ InMemoryZoneFinder zone(RRClass::IN(), Name("example.com"));
+ EXPECT_EQ(Name("example.com"), zone.getOrigin());
+ EXPECT_EQ(RRClass::IN(), zone.getClass());
+
+ InMemoryZoneFinder ch_zone(RRClass::CH(), Name("example"));
+ EXPECT_EQ(Name("example"), ch_zone.getOrigin());
+ EXPECT_EQ(RRClass::CH(), ch_zone.getClass());
+}
+
+TEST(ZoneTest, find) {
+ InMemoryZoneFinder zone(RRClass::IN(), Name("example.com"));
+ EXPECT_EQ(ZoneFinder::NXDOMAIN,
+ zone.find(Name("www.example.com"), RRType::A())->code);
+}
+
+class ZoneTableTest : public ::testing::Test {
+protected:
+ ZoneTableTest() : zone1(new InMemoryZoneFinder(RRClass::IN(),
+ Name("example.com"))),
+ zone2(new InMemoryZoneFinder(RRClass::IN(),
+ Name("example.net"))),
+ zone3(new InMemoryZoneFinder(RRClass::IN(),
+ Name("example"))),
+ zone_table(ZoneTable::create(mem_sgmt_))
+ {}
+
+ ~ZoneTableTest() {
+ ZoneTable::destroy(mem_sgmt_, zone_table);
+ }
+ ZoneFinderPtr zone1, zone2, zone3;
+ isc::util::MemorySegmentLocal mem_sgmt_;
+ ZoneTable* zone_table;
+};
+
+TEST_F(ZoneTableTest, addZone) {
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone1));
+ EXPECT_EQ(result::EXIST, zone_table->addZone(mem_sgmt_, zone1));
+ // names are compared in a case insensitive manner.
+ EXPECT_EQ(result::EXIST, zone_table->addZone(
+ mem_sgmt_,
+ ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
+ Name("EXAMPLE.COM")))));
+
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone2));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone3));
+
+ // Zone table is indexed only by name. Duplicate origin name with
+ // different zone class isn't allowed.
+ EXPECT_EQ(result::EXIST, zone_table->addZone(
+ mem_sgmt_,
+ ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
+ Name("example.com")))));
+
+ /// Bogus zone (NULL)
+ EXPECT_THROW(zone_table->addZone(mem_sgmt_, ZoneFinderPtr()),
+ isc::InvalidParameter);
+}
+
+TEST_F(ZoneTableTest, DISABLED_removeZone) {
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone1));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone2));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone3));
+
+ EXPECT_EQ(result::SUCCESS, zone_table->removeZone(Name("example.net")));
+ EXPECT_EQ(result::NOTFOUND, zone_table->removeZone(Name("example.net")));
+}
+
+TEST_F(ZoneTableTest, findZone) {
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone1));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone2));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone3));
+
+ EXPECT_EQ(result::SUCCESS, zone_table->findZone(Name("example.com")).code);
+ EXPECT_EQ(Name("example.com"),
+ zone_table->findZone(Name("example.com")).zone->getOrigin());
+
+ EXPECT_EQ(result::NOTFOUND,
+ zone_table->findZone(Name("example.org")).code);
+ EXPECT_EQ(ConstZoneFinderPtr(),
+ zone_table->findZone(Name("example.org")).zone);
+
+ // there's no exact match. the result should be the longest match,
+ // and the code should be PARTIALMATCH.
+ EXPECT_EQ(result::PARTIALMATCH,
+ zone_table->findZone(Name("www.example.com")).code);
+ EXPECT_EQ(Name("example.com"),
+ zone_table->findZone(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.
+ ZoneFinderPtr zone_com(new InMemoryZoneFinder(RRClass::IN(), Name("com")));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(mem_sgmt_, zone_com));
+ EXPECT_EQ(Name("example.com"),
+ zone_table->findZone(Name("www.example.com")).zone->getOrigin());
+}
+}
--- /dev/null
+// 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 <util/memory_segment.h>
+
+#include <dns/name.h>
+
+#include <datasrc/zonetable.h>
+#include <datasrc/rbtree.h>
+
+#include <cassert>
+
+using namespace std;
+using namespace isc::dns;
+
+namespace isc {
+namespace datasrc {
+
+/// \short Private data and implementation of ZoneTable
+struct ZoneTable::ZoneTableImpl {
+ // Type aliases to make it shorter
+ typedef RBTree<ZoneFinder> ZoneTree;
+ typedef RBNode<ZoneFinder> ZoneNode;
+
+ // The actual storage
+ ZoneTree* zones_;
+
+ // Constructor
+ ZoneTableImpl(util::MemorySegment& mem_sgmt) :
+ zones_(ZoneTree::create(mem_sgmt))
+ {}
+
+ /*
+ * The implementation methods are here and just wrap-called in the
+ * ZoneTable. We have variables locally (without impl_->), have
+ * type aliases, etc. And they will get inlined anyway.
+ */
+
+ // Implementation of ZoneTable::addZone
+ result::Result addZone(util::MemorySegment& mem_sgmt, ZoneFinderPtr zone) {
+ // Sanity check
+ if (!zone) {
+ isc_throw(InvalidParameter,
+ "Null pointer is passed to ZoneTable::addZone()");
+ }
+
+ // Get the node where we put the zone
+ ZoneNode* node(NULL);
+ switch (zones_->insert(mem_sgmt, zone->getOrigin(), &node)) {
+ // This is OK
+ case ZoneTree::SUCCESS:
+ case ZoneTree::ALREADYEXISTS:
+ break;
+ // Can Not Happen
+ default:
+ assert(0);
+ }
+ // Can Not Happen
+ assert(node);
+
+ // Is it empty? We either just created it or it might be nonterminal
+ if (node->isEmpty()) {
+ node->setData(zone);
+ return (result::SUCCESS);
+ } else { // There's something there already
+ return (result::EXIST);
+ }
+ }
+
+ // Implementation of ZoneTable::findZone
+ ZoneTable::FindResult findZone(const Name& name) const {
+ ZoneNode *node(NULL);
+ result::Result my_result;
+
+ // Translate the return codes
+ switch (zones_->find(name, &node)) {
+ case ZoneTree::EXACTMATCH:
+ my_result = result::SUCCESS;
+ break;
+ case ZoneTree::PARTIALMATCH:
+ my_result = result::PARTIALMATCH;
+ break;
+ // We have no data there, so translate the pointer to NULL as well
+ case ZoneTree::NOTFOUND:
+ return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+ // Can Not Happen
+ default:
+ assert(0);
+ // Because of warning
+ return (FindResult(result::NOTFOUND, ZoneFinderPtr()));
+ }
+
+ // Can Not Happen (remember, NOTFOUND is handled)
+ assert(node);
+
+ return (FindResult(my_result, node->getData()));
+ }
+};
+
+ZoneTable::ZoneTable(util::MemorySegment& mem_sgmt) :
+ impl_(new ZoneTableImpl(mem_sgmt))
+{}
+
+ZoneTable::~ZoneTable() {
+ delete impl_;
+}
+
+ZoneTable*
+ZoneTable::create(util::MemorySegment& mem_sgmt) {
+ // The ZoneTable constructor can throw, so we need to prevent memory leak.
+ // This is ugly, but for now this seems to be the only place we need
+ // this, and since we'll substantially revise this code soon, so we don't
+ // work around it by this hack at the moment.
+ void* p = mem_sgmt.allocate(sizeof(ZoneTable));
+ try {
+ return (new(p) ZoneTable(mem_sgmt));
+ } catch (...) {
+ mem_sgmt.deallocate(p, sizeof(ZoneTable));
+ throw;
+ }
+}
+
+void
+ZoneTable::destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable) {
+ ZoneTableImpl::ZoneTree::destroy(mem_sgmt, ztable->impl_->zones_);
+ ztable->~ZoneTable();
+ mem_sgmt.deallocate(ztable, sizeof(ZoneTable));
+}
+
+result::Result
+ZoneTable::addZone(util::MemorySegment& mem_sgmt, ZoneFinderPtr zone) {
+ return (impl_->addZone(mem_sgmt, zone));
+}
+
+result::Result
+ZoneTable::removeZone(const Name&) {
+ // TODO Implement
+ assert(0);
+ // This should not ever be returned, the assert should kill us by now
+ return (result::SUCCESS);
+}
+
+ZoneTable::FindResult
+ZoneTable::findZone(const Name& name) const {
+ return (impl_->findZone(name));
+}
+
+} // end of namespace datasrc
+} // end of namespace isc
--- /dev/null
+// 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 <util/memory_segment.h>
+
+#include <dns/rrset.h>
+
+#include <datasrc/zone.h>
+
+#include <boost/shared_ptr.hpp>
+
+namespace isc {
+namespace dns {
+class Name;
+class RRClass;
+}
+
+namespace datasrc {
+
+/// \brief A set of authoritative zones.
+///
+/// \c ZoneTable class is primarily intended to be used as a backend for the
+/// \c MemoryDataSrc class, but is exposed as a separate class in case some
+/// application wants to use it directly (e.g. for a customized data source
+/// implementation).
+///
+/// For more descriptions about its struct and interfaces, please refer to the
+/// corresponding struct and interfaces of \c MemoryDataSrc.
+class ZoneTable {
+public:
+ struct FindResult {
+ FindResult(result::Result param_code, const ZoneFinderPtr param_zone) :
+ code(param_code), zone(param_zone)
+ {}
+ const result::Result code;
+ const ZoneFinderPtr 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);
+
+ /// Constructor.
+ ///
+ /// An object of this class is always expected to be created by the
+ /// allocator (\c create()), so the constructor is hidden as private.
+ ///
+ /// This constructor internally involves resource allocation, and if
+ /// it fails, a corresponding standard exception will be thrown.
+ /// It never throws an exception otherwise.
+ ZoneTable(util::MemorySegment& mem_sgmt);
+
+ /// The destructor.
+ ///
+ /// An object of this class is always expected to be destroyed explicitly
+ /// by \c destroy(), so the constructor is hidden as private.
+ ~ZoneTable();
+ //@}
+
+public:
+ /// \brief Allocate and construct \c ZoneTable
+ ///
+ /// This static method allocates memory for a new \c ZoneTable object
+ /// from the given memory segment, constructs the object, and returns
+ /// a pointer to it.
+ ///
+ /// \throw std::bad_alloc Memory allocation fails.
+ ///
+ /// \param mem_sgmt A \c MemorySegment from which memory for the new
+ /// \c ZoneTable is allocated.
+ static ZoneTable* create(util::MemorySegment& mem_sgmt);
+
+ /// \brief Destruct and deallocate \c ZoneTable
+ ///
+ /// \throw none
+ ///
+ /// \param mem_sgmt The \c MemorySegment that allocated memory for
+ /// \c ztable.
+ /// \param ztable A non NULL pointer to a valid \c ZoneTable object
+ /// that was originally created by the \c create() method (the behavior
+ /// is undefined if this condition isn't met).
+ static void destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable);
+
+ /// 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 result::SUCCESS If the zone is successfully
+ /// added to the zone table.
+ /// \return \c result::EXIST The zone table already contains
+ /// zone of the same origin.
+ result::Result addZone(util::MemorySegment& mem_sgmt, ZoneFinderPtr 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 result::SUCCESS If the zone is successfully
+ /// removed from the zone table.
+ /// \return \c result::NOTFOUND The zone table does not
+ /// store the zone that matches \c origin.
+ result::Result removeZone(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 result::SUCCESS: A zone that gives an exact match
+ /// is found
+ /// - \c result::PARTIALMATCH: A zone whose origin is a
+ /// super domain of \c name is found (but there is no exact match)
+ /// - \c result::NOTFOUND: For all other cases.
+ /// - \c zone: A "Boost" shared pointer to the found \c Zone object if one
+ /// is found; otherwise \c NULL.
+ ///
+ /// 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 findZone(const isc::dns::Name& name) const;
+
+private:
+ struct ZoneTableImpl;
+ ZoneTableImpl* impl_;
+};
+}
+}
+#endif // __ZONETABLE_H
+
+// Local Variables:
+// mode: c++
+// End: