summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJINMEI Tatuya <jinmei@isc.org>2012-07-20 01:03:25 +0200
committerJINMEI Tatuya <jinmei@isc.org>2012-07-20 01:03:25 +0200
commit2e99938fc9fd5db8fe35405cecfdc591b0156600 (patch)
tree31710bd127e2209fc64b4e698bd581f06a32c243
parentMerge #2051 (diff)
downloadkea-2e99938fc9fd5db8fe35405cecfdc591b0156600.tar.xz
kea-2e99938fc9fd5db8fe35405cecfdc591b0156600.zip
[2091] use memory segment for creating/destroying RBTrees.
many parts of the code had to be updated, but this is basically pretty straightforward refactoring (except for exception consideration).
-rw-r--r--src/lib/datasrc/memory_datasrc.cc65
-rw-r--r--src/lib/datasrc/rbtree.h51
-rw-r--r--src/lib/datasrc/tests/Makefile.am1
-rw-r--r--src/lib/datasrc/tests/rbtree_unittest.cc51
-rw-r--r--src/lib/datasrc/tests/zonetable_unittest.cc60
-rw-r--r--src/lib/datasrc/zonetable.cc41
-rw-r--r--src/lib/datasrc/zonetable.h39
7 files changed, 249 insertions, 59 deletions
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index c5122bf832..85739a0cac 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -14,6 +14,8 @@
#include <exceptions/exceptions.h>
+#include <util/memory_segment_local.h>
+
#include <dns/name.h>
#include <dns/nsec3hash.h>
#include <dns/rdataclass.h>
@@ -120,8 +122,14 @@ typedef NSEC3Map::value_type NSEC3Pair;
// Actual zone data: Essentially a set of zone's RRs. This is defined as
// a separate structure so that it'll be replaceable on reload.
struct ZoneData {
+ // Note: this code is not entirely exception safe; domains_storage_ could
+ // leak if the constructor throws. But since it's an intermediate version
+ // toward a full revision and the actual risk of leak should be very small
+ // in practice, we leave it open for now.
ZoneData(const Name& origin) :
- domains_(true),
+ domains_storage_(DomainTree::create(local_mem_sgmt_, true)),
+ domains_(*domains_storage_),
+ aux_wild_domains_(NULL),
origin_data_(NULL),
nsec_signed_(false)
{
@@ -131,8 +139,29 @@ struct ZoneData {
origin_data_->setData(origin_domain);
}
- // The main data (name + RRsets)
- DomainTree domains_;
+ ~ZoneData() {
+ DomainTree::destroy(local_mem_sgmt_, domains_storage_);
+ if (aux_wild_domains_ != NULL) {
+ DomainTree::destroy(local_mem_sgmt_, aux_wild_domains_);
+ }
+
+ // The assert may be too harsh, but we assume we'll discard (rewrite)
+ // this code soon enough. Until then this would be a good way to
+ // detect any memory leak.
+ assert(local_mem_sgmt_.allMemoryDeallocated());
+ }
+
+ // Memory segment to allocate/deallocate memory for the tree and the nodes.
+ // (This will eventually have to be abstract; for now we hardcode the
+ // specific derived segment class).
+ util::MemorySegmentLocal local_mem_sgmt_;
+
+ // The main data (name + RRsets). We use domains_ as a reference to
+ // domains_storage_ so we don't have to update the rest of the code;
+ // it will eventually have to be revised substantially, at which point
+ // we should clean this up, too.
+ DomainTree* domains_storage_;
+ DomainTree& domains_;
// An auxiliary tree for wildcard expanded data used in additional data
// processing. It contains names like "ns.wild.example" in the following
@@ -150,11 +179,11 @@ struct ZoneData {
// should be even empty, and even if it has content it should be very
// small.
private:
- scoped_ptr<DomainTree> aux_wild_domains_;
+ DomainTree* aux_wild_domains_;
public:
DomainTree& getAuxWildDomains() {
- if (!aux_wild_domains_) {
- aux_wild_domains_.reset(new DomainTree);
+ if (aux_wild_domains_ == NULL) {
+ aux_wild_domains_ = DomainTree::create(local_mem_sgmt_);
}
return (*aux_wild_domains_);
}
@@ -1782,9 +1811,23 @@ InMemoryZoneFinder::getFileName() const {
/// member variables later for new features.
class InMemoryClient::InMemoryClientImpl {
public:
- InMemoryClientImpl() : zone_count(0) {}
+ InMemoryClientImpl() : zone_count(0),
+ zone_table(ZoneTable::create(local_mem_sgmt_))
+ {}
+ ~InMemoryClientImpl() {
+ ZoneTable::destroy(local_mem_sgmt_, zone_table);
+
+ // see above for the assert().
+ assert(local_mem_sgmt_.allMemoryDeallocated());
+ }
+private:
+ // Memory segment to allocate/deallocate memory for the zone table.
+ // (This will eventually have to be abstract; for now we hardcode the
+ // specific derived segment class).
+ util::MemorySegmentLocal local_mem_sgmt_;
+public:
unsigned int zone_count;
- ZoneTable zone_table;
+ ZoneTable* zone_table;
};
InMemoryClient::InMemoryClient() : impl_(new InMemoryClientImpl)
@@ -1809,7 +1852,7 @@ InMemoryClient::addZone(ZoneFinderPtr zone_finder) {
LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEM_ADD_ZONE).
arg(zone_finder->getOrigin()).arg(zone_finder->getClass().toText());
- const result::Result result = impl_->zone_table.addZone(zone_finder);
+ const result::Result result = impl_->zone_table->addZone(zone_finder);
if (result == result::SUCCESS) {
++impl_->zone_count;
}
@@ -1819,7 +1862,7 @@ InMemoryClient::addZone(ZoneFinderPtr zone_finder) {
InMemoryClient::FindResult
InMemoryClient::findZone(const isc::dns::Name& name) const {
LOG_DEBUG(logger, DBG_TRACE_DATA, DATASRC_MEM_FIND_ZONE).arg(name);
- ZoneTable::FindResult result(impl_->zone_table.findZone(name));
+ ZoneTable::FindResult result(impl_->zone_table->findZone(name));
return (FindResult(result.code, result.zone));
}
@@ -1925,7 +1968,7 @@ public:
ZoneIteratorPtr
InMemoryClient::getIterator(const Name& name, bool separate_rrs) const {
- ZoneTable::FindResult result(impl_->zone_table.findZone(name));
+ ZoneTable::FindResult result(impl_->zone_table->findZone(name));
if (result.code != result::SUCCESS) {
isc_throw(DataSourceError, "No such zone: " + name.toText());
}
diff --git a/src/lib/datasrc/rbtree.h b/src/lib/datasrc/rbtree.h
index a78a399f34..f9a3b05d3a 100644
--- a/src/lib/datasrc/rbtree.h
+++ b/src/lib/datasrc/rbtree.h
@@ -24,11 +24,12 @@
/// to be used as a base data structure by other modules.
#include <exceptions/exceptions.h>
-
+#include <util/memory_segment.h>
#include <dns/name.h>
+
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
-#include <exceptions/exceptions.h>
+
#include <ostream>
#include <algorithm>
#include <cassert>
@@ -708,18 +709,60 @@ public:
ALREADYEXISTS,
};
+ /// \brief Allocate and construct \c RBTree
+ ///
+ /// This static method allocates memory for a new \c RBTree 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 RBTree is allocated.
+ static RBTree* create(util::MemorySegment& mem_sgmt,
+ bool return_empty_node = false)
+ {
+ void* p = mem_sgmt.allocate(sizeof(RBTree<T>));
+ return (new(p) RBTree<T>(return_empty_node));
+ }
+
+ /// \brief Destruct and deallocate \c RBTree
+ ///
+ /// \throw none
+ ///
+ /// \param mem_sgmt The \c MemorySegment that allocated memory for
+ /// \c rbtree.
+ /// \param rbtree A non NULL pointer to a valid \c RBTree 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, RBTree<T>* rbtree) {
+ rbtree->~RBTree<T>();
+ mem_sgmt.deallocate(rbtree, sizeof(RBTree<T>));
+ }
+
+private:
/// \name Constructor and Destructor
//@{
- /// The constructor.
+ /// \brief The constructor.
+ ///
+ /// An object of this class is always expected to be created by the
+ /// allocator (\c create()), so the constructor is hidden as private.
///
/// It never throws an exception.
explicit RBTree(bool returnEmptyNode = false);
- /// \b Note: RBTree is not intended to be inherited so the destructor
+ /// \brief The destructor.
+ ///
+ /// An object of this class is always expected to be destroyed explicitly
+ /// by \c destroy(), so the constructor is hidden as private.
+ ///
+ /// \note RBTree is not intended to be inherited so the destructor
/// is not virtual
~RBTree();
//@}
+public:
+
/// \name Find methods
///
/// \brief Find the node that gives a longest match against the given name.
diff --git a/src/lib/datasrc/tests/Makefile.am b/src/lib/datasrc/tests/Makefile.am
index 0d3ce1ad4d..5db12ea0a6 100644
--- a/src/lib/datasrc/tests/Makefile.am
+++ b/src/lib/datasrc/tests/Makefile.am
@@ -60,6 +60,7 @@ run_unittests_SOURCES += sqlite3_unittest.cc
run_unittests_SOURCES += sqlite3_accessor_unittest.cc
run_unittests_SOURCES += memory_datasrc_unittest.cc
run_unittests_SOURCES += rbnode_rrset_unittest.cc
+run_unittests_SOURCES += zonetable_unittest.cc
run_unittests_SOURCES += zone_finder_context_unittest.cc
run_unittests_SOURCES += faked_nsec3.h faked_nsec3.cc
run_unittests_SOURCES += client_list_unittest.cc
diff --git a/src/lib/datasrc/tests/rbtree_unittest.cc b/src/lib/datasrc/tests/rbtree_unittest.cc
index 8fc5a170d9..99caf3403d 100644
--- a/src/lib/datasrc/tests/rbtree_unittest.cc
+++ b/src/lib/datasrc/tests/rbtree_unittest.cc
@@ -16,6 +16,8 @@
#include <exceptions/exceptions.h>
+#include <util/memory_segment_local.h>
+
#include <dns/name.h>
#include <dns/rrclass.h>
#include <dns/rrset.h>
@@ -54,9 +56,30 @@ const size_t Name::MAX_LABELS;
*/
namespace {
+class TreeHolder {
+public:
+ TreeHolder(util::MemorySegment& mem_sgmt, RBTree<int>* tree) :
+ mem_sgmt_(mem_sgmt), tree_(tree)
+ {}
+ ~TreeHolder() {
+ RBTree<int>::destroy(mem_sgmt_, tree_);
+ }
+ RBTree<int>* get() { return (tree_); }
+private:
+ util::MemorySegment& mem_sgmt_;
+ RBTree<int>* tree_;
+};
+
class RBTreeTest : public::testing::Test {
protected:
- RBTreeTest() : rbtree_expose_empty_node(true), crbtnode(NULL) {
+ RBTreeTest() :
+ rbtree_holder_(mem_sgmt_, RBTree<int>::create(mem_sgmt_)),
+ rbtree_expose_empty_node_holder_(mem_sgmt_,
+ RBTree<int>::create(mem_sgmt_, true)),
+ rbtree(*rbtree_holder_.get()),
+ rbtree_expose_empty_node(*rbtree_expose_empty_node_holder_.get()),
+ crbtnode(NULL)
+ {
const char* const domain_names[] = {
"c", "b", "a", "x.d.e.f", "z.d.e.f", "g.h", "i.g.h", "o.w.y.d.e.f",
"j.z.d.e.f", "p.w.y.d.e.f", "q.w.y.d.e.f", "k.g.h"};
@@ -71,8 +94,11 @@ protected:
}
}
- RBTree<int> rbtree;
- RBTree<int> rbtree_expose_empty_node;
+ util::MemorySegmentLocal mem_sgmt_;
+ TreeHolder rbtree_holder_;
+ TreeHolder rbtree_expose_empty_node_holder_;
+ RBTree<int>& rbtree;
+ RBTree<int>& rbtree_expose_empty_node;
RBNode<int>* rbtnode;
const RBNode<int>* crbtnode;
};
@@ -275,7 +301,8 @@ TEST_F(RBTreeTest, chainLevel) {
// insert one node to the tree and find it. there should be exactly
// one level in the chain.
- RBTree<int> tree(true);
+ TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_, true));
+ RBTree<int>& tree(*tree_holder.get());
Name node_name(Name::ROOT_NAME());
EXPECT_EQ(RBTree<int>::SUCCESS, tree.insert(node_name, &rbtnode));
EXPECT_EQ(RBTree<int>::EXACTMATCH,
@@ -542,7 +569,8 @@ TEST_F(RBTreeTest, previousNode) {
{
SCOPED_TRACE("Lookup in empty tree");
// Just check it doesn't crash, etc.
- RBTree<int> empty_tree;
+ TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_));
+ RBTree<int>& empty_tree(*tree_holder.get());
EXPECT_EQ(RBTree<int>::NOTFOUND,
empty_tree.find(Name("x"), &node, node_path));
EXPECT_EQ(static_cast<void*>(NULL), node);
@@ -586,7 +614,8 @@ TEST_F(RBTreeTest, getLastComparedNode) {
EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
// A search for an empty tree should result in no 'last compared', too.
- RBTree<int> empty_tree;
+ TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_));
+ RBTree<int>& empty_tree(*tree_holder.get());
EXPECT_EQ(RBTree<int>::NOTFOUND,
empty_tree.find(Name("a"), &crbtnode, chain));
EXPECT_EQ(static_cast<void*>(NULL), chain.getLastComparedNode());
@@ -731,7 +760,8 @@ TEST_F(RBTreeTest, swap) {
size_t count1(rbtree.getNodeCount());
// Create second one and store state
- RBTree<int> tree2;
+ TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_));
+ RBTree<int>& tree2(*tree_holder.get());
RBNode<int>* node;
tree2.insert(Name("second"), &node);
std::ostringstream str2;
@@ -757,7 +787,8 @@ TEST_F(RBTreeTest, swap) {
// any domain names should be considered a subdomain of it), so it makes
// sense to test cases with the root zone explicitly.
TEST_F(RBTreeTest, root) {
- RBTree<int> root;
+ TreeHolder tree_holder(mem_sgmt_, RBTree<int>::create(mem_sgmt_));
+ RBTree<int>& root(*tree_holder.get());
root.insert(Name::ROOT_NAME(), &rbtnode);
rbtnode->setData(RBNode<int>::NodeDataPtr(new int(1)));
@@ -778,7 +809,9 @@ TEST_F(RBTreeTest, root) {
// Perform the same tests for the tree that allows matching against empty
// nodes.
- RBTree<int> root_emptyok(true);
+ TreeHolder tree_holder_emptyok(mem_sgmt_,
+ RBTree<int>::create(mem_sgmt_, true));
+ RBTree<int>& root_emptyok(*tree_holder_emptyok.get());
root_emptyok.insert(Name::ROOT_NAME(), &rbtnode);
EXPECT_EQ(RBTree<int>::EXACTMATCH,
root_emptyok.find(Name::ROOT_NAME(), &crbtnode));
diff --git a/src/lib/datasrc/tests/zonetable_unittest.cc b/src/lib/datasrc/tests/zonetable_unittest.cc
index fa74c0eb8c..bfc6d61c25 100644
--- a/src/lib/datasrc/tests/zonetable_unittest.cc
+++ b/src/lib/datasrc/tests/zonetable_unittest.cc
@@ -14,6 +14,8 @@
#include <exceptions/exceptions.h>
+#include <util/memory_segment_local.h>
+
#include <dns/name.h>
#include <dns/rrclass.h>
@@ -40,7 +42,7 @@ TEST(ZoneTest, init) {
TEST(ZoneTest, find) {
InMemoryZoneFinder zone(RRClass::IN(), Name("example.com"));
EXPECT_EQ(ZoneFinder::NXDOMAIN,
- zone.find(Name("www.example.com"), RRType::A()).code);
+ zone.find(Name("www.example.com"), RRType::A())->code);
}
class ZoneTableTest : public ::testing::Test {
@@ -50,68 +52,74 @@ protected:
zone2(new InMemoryZoneFinder(RRClass::IN(),
Name("example.net"))),
zone3(new InMemoryZoneFinder(RRClass::IN(),
- Name("example")))
+ Name("example"))),
+ zone_table(ZoneTable::create(local_mem_sgmt_))
{}
- ZoneTable zone_table;
+
+ ~ZoneTableTest() {
+ ZoneTable::destroy(local_mem_sgmt_, zone_table);
+ }
ZoneFinderPtr zone1, zone2, zone3;
+ isc::util::MemorySegmentLocal local_mem_sgmt_;
+ ZoneTable* zone_table;
};
TEST_F(ZoneTableTest, addZone) {
- EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone1));
- EXPECT_EQ(result::EXIST, zone_table.addZone(zone1));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(zone1));
+ EXPECT_EQ(result::EXIST, zone_table->addZone(zone1));
// names are compared in a case insensitive manner.
- EXPECT_EQ(result::EXIST, zone_table.addZone(
+ EXPECT_EQ(result::EXIST, zone_table->addZone(
ZoneFinderPtr(new InMemoryZoneFinder(RRClass::IN(),
Name("EXAMPLE.COM")))));
- EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone2));
- EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone3));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(zone2));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(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(
+ EXPECT_EQ(result::EXIST, zone_table->addZone(
ZoneFinderPtr(new InMemoryZoneFinder(RRClass::CH(),
Name("example.com")))));
/// Bogus zone (NULL)
- EXPECT_THROW(zone_table.addZone(ZoneFinderPtr()), isc::InvalidParameter);
+ EXPECT_THROW(zone_table->addZone(ZoneFinderPtr()), isc::InvalidParameter);
}
TEST_F(ZoneTableTest, DISABLED_removeZone) {
- EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone1));
- EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone2));
- EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone3));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(zone1));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(zone2));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(zone3));
- EXPECT_EQ(result::SUCCESS, zone_table.removeZone(Name("example.net")));
- EXPECT_EQ(result::NOTFOUND, zone_table.removeZone(Name("example.net")));
+ 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(zone1));
- EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone2));
- EXPECT_EQ(result::SUCCESS, zone_table.addZone(zone3));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(zone1));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(zone2));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(zone3));
- EXPECT_EQ(result::SUCCESS, zone_table.findZone(Name("example.com")).code);
+ EXPECT_EQ(result::SUCCESS, zone_table->findZone(Name("example.com")).code);
EXPECT_EQ(Name("example.com"),
- zone_table.findZone(Name("example.com")).zone->getOrigin());
+ zone_table->findZone(Name("example.com")).zone->getOrigin());
EXPECT_EQ(result::NOTFOUND,
- zone_table.findZone(Name("example.org")).code);
+ zone_table->findZone(Name("example.org")).code);
EXPECT_EQ(ConstZoneFinderPtr(),
- zone_table.findZone(Name("example.org")).zone);
+ 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);
+ zone_table->findZone(Name("www.example.com")).code);
EXPECT_EQ(Name("example.com"),
- zone_table.findZone(Name("www.example.com")).zone->getOrigin());
+ 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(zone_com));
+ EXPECT_EQ(result::SUCCESS, zone_table->addZone(zone_com));
EXPECT_EQ(Name("example.com"),
- zone_table.findZone(Name("www.example.com")).zone->getOrigin());
+ zone_table->findZone(Name("www.example.com")).zone->getOrigin());
}
}
diff --git a/src/lib/datasrc/zonetable.cc b/src/lib/datasrc/zonetable.cc
index 644861cc2c..f2e7e2ccd2 100644
--- a/src/lib/datasrc/zonetable.cc
+++ b/src/lib/datasrc/zonetable.cc
@@ -12,13 +12,15 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include <cassert>
+#include <util/memory_segment.h>
#include <dns/name.h>
#include <datasrc/zonetable.h>
#include <datasrc/rbtree.h>
+#include <cassert>
+
using namespace std;
using namespace isc::dns;
@@ -30,8 +32,14 @@ struct ZoneTable::ZoneTableImpl {
// Type aliases to make it shorter
typedef RBTree<ZoneFinder> ZoneTree;
typedef RBNode<ZoneFinder> ZoneNode;
+
// The actual storage
- ZoneTree zones_;
+ ZoneTree* zones_;
+
+ // Constructor
+ ZoneTableImpl(util::MemorySegment& mem_sgmt) :
+ zones_(ZoneTree::create(mem_sgmt))
+ {}
/*
* The implementation methods are here and just wrap-called in the
@@ -49,7 +57,7 @@ struct ZoneTable::ZoneTableImpl {
// Get the node where we put the zone
ZoneNode* node(NULL);
- switch (zones_.insert(zone->getOrigin(), &node)) {
+ switch (zones_->insert(zone->getOrigin(), &node)) {
// This is OK
case ZoneTree::SUCCESS:
case ZoneTree::ALREADYEXISTS:
@@ -76,7 +84,7 @@ struct ZoneTable::ZoneTableImpl {
result::Result my_result;
// Translate the return codes
- switch (zones_.find(name, &node)) {
+ switch (zones_->find(name, &node)) {
case ZoneTree::EXACTMATCH:
my_result = result::SUCCESS;
break;
@@ -100,13 +108,36 @@ struct ZoneTable::ZoneTableImpl {
}
};
-ZoneTable::ZoneTable() : impl_(new ZoneTableImpl)
+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(ZoneFinderPtr zone) {
return (impl_->addZone(zone));
diff --git a/src/lib/datasrc/zonetable.h b/src/lib/datasrc/zonetable.h
index 5a3448045d..427d1a9b00 100644
--- a/src/lib/datasrc/zonetable.h
+++ b/src/lib/datasrc/zonetable.h
@@ -15,12 +15,14 @@
#ifndef __ZONETABLE_H
#define __ZONETABLE_H 1
-#include <boost/shared_ptr.hpp>
+#include <util/memory_segment.h>
#include <dns/rrset.h>
#include <datasrc/zone.h>
+#include <boost/shared_ptr.hpp>
+
namespace isc {
namespace dns {
class Name;
@@ -58,18 +60,47 @@ private:
ZoneTable(const ZoneTable& source);
ZoneTable& operator=(const ZoneTable& source);
-public:
- /// Default constructor.
+ /// 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();
+ 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