Parcourir la source

[2100] copy the old zone table implementation and tests under "memory" dir.

right now it's a naive copy.  the test wouldn't even compile.
JINMEI Tatuya il y a 12 ans
Parent
commit
57de7551b2

+ 128 - 0
src/lib/datasrc/memory/tests/zone_table_unittest.cc

@@ -0,0 +1,128 @@
+// 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());
+}
+}

+ 160 - 0
src/lib/datasrc/memory/zone_table.cc

@@ -0,0 +1,160 @@
+// 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

+ 160 - 0
src/lib/datasrc/memory/zone_table.h

@@ -0,0 +1,160 @@
+// 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: