Unverified Commit 4163ddf6 authored by Michal 'vorner' Vaner's avatar Michal 'vorner' Vaner
Browse files

Merge #2209

Introduction of the ConfigurableClientList::getCachedZoneWriter() method.
parents 869e658f 98947382
......@@ -200,7 +200,7 @@ public:
}
switch (list->reload(origin)) {
case ConfigurableClientList::ZONE_RELOADED:
case ConfigurableClientList::ZONE_SUCCESS:
// Everything worked fine.
LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_LOAD_ZONE)
.arg(zone_class).arg(origin);
......
......@@ -15,7 +15,6 @@
#include <config.h>
#include <util/io/sockaddr_util.h>
#include <util/memory_segment_local.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
......@@ -74,6 +73,7 @@ using namespace isc::asiodns;
using namespace isc::asiolink;
using namespace isc::testutils;
using namespace isc::server_common::portconfig;
using isc::datasrc::memory::ZoneTableSegment;
using isc::UnitTestUtil;
using boost::scoped_ptr;
......@@ -1401,7 +1401,9 @@ public:
real_list, ThrowWhen throw_when, bool isc_exception,
ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
ConfigurableClientList(RRClass::IN()),
real_(real_list)
real_(real_list),
config_(Element::fromJSON("{}")),
ztable_segment_(ZoneTableSegment::create(*config_, RRClass::IN()))
{
BOOST_FOREACH(const DataSourceInfo& info, real_->getDataSources()) {
const isc::datasrc::DataSourceClientPtr
......@@ -1413,13 +1415,14 @@ public:
data_sources_.push_back(
DataSourceInfo(client.get(),
isc::datasrc::DataSourceClientContainerPtr(),
false, RRClass::IN(), mem_sgmt_));
false, RRClass::IN(), ztable_segment_));
}
}
private:
const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
const ConstElementPtr config_;
boost::shared_ptr<ZoneTableSegment> ztable_segment_;
vector<isc::datasrc::DataSourceClientPtr> clients_;
MemorySegmentLocal mem_sgmt_;
};
} // end anonymous namespace for throwing proxy classes
......
......@@ -12,17 +12,21 @@
// 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/memory_client.h"
#include "memory/zone_table_segment.h"
#include "memory/zone_writer.h"
#include "memory/zone_data_loader.h"
#include "logger.h"
#include <dns/masterload.h>
#include <util/memory_segment_local.h>
#include <memory>
#include <boost/foreach.hpp>
#include <boost/bind.hpp>
using namespace isc::data;
using namespace isc::dns;
......@@ -32,6 +36,7 @@ using boost::lexical_cast;
using boost::shared_ptr;
using boost::dynamic_pointer_cast;
using isc::datasrc::memory::InMemoryClient;
using isc::datasrc::memory::ZoneTableSegment;
namespace isc {
namespace datasrc {
......@@ -39,21 +44,24 @@ namespace datasrc {
ConfigurableClientList::DataSourceInfo::DataSourceInfo(
DataSourceClient* data_src_client,
const DataSourceClientContainerPtr& container, bool has_cache,
const RRClass& rrclass, MemorySegment& mem_sgmt) :
const RRClass& rrclass, const shared_ptr<ZoneTableSegment>& segment) :
data_src_client_(data_src_client),
container_(container)
{
if (has_cache) {
cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
cache_.reset(new InMemoryClient(segment, rrclass));
ztable_segment_ = segment;
}
}
ConfigurableClientList::DataSourceInfo::DataSourceInfo(
const RRClass& rrclass, MemorySegment& mem_sgmt, bool has_cache) :
const RRClass& rrclass, const shared_ptr<ZoneTableSegment>& segment,
bool has_cache) :
data_src_client_(NULL)
{
if (has_cache) {
cache_.reset(new InMemoryClient(mem_sgmt, rrclass));
cache_.reset(new InMemoryClient(segment, rrclass));
ztable_segment_ = segment;
}
}
......@@ -64,21 +72,10 @@ ConfigurableClientList::DataSourceInfo::getCacheClient() const {
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)
......@@ -90,6 +87,8 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
size_t i(0); // Outside of the try to be able to access it in the catch
try {
vector<DataSourceInfo> new_data_sources;
shared_ptr<ZoneTableSegment> ztable_segment(
ZoneTableSegment::create(*config, rrclass_));
for (; i < config->size(); ++i) {
// Extract the parameters
const ConstElementPtr dconf(config->get(i));
......@@ -126,7 +125,8 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
isc_throw(ConfigurationError, "The cache must be enabled "
"for the MasterFiles type");
}
new_data_sources.push_back(DataSourceInfo(rrclass_, *mem_sgmt_,
new_data_sources.push_back(DataSourceInfo(rrclass_,
ztable_segment,
true));
} else {
// Ask the factory to create the data source for us
......@@ -135,7 +135,7 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
// And put it into the vector
new_data_sources.push_back(DataSourceInfo(ds.first, ds.second,
want_cache, rrclass_,
*mem_sgmt_));
ztable_segment));
}
if (want_cache) {
......@@ -337,33 +337,93 @@ ConfigurableClientList::findInternal(MutableResult& candidate,
// and the need_updater parameter is true, get the zone there.
}
// We still provide this method for backward compatibility. But to not have
// duplicate code, it is a thin wrapper around getCachedZoneWriter only.
ConfigurableClientList::ReloadResult
ConfigurableClientList::reload(const Name& name) {
const ZoneWriterPair result(getCachedZoneWriter(name));
if (result.first != ZONE_SUCCESS) {
return (result.first);
}
assert(result.second);
result.second->load();
result.second->install();
result.second->cleanup();
return (ZONE_SUCCESS);
}
namespace {
// We would like to use boost::bind for this. However, the loadZoneData takes
// a reference, while we have a shared pointer to the iterator -- and we need
// to keep it alive as long as the ZoneWriter is alive. Therefore we can't
// really just dereference it and pass it, since it would get destroyed once
// the getCachedZoneWriter would end. This class holds the shared pointer
// alive, otherwise is mostly simple.
//
// It might be doable with nested boost::bind, but it would probably look
// more awkward and complicated than this.
class IteratorLoader {
public:
IteratorLoader(const RRClass& rrclass, const Name& name,
const ZoneIteratorPtr& iterator) :
rrclass_(rrclass),
name_(name),
iterator_(iterator)
{}
memory::ZoneData* operator()(util::MemorySegment& segment) {
return (memory::loadZoneData(segment, rrclass_, name_, *iterator_));
}
private:
const RRClass rrclass_;
const Name name_;
ZoneIteratorPtr iterator_;
};
// We can't use the loadZoneData function directly in boost::bind, since
// it is overloaded and the compiler can't choose the correct version
// reliably and fails. So we simply wrap it into an unique name.
memory::ZoneData*
loadZoneDataFromFile(util::MemorySegment& segment, const RRClass& rrclass,
const Name& name, const string& filename)
{
return (memory::loadZoneData(segment, rrclass, name, filename));
}
}
ConfigurableClientList::ZoneWriterPair
ConfigurableClientList::getCachedZoneWriter(const Name& name) {
if (!allow_cache_) {
return (CACHE_DISABLED);
return (ZoneWriterPair(CACHE_DISABLED, ZoneWriterPtr()));
}
// Try to find the correct zone.
MutableResult result;
findInternal(result, name, true, true);
if (!result.finder) {
return (ZONE_NOT_FOUND);
return (ZoneWriterPair(ZONE_NOT_FOUND, ZoneWriterPtr()));
}
// Try to convert the finder to in-memory one. If it is the cache,
// it should work.
// It is of a different type or there's no cache.
// Try to get the in-memory cache for the zone. If there's none,
// we can't provide the result.
if (!result.info->cache_) {
return (ZONE_NOT_CACHED);
return (ZoneWriterPair(ZONE_NOT_CACHED, ZoneWriterPtr()));
}
memory::LoadAction load_action;
DataSourceClient* client(result.info->data_src_client_);
if (client) {
// Now do the final reload. If it does not exist in client,
if (client != NULL) {
// Now finally provide the writer.
// If it does not exist in client,
// DataSourceError is thrown, which is exactly the result what we
// want, so no need to handle it.
ZoneIteratorPtr iterator(client->getIterator(name));
if (!iterator) {
isc_throw(isc::Unexpected, "Null iterator from " << name);
}
result.info->cache_->load(name, *iterator);
// And wrap the iterator into the correct functor (which
// keeps it alive as long as it is needed).
load_action = IteratorLoader(rrclass_, name, iterator);
} else {
// The MasterFiles special case
const string filename(result.info->cache_->getFileName(name));
......@@ -371,9 +431,14 @@ ConfigurableClientList::reload(const Name& name) {
isc_throw(isc::Unexpected, "Confused about missing both filename "
"and data source");
}
result.info->cache_->load(name, filename);
// boost::bind is enough here.
load_action = boost::bind(loadZoneDataFromFile, _1, rrclass_, name,
filename);
}
return (ZONE_RELOADED);
return (ZoneWriterPair(ZONE_SUCCESS,
ZoneWriterPtr(
result.info->ztable_segment_->
getZoneWriter(load_action, name, rrclass_))));
}
// NOTE: This function is not tested, it would be complicated. However, the
......
......@@ -21,6 +21,7 @@
#include <dns/rrclass.h>
#include <cc/data.h>
#include <exceptions/exceptions.h>
#include "memory/zone_table_segment.h"
#include <vector>
#include <boost/shared_ptr.hpp>
......@@ -42,6 +43,7 @@ typedef boost::shared_ptr<DataSourceClientContainer>
// and hide real definitions except for itself and tests.
namespace memory {
class InMemoryClient;
class ZoneWriter;
}
/// \brief The list of data source clients.
......@@ -219,9 +221,6 @@ public:
/// \param rrclass For which class the list should work.
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:
......@@ -271,7 +270,8 @@ public:
CACHE_DISABLED, ///< The cache is not enabled in this list.
ZONE_NOT_CACHED, ///< Zone is served directly, not from cache.
ZONE_NOT_FOUND, ///< Zone does not exist or not cached.
ZONE_RELOADED ///< The zone was successfully reloaded.
ZONE_SUCCESS ///< The zone was successfully reloaded or
/// the writer provided.
};
/// \brief Reloads a cached zone.
......@@ -288,6 +288,36 @@ public:
/// the original data source no longer contains the cached zone.
ReloadResult reload(const dns::Name& zone);
private:
/// \brief Convenience type shortcut
typedef boost::shared_ptr<memory::ZoneWriter> ZoneWriterPtr;
public:
/// \brief Return value of getCachedZoneWriter()
///
/// A pair containing status and the zone writer, for the
/// getCachedZoneWriter() method.
typedef std::pair<ReloadResult, ZoneWriterPtr> ZoneWriterPair;
/// \brief Return a zone writer that can be used to reload a zone.
///
/// This looks up a cached copy of zone and returns the ZoneWriter
/// that can be used to reload the content of the zone. This can
/// be used instead of reload() -- reload() works synchronously, which
/// is not what is needed every time.
///
/// \param zone The origin of the zone to reload.
/// \return The result has two parts. The first one is a status describing
/// if it worked or not (and in case it didn't, also why). If the
/// status is ZONE_SUCCESS, the second part contains a shared pointer
/// to the writer. If the status is anything else, the second part is
/// NULL.
/// \throw DataSourceError or anything else that the data source
/// containing the zone might throw is propagated.
/// \throw DataSourceError if something unexpected happens, like when
/// the original data source no longer contains the cached zone.
ZoneWriterPair getCachedZoneWriter(const dns::Name& zone);
/// \brief Implementation of the ClientList::find.
virtual FindResult find(const dns::Name& zone,
bool want_exact_match = false,
......@@ -299,12 +329,16 @@ public:
struct DataSourceInfo {
// Plays a role of default constructor too (for vector)
DataSourceInfo(const dns::RRClass& rrclass,
util::MemorySegment& mem_sgmt,
const boost::shared_ptr
<isc::datasrc::memory::ZoneTableSegment>&
ztable_segment,
bool has_cache = false);
DataSourceInfo(DataSourceClient* data_src_client,
const DataSourceClientContainerPtr& container,
bool has_cache, const dns::RRClass& rrclass,
util::MemorySegment& mem_sgmt);
const boost::shared_ptr
<isc::datasrc::memory::ZoneTableSegment>&
ztable_segment);
DataSourceClient* data_src_client_;
DataSourceClientContainerPtr container_;
......@@ -315,6 +349,7 @@ public:
// No other applications or tests may use it.
const DataSourceClient* getCacheClient() const;
boost::shared_ptr<memory::InMemoryClient> cache_;
boost::shared_ptr<memory::ZoneTableSegment> ztable_segment_;
};
/// \brief The collection of data sources.
......@@ -369,12 +404,6 @@ private:
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_;
......
......@@ -22,6 +22,7 @@
#include <datasrc/memory/treenode_rrset.h>
#include <datasrc/memory/zone_finder.h>
#include <datasrc/memory/zone_data_loader.h>
#include <datasrc/memory/zone_table_segment.h>
#include <util/memory_segment_local.h>
......@@ -42,12 +43,14 @@ using namespace std;
using namespace isc::dns;
using namespace isc::dns::rdata;
using namespace isc::datasrc::memory;
using namespace isc::util;
namespace isc {
namespace datasrc {
namespace memory {
using detail::SegmentObjectHolder;
using boost::shared_ptr;
namespace { // unnamed namespace
......@@ -64,25 +67,19 @@ public:
} // end of unnamed namespace
InMemoryClient::InMemoryClient(util::MemorySegment& mem_sgmt,
InMemoryClient::InMemoryClient(shared_ptr<ZoneTableSegment> ztable_segment,
RRClass rrclass) :
mem_sgmt_(mem_sgmt),
ztable_segment_(ztable_segment),
rrclass_(rrclass),
zone_count_(0)
{
SegmentObjectHolder<ZoneTable, RRClass> holder(
mem_sgmt_, ZoneTable::create(mem_sgmt_, rrclass), rrclass_);
file_name_tree_ = FileNameTree::create(mem_sgmt_, false);
zone_table_ = holder.release();
}
zone_count_(0),
file_name_tree_(FileNameTree::create(
ztable_segment_->getMemorySegment(), false))
{}
InMemoryClient::~InMemoryClient() {
MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
FileNameDeleter deleter;
FileNameTree::destroy(mem_sgmt_, file_name_tree_, deleter);
ZoneTable::destroy(mem_sgmt_, zone_table_, rrclass_);
FileNameTree::destroy(mem_sgmt, file_name_tree_, deleter);
}
result::Result
......@@ -90,8 +87,9 @@ InMemoryClient::loadInternal(const isc::dns::Name& zone_name,
const std::string& filename,
ZoneData* zone_data)
{
MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
SegmentObjectHolder<ZoneData, RRClass> holder(
mem_sgmt_, zone_data, rrclass_);
mem_sgmt, zone_data, rrclass_);
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
arg(zone_name).arg(rrclass_);
......@@ -99,7 +97,7 @@ InMemoryClient::loadInternal(const isc::dns::Name& zone_name,
// Set the filename in file_name_tree_ now, so that getFileName()
// can use it (during zone reloading).
FileNameNode* node(NULL);
switch (file_name_tree_->insert(mem_sgmt_, zone_name, &node)) {
switch (file_name_tree_->insert(mem_sgmt, zone_name, &node)) {
case FileNameTree::SUCCESS:
case FileNameTree::ALREADYEXISTS:
// These are OK
......@@ -114,9 +112,10 @@ InMemoryClient::loadInternal(const isc::dns::Name& zone_name,
const std::string* tstr = node->setData(new std::string(filename));
delete tstr;
const ZoneTable::AddResult result(zone_table_->addZone(mem_sgmt_, rrclass_,
zone_name,
holder.release()));
ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
const ZoneTable::AddResult result(zone_table->addZone(mem_sgmt, rrclass_,
zone_name,
holder.release()));
if (result.code == result::SUCCESS) {
// Only increment the zone count if the zone doesn't already
// exist.
......@@ -124,7 +123,7 @@ InMemoryClient::loadInternal(const isc::dns::Name& zone_name,
}
// Destroy the old instance of the zone if there was any
if (result.zone_data != NULL) {
ZoneData::destroy(mem_sgmt_, result.zone_data, rrclass_);
ZoneData::destroy(mem_sgmt, result.zone_data, rrclass_);
}
return (result.code);
......@@ -145,7 +144,8 @@ InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
LOG_DEBUG(logger, DBG_TRACE_DATA,
DATASRC_MEMORY_MEM_FIND_ZONE).arg(zone_name);
ZoneTable::FindResult result(zone_table_->findZone(zone_name));
const ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
const ZoneTable::FindResult result(zone_table->findZone(zone_name));
ZoneFinderPtr finder;
if (result.code != result::NOTFOUND) {
......@@ -157,7 +157,8 @@ InMemoryClient::findZone(const isc::dns::Name& zone_name) const {
const ZoneData*
InMemoryClient::findZoneData(const isc::dns::Name& zone_name) {
ZoneTable::FindResult result(zone_table_->findZone(zone_name));
const ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
const ZoneTable::FindResult result(zone_table->findZone(zone_name));
return (result.zone_data);
}
......@@ -168,14 +169,16 @@ InMemoryClient::load(const isc::dns::Name& zone_name,
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD).arg(zone_name).
arg(filename);
ZoneData* zone_data = loadZoneData(mem_sgmt_, rrclass_, zone_name,
MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
ZoneData* zone_data = loadZoneData(mem_sgmt, rrclass_, zone_name,
filename);
return (loadInternal(zone_name, filename, zone_data));
}
result::Result
InMemoryClient::load(const isc::dns::Name& zone_name, ZoneIterator& iterator) {
ZoneData* zone_data = loadZoneData(mem_sgmt_, rrclass_, zone_name,
MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
ZoneData* zone_data = loadZoneData(mem_sgmt, rrclass_, zone_name,
iterator);
return (loadInternal(zone_name, string(), zone_data));
}
......@@ -207,7 +210,7 @@ private:
bool separate_rrs_;
bool ready_;
public:
MemoryIterator(const RRClass rrclass,
MemoryIterator(const RRClass& rrclass,
const ZoneTree& tree, const Name& origin,
bool separate_rrs) :
rrclass_(rrclass),
......@@ -306,7 +309,8 @@ public:
ZoneIteratorPtr
InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
ZoneTable::FindResult result(zone_table_->findZone(name));
const ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
const ZoneTable::FindResult result(zone_table->findZone(name));
if (result.code != result::SUCCESS) {
isc_throw(DataSourceError, "No such zone: " + name.toText());
}
......
......@@ -22,6 +22,8 @@
#include <datasrc/memory/zone_table.h>
#include <datasrc/memory/zone_data.h>
#include <boost/shared_ptr.hpp>
#include <string>
namespace isc {
......@@ -34,6 +36,8 @@ class RRsetList;
namespace datasrc {
namespace memory {
class ZoneTableSegment;
/// \brief A data source client that holds all necessary data in memory.
///
/// The \c InMemoryClient class provides an access to a conceptual data
......@@ -60,7 +64,7 @@ public:
/// This constructor internally involves resource allocation, and if
/// it fails, a corresponding standard exception will be thrown.
/// It never throws an exception otherwise.
InMemoryClient(util::MemorySegment& mem_sgmt,
InMemoryClient(boost::shared_ptr<ZoneTableSegment> ztable_segment,
isc::dns::RRClass rrclass);
/// The destructor.
......@@ -186,10 +190,9 @@ private:
const std::string& filename,
ZoneData* zone_data);
util::MemorySegment& mem_sgmt_;
boost::shared_ptr<ZoneTableSegment> ztable_segment_;
const isc::dns::RRClass rrclass_;
unsigned int zone_count_;
ZoneTable* zone_table_;
FileNameTree* file_name_tree_;
};
......
......@@ -165,7 +165,7 @@ ZoneDataLoader::getCurrentName() const {
ZoneData*
loadZoneDataInternal(util::MemorySegment& mem_sgmt,
const isc::dns::RRClass rrclass,
const isc::dns::RRClass& rrclass,
const Name& zone_name,
boost::function<void(LoadCallback)> rrset_installer)
{
......@@ -223,7 +223,7 @@ generateRRsetFromIterator(ZoneIterator* iterator, LoadCallback callback) {
ZoneData*
loadZoneData(util::MemorySegment& mem_sgmt,
const isc::dns::RRClass rrclass,
const isc::dns::RRClass& rrclass,
const isc::dns::Name& zone_name,
const std::string& zone_file)
{
......@@ -236,7 +236,7 @@ loadZoneData(util::MemorySegment& mem_sgmt,
ZoneData*
loadZoneData(util::MemorySegment& mem_sgmt,
const isc::dns::RRClass rrclass,
const isc::dns::RRClass& rrclass,
const isc::dns::Name& zone_name,
ZoneIterator& iterator)
{
......
......@@ -48,7 +48,7 @@ struct EmptyZone : public InvalidParameter {
/// \param zone_name The name of the zone that is being loaded.
/// \param zone_file Filename which contains the zone data for \c zone_name.
ZoneData* loadZoneData(util::MemorySegment& mem_sgmt,
const isc::dns::RRClass rrclass,
const isc