Commit 70994c68 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[master] Merge branch 'trac2906'

parents 339c94b4 5c82cc61
......@@ -39,6 +39,9 @@ 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
libb10_datasrc_la_SOURCES += cache_config.h cache_config.cc
libb10_datasrc_la_SOURCES += zone_table_accessor.h
libb10_datasrc_la_SOURCES += zone_table_accessor_cache.h
libb10_datasrc_la_SOURCES += zone_table_accessor_cache.cc
nodist_libb10_datasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
libb10_datasrc_la_LDFLAGS = -no-undefined -version-info 1:0:1
......
......@@ -60,6 +60,7 @@ run_unittests_SOURCES += client_list_unittest.cc
run_unittests_SOURCES += master_loader_callbacks_test.cc
run_unittests_SOURCES += zone_loader_unittest.cc
run_unittests_SOURCES += cache_config_unittest.cc
run_unittests_SOURCES += zone_table_accessor_unittest.cc
# We need the actual module implementation in the tests (they are not part
# of libdatasrc)
......
// 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/zone_table_accessor_cache.h>
#include <datasrc/cache_config.h>
#include <datasrc/tests/mock_client.h>
#include <exceptions/exceptions.h>
#include <cc/data.h>
#include <dns/name.h>
#include <gtest/gtest.h>
using namespace isc::dns;
using namespace isc::datasrc;
using namespace isc::datasrc::internal;
using isc::data::Element;
using isc::datasrc::unittest::MockDataSourceClient;
namespace {
// This test checks the abstract ZoneTableAccessor interface using
// ZoneTableAccessorCache instances, thereby testing the top level interface
// and the derived class behavior. If ZoneTableAccessorCache becomes more
// complicated we may have to separate some test cases into dedicated test
// fixture.
class ZoneTableAccessorTest : public ::testing::Test {
protected:
ZoneTableAccessorTest() :
// The paths of the zone files are dummy and don't even exist,
// but it doesn't matter in this test.
config_spec_(Element::fromJSON(
"{\"cache-enable\": true,"
" \"params\": "
" {\"example.com\": \"/example-com.zone\","
" \"example.org\": \"/example-org.zone\"}"
"}")),
cache_config_("MasterFiles", NULL, *config_spec_, true),
accessor_(cache_config_)
{}
private:
const isc::data::ConstElementPtr config_spec_;
const CacheConfig cache_config_;
protected:
ZoneTableAccessorCache accessor_;
};
TEST_F(ZoneTableAccessorTest, iteratorFromCache) {
// Confirm basic iterator behavior.
ZoneTableAccessor::IteratorPtr it = accessor_.getIterator();
ASSERT_TRUE(it);
EXPECT_FALSE(it->isLast());
EXPECT_EQ(0, it->getCurrent().index); // index is always 0 for this version
EXPECT_EQ(Name("example.com"), it->getCurrent().origin);
it->next();
EXPECT_FALSE(it->isLast());
EXPECT_EQ(0, it->getCurrent().index);
EXPECT_EQ(Name("example.org"), it->getCurrent().origin);
it->next(); // shouldn't cause disruption
EXPECT_TRUE(it->isLast());
// getCurrent() and next() will be rejected once iterator reaches the end
EXPECT_THROW(it->getCurrent(), isc::InvalidOperation);
EXPECT_THROW(it->next(), isc::InvalidOperation);
}
TEST_F(ZoneTableAccessorTest, emptyTable) {
// Empty zone table is possible, while mostly useless.
const CacheConfig empty_config(
"MasterFiles", NULL, *Element::fromJSON(
"{\"cache-enable\": true, \"params\": {}}"), true);
ZoneTableAccessorCache accessor(empty_config);
ZoneTableAccessor::IteratorPtr it = accessor.getIterator();
ASSERT_TRUE(it);
EXPECT_TRUE(it->isLast());
EXPECT_THROW(it->getCurrent(), isc::InvalidOperation);
EXPECT_THROW(it->next(), isc::InvalidOperation);
}
TEST_F(ZoneTableAccessorTest, disabledTable) {
// Zone table based on disabled cache is effectively empty.
const char* zones[] = { "example.org.", "example.com.", NULL };
MockDataSourceClient mock_client(zones);
const CacheConfig mock_config(
"mock", &mock_client, *Element::fromJSON(
"{\"cache-enable\": false,"
" \"cache-zones\": [\"example.com\", \"example.org\"]}"), true);
ZoneTableAccessorCache accessor(mock_config);
ZoneTableAccessor::IteratorPtr it = accessor.getIterator();
ASSERT_TRUE(it);
EXPECT_TRUE(it->isLast());
EXPECT_THROW(it->getCurrent(), isc::InvalidOperation);
EXPECT_THROW(it->next(), isc::InvalidOperation);
}
}
// 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 DATASRC_ZONE_TABLE_ACCESSOR_H
#define DATASRC_ZONE_TABLE_ACCESSOR_H
#include <dns/name.h>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <stdint.h>
namespace isc {
namespace datasrc {
/// \brief Information of a zone stored in a data source zone table.
///
/// This is a straightforward composite type that represents an entry of
/// the conceptual zone table referenced by \c ZoneTableAccessor.
/// An object of this structure is specifically intended to be returned by
/// \c ZoneTableIterator.
///
/// This is essentially a read-only tuple; only created by
/// \c ZoneTableAccessor, and once created it will be immutable.
///
/// \note Once Trac #2144 is completed, this struct must be defined as
/// non-assignable because it has a const member variable.
struct ZoneSpec {
/// \brief Constructor.
ZoneSpec(uint32_t index_param, const dns::Name& origin_param) :
index(index_param), origin(origin_param)
{}
/// \brief Numeric zone index.
///
/// In the current initial version, this field is just a placeholder.
/// In the future, we'll probably define it as a unique index in the table
/// for that particular zone so that applications can distinguish
/// and specify different zones efficiently. Until it's fixed, this field
/// shouldn't be used by applications.
const uint32_t index;
/// \brief The origin name of the zone.
const dns::Name origin;
};
/// \brief A simple iterator of zone table.
///
/// This is an abstract base class providing simple iteration operation
/// over zones stored in a data source. A concrete object of this class
/// is expected to be returned by \c ZoneTableAccessor::getIterator().
///
/// The interface is intentionally simplified and limited: it works
/// "forward-only", i.e, only goes from begin to end one time; it's not
/// copyable, assignable, nor comparable. For the latter reasons it's not
/// compatible with standard iterator traits. It's simplified because it's
/// not clear what kind of primitive can be used in specific data sources.
/// In particular, iteration in a database-based data source would be very
/// restrictive. So it's better to begin with minimal guaranteed features
/// at the base class. If we find it possible to loosen the restriction
/// as we implement more derived versions, we may extend the features later.
///
/// Likewise, this iterator does not guarantee the ordering of the zones
/// returned by \c getCurrent(). It's probably possible to ensure some
/// sorted order, but until we can be sure it's the case for many cases
/// in practice, we'll not rely on it.
///
/// A concrete object of this class is created by specific derived
/// implementation for the corresponding data source. The implementation
/// must ensure the iterator is located at the "beginning" of the zone table,
/// and that subsequent calls to \c next() go through all the zones
/// one by one, until \c isLast() returns \c true. The implementation must
/// support the concept of "empty table"; in that case \c isLast() will
/// return \c true from the beginning.
class ZoneTableIterator : boost::noncopyable {
protected:
/// \brief The constructor.
///
/// This class is not expected to be instantiated directly, so the
/// constructor is hidden from normal applications as protected.
ZoneTableIterator() {}
public:
/// \brief The destructor.
virtual ~ZoneTableIterator() {}
/// \brief Return if the iterator reaches the end of the zone table.
virtual bool isLast() const = 0;
/// \brief Move the iterator to the next zone of the table.
///
/// This method must not be called once the iterator reaches the end
/// of the table.
///
/// \throw InvalidOperation called after reaching the end of table.
void next() {
// Perform common check, and delegate the actual work to the protected
// method.
if (isLast()) {
isc_throw(InvalidOperation,
"next() called on iterator beyond end of zone table");
}
nextImpl();
}
/// \brief Return the information of the zone at which the iterator is
/// currently located in the form of \c ZoneSpec.
///
/// This method must not be called once the iterator reaches the end
/// of the zone table.
///
/// \throw InvalidOperation called after reaching the end of table.
///
/// \return Information of the "current" zone.
ZoneSpec getCurrent() const {
// Perform common check, and delegate the actual work to the protected
// method.
if (isLast()) {
isc_throw(InvalidOperation,
"getCurrent() called on iterator beyond "
"end of zone table");
}
return (getCurrentImpl());
}
protected:
/// \brief Actual implementation of \c next().
///
/// Each derived class must provide the implementation of \c next()
/// in its data source specific form, except for the common
/// validation check.
virtual void nextImpl() = 0;
/// \brief Actual implementation of \c getCurrent().
///
/// Each derived class must provide the implementation of
/// \c getCurrent() in its data source specific form, except for the
/// common validation check.
virtual ZoneSpec getCurrentImpl() const = 0;
};
/// \brief An abstract accessor to conceptual zone table for a data source.
///
/// This is an abstract base class providing common interfaces to get access
/// to a conceptual "zone table" corresponding to a specific data source.
/// A zone table would contain a set of information about DNS zones stored in
/// the data source. It's "conceptual" in that the actual form of the
/// information is specific to the data source implementation.
///
/// The initial version of this class only provides one simple feature:
/// iterating over the table so that an application can get a list of
/// all zones of a specific data source (of a specific RR class). In
/// future, this class will be extended so that, e.g., applications can
/// add or remove zones.
///
/// \note It may make sense to move \c DataSourceClient::createZone()
/// and \c DataSourceClient::deleteZone() to this class.
class ZoneTableAccessor : boost::noncopyable {
protected:
/// \brief The constructor.
///
/// This class is not expected to be instantiated directly, so the
/// constructor is hidden from normal applications as protected.
ZoneTableAccessor() {}
public:
/// \brief Shortcut type for a smart pointer of \c ZoneTableIterator
typedef boost::shared_ptr<ZoneTableIterator> IteratorPtr;
/// \brief The destructor.
virtual ~ZoneTableAccessor() {}
/// \brief Return a zone table iterator.
///
/// In general, the specific implementation of the iterator object would
/// contain some form of reference to the underlying data source
/// (e.g., a database connection or a pointer to memory region), which
/// would be valid only until the object that created the instance of
/// the accessor is destroyed. The iterator must not be used beyond
/// the lifetime of such a creator object, and normally it's expected to
/// be even more ephemeral: it would be created by this method in a
/// single method or function and only used in that limited scope.
///
/// \throw std::bad_alloc Memory allocation for the iterator object failed.
/// \throw Others There will be other cases as more implementations
/// are added (in this initial version, it's not really decided yet).
///
/// \return A smart pointer to a newly created iterator object. Once
/// returned, the \c ZoneTableAccessor effectively releases its ownership.
virtual IteratorPtr getIterator() const = 0;
};
}
}
#endif // DATASRC_ZONE_TABLE_ACCESSOR_H
// Local Variables:
// mode: c++
// End:
// 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/zone_table_accessor_cache.h>
#include <datasrc/cache_config.h>
#include <exceptions/exceptions.h>
namespace isc {
namespace datasrc {
namespace internal {
namespace {
// This is a straightforward wrapper of CacheConfig::ConstZoneIterator to
// implement ZoneTableIterator interfaces.
class ZoneTableIteratorCache : public ZoneTableIterator {
public:
ZoneTableIteratorCache(const CacheConfig& config) :
it_(config.begin()),
it_end_(config.end())
{}
virtual void nextImpl() {
++it_;
}
virtual ZoneSpec getCurrentImpl() const {
return (ZoneSpec(0, it_->first)); // index is always 0 in this version.
}
virtual bool isLast() const {
return (it_ == it_end_);
}
private:
CacheConfig::ConstZoneIterator it_;
CacheConfig::ConstZoneIterator const it_end_;
};
}
ZoneTableAccessor::IteratorPtr
ZoneTableAccessorCache::getIterator() const {
return (ZoneTableAccessor::IteratorPtr(
new ZoneTableIteratorCache(config_)));
}
}
}
}
// 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 DATASRC_ZONE_TABLE_ACCESSOR_CACHE_H
#define DATASRC_ZONE_TABLE_ACCESSOR_CACHE_H
#include <datasrc/zone_table_accessor.h>
#include <boost/noncopyable.hpp>
namespace isc {
namespace datasrc {
namespace internal {
class CacheConfig;
/// \brief A \c ZoneTableAccessor implementation for in-memory cache.
///
/// This class implements the \c ZoneTableAccessor interface for in-memory
/// cache. Its conceptual table consists of the zones that are specified
/// to be loaded into memory in configuration. Note that these zones
/// may or may not actually be loaded in memory. In fact, this class object
/// is intended to be used by applications that load these zones into memory,
/// so that the application can get a list of zones to be loaded. Also, even
/// after loading, some zone may still not be loaded, e.g., due to an error
/// in the corresponding zone file.
///
/// An object of this class is expected to be returned by
/// \c ConfigurableClientList. Normal applications shouldn't instantiate
/// this class directly. It's still defined to be publicly visible for
/// testing purposes but, to clarify the intent, it's hidden in the
/// "internal" namespace.
class ZoneTableAccessorCache : public ZoneTableAccessor {
public:
/// \brief Constructor.
///
/// This class takes a \c CacheConfig object and holds it throughout
/// its lifetime. The caller must ensure that the configuration is
/// valid throughout the lifetime of this accessor object.
///
/// \throw None
///
/// \param config The cache configuration that the accessor refers to.
ZoneTableAccessorCache(const CacheConfig& config) : config_(config) {}
/// \brief In-memory cache version of \c getIterator().
///
/// As returned from this version of iterator, \c ZoneSpec::index
/// will always be set to 0 at the moment.
///
/// \throw None except std::bad_alloc in case of memory allocation failure
virtual IteratorPtr getIterator() const;
private:
const CacheConfig& config_;
};
}
}
}
#endif // DATASRC_ZONE_TABLE_ACCESSOR_CACHE_H
// Local Variables:
// mode: c++
// End:
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment