Commit c0672d18 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[master] Merge branch 'trac2282merge'

parents 30ab0e64 28c92930
......@@ -1193,11 +1193,11 @@ AC_CONFIG_FILES([Makefile
src/lib/exceptions/tests/Makefile
src/lib/datasrc/Makefile
src/lib/datasrc/memory/Makefile
src/lib/datasrc/memory/tests/Makefile
src/lib/datasrc/memory/tests/testdata/Makefile
src/lib/datasrc/memory/benchmarks/Makefile
src/lib/datasrc/tests/Makefile
src/lib/datasrc/tests/testdata/Makefile
src/lib/datasrc/tests/memory/Makefile
src/lib/datasrc/tests/memory/testdata/Makefile
src/lib/xfr/Makefile
src/lib/xfr/tests/Makefile
src/lib/log/Makefile
......
......@@ -57,12 +57,6 @@ b10_auth_SOURCES += common.h common.cc
b10_auth_SOURCES += statistics.cc statistics.h
b10_auth_SOURCES += datasrc_configurator.h
b10_auth_SOURCES += main.cc
# This is a temporary workaround for #1206, where the InMemoryClient has been
# moved to an ldopened library. We could add that library to LDADD, but that
# is nonportable. This should've been moot after #1207, but there is still
# one dependency; the in-memory-specific zone loader call is still in
# auth.
b10_auth_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
nodist_b10_auth_SOURCES = auth_messages.h auth_messages.cc
EXTRA_DIST += auth_messages.mes
......
......@@ -17,12 +17,6 @@ query_bench_SOURCES += ../auth_srv.h ../auth_srv.cc
query_bench_SOURCES += ../auth_config.h ../auth_config.cc
query_bench_SOURCES += ../statistics.h ../statistics.cc
query_bench_SOURCES += ../auth_log.h ../auth_log.cc
# This is a temporary workaround for #1206, where the InMemoryClient has been
# moved to an ldopened library. We could add that library to LDADD, but that
# is nonportable. When #1207 is done this becomes moot anyway, and the
# specific workaround is not needed anymore, so we can then remove this
# line again.
query_bench_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
nodist_query_bench_SOURCES = ../auth_messages.h ../auth_messages.cc
......
......@@ -52,13 +52,6 @@ run_unittests_SOURCES += query_unittest.cc
run_unittests_SOURCES += statistics_unittest.cc
run_unittests_SOURCES += datasrc_configurator_unittest.cc
run_unittests_SOURCES += run_unittests.cc
# This is a temporary workaround for #1206, where the InMemoryClient has been
# moved to an ldopened library. We could add that library to LDADD, but that
# is nonportable. This should've been moot after #1207, but there is still
# one dependency; the in-memory-specific zone loader call is still in
# auth.
run_unittests_SOURCES += ${top_srcdir}/src/lib/datasrc/memory_datasrc.cc
nodist_run_unittests_SOURCES = ../auth_messages.h ../auth_messages.cc
......
......@@ -15,6 +15,7 @@
#include <config.h>
#include <util/io/sockaddr_util.h>
#include <util/memory_segment_local.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
......@@ -1393,16 +1394,19 @@ public:
const isc::datasrc::DataSourceClientPtr
client(new FakeClient(info.data_src_client_ != NULL ?
info.data_src_client_ :
info.cache_.get(),
info.getCacheClient(),
throw_when, isc_exception, fake_rrset));
clients_.push_back(client);
data_sources_.push_back(DataSourceInfo(client.get(),
isc::datasrc::DataSourceClientContainerPtr(), false));
data_sources_.push_back(
DataSourceInfo(client.get(),
isc::datasrc::DataSourceClientContainerPtr(),
false, RRClass::IN(), mem_sgmt_));
}
}
private:
const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
vector<isc::datasrc::DataSourceClientPtr> clients_;
MemorySegmentLocal mem_sgmt_;
};
} // end anonymous namespace for throwing proxy classes
......
SUBDIRS = . memory tests
SUBDIRS = memory . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
......@@ -60,6 +60,7 @@ libb10_datasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libb10-exceptions.
libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/log/libb10-log.la
libb10_datasrc_la_LIBADD += $(top_builddir)/src/lib/cc/libb10-cc.la
libb10_datasrc_la_LIBADD += $(builddir)/memory/libdatasrc_memory.la
libb10_datasrc_la_LIBADD += $(SQLITE_LIBS)
BUILT_SOURCES = datasrc_config.h datasrc_messages.h datasrc_messages.cc
......
......@@ -12,10 +12,12 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <util/memory_segment_local.h>
#include "client_list.h"
#include "client.h"
#include "factory.h"
#include "memory_datasrc.h"
#include "memory/memory_client.h"
#include "logger.h"
#include <dns/masterload.h>
......@@ -25,32 +27,58 @@
using namespace isc::data;
using namespace isc::dns;
using namespace std;
using isc::util::MemorySegment;
using boost::lexical_cast;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
using isc::datasrc::memory::InMemoryClient;
namespace isc {
namespace datasrc {
ConfigurableClientList::DataSourceInfo::DataSourceInfo(
DataSourceClient* data_src_client,
const DataSourceClientContainerPtr& container, bool has_cache) :
const DataSourceClientContainerPtr& container, bool has_cache,
const RRClass& rrclass, MemorySegment& mem_sgmt) :
data_src_client_(data_src_client),
container_(container)
{
if (has_cache) {
cache_.reset(new InMemoryClient);
cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
}
}
ConfigurableClientList::DataSourceInfo::DataSourceInfo(bool has_cache) :
ConfigurableClientList::DataSourceInfo::DataSourceInfo(
const RRClass& rrclass, MemorySegment& mem_sgmt, bool has_cache) :
data_src_client_(NULL)
{
if (has_cache) {
cache_.reset(new InMemoryClient);
cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
}
}
const DataSourceClient*
ConfigurableClientList::DataSourceInfo::getCacheClient() const {
return (cache_.get());
}
ConfigurableClientList::ConfigurableClientList(const RRClass& rrclass) :
rrclass_(rrclass),
mem_sgmt_(new util::MemorySegmentLocal),
configuration_(new isc::data::ListElement),
allow_cache_(false)
{}
ConfigurableClientList::~ConfigurableClientList() {
// Explicitly clear the contained data source clients, and check memory
// leak. assert() (with abort on failure) may be too harsh, but
// it's probably better to find more leaks initially. Once it's stabilized
// we should probably revisit it.
data_sources_.clear();
assert(mem_sgmt_->allMemoryDeallocated());
}
void
ConfigurableClientList::configure(const ConstElementPtr& config,
bool allow_cache)
......@@ -98,14 +126,16 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
isc_throw(ConfigurationError, "The cache must be enabled "
"for the MasterFiles type");
}
new_data_sources.push_back(DataSourceInfo(true));
new_data_sources.push_back(DataSourceInfo(rrclass_, *mem_sgmt_,
true));
} else {
// Ask the factory to create the data source for us
const DataSourcePair ds(this->getDataSourceClient(type,
paramConf));
// And put it into the vector
new_data_sources.push_back(DataSourceInfo(ds.first, ds.second,
want_cache));
want_cache, rrclass_,
*mem_sgmt_));
}
if (want_cache) {
......@@ -141,13 +171,10 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
for (vector<string>::const_iterator it(zones_origins.begin());
it != zones_origins.end(); ++it) {
const Name origin(*it);
shared_ptr<InMemoryZoneFinder>
finder(new
InMemoryZoneFinder(rrclass_, origin));
if (type == "MasterFiles") {
try {
finder->load(paramConf->get(*it)->stringValue());
cache->addZone(finder);
cache->load(origin,
paramConf->get(*it)->stringValue());
} catch (const isc::dns::MasterLoadError& mle) {
LOG_ERROR(logger, DATASRC_MASTERLOAD_ERROR)
.arg(mle.what());
......@@ -165,8 +192,7 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
isc_throw(isc::Unexpected, "Got NULL iterator "
"for zone " << origin);
}
finder->load(*iterator);
cache->addZone(finder);
cache->load(origin, *iterator);
}
}
}
......@@ -324,14 +350,11 @@ ConfigurableClientList::reload(const Name& name) {
}
// Try to convert the finder to in-memory one. If it is the cache,
// it should work.
shared_ptr<InMemoryZoneFinder>
finder(dynamic_pointer_cast<InMemoryZoneFinder>(result.finder));
const DataSourceInfo* info(result.info);
// It is of a different type or there's no cache.
if (!info->cache_ || !finder) {
if (!result.info->cache_) {
return (ZONE_NOT_CACHED);
}
DataSourceClient* client(info->data_src_client_);
DataSourceClient* client(result.info->data_src_client_);
if (client) {
// Now do the final reload. If it does not exist in client,
// DataSourceError is thrown, which is exactly the result what we
......@@ -340,15 +363,15 @@ ConfigurableClientList::reload(const Name& name) {
if (!iterator) {
isc_throw(isc::Unexpected, "Null iterator from " << name);
}
finder->load(*iterator);
result.info->cache_->load(name, *iterator);
} else {
// The MasterFiles special case
const string filename(finder->getFileName());
const string filename(result.info->cache_->getFileName(name));
if (filename.empty()) {
isc_throw(isc::Unexpected, "Confused about missing both filename "
"and data source");
}
finder->load(filename);
result.info->cache_->load(name, filename);
}
return (ZONE_RELOADED);
}
......
......@@ -15,6 +15,8 @@
#ifndef DATASRC_CONTAINER_H
#define DATASRC_CONTAINER_H
#include <util/memory_segment.h>
#include <dns/name.h>
#include <dns/rrclass.h>
#include <cc/data.h>
......@@ -22,6 +24,7 @@
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/noncopyable.hpp>
namespace isc {
......@@ -34,7 +37,13 @@ typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
class DataSourceClientContainer;
typedef boost::shared_ptr<DataSourceClientContainer>
DataSourceClientContainerPtr;
// XXX: it's better to even hide the existence of the "memory" namespace.
// We should probably consider pimpl for details of ConfigurableClientList
// and hide real definitions except for itself and tests.
namespace memory {
class InMemoryClient;
}
/// \brief The list of data source clients.
///
......@@ -209,11 +218,11 @@ public:
/// \brief Constructor
///
/// \param rrclass For which class the list should work.
ConfigurableClientList(const isc::dns::RRClass &rrclass) :
rrclass_(rrclass),
configuration_(new isc::data::ListElement),
allow_cache_(false)
{}
ConfigurableClientList(const isc::dns::RRClass& rrclass);
/// \brief Destructor
virtual ~ConfigurableClientList();
/// \brief Exception thrown when there's an error in configuration.
class ConfigurationError : public Exception {
public:
......@@ -290,24 +299,27 @@ public:
/// \todo The content yet to be defined.
struct DataSourceInfo {
// Plays a role of default constructor too (for vector)
DataSourceInfo(bool has_cache = false);
DataSourceInfo(const dns::RRClass& rrclass,
util::MemorySegment& mem_sgmt,
bool has_cache = false);
DataSourceInfo(DataSourceClient* data_src_client,
const DataSourceClientContainerPtr& container,
bool has_cache);
bool has_cache, const dns::RRClass& rrclass,
util::MemorySegment& mem_sgmt);
DataSourceClient* data_src_client_;
DataSourceClientContainerPtr container_;
boost::shared_ptr<InMemoryClient> cache_;
// Accessor to cache_ in the form of DataSourceClient, hiding
// the existence of InMemoryClient as much as possible. We should
// really consider cleaner abstraction, but for now it works.
// This is also only intended to be used in auth unit tests right now.
// No other applications or tests may use it.
const DataSourceClient* getCacheClient() const;
boost::shared_ptr<memory::InMemoryClient> cache_;
};
/// \brief The collection of data sources.
typedef std::vector<DataSourceInfo> DataSources;
protected:
/// \brief The data sources held here.
///
/// All our data sources are stored here. It is protected to let the
/// tests in. You should consider it private if you ever want to
/// derive this class (which is not really recommended anyway).
DataSources data_sources_;
/// \brief Convenience type alias.
///
......@@ -357,10 +369,26 @@ private:
void findInternal(MutableResult& result, const dns::Name& name,
bool want_exact_match, bool want_finder) const;
const isc::dns::RRClass rrclass_;
/// \brief Memory segment for in-memory cache.
///
/// Note that this must be placed before data_sources_ so it won't be
/// destroyed before the built objects in the destructor.
boost::scoped_ptr<util::MemorySegment> mem_sgmt_;
/// \brief Currently active configuration.
isc::data::ConstElementPtr configuration_;
/// \brief The last set value of allow_cache.
bool allow_cache_;
protected:
/// \brief The data sources held here.
///
/// All our data sources are stored here. It is protected to let the
/// tests in. You should consider it private if you ever want to
/// derive this class (which is not really recommended anyway).
DataSources data_sources_;
};
} // namespace datasrc
......
SUBDIRS = . tests benchmarks
SUBDIRS = . benchmarks
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
......
......@@ -373,10 +373,23 @@ private:
}
}
/// \brief returns if the node is a subtree's root node
///
/// This method takes a node and returns \c true if it is the root
/// node of the subtree it belongs to.
///
/// This method never throws an exception.
bool isSubTreeRoot() const {
return ((flags_ & FLAG_SUBTREE_ROOT) != 0);
}
/// \brief returns the root of its subtree
///
/// This method takes a node and returns the root of its subtree.
///
/// This method never throws an exception.
const DomainTreeNode<T>* getSubTreeRoot() const;
public:
/// \brief returns the parent of the root of its subtree
///
......@@ -388,7 +401,6 @@ public:
/// This method never throws an exception.
const DomainTreeNode<T>* getUpperNode() const;
private:
/// \brief return the next node which is bigger than current node
/// in the same subtree
///
......@@ -423,6 +435,7 @@ private:
/// This method never throws an exception.
const DomainTreeNode<T>* predecessor() const;
private:
/// \brief private shared implementation of successor and predecessor
///
/// As the two mentioned functions are merely mirror images of each other,
......@@ -538,7 +551,7 @@ DomainTreeNode<T>::~DomainTreeNode() {
template <typename T>
const DomainTreeNode<T>*
DomainTreeNode<T>::getUpperNode() const {
DomainTreeNode<T>::getSubTreeRoot() const {
const DomainTreeNode<T>* current = this;
// current would never be equal to NULL here (in a correct tree
......@@ -547,7 +560,13 @@ DomainTreeNode<T>::getUpperNode() const {
current = current->getParent();
}
return (current->getParent());
return (current);
}
template <typename T>
const DomainTreeNode<T>*
DomainTreeNode<T>::getUpperNode() const {
return (getSubTreeRoot()->getParent());
}
template <typename T>
......@@ -555,7 +574,17 @@ isc::dns::LabelSequence
DomainTreeNode<T>::getAbsoluteLabels(
uint8_t buf[isc::dns::LabelSequence::MAX_SERIALIZED_LENGTH]) const
{
isc::dns::LabelSequence result(getLabels(), buf);
// If the current node already has absolute labels, just return it.
// This should normally be the case for the origin node if this tree
// is used to represent a single DNS zone.
const isc::dns::LabelSequence cur_labels(getLabels());
if (cur_labels.isAbsolute()) {
return (cur_labels);
}
// Otherwise, build the absolute sequence traversing the tree of tree
// toward the top root.
isc::dns::LabelSequence result(cur_labels, buf);
const DomainTreeNode<T>* upper = getUpperNode();
while (upper != NULL) {
result.extend(upper->getLabels(), buf);
......@@ -672,14 +701,26 @@ public:
/// The default constructor.
///
/// \exception None
DomainTreeNodeChain() : node_count_(0), last_compared_(NULL),
DomainTreeNodeChain() : level_count_(0), last_compared_(NULL),
// XXX: meaningless initial values:
last_comparison_(0, 0,
isc::dns::NameComparisonResult::EQUAL)
{}
/// \brief Copy constructor.
///
/// \exception None
DomainTreeNodeChain(const DomainTreeNodeChain<T>& other) :
level_count_(other.level_count_),
last_compared_(other.last_compared_),
last_comparison_(other.last_comparison_)
{
for (size_t i = 0; i < level_count_; i++) {
nodes_[i] = other.nodes_[i];
}
}
private:
DomainTreeNodeChain(const DomainTreeNodeChain<T>&);
DomainTreeNodeChain<T>& operator=(const DomainTreeNodeChain<T>&);
//@}
......@@ -691,7 +732,7 @@ public:
///
/// \exception None
void clear() {
node_count_ = 0;
level_count_ = 0;
last_compared_ = NULL;
}
......@@ -732,7 +773,7 @@ public:
/// chain, 0 will be returned.
///
/// \exception None
unsigned int getLevelCount() const { return (node_count_); }
size_t getLevelCount() const { return (level_count_); }
/// \brief return the absolute name for the node which this
/// \c DomainTreeNodeChain currently refers to.
......@@ -750,11 +791,11 @@ public:
const DomainTreeNode<T>* top_node = top();
isc::dns::Name absolute_name = top_node->getName();
int node_count = node_count_ - 1;
while (node_count > 0) {
top_node = nodes_[node_count - 1];
size_t level = level_count_ - 1;
while (level > 0) {
top_node = nodes_[level - 1];
absolute_name = absolute_name.concatenate(top_node->getName());
--node_count;
--level;
}
return (absolute_name);
}
......@@ -768,7 +809,7 @@ private:
/// \brief return whether node chain has node in it.
///
/// \exception None
bool isEmpty() const { return (node_count_ == 0); }
bool isEmpty() const { return (level_count_ == 0); }
/// \brief return the top node for the node chain
///
......@@ -778,7 +819,7 @@ private:
/// \exception None
const DomainTreeNode<T>* top() const {
assert(!isEmpty());
return (nodes_[node_count_ - 1]);
return (nodes_[level_count_ - 1]);
}
/// \brief pop the top node from the node chain
......@@ -789,7 +830,7 @@ private:
/// \exception None
void pop() {
assert(!isEmpty());
--node_count_;
--level_count_;
}
/// \brief add the node into the node chain
......@@ -800,8 +841,8 @@ private:
///
/// \exception None
void push(const DomainTreeNode<T>* node) {
assert(node_count_ < RBT_MAX_LEVEL);
nodes_[node_count_++] = node;
assert(level_count_ < RBT_MAX_LEVEL);
nodes_[level_count_++] = node;
}
private:
......@@ -810,7 +851,7 @@ private:
// it's also equal to the possible maximum level.
const static int RBT_MAX_LEVEL = isc::dns::Name::MAX_LABELS;
int node_count_;
size_t level_count_;
const DomainTreeNode<T>* nodes_[RBT_MAX_LEVEL];
const DomainTreeNode<T>* last_compared_;
isc::dns::NameComparisonResult last_comparison_;
......@@ -1265,12 +1306,20 @@ public:
const DomainTreeNode<T>*
previousNode(DomainTreeNodeChain<T>& node_path) const;
/// \brief return the largest node in the tree of trees.
///
/// \throw none
///
/// \return A \c DomainTreeNode that is the largest node in the
/// tree. If there are no nodes, then \c NULL is returned.
const DomainTreeNode<T>* largestNode() const;
/// \brief Get the total number of nodes in the tree
///
/// It includes nodes internally created as a result of adding a domain
/// name that is a subdomain of an existing node of the tree.
/// This function is mainly intended to be used for debugging.
int getNodeCount() const { return (node_count_); }
uint32_t getNodeCount() const { return (node_count_); }
/// \name Debug function
//@{
......@@ -1402,8 +1451,15 @@ private:
//@}
typename DomainTreeNode<T>::DomainTreeNodePtr root_;
/// the node count of current tree
unsigned int node_count_;
/// the node count of current tree.
///
/// Note: uint32_t may look awkward, but we intentionally choose it so
/// that needsReturnEmptyNode_ below won't make cause extra padding
/// in 64-bit machines (and we can minimize the total size of this class).
/// 2^32 - 1 should be a reasonable max of possible number of nodes.
uint32_t node_count_;
/// search policy for domaintree
const bool needsReturnEmptyNode_;
};
......@@ -1709,6 +1765,24 @@ DomainTree<T>::previousNode(DomainTreeNodeChain<T>& node_path) const {
return (node);
}
template <typename T>
const DomainTreeNode<T>*
DomainTree<T>::largestNode() const {
const DomainTreeNode<T>* node = root_.get();
while (node != NULL) {
// We go right first, then down.
if (node->getRight() != NULL) {
node = node->getRight();
} else if (node->getDown() != NULL) {
node = node->getDown();
} else {
break;
}
}
return (node);