From: JINMEI Tatuya Date: Wed, 8 Aug 2012 01:06:40 +0000 (-0700) Subject: [2100] copy the old zone table implementation and tests under "memory" dir. X-Git-Tag: trac2351_base~115^2~3^2~16 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=57de7551b2cc0206f8d1a3ffae9d60b4097ecde1;p=thirdparty%2Fkea.git [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. --- diff --git a/src/lib/datasrc/memory/tests/zone_table_unittest.cc b/src/lib/datasrc/memory/tests/zone_table_unittest.cc new file mode 100644 index 0000000000..5a29a44a77 --- /dev/null +++ b/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 + +#include + +#include +#include + +#include +// We use InMemoryZone to put something into the table +#include + +#include + +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()); +} +} diff --git a/src/lib/datasrc/memory/zone_table.cc b/src/lib/datasrc/memory/zone_table.cc new file mode 100644 index 0000000000..11931819e6 --- /dev/null +++ b/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 + +#include + +#include +#include + +#include + +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 ZoneTree; + typedef RBNode 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 diff --git a/src/lib/datasrc/memory/zone_table.h b/src/lib/datasrc/memory/zone_table.h new file mode 100644 index 0000000000..93a021c9e8 --- /dev/null +++ b/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 + +#include + +#include + +#include + +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: