Commit 5f581c32 authored by Michal Vaner's avatar Michal Vaner
Browse files

Merge #444 (MemoryZone class)

git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@3952 e5f2f494-b856-4b98-b285-d166d9295462
......@@ -18,6 +18,7 @@
#include <dns/rrtype.h>
#include <datasrc/zonetable.h>
#include <datasrc/memory_datasrc.h>
#include <auth/query.h>
......
......@@ -15,6 +15,8 @@ libdatasrc_la_SOURCES += static_datasrc.h static_datasrc.cc
libdatasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
libdatasrc_la_SOURCES += query.h query.cc
libdatasrc_la_SOURCES += cache.h cache.cc
libdatasrc_la_SOURCES += rbtree.h
libdatasrc_la_SOURCES += rbtree.h
libdatasrc_la_SOURCES += zonetable.h zonetable.cc
libdatasrc_la_SOURCES += memory_datasrc.h memory_datasrc.cc
libdatasrc_la_SOURCES += zone.h
libdatasrc_la_SOURCES += result.h
......@@ -12,8 +12,14 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <map>
#include <boost/shared_ptr.hpp>
#include <dns/name.h>
#include <dns/rrclass.h>
#include <datasrc/memory_datasrc.h>
#include <datasrc/rbtree.h>
using namespace std;
using namespace isc::dns;
......@@ -21,6 +27,63 @@ using namespace isc::dns;
namespace isc {
namespace datasrc {
// Private data and hidden methods of MemoryZone
struct MemoryZone::MemoryZoneImpl {
// Constructor
MemoryZoneImpl(const RRClass& zone_class, const Name& origin) :
zone_class_(zone_class), origin_(origin)
{}
// Information about the zone
RRClass zone_class_;
Name origin_;
// Some type aliases
/*
* Each domain consists of some RRsets. They will be looked up by the
* RRType.
*
* The use of map is questionable with regard to performance - there'll
* be usually only few RRsets in the domain, so the log n benefit isn't
* much and a vector/array might be faster due to its simplicity and
* continuous memory location. But this is unlikely to be a performance
* critical place and map has better interface for the lookups, so we use
* that.
*/
typedef map<RRType, ConstRRsetPtr> Domain;
typedef boost::shared_ptr<Domain> DomainPtr;
// The tree stores domains
typedef RBTree<Domain> DomainTree;
typedef RBNode<Domain> DomainNode;
// The actual zone data
DomainTree domains_;
};
MemoryZone::MemoryZone(const RRClass& zone_class, const Name& origin) :
impl_(new MemoryZoneImpl(zone_class, origin))
{
}
MemoryZone::~MemoryZone() {
delete impl_;
}
const Name&
MemoryZone::getOrigin() const {
return (impl_->origin_);
}
const RRClass&
MemoryZone::getClass() const {
return (impl_->zone_class_);
}
Zone::FindResult
MemoryZone::find(const Name&, const RRType&) const {
// This is a tentative implementation that always returns NXDOMAIN.
return (FindResult(NXDOMAIN, RRsetPtr()));
}
/// Implementation details for \c MemoryDataSrc hidden from the public
/// interface.
///
......
......@@ -24,6 +24,51 @@ class Name;
namespace datasrc {
/// A derived zone class intended to be used with the memory data source.
class MemoryZone : public 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:
MemoryZone(const MemoryZone& source);
MemoryZone& operator=(const MemoryZone& 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.
MemoryZone(const isc::dns::RRClass& rrclass, const isc::dns::Name& origin);
/// The destructor.
virtual ~MemoryZone();
//@}
/// \brief Returns the origin of the zone.
virtual const isc::dns::Name& getOrigin() const;
/// \brief Returns the class of the zone.
virtual const isc::dns::RRClass& getClass() const;
/// \brief Looks up an RRset in the zone.
///
/// See documentation in \c Zone.
virtual FindResult find(const isc::dns::Name& name,
const isc::dns::RRType& type) const;
private:
/// \name Hidden private data
//@{
struct MemoryZoneImpl;
MemoryZoneImpl* impl_;
//@}
};
/// \brief A data source that uses in memory dedicated backend.
///
/// The \c MemoryDataSrc class represents a data source and provides a
......
// Copyright (C) 2010 CZ NIC
// 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 __DATASRC_RESULT_H
#define __DATASRC_RESULT_H 1
namespace isc {
namespace datasrc {
namespace result {
/// Result codes of various public methods of in memory data source
///
/// The detailed semantics may differ in different methods.
/// See the description of specific methods for more details.
///
/// Note: this is intended to be used from other data sources eventually,
/// but for now it's specific to in memory data source and its backend.
enum Result {
SUCCESS, ///< The operation is successful.
EXIST, ///< The search key is already stored.
NOTFOUND, ///< The specified object is not found.
PARTIALMATCH ///< Only a partial match is found.
};
}
}
}
#endif
......@@ -17,7 +17,6 @@
#include <dns/name.h>
#include <dns/rrclass.h>
#include <datasrc/zonetable.h>
#include <datasrc/memory_datasrc.h>
#include <gtest/gtest.h>
......@@ -112,4 +111,31 @@ TEST_F(MemoryDataSrcTest, add_find_Zone) {
EXPECT_EQ(Name("i.g.h"),
memory_datasrc.findZone(Name("z.i.g.h")).zone->getOrigin());
}
/// \brief Test fixture for the MemoryZone class
class MemoryZoneTest : public ::testing::Test {
public:
MemoryZoneTest() :
class_(RRClass::IN()),
origin_("example.org"),
zone_(class_, origin_)
{ }
// Some data to test with
RRClass class_;
Name origin_;
// The zone to torture by tests
MemoryZone zone_;
};
/**
* \brief Test MemoryZone::MemoryZone constructor.
*
* Takes the created zone and checks its properties they are the same
* as passed parameters.
*/
TEST_F(MemoryZoneTest, Constructor) {
ASSERT_EQ(class_, zone_.getClass());
ASSERT_EQ(origin_, zone_.getOrigin());
}
}
......@@ -18,6 +18,8 @@
#include <dns/rrclass.h>
#include <datasrc/zonetable.h>
// We use MemoryZone to put something into the table
#include <datasrc/memory_datasrc.h>
#include <gtest/gtest.h>
......
// Copyright (C) 2010 CZ NIC
// 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 __ZONE_H
#define __ZONE_H 1
#include <datasrc/result.h>
namespace isc {
namespace datasrc {
/// \brief The base class for a single authoritative zone
///
/// The \c Zone class is an abstract base class for representing
/// a DNS zone as part of data source.
///
/// At the moment this is provided mainly for making the \c ZoneTable class
/// and the authoritative query logic 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.
///
/// The idea is to provide a specific derived zone class for each data
/// source, beginning with in memory one. At that point the derived classes
/// will have more specific features. For example, they will maintain
/// information about the location of a zone file, whether it's loaded in
/// memory, etc.
///
/// It's not yet clear how the derived zone classes work with various other
/// data sources when we integrate these components, but one possibility is
/// something like this:
/// - If the underlying database such as some variant of SQL doesn't have an
/// explicit representation of zones (as part of public interface), we can
/// probably use a "default" zone class that simply encapsulates the
/// corresponding data source and calls a common "find" like method.
/// - Some data source may want to specialize it by inheritance as an
/// optimization. For example, in the current schema design of the sqlite3
/// data source, its (derived) zone class would contain the information of
/// the "zone ID".
///
/// <b>Note:</b> Unlike some other abstract base classes we don't name the
/// class beginning with "Abstract". This is because we want to have
/// commonly used definitions such as \c Result and \c ZonePtr, and we want
/// to make them look more intuitive.
class Zone {
public:
/// Result codes of the \c find() method.
///
/// Note: the codes are tentative. We may need more, or we may find
/// some of them unnecessary as we implement more details.
enum Result {
SUCCESS, ///< An exact match is found.
DELEGATION, ///< The search encounters a zone cut.
NXDOMAIN, ///< There is no domain name that matches the search name
NXRRSET, ///< There is a matching name but no RRset of the search type
CNAME, ///< The search encounters and returns a CNAME RR
DNAME ///< The search encounters and returns a DNAME RR
};
/// A helper structure to represent the search result of \c find().
///
/// This is a straightforward tuple of the result code and a pointer
/// to the found RRset to represent the result of \c find()
/// (there will be more members in the future - see the class
/// description).
/// 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 whose internal state never changes,
/// so for convenience we allow the applications to refer to the members
/// directly.
///
/// Note: we should eventually include a notion of "zone node", which
/// corresponds to a particular domain name of the zone, so that we can
/// find RRsets of a different RR type for that name (e.g. for type ANY
/// query or to include DS RRs with delegation).
///
/// Note: we may also want to include the closest enclosure "node" to
/// optimize including the NSEC for no-wildcard proof (FWIW NSD does that).
struct FindResult {
FindResult(Result param_code,
const isc::dns::ConstRRsetPtr param_rrset) :
code(param_code), rrset(param_rrset)
{}
const Result code;
const isc::dns::ConstRRsetPtr rrset;
};
///
/// \name Constructors and Destructor.
///
//@{
protected:
/// The default constructor.
///
/// This is intentionally defined as \c protected as this base class should
/// never be instantiated (except as part of a derived class).
Zone() {}
public:
/// The destructor.
virtual ~Zone() {}
//@}
///
/// \name Getter Methods
///
/// These methods should never throw an exception.
//@{
/// Return the origin name of the zone.
virtual const isc::dns::Name& getOrigin() const = 0;
/// Return the RR class of the zone.
virtual const isc::dns::RRClass& getClass() const = 0;
//@}
///
/// \name Search Method
///
//@{
/// Search the zone for a given pair of domain name and RR type.
///
/// Each derived version of this method searches the underlying backend
/// for the data that best matches the given name and type.
/// This method is expected to be "intelligent", and identifies the
/// best possible answer for the search key. Specifically,
/// - If the search name belongs under a zone cut, it returns the code
/// of \c DELEGATION and the NS RRset at the zone cut.
/// - If there is no matching name, it returns the code of \c NXDOMAIN,
/// and, if DNSSEC is requested, the NSEC RRset that proves the
/// non-existence.
/// - If there is a matching name but no RRset of the search type, it
/// returns the code of \c NXRRSET, and, if DNSSEC is required,
/// the NSEC RRset for that name.
/// - If there is a matching name with CNAME, it returns the code of
/// \c CNAME and that CNAME RR.
/// - If the search name matches a delegation point of DNAME, it returns
/// the code of \c DNAME and that DNAME RR.
///
/// A derived version of this method may involve internal resource
/// allocation, especially for constructing the resulting RRset, and may
/// throw an exception if it fails.
/// It should not throw other types of exceptions.
///
/// Note: It's quite likely that we'll need to specify search options.
/// For example, we should be able to specify whether to allow returning
/// glue records at or under a zone cut. We leave this interface open
/// at this moment.
///
/// \param name The domain name to be searched for.
/// \param type The RR type to be searched for.
/// \return A \c FindResult object enclosing the search result (see above).
virtual FindResult find(const isc::dns::Name& name,
const isc::dns::RRType& type) const = 0;
//@}
};
/// \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;
}
}
#endif
......@@ -18,7 +18,6 @@
#include <utility>
#include <dns/name.h>
#include <dns/rrclass.h>
#include <datasrc/zonetable.h>
......@@ -28,39 +27,6 @@ using namespace isc::dns;
namespace isc {
namespace datasrc {
struct MemoryZone::MemoryZoneImpl {
MemoryZoneImpl(const RRClass& zone_class, const Name& origin) :
zone_class_(zone_class), origin_(origin)
{}
RRClass zone_class_;
Name origin_;
};
MemoryZone::MemoryZone(const RRClass& zone_class, const Name& origin) :
impl_(new MemoryZoneImpl(zone_class, origin))
{
}
MemoryZone::~MemoryZone() {
delete impl_;
}
const Name&
MemoryZone::getOrigin() const {
return (impl_->origin_);
}
const RRClass&
MemoryZone::getClass() const {
return (impl_->zone_class_);
}
Zone::FindResult
MemoryZone::find(const Name&, const RRType&) const {
// This is a tentative implementation that always returns NXDOMAIN.
return (FindResult(NXDOMAIN, RRsetPtr()));
}
// This is a temporary, inefficient implementation using std::map and handmade
// iteration to realize longest match.
......
......@@ -19,6 +19,8 @@
#include <dns/rrset.h>
#include <datasrc/zone.h>
namespace isc {
namespace dns {
class Name;
......@@ -26,215 +28,6 @@ class RRClass;
};
namespace datasrc {
namespace result {
/// Result codes of various public methods of in memory data source
///
/// The detailed semantics may differ in different methods.
/// See the description of specific methods for more details.
///
/// Note: this is intended to be used from other data sources eventually,
/// but for now it's specific to in memory data source and its backend.
enum Result {
SUCCESS, ///< The operation is successful.
EXIST, ///< The search key is already stored.
NOTFOUND, ///< The specified object is not found.
PARTIALMATCH ///< \c Only a partial match is found.
};
}
/// \brief The base class for a single authoritative zone
///
/// The \c Zone class is an abstract base class for representing
/// a DNS zone as part of data source.
///
/// At the moment this is provided mainly for making the \c ZoneTable class
/// and the authoritative query logic 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.
///
/// The idea is to provide a specific derived zone class for each data
/// source, beginning with in memory one. At that point the derived classes
/// will have more specific features. For example, they will maintain
/// information about the location of a zone file, whether it's loaded in
/// memory, etc.
///
/// It's not yet clear how the derived zone classes work with various other
/// data sources when we integrate these components, but one possibility is
/// something like this:
/// - If the underlying database such as some variant of SQL doesn't have an
/// explicit representation of zones (as part of public interface), we can
/// probably use a "default" zone class that simply encapsulates the
/// corresponding data source and calls a common "find" like method.
/// - Some data source may want to specialize it by inheritance as an
/// optimization. For example, in the current schema design of the sqlite3
/// data source, its (derived) zone class would contain the information of
/// the "zone ID".
///
/// <b>Note:</b> Unlike some other abstract base classes we don't name the
/// class beginning with "Abstract". This is because we want to have
/// commonly used definitions such as \c Result and \c ZonePtr, and we want
/// to make them look more intuitive.
class Zone {
public:
/// Result codes of the \c find() method.
///
/// Note: the codes are tentative. We may need more, or we may find
/// some of them unnecessary as we implement more details.
enum Result {
SUCCESS, ///< An exact match is found.
DELEGATION, ///< The search encounters a zone cut.
NXDOMAIN, ///< There is no domain name that matches the search name
NXRRSET, ///< There is a matching name but no RRset of the search type
CNAME, ///< The search encounters and returns a CNAME RR
DNAME ///< The search encounters and returns a DNAME RR
};
/// A helper structure to represent the search result of \c find().
///
/// This is a straightforward tuple of the result code and a pointer
/// to the found RRset to represent the result of \c find()
/// (there will be more members in the future - see the class
/// description).
/// 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 whose internal state never changes,
/// so for convenience we allow the applications to refer to the members
/// directly.
///
/// Note: we should eventually include a notion of "zone node", which
/// corresponds to a particular domain name of the zone, so that we can
/// find RRsets of a different RR type for that name (e.g. for type ANY
/// query or to include DS RRs with delegation).
///
/// Note: we may also want to include the closest enclosure "node" to
/// optimize including the NSEC for no-wildcard proof (FWIW NSD does that).
struct FindResult {
FindResult(Result param_code,
const isc::dns::ConstRRsetPtr param_rrset) :
code(param_code), rrset(param_rrset)
{}
const Result code;
const isc::dns::ConstRRsetPtr rrset;
};
///
/// \name Constructors and Destructor.
///
//@{
protected:
/// The default constructor.
///
/// This is intentionally defined as \c protected as this base class should
/// never be instantiated (except as part of a derived class).
Zone() {}
public:
/// The destructor.
virtual ~Zone() {}
//@}
///
/// \name Getter Methods
///
/// These methods should never throw an exception.
//@{
/// Return the origin name of the zone.
virtual const isc::dns::Name& getOrigin() const = 0;
/// Return the RR class of the zone.
virtual const isc::dns::RRClass& getClass() const = 0;
//@}
///
/// \name Search Method
///
//@{
/// Search the zone for a given pair of domain name and RR type.
///
/// Each derived version of this method searches the underlying backend
/// for the data that best matches the given name and type.
/// This method is expected to be "intelligent", and identifies the
/// best possible answer for the search key. Specifically,
/// - If the search name belongs under a zone cut, it returns the code
/// of \c DELEGATION and the NS RRset at the zone cut.
/// - If there is no matching name, it returns the code of \c NXDOMAIN,
/// and, if DNSSEC is requested, the NSEC RRset that proves the
/// non-existence.
/// - If there is a matching name but no RRset of the search type, it
/// returns the code of \c NXRRSET, and, if DNSSEC is required,
/// the NSEC RRset for that name.
/// - If there is a matching name with CNAME, it returns the code of
/// \c CNAME and that CNAME RR.
/// - If the search name matches a delegation point of DNAME, it returns
/// the code of \c DNAME and that DNAME RR.
///
/// A derived version of this method may involve internal resource
/// allocation, especially for constructing the resulting RRset, and may
/// throw an exception if it fails.
/// It should not throw other types of exceptions.