BIND 10 master, updated. 650c6ce282800e712fb378741638ac66240d59c0 Merge branch 'trac2850_2'

BIND 10 source code commits bind10-changes at lists.isc.org
Tue May 14 13:36:03 UTC 2013


The branch, master has been updated
       via  650c6ce282800e712fb378741638ac66240d59c0 (commit)
       via  7ad877ff1d3b88b2b8430a80f6102590837c2e74 (commit)
       via  c312fa4f4866b21aca35bc4987f8f0e83b198ef9 (commit)
       via  211389e129c7c27129fda481deda0dd649630a98 (commit)
       via  de6e68cf258f9349795368f5bf773f8911a79acf (commit)
       via  3c98ade56f07c44740f1bde2e37f8fdc9842bd18 (commit)
       via  bf30f052334922f729c8805f109f838ec1a126b9 (commit)
       via  17590957db6a352e86c208c3520a340349b340ea (commit)
       via  e2889aabb93e201bfaf49046472ffc42df8b4b77 (commit)
       via  9e44958839b3f9d8fbe6cbd1f0c8f711763396fb (commit)
       via  76e6edb548bfa6eb3df302ddd74ecff71caee3eb (commit)
       via  6bff7db76bded2e571e2ee827c776c45bdcd6c6d (commit)
       via  5bfdcfaa4a495e36255de546354d1673e4581d3c (commit)
       via  46bf6c05bd7c5aa7cc79af834843db68cb6b5471 (commit)
       via  c6cadebf7b86855a7da91f14f66bd7d605ee13ea (commit)
       via  8ba0a7bc496c135f80c71bf035fcca0687a16e27 (commit)
       via  db8cec0cd9505bd0ab091e6258822dcb2891338c (commit)
       via  bc3d482930fad8d97305f07e116093ace8110e9c (commit)
       via  32d750c6674613bd630eb1e724adc82b8ec8a622 (commit)
       via  7bea7dd8c15ce158908b8c42c93533089d12da8a (commit)
       via  4cac3ddb232eac0e52451c0aff718f3207fc7977 (commit)
       via  eda6761d2607385c10bb6a9e8bdc5c1209405093 (commit)
       via  8d9a833a05515867753578af948c537a4d8ad127 (commit)
       via  14a35130eaf81efdc8483fdfb1b8eabbc97653be (commit)
       via  cea0d1058d5b96e616ce8f71afd0b45a1f81b103 (commit)
       via  3ebd4b039b2596328c1c112398a9e629c9a73001 (commit)
       via  299f1f5ff94bb77306019c1d26d12e57a30a9ab4 (commit)
       via  ad0e3e26471403d9b019352132cbc04b2c1c055c (commit)
       via  2015f7356237f5004c6aa9b678b442575476681b (commit)
       via  a7dac3f7ff64093a4958710cc45a7dc28f727182 (commit)
       via  e6d1be1a6718874ab37b0f403c3e266c90bcdf87 (commit)
       via  148c5bbf6132ac5b149a0a97286f13ec212443cb (commit)
       via  4542e8960d4accbef74ac41e5082209f3776b5b8 (commit)
       via  56d109e8a0c5d46ac542870723ba324aa2425b88 (commit)
       via  9d90db228e26173b0781d090ea2b0e078c7969f6 (commit)
       via  d003ebd54cb9b0454e60af6270177e202c766892 (commit)
       via  9b930275a2a875d91aa425cf8bcbe552c5bee453 (commit)
       via  f7cfb3332667e260a60660af23290087fd0c4fbc (commit)
       via  1fd14dfefcd2339d9dea25b30dc9204bd10548f4 (commit)
       via  39fba2a15cb200dbe77ae3c9a4d894496f9eee66 (commit)
       via  557794895c01555c32906ad8422d5d6fbb878fe8 (commit)
       via  3af2603f0f08ad709590766051eea370c470642f (commit)
       via  03ce449ee10c5a8d8f60a68cb42839b9ae63ec00 (commit)
       via  9784a1841ff7a5f08c92a0c646bbc4ff9a0b4ccb (commit)
       via  5082c255bbeb8c83f9ab08d4e28429cc271b2fec (commit)
       via  3599c07417b1bcf40ae8e59959278b4a59ede827 (commit)
       via  043b3d2952712cd61e7ffb4f73f3253d11ce6bd2 (commit)
       via  b5cd040334461d9f5ab0f1267d505bc7ac3e0ca9 (commit)
       via  54a1d02e8816b53e0d4ab77817380946ddf156d4 (commit)
       via  7d1a2ca88d0daac2779ecccf50c4308eb0914ebd (commit)
       via  ad233427c14503e34980780761700596f13e14f4 (commit)
       via  0dccb67c0e49f3448e7fc3da7a5e414113bf36dc (commit)
       via  622d3e7123555d0115149e3f4527dbe5f11da864 (commit)
       via  6bb2e2de9bc899e31c8233c1ef74e8ff79c1bccc (commit)
       via  366cf13a9ca23ea0ace26677754d1968106c277b (commit)
       via  186195174b0d8256da12f91395f8e57c17ea6a7c (commit)
       via  6548cfede8e4f8fb9457eb62b0c458969a358155 (commit)
       via  02c2f7f80e6d858233a595cae04842666fbd29c8 (commit)
       via  ca15d37a2e8d6eff63b52eb5fef0e8d3bdb3e2c2 (commit)
       via  10386454c422828a5d46a3b927b1c284e6216372 (commit)
       via  f41e4c3104480b6a8a6aa08cc5c28cf71a13a3bc (commit)
       via  b30eb9348603cb2181794ca00acbc1bcffa54db7 (commit)
       via  ac473294894ef65cd01174114183a42657d6151d (commit)
       via  3456e30bce45c286b120d176a517ca88e9e21b1c (commit)
       via  4325f3dfd81569be4ef09a84cf0fb74246a5b666 (commit)
       via  74bad1ad71292fa998f14ad3953236f7e979efac (commit)
       via  035fbe1da0e77a45d108046e5399c5a676e098a8 (commit)
       via  5d65c74c127243790200028375786fced2bd1ad7 (commit)
       via  2b96d4487c517ab209a1ca5fce4af877fecae0a7 (commit)
       via  79fe8bd49de676e941f804350bde4115ab454124 (commit)
       via  1815740f4154dea79aa15ec64cffe2f5d010769d (commit)
       via  0b7af64f6b3a567371a38ceb83001008dcc8f4b2 (commit)
       via  a1d81937904fd5f646f40c655975855aea5985d4 (commit)
       via  26326a8f0780a2603c7ff7268998fbcce7bc5dbc (commit)
       via  7a49270e4d0117b5432dfedec70e41a9c399745a (commit)
       via  c45efc1b129fc4b64d79040e0bec33f08658b170 (commit)
       via  4a5506ec8f3474513c7de10969628385cec138b2 (commit)
       via  e646d8af58ff6b9863a89ae65b6244275405bce0 (commit)
       via  68343c845a46a9be3f38c38388ec02a8bb4ef884 (commit)
       via  10f2ae4625a238a4899372432df13d29eca9f9b3 (commit)
       via  bd7e56727b6d8228f2fdc685bff3a18349415c69 (commit)
       via  85873bf8615dc643db8619414e417dffef827c4f (commit)
       via  909a05ac4185589eb2304d815b5ccd108f92f4b7 (commit)
       via  1453084c9e0ecc7c3663678031f3d19c5f91adff (commit)
       via  fa4c5b912c4e4deab0e42af46eaeb6ef3e41df72 (commit)
       via  53a1410acc5726fe8ed83ded19b65be7c9002ee1 (commit)
       via  832eddac5d9724af4b228cb123a84ed7ddae0473 (commit)
       via  c055314da48eaadb3f88b64eda17263fc6b387fa (commit)
       via  d86119932d1b6f2674f3685515c35be147f2d327 (commit)
       via  846996720639e0a37682312641bd6ed504870488 (commit)
       via  58a2bdc6b084fdb4ac57726b305f49463370cc2c (commit)
       via  08f6a3e96b00395c6132b7558ca8c3e0764e7adf (commit)
      from  69cdc5f74d067196ec35daad43f842f716897bcc (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 650c6ce282800e712fb378741638ac66240d59c0
Merge: 69cdc5f 7ad877f
Author: Mukund Sivaraman <muks at isc.org>
Date:   Tue May 14 18:50:29 2013 +0530

    Merge branch 'trac2850_2'

-----------------------------------------------------------------------

Summary of changes:
 configure.ac                                       |    3 +
 src/lib/datasrc/client_list.cc                     |   17 +-
 src/lib/datasrc/memory/Makefile.am                 |    8 +-
 src/lib/datasrc/memory/zone_table_segment.cc       |   10 +
 src/lib/datasrc/memory/zone_table_segment.h        |  260 ++++++++-
 src/lib/datasrc/memory/zone_table_segment_local.cc |   37 +-
 src/lib/datasrc/memory/zone_table_segment_local.h  |   69 ++-
 .../datasrc/memory/zone_table_segment_mapped.cc    |  386 +++++++++++++
 src/lib/datasrc/memory/zone_table_segment_mapped.h |  150 +++++
 .../{zone_writer_local.cc => zone_writer.cc}       |   46 +-
 src/lib/datasrc/memory/zone_writer.h               |   61 +-
 src/lib/datasrc/memory/zone_writer_local.h         |   95 ----
 src/lib/datasrc/tests/client_list_unittest.cc      |    3 +-
 src/lib/datasrc/tests/memory/Makefile.am           |   10 +-
 .../datasrc/tests/memory/memory_client_unittest.cc |   12 +-
 ...memory_segment_test.h => memory_segment_mock.h} |    4 +-
 .../tests/memory/rrset_collection_unittest.cc      |    6 +-
 .../tests/memory/zone_data_loader_unittest.cc      |    4 +-
 src/lib/datasrc/tests/memory/zone_data_unittest.cc |    7 +-
 .../tests/memory/zone_data_updater_unittest.cc     |    4 +-
 .../datasrc/tests/memory/zone_finder_unittest.cc   |   10 +-
 src/lib/datasrc/tests/memory/zone_loader_util.cc   |   25 +-
 .../memory/zone_table_segment_mapped_unittest.cc   |  590 ++++++++++++++++++++
 ...le_segment_test.h => zone_table_segment_mock.h} |   79 +--
 .../tests/memory/zone_table_segment_unittest.cc    |   54 +-
 .../datasrc/tests/memory/zone_table_unittest.cc    |    6 +-
 .../datasrc/tests/memory/zone_writer_unittest.cc   |  103 +++-
 .../datasrc/tests/zone_finder_context_unittest.cc  |   14 +-
 src/lib/datasrc/tests/zone_loader_unittest.cc      |    6 +-
 src/lib/util/memory_segment.h                      |   20 +-
 src/lib/util/memory_segment_local.cc               |   13 +-
 src/lib/util/memory_segment_local.h                |    4 +-
 src/lib/util/memory_segment_mapped.cc              |   75 ++-
 src/lib/util/memory_segment_mapped.h               |    4 +-
 src/lib/util/random/random_number_generator.h      |   10 +-
 .../util/tests/memory_segment_common_unittest.cc   |   24 +-
 .../util/tests/memory_segment_mapped_unittest.cc   |   66 ++-
 .../util/tests/random_number_generator_unittest.cc |   34 +-
 38 files changed, 1926 insertions(+), 403 deletions(-)
 create mode 100644 src/lib/datasrc/memory/zone_table_segment_mapped.cc
 create mode 100644 src/lib/datasrc/memory/zone_table_segment_mapped.h
 rename src/lib/datasrc/memory/{zone_writer_local.cc => zone_writer.cc} (66%)
 delete mode 100644 src/lib/datasrc/memory/zone_writer_local.h
 rename src/lib/datasrc/tests/memory/{memory_segment_test.h => memory_segment_mock.h} (95%)
 create mode 100644 src/lib/datasrc/tests/memory/zone_table_segment_mapped_unittest.cc
 rename src/lib/datasrc/tests/memory/{zone_table_segment_test.h => zone_table_segment_mock.h} (51%)

-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 1b5e39b..159841f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -891,6 +891,9 @@ if test X$use_shared_memory = Xyes -a "$BOOST_MAPPED_FILE_WOULDFAIL" = "yes"; th
     AC_MSG_ERROR([Boost shared memory does not compile on this system.  If you don't need it (most normal users won't) build without it by rerunning this script with --without-shared-memory; using a different compiler or a different version of Boost may also help.])
 fi
 AM_CONDITIONAL([USE_SHARED_MEMORY], [test x$use_shared_memory = xyes])
+if test "x$use_shared_memory" = "xyes"; then
+    AC_DEFINE(USE_SHARED_MEMORY, 1, [Define to 1 if shared memory support is enabled])
+fi
 AC_SUBST(BOOST_MAPPED_FILE_CXXFLAG)
 
 # Add some default CPP flags needed for Boost, identified by the AX macro.
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
index c9bdee0..19f12c0 100644
--- a/src/lib/datasrc/client_list.cc
+++ b/src/lib/datasrc/client_list.cc
@@ -153,13 +153,13 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                               << zname << "/" << rrclass_);
                 }
                 assert(load_action); // in this loop this should be always true
-                boost::scoped_ptr<memory::ZoneWriter> writer;
                 try {
-                    writer.reset(new_data_sources.back().ztable_segment_->
-                                 getZoneWriter(load_action, zname, rrclass_));
-                    writer->load();
-                    writer->install();
-                    writer->cleanup();
+                    memory::ZoneWriter writer(
+                        *new_data_sources.back().ztable_segment_,
+                        load_action, zname, rrclass_);
+                    writer.load();
+                    writer.install();
+                    writer.cleanup();
                 } catch (const ZoneLoaderException& e) {
                     LOG_ERROR(logger, DATASRC_LOAD_ZONE_ERROR)
                         .arg(zname).arg(rrclass_).arg(name).arg(e.what());
@@ -348,8 +348,9 @@ ConfigurableClientList::getCachedZoneWriter(const Name& name) {
     }
     return (ZoneWriterPair(ZONE_SUCCESS,
                            ZoneWriterPtr(
-                               result.info->ztable_segment_->
-                               getZoneWriter(load_action, name, rrclass_))));
+                               new memory::ZoneWriter(
+                                   *result.info->ztable_segment_,
+                                   load_action, name, rrclass_))));
 }
 
 // NOTE: This function is not tested, it would be complicated. However, the
diff --git a/src/lib/datasrc/memory/Makefile.am b/src/lib/datasrc/memory/Makefile.am
index c0ee688..44fe806 100644
--- a/src/lib/datasrc/memory/Makefile.am
+++ b/src/lib/datasrc/memory/Makefile.am
@@ -22,11 +22,15 @@ libdatasrc_memory_la_SOURCES += zone_table.h zone_table.cc
 libdatasrc_memory_la_SOURCES += zone_finder.h zone_finder.cc
 libdatasrc_memory_la_SOURCES += zone_table_segment.h zone_table_segment.cc
 libdatasrc_memory_la_SOURCES += zone_table_segment_local.h zone_table_segment_local.cc
+
+if USE_SHARED_MEMORY
+libdatasrc_memory_la_SOURCES += zone_table_segment_mapped.h zone_table_segment_mapped.cc
+endif
+
 libdatasrc_memory_la_SOURCES += zone_data_updater.h zone_data_updater.cc
 libdatasrc_memory_la_SOURCES += zone_data_loader.h zone_data_loader.cc
 libdatasrc_memory_la_SOURCES += memory_client.h memory_client.cc
-libdatasrc_memory_la_SOURCES += zone_writer.h
-libdatasrc_memory_la_SOURCES += zone_writer_local.h zone_writer_local.cc
+libdatasrc_memory_la_SOURCES += zone_writer.h zone_writer.cc
 libdatasrc_memory_la_SOURCES += load_action.h
 libdatasrc_memory_la_SOURCES += util_internal.h
 
diff --git a/src/lib/datasrc/memory/zone_table_segment.cc b/src/lib/datasrc/memory/zone_table_segment.cc
index 1253102..2e1a1dc 100644
--- a/src/lib/datasrc/memory/zone_table_segment.cc
+++ b/src/lib/datasrc/memory/zone_table_segment.cc
@@ -12,8 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include "config.h"
+
 #include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/memory/zone_table_segment_local.h>
+#ifdef USE_SHARED_MEMORY
+#include <datasrc/memory/zone_table_segment_mapped.h>
+#endif
+#include <datasrc/memory/zone_writer.h>
 
 #include <string>
 
@@ -30,6 +36,10 @@ ZoneTableSegment::create(const RRClass& rrclass, const std::string& type) {
     // Until that it becomes a real issue we won't be too smart.
     if (type == "local") {
         return (new ZoneTableSegmentLocal(rrclass));
+#ifdef USE_SHARED_MEMORY
+    } else if (type == "mapped") {
+        return (new ZoneTableSegmentMapped(rrclass));
+#endif
     }
     isc_throw(UnknownSegmentType, "Zone table segment type not supported: "
               << type);
diff --git a/src/lib/datasrc/memory/zone_table_segment.h b/src/lib/datasrc/memory/zone_table_segment.h
index 1440a2e..4761c46 100644
--- a/src/lib/datasrc/memory/zone_table_segment.h
+++ b/src/lib/datasrc/memory/zone_table_segment.h
@@ -40,8 +40,8 @@ namespace datasrc {
 namespace memory {
 class ZoneWriter;
 
-/// \brief Exception thrown when unknown or unsupported type of zone table
-/// segment is specified.
+/// \brief Exception thrown when unknown or unsupported type of
+/// ZoneTableSegment is asked to be created.
 class UnknownSegmentType : public Exception {
 public:
     UnknownSegmentType(const char* file, size_t line, const char* what) :
@@ -49,12 +49,36 @@ public:
     {}
 };
 
+/// \brief Exception thrown when a \c reset() on a \c ZoneTableSegment
+/// fails (due to various reasons). When this exception is thrown, a
+/// strong exception safety guarantee is provided, and the
+/// \c ZoneTableSegment is usable as before.
+class ResetFailed : public isc::Exception {
+public:
+    ResetFailed(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what)
+    {}
+};
+
+/// \brief Exception thrown when a \c reset() on a \c ZoneTableSegment
+/// fails (due to various reasons), and it was not able to preserve the
+/// state of the \c ZoneTableSegment. When this exception is thrown,
+/// only basic exception safety guarantee is provided and the
+/// \c ZoneTableSegment must be expected as cleared.
+class ResetFailedAndSegmentCleared : public isc::Exception {
+public:
+    ResetFailedAndSegmentCleared(const char* file, size_t line,
+                                 const char* what) :
+        isc::Exception(file, line, what)
+    {}
+};
+
 /// \brief Memory-management independent entry point that contains a
 /// pointer to a zone table in memory.
 ///
-/// An instance of this type lives inside a ZoneTableSegment
-/// implementation. It contains an offset pointer to the zone table (a
-/// map from domain names to zone locators) in memory.
+/// An instance of this type lives inside a \c ZoneTableSegment
+/// implementation. It contains an offset pointer to the \c ZoneTable (a
+/// map from domain names to zone locators) in the \c ZoneTableSegment.
 struct ZoneTableHeader {
 public:
     ZoneTableHeader(ZoneTable* zone_table) :
@@ -74,14 +98,20 @@ private:
     boost::interprocess::offset_ptr<ZoneTable> table_;
 };
 
-/// \brief Manages a ZoneTableHeader, an entry point into a table of
+/// \brief Manages a \c ZoneTableHeader, an entry point into a table of
 /// zones
 ///
 /// This class specifies an interface for derived implementations which
-/// return a pointer to an object of type ZoneTableHeader, an entry
+/// return a pointer to an object of type \c ZoneTableHeader, an entry
 /// point into a table of zones regardless of the underlying memory
-/// management implementation. Derived classes would implement the
-/// interface for specific memory-implementation behavior.
+/// management implementation. Derived classes implement the interface
+/// for the specific memory-implementation behavior.
+///
+/// Note: At some point in the future, methods such as \c reset(),
+/// \c clear(), \c resetHeader(), \c getHeader(), \c isWritable(),
+/// \c isUsable() may become non-virtual methods. Such a change should
+/// not affect any code that uses this class, but please be aware of
+/// such plans.
 class ZoneTableSegment {
 protected:
     /// \brief Protected constructor
@@ -89,24 +119,63 @@ protected:
     /// An instance implementing this interface is expected to be
     /// created by the factory method (\c create()), so this constructor
     /// is protected.
-    ZoneTableSegment(isc::dns::RRClass)
+    ZoneTableSegment(const isc::dns::RRClass&)
     {}
 public:
     /// \brief Destructor
     virtual ~ZoneTableSegment() {}
 
-    /// \brief Return the ZoneTableHeader for the zone table segment.
+    /// \brief Return a string name for the \c ZoneTableSegment
+    /// implementation.
+    ///
+    /// \throw None This method's implementations must be
+    /// exception-free.
+    virtual const std::string& getImplType() const = 0;
+
+    /// \brief Return the \c ZoneTableHeader for the zone table segment.
+    ///
+    /// As long as \c isUsable() returns true, this method must always
+    /// succeed without throwing an exception.  If \c isUsable() returns
+    /// false, a derived class implementation can throw
+    /// \c isc::InvalidOperation depending on its implementation
+    /// details. Applications are generally expected to call this
+    /// method only when \c isUsable() returns true (either by making
+    /// sure explicitly or by some other indirect means).
+    ///
+    /// \throw isc::InvalidOperation may be thrown by some
+    /// implementations if this method is called without calling
+    /// \c reset() successfully first.
     virtual ZoneTableHeader& getHeader() = 0;
 
-    /// \brief const version of \c getHeader().
+    /// \brief \c const version of \c getHeader().
+    ///
+    /// See the non- \c const version for documentation.
     virtual const ZoneTableHeader& getHeader() const = 0;
 
     /// \brief Return the MemorySegment for the zone table segment.
+    ///
+    /// \throw isc::InvalidOperation may be thrown by some
+    /// implementations if this method is called without calling
+    /// \c reset() successfully first.
     virtual isc::util::MemorySegment& getMemorySegment() = 0;
 
-    /// \brief Create an instance depending on the memory segment model
+    /// \brief Return true if the segment is writable.
+    ///
+    /// The user of the zone table segment will load or update zones
+    /// into the segment only for writable ones.  The precise definition
+    /// of "writability" differs in different derived classes (see
+    /// derived class documentation).  In general, however, the user
+    /// should only rely on this interface rather than assume a specific
+    /// definition for a specific type of segment.
     ///
-    /// This is a factory method to create a derived ZoneTableSegment
+    /// \throw None This method's implementations must be
+    /// exception-free.
+    virtual bool isWritable() const = 0;
+
+    /// \brief Create an instance depending on the requested memory
+    /// segment implementation type.
+    ///
+    /// This is a factory method to create a derived \c ZoneTableSegment
     /// object based on the \c config passed. The method returns a
     /// dynamically-allocated object. The caller is responsible for
     /// destroying it with \c ZoneTableSegment::destroy().
@@ -115,33 +184,162 @@ public:
     /// \c config is not known or not supported in this implementation.
     ///
     /// \param rrclass The RR class of the zones to be maintained in the table.
-    /// \param type The memory segment type used for the zone table segment.
-    /// \return Returns a ZoneTableSegment object of the specified type.
+    /// \param type The memory segment type to be used.
+    /// \return Returns a \c ZoneTableSegment object of the specified type.
     static ZoneTableSegment* create(const isc::dns::RRClass& rrclass,
                                     const std::string& type);
 
-    /// \brief Destroy a ZoneTableSegment
+    /// \brief Destroy a \c ZoneTableSegment
     ///
-    /// This method destroys the passed ZoneTableSegment. It must be
-    /// passed a segment previously created by \c ZoneTableSegment::create().
+    /// This method destroys the passed \c ZoneTableSegment. It must be
+    /// passed a segment previously created by
+    /// \c ZoneTableSegment::create().
     ///
     /// \param segment The segment to destroy.
     static void destroy(ZoneTableSegment* segment);
 
-    /// \brief Create a zone write corresponding to this segment
+    /// \brief The mode using which to create a MemorySegment.
+    ///
+    /// Here, a \c MemorySegment (see its class documentation) is an
+    /// interface to a storage area, and provides operations to allocate
+    /// and deallocate from that storage area, and also to look up
+    /// addresses in that area. The storage area can be a buffer in
+    /// memory, a file on disk, or some kind of shared memory depending
+    /// on the \c MemorySegment implementation being used.  In every
+    /// case in the documentation below, when we mention \c
+    /// MemorySegment, we mean both the \c MemorySegment object which
+    /// interfaces to the storage area and the contents of the
+    /// associated storage area.
+    ///
+    /// - CREATE: If the \c MemorySegment's storage area doesn't exist,
+    ///           create it. If it exists, overwrite it with a new
+    ///           storage area (which does not remember old data). In
+    ///           both cases, create a \c MemorySegment for it in
+    ///           read+write mode.
     ///
-    /// This creates a new write that can be used to update zones
-    /// inside this zone table segment.
+    /// - READ_WRITE: If the \c MemorySegment's storage area doesn't
+    ///               exist, create it. If it exists, use the existing
+    ///               storage area as-is (keeping the existing data
+    ///               intact). In both cases, create a \c MemorySegment
+    ///               for it in read+write mode.
+    ///
+    /// - READ_ONLY: If the \c MemorySegment's storage area doesn't
+    ///              exist, throw an exception. If it exists, create a
+    ///              \c MemorySegment for it in read-only mode.
+    enum MemorySegmentOpenMode {
+        CREATE,
+        READ_WRITE,
+        READ_ONLY
+    };
+
+    /// \brief Close the current \c MemorySegment (if open) and open the
+    /// requested one.
+    ///
+    /// When we talk about "opening" a \c MemorySegment, it means to
+    /// construct a usable \c MemorySegment object that interfaces to
+    /// the actual memory storage area. "Closing" is the opposite
+    /// operation of opening.
+    ///
+    /// In case opening the new \c MemorySegment fails for some reason,
+    /// one of the following documented (further below) exceptions may
+    /// be thrown. In case failures occur, implementations of this
+    /// method must strictly provide the associated behavior as follows
+    /// and in the exception documentation below.  Code that uses
+    /// \c ZoneTableSegment would depend on such assurances.
+    ///
+    /// First, in case a \c ZoneTableSegment was reset successfully
+    /// before and is currently usable (\c isUsable() returns true), and
+    /// an invalid configuration is passed in \c params to \c reset(),
+    /// the isc::InvalidParameter exception must be thrown. In this
+    /// case, a strong exception safety guarantee must be provided, and
+    /// the \c ZoneTableSegment must be usable as before.
+    ///
+    /// In case a \c ZoneTableSegment was reset successfully before and
+    /// is currently usable (\c isUsable() returns true), and the attempt
+    /// to reset to a different \c MemorySegment storage area fails,
+    /// the \c ResetFailed exception must be thrown. In this
+    /// case, a strong exception safety guarantee must be provided, and
+    /// the \c ZoneTableSegment must be usable as before.
+    ///
+    /// In case a \c ZoneTableSegment was reset successfully before and
+    /// is currently usable (\c isUsable() returns true), and the attempt
+    /// to reset to the same \c MemorySegment storage area fails, the
+    /// \c ResetFailedAndSegmentCleared exception must be thrown. In
+    /// this case, only basic exception safety guarantee is provided and
+    /// the \c ZoneTableSegment must be expected as cleared.
+    ///
+    /// In case a \c ZoneTableSegment was not reset successfully before
+    /// and is currently not usable (\c isUsable() returns false), and
+    /// the attempt to reset fails, the \c ResetFailed exception must be
+    /// thrown. In this unique case, a strong exception safety guarantee
+    /// is provided by default, as the \c ZoneTableSegment was clear
+    /// previously, and remains cleared.
+    ///
+    /// In all other cases, \c ZoneTableSegment contents can be expected
+    /// as reset.
+    ///
+    /// See \c MemorySegmentOpenMode for a definition of "storage area"
+    /// and the various modes in which a \c MemorySegment can be opened.
+    ///
+    /// \c params should contain an implementation-defined
+    /// configuration. See the specific \c ZoneTableSegment
+    /// implementation class for details of what to pass in this
+    /// argument.
+    ///
+    /// \throw isc::InvalidParameter if the configuration in \c params
+    /// has incorrect syntax, but there is a strong exception safety
+    /// guarantee and the \c ZoneTableSegment is usable or unusable as
+    /// before.
+    ///
+    /// \throw ResetFailed if there was a problem in opening the new
+    /// memory store, but there is a strong exception safety guarantee
+    /// and the \c ZoneTableSegment is usable or unusable as before.
+    ///
+    /// \throw ResetFailedAndSegmentCleared if there was a problem in
+    /// opening the new memory store, but there is only a basic
+    /// exception safety guarantee and the \c ZoneTableSegment is not
+    /// usable without a further successful \c reset().
+    ///
+    /// \throw isc::NotImplemented Some implementations may choose to
+    /// not implement this method. In this case, there must be a strong
+    /// exception safety guarantee and the \c ZoneTableSegment is usable
+    /// or unusable as before.
+    ///
+    /// \param mode The open mode (see the MemorySegmentOpenMode
+    /// documentation).
+    /// \param params An element containing implementation-specific
+    /// config (see the description).
+    virtual void reset(MemorySegmentOpenMode mode,
+                       isc::data::ConstElementPtr params) = 0;
+
+    /// \brief Close the currently configured \c MemorySegment (if
+    /// open).
+    ///
+    /// See the \c reset() method's documentation for a definition of
+    /// "open" and "close".
+    ///
+    /// Implementations of this method should close any currently
+    /// configured \c MemorySegment and clear the `ZoneTableSegment` to
+    /// a freshly constructed state.
+    ///
+    /// \throw isc::NotImplemented Some implementations may choose to
+    /// not implement this method. In this case, there must be a strong
+    /// exception safety guarantee and the \c ZoneTableSegment is usable
+    /// or unusable as before.
+    virtual void clear() = 0;
+
+    /// \brief Return true if the \c ZoneTableSegment has been
+    /// successfully \c reset().
+    ///
+    /// Note that after calling \c clear(), this method will return
+    /// false until the segment is reset successfully again.
+    virtual bool isUsable() const = 0;
+
+    /// \brief Reset the table header address.
     ///
-    /// \param loadAction Callback to provide the actual data.
-    /// \param origin The origin of the zone to reload.
-    /// \param rrclass The class of the zone to reload.
-    /// \return New instance of a zone writer. The ownership is passed
-    ///     onto the caller and the caller needs to \c delete it when
-    ///     it's done with the writer.
-    virtual ZoneWriter* getZoneWriter(const LoadAction& load_action,
-                                      const dns::Name& origin,
-                                      const dns::RRClass& rrclass) = 0;
+    /// This method must recalculate the \c ZoneTableHeader address, so
+    /// that it is valid when requested using the \c getHeader() method.
+    virtual void resetHeader() = 0;
 };
 
 } // namespace memory
diff --git a/src/lib/datasrc/memory/zone_table_segment_local.cc b/src/lib/datasrc/memory/zone_table_segment_local.cc
index fdaf678..6a3247b 100644
--- a/src/lib/datasrc/memory/zone_table_segment_local.cc
+++ b/src/lib/datasrc/memory/zone_table_segment_local.cc
@@ -13,7 +13,6 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <datasrc/memory/zone_table_segment_local.h>
-#include "zone_writer_local.h"
 
 using namespace isc::dns;
 using namespace isc::util;
@@ -24,6 +23,7 @@ namespace memory {
 
 ZoneTableSegmentLocal::ZoneTableSegmentLocal(const RRClass& rrclass) :
     ZoneTableSegment(rrclass),
+    impl_type_("local"),
     header_(ZoneTable::create(mem_sgmt_, rrclass))
 {
 }
@@ -38,6 +38,33 @@ ZoneTableSegmentLocal::~ZoneTableSegmentLocal() {
     assert(mem_sgmt_.allMemoryDeallocated());
 }
 
+const std::string&
+ZoneTableSegmentLocal::getImplType() const {
+    return (impl_type_);
+}
+
+void
+ZoneTableSegmentLocal::reset(MemorySegmentOpenMode,
+                             isc::data::ConstElementPtr)
+{
+    isc_throw(isc::NotImplemented,
+              "ZoneTableSegmentLocal::reset() is not implemented and "
+              "should not be used.");
+}
+
+void
+ZoneTableSegmentLocal::clear()
+{
+    isc_throw(isc::NotImplemented,
+              "ZoneTableSegmentLocal::clear() is not implemented and "
+              "should not be used.");
+}
+
+void
+ZoneTableSegmentLocal::resetHeader() {
+    // This method does not have to do anything in this implementation.
+}
+
 // After more methods' definitions are added here, it would be a good
 // idea to move getHeader() and getMemorySegment() definitions to the
 // header file.
@@ -56,14 +83,6 @@ ZoneTableSegmentLocal::getMemorySegment() {
      return (mem_sgmt_);
 }
 
-ZoneWriter*
-ZoneTableSegmentLocal::getZoneWriter(const LoadAction& load_action,
-                                     const dns::Name& name,
-                                     const dns::RRClass& rrclass)
-{
-    return (new ZoneWriterLocal(this, load_action, name, rrclass));
-}
-
 } // namespace memory
 } // namespace datasrc
 } // namespace isc
diff --git a/src/lib/datasrc/memory/zone_table_segment_local.h b/src/lib/datasrc/memory/zone_table_segment_local.h
index e08ca39..d3b61f6 100644
--- a/src/lib/datasrc/memory/zone_table_segment_local.h
+++ b/src/lib/datasrc/memory/zone_table_segment_local.h
@@ -18,19 +18,22 @@
 #include <datasrc/memory/zone_table_segment.h>
 #include <util/memory_segment_local.h>
 
+#include <string>
+
 namespace isc {
 namespace datasrc {
 namespace memory {
 
-/// \brief Local implementation of ZoneTableSegment class
+/// \brief Local implementation of \c ZoneTableSegment class
 ///
 /// This class specifies a concrete implementation for a
-/// MemorySegmentLocal based ZoneTableSegment. Please see the
-/// ZoneTableSegment class documentation for usage.
+/// \c MemorySegmentLocal -based \c ZoneTableSegment. Please see the
+/// \c ZoneTableSegment class documentation for usage.
 class ZoneTableSegmentLocal : public ZoneTableSegment {
-    // This is so that ZoneTableSegmentLocal can be instantiated from
-    // ZoneTableSegment::create().
+    // This is so that \c ZoneTableSegmentLocal can be instantiated from
+    // \c ZoneTableSegment::create().
     friend class ZoneTableSegment;
+
 protected:
     /// \brief Protected constructor
     ///
@@ -38,26 +41,64 @@ protected:
     /// (\c ZoneTableSegment::create()), so this constructor is
     /// protected.
     ZoneTableSegmentLocal(const isc::dns::RRClass& rrclass);
+
 public:
     /// \brief Destructor
     virtual ~ZoneTableSegmentLocal();
 
-    /// \brief Return the ZoneTableHeader for the local zone table
-    /// segment implementation.
+    /// \brief Returns "local" as the implementation type.
+    virtual const std::string& getImplType() const;
+
+    /// \brief This method does not have to do anything in this
+    /// implementation. It has an empty definition.
+    virtual void resetHeader();
+
+    /// \brief Return the \c ZoneTableHeader for this local zone table
+    /// segment.
     virtual ZoneTableHeader& getHeader();
 
-    /// \brief const version of \c getHeader().
+    /// \brief \c const version of \c getHeader().
     virtual const ZoneTableHeader& getHeader() const;
 
-    /// \brief Return the MemorySegment for the local zone table segment
-    /// implementation (a MemorySegmentLocal instance).
+    /// \brief Return the \c MemorySegment for the local zone table
+    /// segment implementation (a \c MemorySegmentLocal instance).
     virtual isc::util::MemorySegment& getMemorySegment();
 
-    /// \brief Concrete implementation of ZoneTableSegment::getZoneWriter
-    virtual ZoneWriter* getZoneWriter(const LoadAction& load_action,
-                                      const dns::Name& origin,
-                                      const dns::RRClass& rrclass);
+    /// \brief Return true if the segment is writable.
+    ///
+    /// Local segments are always writable. This implementation always
+    /// returns true.
+    virtual bool isWritable() const {
+        return (true);
+    }
+
+    /// \brief This method is not implemented.
+    ///
+    /// Resetting a local \c ZoneTableSegment is not supported at this
+    /// time.
+    ///
+    /// \throw isc::NotImplemented
+    virtual void reset(MemorySegmentOpenMode mode,
+                       isc::data::ConstElementPtr params);
+
+    /// \brief This method is not implemented.
+    ///
+    /// Clearing a local \c ZoneTableSegment is not supported at this
+    /// time.
+    ///
+    /// \throw isc::NotImplemented
+    virtual void clear();
+
+    /// \brief Return true if the segment is usable.
+    ///
+    /// Local segments are always usable. This implementation always
+    /// returns true.
+    virtual bool isUsable() const {
+        return (true);
+    }
+
 private:
+    std::string impl_type_;
     isc::util::MemorySegmentLocal mem_sgmt_;
     ZoneTableHeader header_;
 };
diff --git a/src/lib/datasrc/memory/zone_table_segment_mapped.cc b/src/lib/datasrc/memory/zone_table_segment_mapped.cc
new file mode 100644
index 0000000..45bd880
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_table_segment_mapped.cc
@@ -0,0 +1,386 @@
+// 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/memory/zone_table_segment_mapped.h>
+
+#include <memory>
+
+using namespace isc::data;
+using namespace isc::dns;
+using namespace isc::util;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+namespace { // unnamed namespace
+
+// The name with which the zone table checksum is associated in the segment.
+const char* const ZONE_TABLE_CHECKSUM_NAME = "zone_table_checksum";
+
+// The name with which the zone table header is associated in the segment.
+const char* const ZONE_TABLE_HEADER_NAME = "zone_table_header";
+
+} // end of unnamed namespace
+
+ZoneTableSegmentMapped::ZoneTableSegmentMapped(const RRClass& rrclass) :
+    ZoneTableSegment(rrclass),
+    impl_type_("mapped"),
+    rrclass_(rrclass),
+    cached_header_(NULL)
+{
+}
+
+ZoneTableSegmentMapped::~ZoneTableSegmentMapped() {
+    sync();
+}
+
+const std::string&
+ZoneTableSegmentMapped::getImplType() const {
+    return (impl_type_);
+}
+
+bool
+ZoneTableSegmentMapped::processChecksum(MemorySegmentMapped& segment,
+                                        bool create,
+                                        std::string& error_msg)
+{
+    const MemorySegment::NamedAddressResult result =
+        segment.getNamedAddress(ZONE_TABLE_CHECKSUM_NAME);
+    if (result.first) {
+        if (create) {
+            // There must be no previously saved checksum.
+            error_msg = "There is already a saved checksum in the segment "
+                 "opened in create mode";
+            return (false);
+        } else {
+            // The segment was already shrunk when it was last
+            // closed. Check that its checksum is consistent.
+            assert(result.second);
+            size_t* checksum = static_cast<size_t*>(result.second);
+            const size_t saved_checksum = *checksum;
+            // First, clear the checksum so that getCheckSum() returns a
+            // consistent value.
+            *checksum = 0;
+            const size_t new_checksum = segment.getCheckSum();
+            if (saved_checksum != new_checksum) {
+                error_msg = "Saved checksum doesn't match segment data";
+                return (false);
+            }
+        }
+    } else {
+        // Allocate space for a checksum (which is saved during close).
+        void* checksum = NULL;
+        while (!checksum) {
+            try {
+                checksum = segment.allocate(sizeof(size_t));
+            } catch (const MemorySegmentGrown&) {
+                // Do nothing and try again.
+            }
+        }
+        *static_cast<size_t*>(checksum) = 0;
+        const bool grew = segment.setNamedAddress(ZONE_TABLE_CHECKSUM_NAME,
+                                                  checksum);
+        assert(!grew);
+    }
+
+    return (true);
+}
+
+bool
+ZoneTableSegmentMapped::processHeader(MemorySegmentMapped& segment,
+                                      bool create,
+                                      std::string& error_msg)
+{
+    const MemorySegment::NamedAddressResult result =
+        segment.getNamedAddress(ZONE_TABLE_HEADER_NAME);
+    if (result.first) {
+        if (create) {
+            // There must be no previously saved checksum.
+            error_msg = "There is already a saved ZoneTableHeader in the "
+                 "segment opened in create mode";
+            return (false);
+        } else {
+            assert(result.second);
+        }
+    } else {
+        void* ptr = NULL;
+        while (!ptr) {
+            try {
+                ptr = segment.allocate(sizeof(ZoneTableHeader));
+            } catch (const MemorySegmentGrown&) {
+                // Do nothing and try again.
+            }
+        }
+        try {
+            ZoneTableHeader* new_header = new(ptr)
+                ZoneTableHeader(ZoneTable::create(segment, rrclass_));
+            const bool grew = segment.setNamedAddress(ZONE_TABLE_HEADER_NAME,
+                                                      new_header);
+            assert(!grew);
+        } catch (const MemorySegmentGrown&) {
+            // This is extremely unlikely and we just throw a fatal
+            // exception here without attempting to recover.
+
+            throw std::bad_alloc();
+        }
+    }
+
+    return (true);
+}
+
+MemorySegmentMapped*
+ZoneTableSegmentMapped::openReadWrite(const std::string& filename,
+                                      bool create)
+{
+    const MemorySegmentMapped::OpenMode mode = create ?
+         MemorySegmentMapped::CREATE_ONLY :
+         MemorySegmentMapped::OPEN_OR_CREATE;
+    // In case there is a problem, we throw. We want the segment to be
+    // automatically destroyed then.
+    std::auto_ptr<MemorySegmentMapped> segment
+        (new MemorySegmentMapped(filename, mode));
+
+    std::string error_msg;
+    if ((!processChecksum(*segment, create, error_msg)) ||
+        (!processHeader(*segment, create, error_msg))) {
+         if (mem_sgmt_) {
+              isc_throw(ResetFailed,
+                        "Error in resetting zone table segment to use "
+                        << filename << ": " << error_msg);
+         } else {
+              isc_throw(ResetFailedAndSegmentCleared,
+                        "Error in resetting zone table segment to use "
+                        << filename << ": " << error_msg);
+         }
+    }
+
+    return (segment.release());
+}
+
+MemorySegmentMapped*
+ZoneTableSegmentMapped::openReadOnly(const std::string& filename) {
+    // In case the checksum or table header is missing, we throw. We
+    // want the segment to be automatically destroyed then.
+    std::auto_ptr<MemorySegmentMapped> segment
+        (new MemorySegmentMapped(filename));
+    // There must be a previously saved checksum.
+    MemorySegment::NamedAddressResult result =
+        segment->getNamedAddress(ZONE_TABLE_CHECKSUM_NAME);
+    if (!result.first) {
+         const std::string error_msg =
+             "There is no previously saved checksum in a "
+             "mapped segment opened in read-only mode";
+         if (mem_sgmt_) {
+              isc_throw(ResetFailed,
+                        "Error in resetting zone table segment to use "
+                        << filename << ": " << error_msg);
+         } else {
+              isc_throw(ResetFailedAndSegmentCleared,
+                        "Error in resetting zone table segment to use "
+                        << filename << ": " << error_msg);
+         }
+    }
+
+    // We can't verify the checksum here as we can't set the checksum to
+    // 0 for checksum calculation in a read-only segment. So we continue
+    // without verifying the checksum.
+
+    // There must be a previously saved ZoneTableHeader.
+    result = segment->getNamedAddress(ZONE_TABLE_HEADER_NAME);
+    if (result.first) {
+        assert(result.second);
+    } else {
+         const std::string error_msg =
+             "There is no previously saved ZoneTableHeader in a "
+             "mapped segment opened in read-only mode.";
+         if (mem_sgmt_) {
+              isc_throw(ResetFailed,
+                        "Error in resetting zone table segment to use "
+                        << filename << ": " << error_msg);
+         } else {
+              isc_throw(ResetFailedAndSegmentCleared,
+                        "Error in resetting zone table segment to use "
+                        << filename << ": " << error_msg);
+         }
+    }
+
+    return (segment.release());
+}
+
+void
+ZoneTableSegmentMapped::reset(MemorySegmentOpenMode mode,
+                              isc::data::ConstElementPtr params)
+{
+    if (!params || params->getType() != Element::map) {
+        isc_throw(isc::InvalidParameter,
+                  "Configuration does not contain a map");
+    }
+
+    if (!params->contains("mapped-file")) {
+        isc_throw(isc::InvalidParameter,
+                  "Configuration does not contain a \"mapped-file\" key");
+    }
+
+    ConstElementPtr mapped_file = params->get("mapped-file");
+    if ((!mapped_file) || (mapped_file->getType() != Element::string)) {
+        isc_throw(isc::InvalidParameter,
+                  "Value of \"mapped-file\" is not a string");
+    }
+
+    const std::string filename = mapped_file->stringValue();
+
+    if (mem_sgmt_ && (filename == current_filename_)) {
+        // This reset() is an attempt to re-open the currently open
+        // mapped file. We cannot do this in many mode combinations
+        // unless we close the existing mapped file. So just close it.
+        clear();
+    } else {
+        sync();
+    }
+
+    // In case current_filename_ below fails, we want the segment to be
+    // automatically destroyed.
+    std::auto_ptr<MemorySegmentMapped> segment;
+
+    switch (mode) {
+    case CREATE:
+        segment.reset(openReadWrite(filename, true));
+        break;
+
+    case READ_WRITE:
+        segment.reset(openReadWrite(filename, false));
+        break;
+
+    case READ_ONLY:
+        segment.reset(openReadOnly(filename));
+        break;
+
+    default:
+        isc_throw(isc::InvalidOperation,
+                  "Invalid MemorySegmentOpenMode passed to reset()");
+    }
+
+    current_filename_ = filename;
+    current_mode_ = mode;
+    mem_sgmt_.reset(segment.release());
+
+    // Given what we setup above, resetHeader() must not throw at this
+    // point. If it does, all bets are off.
+    resetHeader();
+}
+
+void
+ZoneTableSegmentMapped::sync() {
+    // Synchronize checksum, etc.
+    if (mem_sgmt_ && isWritable()) {
+        // If there is a previously opened segment, and it was opened in
+        // read-write mode, update its checksum.
+        mem_sgmt_->shrinkToFit();
+        const MemorySegment::NamedAddressResult result =
+            mem_sgmt_->getNamedAddress(ZONE_TABLE_CHECKSUM_NAME);
+        assert(result.first);
+        assert(result.second);
+        size_t* checksum = static_cast<size_t*>(result.second);
+        // First, clear the checksum so that getCheckSum() returns a
+        // consistent value.
+        *checksum = 0;
+        const size_t new_checksum = mem_sgmt_->getCheckSum();
+        // Now, update it into place.
+        *checksum = new_checksum;
+    }
+}
+
+void
+ZoneTableSegmentMapped::clear() {
+    if (mem_sgmt_) {
+        sync();
+        mem_sgmt_.reset();
+    }
+}
+
+void
+ZoneTableSegmentMapped::resetHeader() {
+    // We cannot perform resetHeader() lazily during getHeader() as
+    // getHeader() has to work on const objects too. So we do it here
+    // now.
+
+    if (!isUsable()) {
+        isc_throw(isc::InvalidOperation,
+                  "resetHeader() called without calling reset() first");
+    }
+
+    const MemorySegment::NamedAddressResult result =
+        mem_sgmt_->getNamedAddress(ZONE_TABLE_HEADER_NAME);
+    if (!result.first) {
+        isc_throw(isc::Unexpected,
+                  "Unable to look up the address of the table header in "
+                  "getHeader()");
+    }
+
+    cached_header_ = static_cast<ZoneTableHeader*>(result.second);
+}
+
+template<typename T>
+T*
+ZoneTableSegmentMapped::getHeaderHelper() const {
+    if (!isUsable()) {
+        isc_throw(isc::InvalidOperation,
+                  "getHeader() called without calling reset() first");
+    }
+
+    assert(cached_header_);
+    return (cached_header_);
+}
+
+ZoneTableHeader&
+ZoneTableSegmentMapped::getHeader() {
+    return (*getHeaderHelper<ZoneTableHeader>());
+}
+
+const ZoneTableHeader&
+ZoneTableSegmentMapped::getHeader() const {
+    return (*getHeaderHelper<const ZoneTableHeader>());
+}
+
+MemorySegment&
+ZoneTableSegmentMapped::getMemorySegment() {
+    if (!isUsable()) {
+        isc_throw(isc::InvalidOperation,
+                  "getMemorySegment() called without calling reset() first");
+    }
+    return (*mem_sgmt_);
+}
+
+bool
+ZoneTableSegmentMapped::isUsable() const {
+    // If mem_sgmt_ is not empty, then it is usable.
+    return (mem_sgmt_);
+}
+
+bool
+ZoneTableSegmentMapped::isWritable() const {
+    if (!isUsable()) {
+        // If reset() was never performed for this segment, or if the
+        // most recent reset() had failed, then the segment is not
+        // writable.
+        return (false);
+    }
+
+    return ((current_mode_ == CREATE) || (current_mode_ == READ_WRITE));
+}
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
diff --git a/src/lib/datasrc/memory/zone_table_segment_mapped.h b/src/lib/datasrc/memory/zone_table_segment_mapped.h
new file mode 100644
index 0000000..93bd7fa
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_table_segment_mapped.h
@@ -0,0 +1,150 @@
+// 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 ZONE_TABLE_SEGMENT_MAPPED_H
+#define ZONE_TABLE_SEGMENT_MAPPED_H
+
+#include <datasrc/memory/zone_table_segment.h>
+#include <util/memory_segment_mapped.h>
+
+#include <boost/scoped_ptr.hpp>
+#include <string>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+/// \brief Mapped-file based implementation of \c ZoneTableSegment class
+///
+/// This class specifies a concrete implementation for a memory-mapped
+/// \c ZoneTableSegment. Please see the \c ZoneTableSegment class
+/// documentation for usage.
+class ZoneTableSegmentMapped : public ZoneTableSegment {
+    // This is so that \c ZoneTableSegmentMapped can be instantiated
+    // from \c ZoneTableSegment::create().
+    friend class ZoneTableSegment;
+
+protected:
+    /// \brief Protected constructor
+    ///
+    /// Instances are expected to be created by the factory method
+    /// (\c ZoneTableSegment::create()), so this constructor is
+    /// protected.
+    ZoneTableSegmentMapped(const isc::dns::RRClass& rrclass);
+
+public:
+    /// \brief Destructor
+    virtual ~ZoneTableSegmentMapped();
+
+    /// \brief Returns "mapped" as the implementation type.
+    virtual const std::string& getImplType() const;
+
+    /// \brief Resets the \c ZoneTableHeader address from the named
+    /// address in the mapped file. This method should be called once
+    /// before calls to \c getHeader() if the mapped \c MemorySegment
+    /// has grown.
+    virtual void resetHeader();
+
+    /// \brief Return the \c ZoneTableHeader for this mapped zone table
+    /// segment.
+    ///
+    /// \throws isc::InvalidOperation if this method is called without a
+    /// successful \c reset() call first.
+    virtual ZoneTableHeader& getHeader();
+
+    /// \brief const version of \c getHeader().
+    virtual const ZoneTableHeader& getHeader() const;
+
+    /// \brief Return the \c MemorySegment for the memory-mapped zone
+    /// table segment implementation (a \c MemorySegmentMapped
+    /// instance).
+    ///
+    /// \throws isc::InvalidOperation if this method is called without a
+    /// successful \c reset() call first.
+    virtual isc::util::MemorySegment& getMemorySegment();
+
+    /// \brief Returns if the segment is writable.
+    ///
+    /// Segments successfully opened in CREATE or READ_WRITE modes are
+    /// writable. Segments opened in READ_ONLY mode are not writable.
+    /// If the \c ZoneTableSegment was cleared for some reason, it is
+    /// not writable until it is reset successfully.
+    virtual bool isWritable() const;
+
+    /// \brief Close the current \c MemorySegment (if open) and open the
+    /// requested one.
+    ///
+    /// See \c MemorySegmentOpenMode for a definition of "storage area"
+    /// and the various modes in which a \c MemorySegment can be opened.
+    ///
+    /// \c params should be a map containing a "mapped-file" key that
+    /// points to a string value containing the filename of a mapped
+    /// file. E.g.,
+    ///
+    ///  {"mapped-file": "/var/bind10/mapped-files/zone-sqlite3.mapped.0"}
+    ///
+    /// Please see the \c ZoneTableSegment API documentation for the
+    /// behavior in case of exceptions.
+    ///
+    /// \throws isc::Unexpected when it's unable to lookup a named
+    /// address that it expected to be present. This is extremely
+    /// unlikely, and it points to corruption.
+    ///
+    /// \param mode The open mode (see the \c MemorySegmentOpenMode
+    /// documentation in \c ZoneTableSegment class).
+    /// \param params An element containing config for the mapped file
+    /// (see the description).
+    virtual void reset(MemorySegmentOpenMode mode,
+                       isc::data::ConstElementPtr params);
+
+    /// \brief Close the currently configured \c MemorySegment (if
+    /// open). See the base class for a definition of "open" and
+    /// "close".
+    virtual void clear();
+
+    /// \brief Return true if the segment is usable.
+    ///
+    /// See the base class for the description.
+    virtual bool isUsable() const;
+
+private:
+    void sync();
+
+    bool processChecksum(isc::util::MemorySegmentMapped& segment, bool create,
+                         std::string& error_msg);
+    bool processHeader(isc::util::MemorySegmentMapped& segment, bool create,
+                       std::string& error_msg);
+
+    isc::util::MemorySegmentMapped* openReadWrite(const std::string& filename,
+                                                  bool create);
+    isc::util::MemorySegmentMapped* openReadOnly(const std::string& filename);
+
+    template<typename T> T* getHeaderHelper() const;
+
+private:
+    std::string impl_type_;
+    isc::dns::RRClass rrclass_;
+    MemorySegmentOpenMode current_mode_;
+    std::string current_filename_;
+    // Internally holds a MemorySegmentMapped. This is NULL on
+    // construction, and is set by the \c reset() method.
+    boost::scoped_ptr<isc::util::MemorySegmentMapped> mem_sgmt_;
+    ZoneTableHeader* cached_header_;
+};
+
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // ZONE_TABLE_SEGMENT_MAPPED_H
diff --git a/src/lib/datasrc/memory/zone_writer.cc b/src/lib/datasrc/memory/zone_writer.cc
new file mode 100644
index 0000000..3cb646a
--- /dev/null
+++ b/src/lib/datasrc/memory/zone_writer.cc
@@ -0,0 +1,101 @@
+// Copyright (C) 2012  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/memory/zone_writer.h>
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/zone_table_segment.h>
+
+#include <memory>
+
+using std::auto_ptr;
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+
+ZoneWriter::ZoneWriter(ZoneTableSegment& segment,
+                       const LoadAction& load_action,
+                       const dns::Name& origin,
+                       const dns::RRClass& rrclass) :
+    segment_(segment),
+    load_action_(load_action),
+    origin_(origin),
+    rrclass_(rrclass),
+    zone_data_(NULL),
+    state_(ZW_UNUSED)
+{
+    if (!segment.isWritable()) {
+        isc_throw(isc::InvalidOperation,
+                  "Attempt to construct ZoneWriter for a read-only segment");
+    }
+}
+
+ZoneWriter::~ZoneWriter() {
+    // Clean up everything there might be left if someone forgot, just
+    // in case.
+    cleanup();
+}
+
+void
+ZoneWriter::load() {
+    if (state_ != ZW_UNUSED) {
+        isc_throw(isc::InvalidOperation, "Trying to load twice");
+    }
+
+    zone_data_ = load_action_(segment_.getMemorySegment());
+
+    if (!zone_data_) {
+        // Bug inside load_action_.
+        isc_throw(isc::InvalidOperation, "No data returned from load action");
+    }
+
+    segment_.resetHeader();
+
+    state_ = ZW_LOADED;
+}
+
+void
+ZoneWriter::install() {
+    if (state_ != ZW_LOADED) {
+        isc_throw(isc::InvalidOperation, "No data to install");
+    }
+
+    ZoneTable* table(segment_.getHeader().getTable());
+    if (!table) {
+        isc_throw(isc::Unexpected, "No zone table present");
+    }
+    const ZoneTable::AddResult result(table->addZone(
+                                          segment_.getMemorySegment(),
+                                          rrclass_, origin_, zone_data_));
+
+    state_ = ZW_INSTALLED;
+    zone_data_ = result.zone_data;
+
+    segment_.resetHeader();
+}
+
+void
+ZoneWriter::cleanup() {
+    // We eat the data (if any) now.
+
+    if (zone_data_ != NULL) {
+        ZoneData::destroy(segment_.getMemorySegment(), zone_data_, rrclass_);
+        zone_data_ = NULL;
+        state_ = ZW_CLEANED;
+    }
+}
+
+}
+}
+}
diff --git a/src/lib/datasrc/memory/zone_writer.h b/src/lib/datasrc/memory/zone_writer.h
index 0e8f285..1c4e944 100644
--- a/src/lib/datasrc/memory/zone_writer.h
+++ b/src/lib/datasrc/memory/zone_writer.h
@@ -15,7 +15,11 @@
 #ifndef MEM_ZONE_WRITER_H
 #define MEM_ZONE_WRITER_H
 
-#include "load_action.h"
+#include <datasrc/memory/zone_table_segment.h>
+#include <datasrc/memory/load_action.h>
+
+#include <dns/rrclass.h>
+#include <dns/name.h>
 
 namespace isc {
 namespace datasrc {
@@ -23,22 +27,33 @@ namespace memory {
 
 /// \brief Does an update to a zone.
 ///
-/// This abstract base class represents the work of a reload of a zone.
-/// The work is divided into three stages -- load(), install() and cleanup().
-/// They should be called in this order for the effect to take place.
+/// This represents the work of a (re)load of a zone.  The work is divided
+/// into three stages -- load(), install() and cleanup().  They should
+/// be called in this order for the effect to take place.
 ///
 /// We divide them so the update of zone data can be done asynchronously,
 /// in a different thread. The install() operation is the only one that needs
 /// to be done in a critical section.
 ///
-/// Each derived class implementation must provide the strong exception
-/// guarantee for each public method. That is, when any of the methods
-/// throws, the entire state should stay the same as before the call
-/// (how to achieve that may be implementation dependant).
+/// This class provides strong exception guarantee for each public
+/// method. That is, when any of the methods throws, the entire state
+/// stays the same as before the call.
 class ZoneWriter {
 public:
-    /// \brief Virtual destructor.
-    virtual ~ZoneWriter() {};
+    /// \brief Constructor
+    ///
+    /// \throw isc::InvalidOperation if \c segment is read-only.
+    ///
+    /// \param segment The zone table segment to store the zone into.
+    /// \param load_action The callback used to load data.
+    /// \param name The name of the zone.
+    /// \param rrclass The class of the zone.
+    ZoneWriter(ZoneTableSegment& segment,
+               const LoadAction& load_action, const dns::Name& name,
+               const dns::RRClass& rrclass);
+
+    /// \brief Destructor.
+    ~ZoneWriter();
 
     /// \brief Get the zone data into memory.
     ///
@@ -56,7 +71,7 @@ public:
     /// \note After successful load(), you have to call cleanup() some time
     ///     later.
     /// \throw isc::InvalidOperation if called second time.
-    virtual void load() = 0;
+    void load();
 
     /// \brief Put the changes to effect.
     ///
@@ -68,12 +83,12 @@ public:
     /// The operation is expected to be fast and is meant to be used inside
     /// a critical section.
     ///
-    /// This may throw in rare cases, depending on the concrete implementation.
-    /// If it throws, you still need to call cleanup().
+    /// This may throw in rare cases.  If it throws, you still need to
+    /// call cleanup().
     ///
     /// \throw isc::InvalidOperation if called without previous load() or for
     ///     the second time or cleanup() was called already.
-    virtual void install() = 0;
+    void install();
 
     /// \brief Clean up resources.
     ///
@@ -81,8 +96,22 @@ public:
     /// one loaded by load() in case install() was not called or was not
     /// successful, or the one replaced in install().
     ///
-    /// Generally, this should never throw.
-    virtual void cleanup() = 0;
+    /// \throw none
+    void cleanup();
+
+private:
+    ZoneTableSegment& segment_;
+    const LoadAction load_action_;
+    const dns::Name origin_;
+    const dns::RRClass rrclass_;
+    ZoneData* zone_data_;
+    enum State {
+        ZW_UNUSED,
+        ZW_LOADED,
+        ZW_INSTALLED,
+        ZW_CLEANED
+    };
+    State state_;
 };
 
 }
diff --git a/src/lib/datasrc/memory/zone_writer_local.cc b/src/lib/datasrc/memory/zone_writer_local.cc
deleted file mode 100644
index 0cd9587..0000000
--- a/src/lib/datasrc/memory/zone_writer_local.cc
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright (C) 2012  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 "zone_writer_local.h"
-#include "zone_data.h"
-#include "zone_table_segment_local.h"
-
-#include <memory>
-
-using std::auto_ptr;
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-
-ZoneWriterLocal::ZoneWriterLocal(ZoneTableSegmentLocal* segment,
-                                 const LoadAction& load_action,
-                                 const dns::Name& origin,
-                                 const dns::RRClass& rrclass) :
-    segment_(segment),
-    load_action_(load_action),
-    origin_(origin),
-    rrclass_(rrclass),
-    zone_data_(NULL),
-    state_(ZW_UNUSED)
-{}
-
-ZoneWriterLocal::~ZoneWriterLocal() {
-    // Clean up everything there might be left if someone forgot, just
-    // in case.
-    cleanup();
-}
-
-void
-ZoneWriterLocal::load() {
-    if (state_ != ZW_UNUSED) {
-        isc_throw(isc::InvalidOperation, "Trying to load twice");
-    }
-
-    zone_data_ = load_action_(segment_->getMemorySegment());
-
-    if (zone_data_ == NULL) {
-        // Bug inside load_action_.
-        isc_throw(isc::InvalidOperation, "No data returned from load action");
-    }
-
-    state_ = ZW_LOADED;
-}
-
-void
-ZoneWriterLocal::install() {
-    if (state_ != ZW_LOADED) {
-        isc_throw(isc::InvalidOperation, "No data to install");
-    }
-
-
-    ZoneTable* table(segment_->getHeader().getTable());
-    if (table == NULL) {
-        isc_throw(isc::Unexpected, "No zone table present");
-    }
-    const ZoneTable::AddResult result(table->addZone(
-                                          segment_->getMemorySegment(),
-                                          rrclass_, origin_, zone_data_));
-
-    state_ = ZW_INSTALLED;
-    zone_data_ = result.zone_data;
-}
-
-void
-ZoneWriterLocal::cleanup() {
-    // We eat the data (if any) now.
-
-    if (zone_data_ != NULL) {
-        ZoneData::destroy(segment_->getMemorySegment(), zone_data_, rrclass_);
-        zone_data_ = NULL;
-        state_ = ZW_CLEANED;
-    }
-}
-
-}
-}
-}
diff --git a/src/lib/datasrc/memory/zone_writer_local.h b/src/lib/datasrc/memory/zone_writer_local.h
deleted file mode 100644
index 7231a57..0000000
--- a/src/lib/datasrc/memory/zone_writer_local.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright (C) 2012  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 MEM_ZONE_WRITER_LOCAL_H
-#define MEM_ZONE_WRITER_LOCAL_H
-
-#include "zone_writer.h"
-
-#include <dns/rrclass.h>
-#include <dns/name.h>
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-
-class ZoneData;
-class ZoneTableSegmentLocal;
-
-/// \brief Writer implementation which loads data locally.
-///
-/// This implementation prepares a clean zone data and lets one callback
-/// to fill it and another to install it somewhere. The class does mostly
-/// nothing (and delegates the work to the callbacks), just stores little bit
-/// of state between the calls.
-class ZoneWriterLocal : public ZoneWriter {
-public:
-    /// \brief Constructor
-    ///
-    /// \param segment The zone table segment to store the zone into.
-    /// \param load_action The callback used to load data.
-    /// \param install_action The callback used to install the loaded zone.
-    /// \param rrclass The class of the zone.
-    ZoneWriterLocal(ZoneTableSegmentLocal* segment,
-                    const LoadAction& load_action, const dns::Name& name,
-                    const dns::RRClass& rrclass);
-
-    /// \brief Destructor
-    ~ZoneWriterLocal();
-
-    /// \brief Loads the data.
-    ///
-    /// This calls the load_action (passed to constructor) and stores the
-    /// data for future use.
-    ///
-    /// \throw isc::InvalidOperation if it is called the second time in
-    ///     lifetime of the object.
-    /// \throw Whatever the load_action throws, it is propagated up.
-    virtual void load();
-
-    /// \brief Installs the zone.
-    ///
-    /// It modifies the zone table accessible through the segment (passed to
-    /// constructor).
-    ///
-    /// \throw isc::InvalidOperation if it is called the second time in
-    ///     lifetime of the object or if load() was not called previously or if
-    ///     cleanup() was already called.
-    virtual void install();
-
-    /// \brief Clean up memory.
-    ///
-    /// Cleans up the memory used by load()ed zone if not yet installed, or
-    /// the old zone replaced by install().
-    virtual void cleanup();
-private:
-    ZoneTableSegmentLocal* segment_;
-    LoadAction load_action_;
-    dns::Name origin_;
-    dns::RRClass rrclass_;
-    ZoneData* zone_data_;
-    enum State {
-        ZW_UNUSED,
-        ZW_LOADED,
-        ZW_INSTALLED,
-        ZW_CLEANED
-    };
-    State state_;
-};
-
-}
-}
-}
-
-#endif
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index 8013f01..2a67418 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -166,7 +166,8 @@ public:
         // Load the data into the zone table.
         if (enabled) {
             boost::scoped_ptr<memory::ZoneWriter> writer(
-                dsrc_info.ztable_segment_->getZoneWriter(
+                new memory::ZoneWriter(
+                    *dsrc_info.ztable_segment_,
                     cache_conf->getLoadAction(rrclass_, zone),
                     zone, rrclass_));
             writer->load();
diff --git a/src/lib/datasrc/tests/memory/Makefile.am b/src/lib/datasrc/tests/memory/Makefile.am
index e0fc0f5..c3d6a40 100644
--- a/src/lib/datasrc/tests/memory/Makefile.am
+++ b/src/lib/datasrc/tests/memory/Makefile.am
@@ -4,6 +4,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
 AM_CPPFLAGS += -I$(top_builddir)/src/lib/dns -I$(top_srcdir)/src/lib/dns
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_srcdir)/testdata\"
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_builddir)\"
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
 
@@ -30,14 +31,19 @@ run_unittests_SOURCES += zone_table_unittest.cc
 run_unittests_SOURCES += zone_data_unittest.cc
 run_unittests_SOURCES += zone_finder_unittest.cc
 run_unittests_SOURCES += ../../tests/faked_nsec3.h ../../tests/faked_nsec3.cc
-run_unittests_SOURCES += memory_segment_test.h
+run_unittests_SOURCES += memory_segment_mock.h
 run_unittests_SOURCES += segment_object_holder_unittest.cc
 run_unittests_SOURCES += memory_client_unittest.cc
 run_unittests_SOURCES += rrset_collection_unittest.cc
 run_unittests_SOURCES += zone_data_loader_unittest.cc
 run_unittests_SOURCES += zone_data_updater_unittest.cc
-run_unittests_SOURCES += zone_table_segment_test.h
+run_unittests_SOURCES += zone_table_segment_mock.h
 run_unittests_SOURCES += zone_table_segment_unittest.cc
+
+if USE_SHARED_MEMORY
+run_unittests_SOURCES += zone_table_segment_mapped_unittest.cc
+endif
+
 run_unittests_SOURCES += zone_writer_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index f5b72a0..2092b44 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -37,8 +37,8 @@
 
 #include <testutils/dnsmessage_test.h>
 
-#include "memory_segment_test.h"
-#include "zone_table_segment_test.h"
+#include <datasrc/tests/memory/memory_segment_mock.h>
+#include <datasrc/tests/memory/zone_table_segment_mock.h>
 
 #include <gtest/gtest.h>
 
@@ -169,7 +169,7 @@ public:
 class MemoryClientTest : public ::testing::Test {
 protected:
     MemoryClientTest() : zclass_(RRClass::IN()),
-                         ztable_segment_(new test::ZoneTableSegmentTest(
+                         ztable_segment_(new test::ZoneTableSegmentMock(
                              zclass_, mem_sgmt_)),
                          client_(new InMemoryClient(ztable_segment_, zclass_))
     {}
@@ -179,7 +179,7 @@ protected:
         EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
     }
     const RRClass zclass_;
-    test::MemorySegmentTest mem_sgmt_;
+    test::MemorySegmentMock mem_sgmt_;
     shared_ptr<ZoneTableSegment> ztable_segment_;
     boost::scoped_ptr<InMemoryClient> client_;
 };
@@ -305,12 +305,12 @@ TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
         mem_sgmt_.setThrowCount(i);
         EXPECT_THROW({
             shared_ptr<ZoneTableSegment> ztable_segment(
-                new test::ZoneTableSegmentTest(
+                new test::ZoneTableSegmentMock(
                     zclass_, mem_sgmt_));
 
             // Include the InMemoryClient construction too here. Now,
             // even allocations done from InMemoryClient constructor
-            // fail (due to MemorySegmentTest throwing) and we check for
+            // fail (due to MemorySegmentMock throwing) and we check for
             // leaks when this happens.
             InMemoryClient client2(ztable_segment, zclass_);
             loadZoneIntoTable(*ztable_segment, Name("example.org"), zclass_,
diff --git a/src/lib/datasrc/tests/memory/memory_segment_mock.h b/src/lib/datasrc/tests/memory/memory_segment_mock.h
new file mode 100644
index 0000000..92c291d
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/memory_segment_mock.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2012  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_MEMORY_SEGMENT_TEST_H
+#define DATASRC_MEMORY_SEGMENT_TEST_H 1
+
+#include <util/memory_segment_local.h>
+
+#include <cstddef>              // for size_t
+#include <new>                  // for bad_alloc
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+namespace test {
+
+// A special memory segment that can be used for tests.  It normally behaves
+// like a "local" memory segment.  If "throw count" is set to non 0 via
+// setThrowCount(), it continues the normal behavior until the specified
+// number of calls to allocate(), exclusive, and throws an exception at the
+// next call.  For example, if count is set to 3, the next two calls to
+// allocate() will succeed, and the 3rd call will fail with an exception.
+// This segment object can be used after the exception is thrown, and the
+// count is internally reset to 0.
+class MemorySegmentMock : public isc::util::MemorySegmentLocal {
+public:
+    MemorySegmentMock() : throw_count_(0) {}
+    virtual void* allocate(std::size_t size) {
+        if (throw_count_ > 0) {
+            if (--throw_count_ == 0) {
+                throw std::bad_alloc();
+            }
+        }
+        return (isc::util::MemorySegmentLocal::allocate(size));
+    }
+    void setThrowCount(std::size_t count) { throw_count_ = count; }
+
+private:
+    std::size_t throw_count_;
+};
+
+} // namespace test
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_MEMORY_SEGMENT_TEST_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/memory/memory_segment_test.h b/src/lib/datasrc/tests/memory/memory_segment_test.h
deleted file mode 100644
index 3195a9b..0000000
--- a/src/lib/datasrc/tests/memory/memory_segment_test.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright (C) 2012  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_MEMORY_SEGMENT_TEST_H
-#define DATASRC_MEMORY_SEGMENT_TEST_H 1
-
-#include <util/memory_segment_local.h>
-
-#include <cstddef>              // for size_t
-#include <new>                  // for bad_alloc
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-namespace test {
-
-// A special memory segment that can be used for tests.  It normally behaves
-// like a "local" memory segment.  If "throw count" is set to non 0 via
-// setThrowCount(), it continues the normal behavior until the specified
-// number of calls to allocate(), exclusive, and throws an exception at the
-// next call.  For example, if count is set to 3, the next two calls to
-// allocate() will succeed, and the 3rd call will fail with an exception.
-// This segment object can be used after the exception is thrown, and the
-// count is internally reset to 0.
-class MemorySegmentTest : public isc::util::MemorySegmentLocal {
-public:
-    MemorySegmentTest() : throw_count_(0) {}
-    virtual void* allocate(std::size_t size) {
-        if (throw_count_ > 0) {
-            if (--throw_count_ == 0) {
-                throw std::bad_alloc();
-            }
-        }
-        return (isc::util::MemorySegmentLocal::allocate(size));
-    }
-    void setThrowCount(std::size_t count) { throw_count_ = count; }
-
-private:
-    std::size_t throw_count_;
-};
-
-} // namespace test
-} // namespace memory
-} // namespace datasrc
-} // namespace isc
-
-#endif // DATASRC_MEMORY_SEGMENT_TEST_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc b/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc
index 04e285b..6329b6b 100644
--- a/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc
+++ b/src/lib/datasrc/tests/memory/rrset_collection_unittest.cc
@@ -15,13 +15,13 @@
 
 #include <datasrc/memory/rrset_collection.h>
 
-#include "memory_segment_test.h"
-
 #include <datasrc/memory/zone_data_loader.h>
 #include <datasrc/memory/segment_object_holder.h>
 #include <dns/rrttl.h>
 #include <dns/rdataclass.h>
 
+#include <datasrc/tests/memory/memory_segment_mock.h>
+
 #include <gtest/gtest.h>
 
 using namespace isc::dns;
@@ -52,7 +52,7 @@ public:
     const RRClass rrclass;
     const Name origin;
     std::string zone_file;
-    test::MemorySegmentTest mem_sgmt;
+    test::MemorySegmentMock mem_sgmt;
     SegmentObjectHolder<ZoneData, RRClass> zone_data_holder;
     RRsetCollection collection;
 };
diff --git a/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
index abc6f13..47ec4d3 100644
--- a/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_data_loader_unittest.cc
@@ -22,7 +22,7 @@
 #include <dns/name.h>
 #include <dns/rrclass.h>
 
-#include "memory_segment_test.h"
+#include <datasrc/tests/memory/memory_segment_mock.h>
 
 #include <gtest/gtest.h>
 
@@ -41,7 +41,7 @@ protected:
         EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
     }
     const RRClass zclass_;
-    test::MemorySegmentTest mem_sgmt_;
+    test::MemorySegmentMock mem_sgmt_;
     ZoneData* zone_data_;
 };
 
diff --git a/src/lib/datasrc/tests/memory/zone_data_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_unittest.cc
index ffbd0f6..983e588 100644
--- a/src/lib/datasrc/tests/memory/zone_data_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_data_unittest.cc
@@ -16,8 +16,6 @@
 #include <datasrc/memory/rdata_serialization.h>
 #include <datasrc/memory/rdataset.h>
 
-#include "memory_segment_test.h"
-
 #include <dns/rdataclass.h>
 
 #include <exceptions/exceptions.h>
@@ -30,6 +28,7 @@
 #include <dns/rrttl.h>
 
 #include <testutils/dnsmessage_test.h>
+#include <datasrc/tests/memory/memory_segment_mock.h>
 
 #include <gtest/gtest.h>
 
@@ -73,7 +72,7 @@ protected:
         EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated());
     }
 
-    MemorySegmentTest mem_sgmt_;
+    MemorySegmentMock mem_sgmt_;
     NSEC3Data* nsec3_data_;
     const generic::NSEC3PARAM param_rdata_, param_rdata_nosalt_,
         param_rdata_largesalt_;
@@ -88,7 +87,7 @@ protected:
 // Shared by both test cases using NSEC3 and NSEC3PARAM Rdata
 template <typename RdataType>
 void
-checkNSEC3Data(MemorySegmentTest& mem_sgmt,
+checkNSEC3Data(MemorySegmentMock& mem_sgmt,
                const Name& zone_name,
                const RdataType& expect_rdata)
 {
diff --git a/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc b/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
index 6399923..94870f9 100644
--- a/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_data_updater_unittest.cc
@@ -25,7 +25,7 @@
 #include <dns/rrset.h>
 #include <dns/rrttl.h>
 
-#include "memory_segment_test.h"
+#include <datasrc/tests/memory/memory_segment_mock.h>
 
 #include <gtest/gtest.h>
 
@@ -66,7 +66,7 @@ protected:
 
     const Name zname_;
     const RRClass zclass_;
-    test::MemorySegmentTest mem_sgmt_;
+    test::MemorySegmentMock mem_sgmt_;
     ZoneData* zone_data_;
     boost::scoped_ptr<ZoneDataUpdater> updater_;
 };
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index 0350ed9..be53820 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -12,8 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <datasrc/tests/memory/memory_segment_test.h>
-#include <datasrc/tests/memory/zone_table_segment_test.h>
+#include <datasrc/tests/memory/memory_segment_mock.h>
+#include <datasrc/tests/memory/zone_table_segment_mock.h>
 #include <datasrc/tests/memory/zone_loader_util.h>
 
 // NOTE: this faked_nsec3 inclusion (and all related code below)
@@ -221,7 +221,7 @@ protected:
     const RRClass class_;
     const Name origin_;
     // The zone finder to torture by tests
-    MemorySegmentTest mem_sgmt_;
+    MemorySegmentMock mem_sgmt_;
     memory::ZoneData* zone_data_;
     memory::InMemoryZoneFinder zone_finder_;
     ZoneDataUpdater updater_;
@@ -1613,7 +1613,7 @@ TEST_F(InMemoryZoneFinderTest, findOrphanRRSIG) {
 TEST_F(InMemoryZoneFinderTest, NSECNonExistentTest) {
     const Name name("example.com.");
     shared_ptr<ZoneTableSegment> ztable_segment(
-         new ZoneTableSegmentTest(class_, mem_sgmt_));
+         new ZoneTableSegmentMock(class_, mem_sgmt_));
     loadZoneIntoTable(*ztable_segment, name, class_,
                       TEST_DATA_DIR "/2504-test.zone");
     InMemoryClient client(ztable_segment, class_);
@@ -1775,7 +1775,7 @@ TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3MissingOrigin) {
 
      const Name name("example.com.");
      shared_ptr<ZoneTableSegment> ztable_segment(
-          new ZoneTableSegmentTest(class_, mem_sgmt_));
+          new ZoneTableSegmentMock(class_, mem_sgmt_));
      loadZoneIntoTable(*ztable_segment, name, class_,
                        TEST_DATA_DIR "/2503-test.zone");
      InMemoryClient client(ztable_segment, class_);
diff --git a/src/lib/datasrc/tests/memory/zone_loader_util.cc b/src/lib/datasrc/tests/memory/zone_loader_util.cc
index 1bf9cfa..bd55e66 100644
--- a/src/lib/datasrc/tests/memory/zone_loader_util.cc
+++ b/src/lib/datasrc/tests/memory/zone_loader_util.cc
@@ -24,9 +24,6 @@
 
 #include <cc/data.h>
 
-#include <boost/bind.hpp>
-#include <boost/scoped_ptr.hpp>
-
 #include <string>
 
 namespace isc {
@@ -43,12 +40,11 @@ loadZoneIntoTable(ZoneTableSegment& zt_sgmt, const dns::Name& zname,
             "{\"cache-enable\": true,"
             " \"params\": {\"" + zname.toText() + "\": \"" + zone_file +
             "\"}}"), true);
-    boost::scoped_ptr<memory::ZoneWriter> writer(
-        zt_sgmt.getZoneWriter(cache_conf.getLoadAction(zclass, zname),
-                              zname, zclass));
-    writer->load();
-    writer->install();
-    writer->cleanup();
+    memory::ZoneWriter writer(zt_sgmt, cache_conf.getLoadAction(zclass, zname),
+                              zname, zclass);
+    writer.load();
+    writer.install();
+    writer.cleanup();
 }
 
 namespace {
@@ -75,12 +71,11 @@ void
 loadZoneIntoTable(ZoneTableSegment& zt_sgmt, const dns::Name& zname,
                   const dns::RRClass& zclass, ZoneIterator& iterator)
 {
-    boost::scoped_ptr<memory::ZoneWriter> writer(
-        zt_sgmt.getZoneWriter(IteratorLoader(zclass, zname, iterator),
-                              zname, zclass));
-    writer->load();
-    writer->install();
-    writer->cleanup();
+    memory::ZoneWriter writer(zt_sgmt, IteratorLoader(zclass, zname, iterator),
+                              zname, zclass);
+    writer.load();
+    writer.install();
+    writer.cleanup();
 }
 
 } // namespace test
diff --git a/src/lib/datasrc/tests/memory/zone_table_segment_mapped_unittest.cc b/src/lib/datasrc/tests/memory/zone_table_segment_mapped_unittest.cc
new file mode 100644
index 0000000..441f433
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_table_segment_mapped_unittest.cc
@@ -0,0 +1,590 @@
+// 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/memory/zone_writer.h>
+#include <datasrc/memory/zone_table_segment_mapped.h>
+#include <util/random/random_number_generator.h>
+#include <util/unittests/check_valgrind.h>
+
+#include <gtest/gtest.h>
+#include <boost/format.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/interprocess/file_mapping.hpp>
+
+#include <memory>
+#include <cerrno>
+
+#include <sys/stat.h>
+
+using namespace isc::dns;
+using namespace isc::datasrc::memory;
+using namespace isc::data;
+using namespace isc::util;
+using namespace isc::util::random;
+using namespace std;
+using boost::scoped_ptr;
+
+namespace {
+
+const char* const mapped_file  = TEST_DATA_BUILDDIR "/test.mapped";
+const char* const mapped_file2 = TEST_DATA_BUILDDIR "/test2.mapped";
+
+class ZoneTableSegmentMappedTest : public ::testing::Test {
+protected:
+    ZoneTableSegmentMappedTest() :
+        ztable_segment_(
+            ZoneTableSegment::create(RRClass::IN(), "mapped")),
+        config_params_(
+            Element::fromJSON(
+                "{\"mapped-file\": \"" + std::string(mapped_file) + "\"}")),
+        config_params2_(
+            Element::fromJSON(
+                "{\"mapped-file\": \"" + std::string(mapped_file2) + "\"}"))
+    {
+        EXPECT_NE(static_cast<void*>(NULL), ztable_segment_.get());
+        // Verify that a ZoneTableSegmentMapped is created.
+        ZoneTableSegmentMapped* mapped_segment =
+            dynamic_cast<ZoneTableSegmentMapped*>(ztable_segment_.get());
+        EXPECT_NE(static_cast<void*>(NULL), mapped_segment);
+
+        createTestData();
+    }
+
+    ~ZoneTableSegmentMappedTest() {
+        ZoneTableSegment::destroy(ztable_segment_.release());
+        boost::interprocess::file_mapping::remove(mapped_file);
+        boost::interprocess::file_mapping::remove(mapped_file2);
+    }
+
+    typedef std::pair<std::string, int> TestDataElement;
+
+    void createTestData() {
+        UniformRandomIntegerGenerator gen(0, INT_MAX);
+        for (int i = 0; i < 256; ++i) {
+            const string name(boost::str(boost::format("name%d") % i));
+            const int value = gen();
+            test_data_.push_back(TestDataElement(name, value));
+        }
+    }
+
+    void setupMappedFiles();
+    void addData(MemorySegment& segment);
+    bool verifyData(const MemorySegment& segment);
+
+    // Ideally, this should be something similar to a
+    // SegmentObjectHolder, not an auto_ptr.
+    std::auto_ptr<ZoneTableSegment> ztable_segment_;
+    const ConstElementPtr config_params_;
+    const ConstElementPtr config_params2_;
+    std::vector<TestDataElement> test_data_;
+};
+
+bool
+fileExists(const char* path) {
+    struct stat sb;
+    const int status = stat(path, &sb);
+    if (status != 0) {
+        EXPECT_EQ(ENOENT, errno);
+        return (false);
+    }
+    return (true);
+}
+
+void
+deleteChecksum(MemorySegment& segment) {
+    segment.clearNamedAddress("zone_table_checksum");
+}
+
+void
+corruptChecksum(MemorySegment& segment) {
+    const MemorySegment::NamedAddressResult result =
+        segment.getNamedAddress("zone_table_checksum");
+    ASSERT_TRUE(result.first);
+
+    size_t checksum = *static_cast<size_t*>(result.second);
+    ++checksum;
+    *static_cast<size_t*>(result.second) = checksum;
+}
+
+void
+deleteHeader(MemorySegment& segment) {
+    segment.clearNamedAddress("zone_table_header");
+}
+
+void
+ZoneTableSegmentMappedTest::addData(MemorySegment& segment) {
+    // For purposes of this test, we assume that the following
+    // allocations do not resize the mapped segment. For this, we have
+    // to keep the size of test data reasonably small in
+    // createTestData().
+
+    // One by one, add all the elements in test_data_.
+    for (int i = 0; i < test_data_.size(); ++i) {
+        void* ptr = segment.allocate(sizeof(int));
+        ASSERT_TRUE(ptr);
+        *static_cast<int*>(ptr) = test_data_[i].second;
+        const bool grew = segment.setNamedAddress(test_data_[i].first.c_str(),
+                                                  ptr);
+        ASSERT_FALSE(grew);
+    }
+}
+
+bool
+ZoneTableSegmentMappedTest::verifyData(const MemorySegment& segment) {
+    // One by one, verify all the elements in test_data_ exist and have
+    // the expected values.
+    for (int i = 0; i < test_data_.size(); ++i) {
+        const MemorySegment::NamedAddressResult result =
+            segment.getNamedAddress(test_data_[i].first.c_str());
+        if (!result.first) {
+            return (false);
+        }
+        if (*static_cast<int*>(result.second) != test_data_[i].second) {
+            return (false);
+        }
+    }
+
+    return (true);
+}
+
+void
+ZoneTableSegmentMappedTest::setupMappedFiles() {
+    ztable_segment_->reset(ZoneTableSegment::CREATE, config_params_);
+    addData(ztable_segment_->getMemorySegment());
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    ztable_segment_->reset(ZoneTableSegment::CREATE, config_params2_);
+    addData(ztable_segment_->getMemorySegment());
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // Now, clear the segment, closing the underlying mapped file.
+    ztable_segment_->clear();
+}
+
+TEST_F(ZoneTableSegmentMappedTest, getImplType) {
+    EXPECT_EQ("mapped", ztable_segment_->getImplType());
+}
+
+TEST_F(ZoneTableSegmentMappedTest, getHeaderUninitialized) {
+    // This should throw as we haven't called reset() yet.
+    EXPECT_THROW(ztable_segment_->getHeader(), isc::InvalidOperation);
+}
+
+TEST_F(ZoneTableSegmentMappedTest, getMemorySegmentUninitialized) {
+    // This should throw as we haven't called reset() yet.
+    EXPECT_THROW(ztable_segment_->getMemorySegment(), isc::InvalidOperation);
+}
+
+TEST_F(ZoneTableSegmentMappedTest, isUsableUninitialized) {
+    // isUsable() must return false by default, when the segment has not
+    // been reset() yet.
+    EXPECT_FALSE(ztable_segment_->isUsable());
+}
+
+TEST_F(ZoneTableSegmentMappedTest, isWritableUninitialized) {
+    // isWritable() must return false by default, when the segment has
+    // not been reset() yet.
+    EXPECT_FALSE(ztable_segment_->isWritable());
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetBadConfig) {
+    // Open a mapped file in create mode.
+    ztable_segment_->reset(ZoneTableSegment::CREATE, config_params_);
+
+    // Populate it with some data.
+    addData(ztable_segment_->getMemorySegment());
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // All the following resets() with invalid configuration must
+    // provide a strong exception guarantee that the segment is still
+    // usable as before.
+
+    // NULL is passed in config params
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::CREATE,
+                               ConstElementPtr());
+    }, isc::InvalidParameter);
+
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // Not a map
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::CREATE,
+                               Element::fromJSON("42"));
+    }, isc::InvalidParameter);
+
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // Empty map
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::CREATE,
+                               Element::fromJSON("{}"));
+    }, isc::InvalidParameter);
+
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // No "mapped-file" key
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::CREATE,
+                               Element::fromJSON("{\"foo\": \"bar\"}"));
+    }, isc::InvalidParameter);
+
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // Value of "mapped-file" key is not a string
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::CREATE,
+                               Element::fromJSON("{\"mapped-file\": 42}"));
+    }, isc::InvalidParameter);
+
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+}
+
+TEST_F(ZoneTableSegmentMappedTest, reset) {
+    // By default, the mapped file doesn't exist, so we cannot open it
+    // in READ_ONLY mode (which does not create the file).
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::READ_ONLY, config_params_);
+    }, MemorySegmentOpenError);
+
+    // The following should still throw, unaffected by the failed open.
+    EXPECT_THROW(ztable_segment_->getHeader(), isc::InvalidOperation);
+    EXPECT_THROW(ztable_segment_->getMemorySegment(), isc::InvalidOperation);
+
+    // isUsable() and isWritable() must still return false, because the
+    // segment has not been successfully reset() yet.
+    EXPECT_FALSE(ztable_segment_->isUsable());
+    EXPECT_FALSE(ztable_segment_->isWritable());
+
+    // READ_WRITE mode must create the mapped file if it doesn't exist
+    // (and must not result in an exception).
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+
+    // The following method calls should no longer throw:
+    EXPECT_NO_THROW(ztable_segment_->getHeader());
+    EXPECT_NO_THROW(ztable_segment_->getMemorySegment());
+
+    // Let's try to re-open the mapped file in READ_ONLY mode. It should
+    // not fail now.
+    ztable_segment_->reset(ZoneTableSegment::READ_ONLY, config_params_);
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_FALSE(ztable_segment_->isWritable());
+
+    // Re-creating the mapped file should erase old data and should not
+    // trigger any exceptions inside reset() due to old data (such as
+    // named addresses).
+    ztable_segment_->reset(ZoneTableSegment::CREATE, config_params_);
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+
+    // When we reset() with an invalid paramter and it fails, then the
+    // segment should still be usable.
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::CREATE,
+                               Element::fromJSON("{}"));
+    }, isc::InvalidParameter);
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+    // The following should not throw.
+    EXPECT_NO_THROW(ztable_segment_->getHeader());
+    EXPECT_NO_THROW(ztable_segment_->getMemorySegment());
+
+    // READ_WRITE with an existing map file ought to work too. This
+    // would use existing named addresses. This actually re-opens the
+    // currently open map.
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetCreate) {
+    // At this point, the underlying file must not exist.
+    ASSERT_FALSE(fileExists(mapped_file));
+
+    // Open the underlying mapped file in create mode.
+    ztable_segment_->reset(ZoneTableSegment::CREATE, config_params_);
+
+    ASSERT_TRUE(ztable_segment_->isUsable());
+    ASSERT_TRUE(ztable_segment_->isWritable());
+
+    // Add the data.
+    addData(ztable_segment_->getMemorySegment());
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // Close the segment.
+    ztable_segment_->clear();
+
+    // At this point, the underlying file must still exist.
+    ASSERT_TRUE(fileExists(mapped_file));
+
+    // Open the underlying mapped file in create mode again.
+    ztable_segment_->reset(ZoneTableSegment::CREATE, config_params_);
+
+    // The old data should be gone.
+    EXPECT_FALSE(verifyData(ztable_segment_->getMemorySegment()));
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetReadWrite) {
+    // At this point, the underlying file must not exist.
+    ASSERT_FALSE(fileExists(mapped_file));
+
+    // Open the underlying mapped file in read+write mode.
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+
+    ASSERT_TRUE(ztable_segment_->isUsable());
+    ASSERT_TRUE(ztable_segment_->isWritable());
+
+    // Add the data.
+    addData(ztable_segment_->getMemorySegment());
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // Close the segment.
+    ztable_segment_->clear();
+
+    // At this point, the underlying file must still exist.
+    ASSERT_TRUE(fileExists(mapped_file));
+
+    // Open the underlying mapped file in read+write mode again.
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+
+    // The old data should still be available.
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetReadOnly) {
+    // At this point, the underlying file must not exist.
+    ASSERT_FALSE(fileExists(mapped_file));
+
+    // Open the underlying mapped file in read+write mode.
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+
+    ASSERT_TRUE(ztable_segment_->isUsable());
+    ASSERT_TRUE(ztable_segment_->isWritable());
+
+    // Add the data.
+    addData(ztable_segment_->getMemorySegment());
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // Close the segment.
+    ztable_segment_->clear();
+
+    // At this point, the underlying file must still exist.
+    ASSERT_TRUE(fileExists(mapped_file));
+
+    // Open the underlying mapped file in read-only mode again.
+    ztable_segment_->reset(ZoneTableSegment::READ_ONLY, config_params_);
+
+    // The old data should still be available.
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // But trying to allocate new data should result in an exception as
+    // the segment is read-only!
+    EXPECT_THROW(addData(ztable_segment_->getMemorySegment()),
+                 MemorySegmentError);
+}
+
+TEST_F(ZoneTableSegmentMappedTest, clearUninitialized) {
+    // Clearing a segment that has not been reset() is a nop, as clear()
+    // returns it to a fresh uninitialized state anyway.
+    EXPECT_NO_THROW(ztable_segment_->clear());
+
+    // The following should still throw, because the segment has not
+    // been successfully reset() yet.
+    EXPECT_THROW(ztable_segment_->getHeader(), isc::InvalidOperation);
+    EXPECT_THROW(ztable_segment_->getMemorySegment(), isc::InvalidOperation);
+
+    // isWritable() must still return false, because the segment has not
+    // been successfully reset() yet.
+    EXPECT_FALSE(ztable_segment_->isUsable());
+    EXPECT_FALSE(ztable_segment_->isWritable());
+}
+
+TEST_F(ZoneTableSegmentMappedTest, clear) {
+    // First, open an underlying mapped file in read+write mode (doesn't
+    // exist yet)
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+    // The following method calls should no longer throw:
+    EXPECT_NO_THROW(ztable_segment_->getHeader());
+    EXPECT_NO_THROW(ztable_segment_->getMemorySegment());
+
+    // Now, clear the segment.
+    ztable_segment_->clear();
+
+    EXPECT_FALSE(ztable_segment_->isUsable());
+    EXPECT_FALSE(ztable_segment_->isWritable());
+    // The following method calls should now throw.
+    EXPECT_THROW(ztable_segment_->getHeader(), isc::InvalidOperation);
+    EXPECT_THROW(ztable_segment_->getMemorySegment(), isc::InvalidOperation);
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetFailedCorruptedChecksum) {
+    setupMappedFiles();
+
+    // Open mapped file 1 in read-write mode
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+
+    // Corrupt mapped file 2.
+    scoped_ptr<MemorySegmentMapped> segment
+        (new MemorySegmentMapped(mapped_file2,
+                                 MemorySegmentMapped::OPEN_OR_CREATE));
+    EXPECT_TRUE(verifyData(*segment));
+    corruptChecksum(*segment);
+    segment.reset();
+
+    // Resetting to mapped file 2 in read-write mode should fail
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params2_);
+    }, ResetFailed);
+
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+    // Check for the old data in the segment to make sure it is still
+    // available and correct.
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetFailedMissingChecksum) {
+    setupMappedFiles();
+
+    // Open mapped file 1 in read-write mode
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+
+    // Corrupt mapped file 2.
+    scoped_ptr<MemorySegmentMapped> segment
+        (new MemorySegmentMapped(mapped_file2,
+                                 MemorySegmentMapped::OPEN_OR_CREATE));
+    EXPECT_TRUE(verifyData(*segment));
+    deleteChecksum(*segment);
+    segment.reset();
+
+    // Resetting to mapped file 2 in read-only mode should fail
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::READ_ONLY, config_params2_);
+    }, ResetFailed);
+
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+    // Check for the old data in the segment to make sure it is still
+    // available and correct.
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetFailedMissingHeader) {
+    setupMappedFiles();
+
+    // Open mapped file 1 in read-write mode
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+
+    // Corrupt mapped file 2.
+    scoped_ptr<MemorySegmentMapped> segment
+        (new MemorySegmentMapped(mapped_file2,
+                                 MemorySegmentMapped::OPEN_OR_CREATE));
+    EXPECT_TRUE(verifyData(*segment));
+    deleteHeader(*segment);
+    segment.reset();
+
+    // Resetting to mapped file 2 in read-only mode should fail
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::READ_ONLY, config_params2_);
+    }, ResetFailed);
+
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+    // Check for the old data in the segment to make sure it is still
+    // available and correct.
+    EXPECT_TRUE(verifyData(ztable_segment_->getMemorySegment()));
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetCreateOverCorruptedFile) {
+    setupMappedFiles();
+
+    // Corrupt mapped file 1.
+    scoped_ptr<MemorySegmentMapped> segment
+        (new MemorySegmentMapped(mapped_file,
+                                 MemorySegmentMapped::OPEN_OR_CREATE));
+    EXPECT_TRUE(verifyData(*segment));
+    corruptChecksum(*segment);
+    segment.reset();
+
+    // Resetting to mapped file 1 in CREATE mode over a corrupted file
+    // should pass.
+    EXPECT_NO_THROW(ztable_segment_->reset(ZoneTableSegment::CREATE,
+                                           config_params_));
+
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+    // Check for the old data in the segment. It should not be present
+    // (as we opened the segment in CREATE mode).
+    EXPECT_FALSE(verifyData(ztable_segment_->getMemorySegment()));
+
+    // Now try the same with missing checksum.
+    setupMappedFiles();
+
+    // Corrupt mapped file 1.
+    segment.reset(new MemorySegmentMapped(mapped_file,
+                                          MemorySegmentMapped::OPEN_OR_CREATE));
+    EXPECT_TRUE(verifyData(*segment));
+    deleteChecksum(*segment);
+    segment.reset();
+
+    // Resetting to mapped file 1 in CREATE mode over a file missing
+    // checksum should pass.
+    EXPECT_NO_THROW(ztable_segment_->reset(ZoneTableSegment::CREATE,
+                                           config_params_));
+
+    EXPECT_TRUE(ztable_segment_->isUsable());
+    EXPECT_TRUE(ztable_segment_->isWritable());
+    // Check for the old data in the segment. It should not be present
+    // (as we opened the segment in CREATE mode).
+    EXPECT_FALSE(verifyData(ztable_segment_->getMemorySegment()));
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetHeaderUninitialized) {
+    // This should throw as we haven't called reset() yet.
+    EXPECT_THROW(ztable_segment_->resetHeader(), isc::InvalidOperation);
+}
+
+TEST_F(ZoneTableSegmentMappedTest, resetHeader) {
+    // First, open an underlying mapped file in read+write mode (doesn't
+    // exist yet)
+    ztable_segment_->reset(ZoneTableSegment::READ_WRITE, config_params_);
+
+    // Check if a valid ZoneTable is found.
+    {
+        const ZoneTableHeader& header = ztable_segment_->getHeader();
+        const ZoneTable* table = header.getTable();
+        EXPECT_EQ(0, table->getZoneCount());
+    }
+
+    // Grow the segment by allocating something large.
+    EXPECT_THROW(ztable_segment_->getMemorySegment().allocate(1<<16),
+                 MemorySegmentGrown);
+
+    // Reset the header address. This should not throw now.
+    EXPECT_NO_THROW(ztable_segment_->resetHeader());
+
+    // Check if a valid ZoneTable is found.
+    {
+        const ZoneTableHeader& header = ztable_segment_->getHeader();
+        const ZoneTable* table = header.getTable();
+        EXPECT_EQ(0, table->getZoneCount());
+    }
+}
+
+} // anonymous namespace
diff --git a/src/lib/datasrc/tests/memory/zone_table_segment_mock.h b/src/lib/datasrc/tests/memory/zone_table_segment_mock.h
new file mode 100644
index 0000000..bd10c1e
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_table_segment_mock.h
@@ -0,0 +1,99 @@
+// Copyright (C) 2012  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_MEMORY_ZONE_TABLE_SEGMENT_TEST_H
+#define DATASRC_MEMORY_ZONE_TABLE_SEGMENT_TEST_H 1
+
+#include <datasrc/memory/zone_table_segment.h>
+#include <datasrc/memory/zone_table.h>
+#include <datasrc/memory/zone_data.h>
+#include <datasrc/memory/zone_writer.h>
+
+#include <string>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+namespace test {
+
+// A special ZoneTableSegment that can be used for tests.  It can be
+// passed a MemorySegment that can be used later to test if all memory
+// was de-allocated on it.
+class ZoneTableSegmentMock : public ZoneTableSegment {
+public:
+    ZoneTableSegmentMock(const isc::dns::RRClass& rrclass,
+                         isc::util::MemorySegment& mem_sgmt) :
+        ZoneTableSegment(rrclass),
+        impl_type_("mock"),
+        mem_sgmt_(mem_sgmt),
+        header_(ZoneTable::create(mem_sgmt_, rrclass))
+    {}
+
+    virtual ~ZoneTableSegmentMock() {
+        ZoneTable::destroy(mem_sgmt_, header_.getTable());
+    }
+
+    const std::string& getImplType() const {
+        return (impl_type_);
+    }
+
+    virtual void reset(MemorySegmentOpenMode, isc::data::ConstElementPtr) {
+        isc_throw(isc::NotImplemented, "reset() is not implemented");
+    }
+
+    virtual void clear() {
+        isc_throw(isc::NotImplemented, "clear() is not implemented");
+    }
+
+    virtual void resetHeader() {
+        // This method does not have to do anything in this
+        // implementation.
+    }
+
+    virtual ZoneTableHeader& getHeader() {
+        return (header_);
+    }
+
+    virtual const ZoneTableHeader& getHeader() const {
+        return (header_);
+    }
+
+    virtual isc::util::MemorySegment& getMemorySegment() {
+        return (mem_sgmt_);
+    }
+
+    virtual bool isUsable() const {
+        return (true);
+    }
+
+    virtual bool isWritable() const {
+        return (true);
+    }
+
+private:
+    std::string impl_type_;
+    isc::util::MemorySegment& mem_sgmt_;
+    ZoneTableHeader header_;
+};
+
+} // namespace test
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_MEMORY_ZONE_TABLE_SEGMENT_TEST_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/memory/zone_table_segment_test.h b/src/lib/datasrc/tests/memory/zone_table_segment_test.h
deleted file mode 100644
index 2078036..0000000
--- a/src/lib/datasrc/tests/memory/zone_table_segment_test.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright (C) 2012  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_MEMORY_ZONE_TABLE_SEGMENT_TEST_H
-#define DATASRC_MEMORY_ZONE_TABLE_SEGMENT_TEST_H 1
-
-#include <datasrc/memory/zone_table_segment.h>
-#include <datasrc/memory/zone_table.h>
-#include <datasrc/memory/zone_data.h>
-#include <datasrc/memory/zone_writer_local.h>
-
-namespace isc {
-namespace datasrc {
-namespace memory {
-namespace test {
-
-// A special ZoneTableSegment that can be used for tests.  It can be
-// passed a MemorySegment that can be used later to test if all memory
-// was de-allocated on it.
-class ZoneTableSegmentTest : public ZoneTableSegment {
-public:
-    ZoneTableSegmentTest(isc::dns::RRClass rrclass,
-                         isc::util::MemorySegment& mem_sgmt) :
-        ZoneTableSegment(rrclass),
-        mem_sgmt_(mem_sgmt),
-        header_(ZoneTable::create(mem_sgmt_, rrclass))
-    {}
-
-    virtual ~ZoneTableSegmentTest() {
-        ZoneTable::destroy(mem_sgmt_, header_.getTable());
-    }
-
-    virtual ZoneTableHeader& getHeader() {
-        return (header_);
-    }
-
-    virtual const ZoneTableHeader& getHeader() const {
-        return (header_);
-    }
-
-    virtual isc::util::MemorySegment& getMemorySegment() {
-        return (mem_sgmt_);
-    }
-
-    virtual ZoneWriter* getZoneWriter(const LoadAction& load_action,
-                                      const dns::Name& name,
-                                      const dns::RRClass& rrclass)
-    {
-        return (new Writer(this, load_action, name, rrclass));
-    }
-
-private:
-    isc::util::MemorySegment& mem_sgmt_;
-    ZoneTableHeader header_;
-
-    // A writer for this segment. The implementation is similar
-    // to ZoneWriterLocal, but all the error handling is stripped
-    // for simplicity. Also, we do everything inside the
-    // install(), for the same reason. We just need something
-    // inside the tests, not a full-blown implementation
-    // for background loading.
-    class Writer : public ZoneWriter {
-    public:
-        Writer(ZoneTableSegmentTest* segment, const LoadAction& load_action,
-               const dns::Name& name, const dns::RRClass& rrclass) :
-            segment_(segment),
-            load_action_(load_action),
-            name_(name),
-            rrclass_(rrclass)
-        {}
-
-        void load() {}
-
-        void install() {
-            ZoneTable* table(segment_->getHeader().getTable());
-            const ZoneTable::AddResult
-                result(table->addZone(segment_->getMemorySegment(), rrclass_,
-                                      name_,
-                                      load_action_(segment_->
-                                                   getMemorySegment())));
-            if (result.zone_data != NULL) {
-                ZoneData::destroy(segment_->getMemorySegment(),
-                                  result.zone_data, rrclass_);
-            }
-        }
-
-        virtual void cleanup() {}
-    private:
-        ZoneTableSegmentTest* segment_;
-        LoadAction load_action_;
-        dns::Name name_;
-        dns::RRClass rrclass_;
-    };
-};
-
-} // namespace test
-} // namespace memory
-} // namespace datasrc
-} // namespace isc
-
-#endif // DATASRC_MEMORY_ZONE_TABLE_SEGMENT_TEST_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/datasrc/tests/memory/zone_table_segment_unittest.cc b/src/lib/datasrc/tests/memory/zone_table_segment_unittest.cc
index 51d5e0f..f0a07da 100644
--- a/src/lib/datasrc/tests/memory/zone_table_segment_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_table_segment_unittest.cc
@@ -12,9 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <datasrc/memory/zone_writer_local.h>
+#include <datasrc/memory/zone_writer.h>
 #include <datasrc/memory/zone_table_segment_local.h>
-#include <util/memory_segment_local.h>
 
 #include <gtest/gtest.h>
 #include <boost/scoped_ptr.hpp>
@@ -42,6 +41,9 @@ protected:
     ZoneTableSegment* ztable_segment_;
 };
 
+TEST_F(ZoneTableSegmentTest, getImplType) {
+    EXPECT_EQ("local", ztable_segment_->getImplType());
+}
 
 TEST_F(ZoneTableSegmentTest, create) {
     // By default, a local zone table segment is created.
@@ -52,6 +54,21 @@ TEST_F(ZoneTableSegmentTest, create) {
                  UnknownSegmentType);
 }
 
+TEST_F(ZoneTableSegmentTest, reset) {
+    // reset() should throw that it's not implemented so that any
+    // accidental calls are found out.
+    EXPECT_THROW({
+        ztable_segment_->reset(ZoneTableSegment::CREATE,
+                               Element::fromJSON("{}"));
+    }, isc::NotImplemented);
+}
+
+TEST_F(ZoneTableSegmentTest, clear) {
+    // clear() should throw that it's not implemented so that any
+    // accidental calls are found out.
+    EXPECT_THROW(ztable_segment_->clear(), isc::NotImplemented);
+}
+
 // Helper function to check const and non-const methods.
 template <typename TS, typename TH, typename TT>
 void
@@ -71,6 +88,19 @@ TEST_F(ZoneTableSegmentTest, getHeader) {
     // const version.
     testGetHeader<const ZoneTableSegment, const ZoneTableHeader,
                   const ZoneTable>(ztable_segment_);
+
+    // This is a nop for local segments.
+    ztable_segment_->resetHeader();
+
+    // The following still behave as before after resetHeader().
+
+    // non-const version.
+    testGetHeader<ZoneTableSegment, ZoneTableHeader, ZoneTable>
+        (ztable_segment_);
+
+    // const version.
+    testGetHeader<const ZoneTableSegment, const ZoneTableHeader,
+                  const ZoneTable>(ztable_segment_);
 }
 
 TEST_F(ZoneTableSegmentTest, getMemorySegment) {
@@ -79,22 +109,14 @@ TEST_F(ZoneTableSegmentTest, getMemorySegment) {
     mem_sgmt.allMemoryDeallocated(); // use mem_sgmt
 }
 
-ZoneData*
-loadAction(MemorySegment&) {
-    // The function won't be called, so this is OK
-    return (NULL);
+TEST_F(ZoneTableSegmentTest, isUsable) {
+    // Local segments are always usable.
+    EXPECT_TRUE(ztable_segment_->isUsable());
 }
 
-// Test we can get a writer.
-TEST_F(ZoneTableSegmentTest, getZoneWriter) {
-    scoped_ptr<ZoneWriter>
-        writer(ztable_segment_->getZoneWriter(loadAction, Name("example.org"),
-                                              RRClass::IN()));
-    // We have to get something
-    EXPECT_NE(static_cast<void*>(NULL), writer.get());
-    // And for now, it should be the local writer
-    EXPECT_NE(static_cast<void*>(NULL),
-              dynamic_cast<ZoneWriterLocal*>(writer.get()));
+TEST_F(ZoneTableSegmentTest, isWritable) {
+    // Local segments are always writable.
+    EXPECT_TRUE(ztable_segment_->isWritable());
 }
 
 } // anonymous namespace
diff --git a/src/lib/datasrc/tests/memory/zone_table_unittest.cc b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
index 0109793..6599f3b 100644
--- a/src/lib/datasrc/tests/memory/zone_table_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
@@ -12,8 +12,6 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include "memory_segment_test.h"
-
 #include <exceptions/exceptions.h>
 
 #include <util/memory_segment_local.h>
@@ -26,6 +24,8 @@
 #include <datasrc/memory/zone_table.h>
 #include <datasrc/memory/segment_object_holder.h>
 
+#include <datasrc/tests/memory/memory_segment_mock.h>
+
 #include <gtest/gtest.h>
 
 #include <new>                  // for bad_alloc
@@ -56,7 +56,7 @@ protected:
     }
     const RRClass zclass_;
     const Name zname1, zname2, zname3;
-    test::MemorySegmentTest mem_sgmt_;
+    test::MemorySegmentMock mem_sgmt_;
     ZoneTable* zone_table;
 };
 
diff --git a/src/lib/datasrc/tests/memory/zone_writer_unittest.cc b/src/lib/datasrc/tests/memory/zone_writer_unittest.cc
index 5d2cd0a..f4f2295 100644
--- a/src/lib/datasrc/tests/memory/zone_writer_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_writer_unittest.cc
@@ -12,13 +12,16 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <datasrc/memory/zone_writer_local.h>
+#include <datasrc/memory/zone_writer.h>
 #include <datasrc/memory/zone_table_segment_local.h>
 #include <datasrc/memory/zone_data.h>
 
 #include <dns/rrclass.h>
 #include <dns/name.h>
 
+#include <datasrc/tests/memory/memory_segment_mock.h>
+#include <datasrc/tests/memory/zone_table_segment_mock.h>
+
 #include <gtest/gtest.h>
 
 #include <boost/scoped_ptr.hpp>
@@ -29,37 +32,52 @@ using boost::bind;
 using isc::dns::RRClass;
 using isc::dns::Name;
 using namespace isc::datasrc::memory;
+using namespace isc::datasrc::memory::test;
 
 namespace {
 
 class TestException {};
 
-class ZoneWriterLocalTest : public ::testing::Test {
+class ZoneTableSegmentHelper : public ZoneTableSegmentMock {
 public:
-    ZoneWriterLocalTest() :
-        segment_(ZoneTableSegment::create(RRClass::IN(), "local")),
+    ZoneTableSegmentHelper(const isc::dns::RRClass& rrclass,
+                           isc::util::MemorySegment& mem_sgmt) :
+        ZoneTableSegmentMock(rrclass, mem_sgmt),
+        reset_header_called_(false)
+    {}
+
+    virtual void resetHeader() {
+        reset_header_called_ = true;
+    }
+
+    bool reset_header_called_;
+};
+
+class ZoneWriterTest : public ::testing::Test {
+protected:
+    ZoneWriterTest() :
+        segment_(new ZoneTableSegmentHelper(RRClass::IN(), mem_sgmt_)),
         writer_(new
-            ZoneWriterLocal(dynamic_cast<ZoneTableSegmentLocal*>(segment_.
-                                                                 get()),
-                            bind(&ZoneWriterLocalTest::loadAction, this, _1),
-                            Name("example.org"), RRClass::IN())),
+            ZoneWriter(*segment_,
+                       bind(&ZoneWriterTest::loadAction, this, _1),
+                       Name("example.org"), RRClass::IN())),
         load_called_(false),
         load_throw_(false),
         load_null_(false),
         load_data_(false)
     {}
-    void TearDown() {
+    virtual void TearDown() {
         // Release the writer
         writer_.reset();
     }
-protected:
-    scoped_ptr<ZoneTableSegment> segment_;
-    scoped_ptr<ZoneWriterLocal> writer_;
+    MemorySegmentMock mem_sgmt_;
+    scoped_ptr<ZoneTableSegmentHelper> segment_;
+    scoped_ptr<ZoneWriter> writer_;
     bool load_called_;
     bool load_throw_;
     bool load_null_;
     bool load_data_;
-private:
+public:
     ZoneData* loadAction(isc::util::MemorySegment& segment) {
         // Make sure it is the correct segment passed. We know the
         // exact instance, can compare pointers to them.
@@ -86,38 +104,76 @@ private:
     }
 };
 
+class ReadOnlySegment : public ZoneTableSegmentMock {
+public:
+    ReadOnlySegment(const isc::dns::RRClass& rrclass,
+                    isc::util::MemorySegment& mem_sgmt) :
+        ZoneTableSegmentMock(rrclass, mem_sgmt)
+    {}
+
+    // Returns false indicating that the segment is not usable. We
+    // override this too as ZoneTableSegment implementations may use it
+    // internally.
+    virtual bool isUsable() const {
+        return (false);
+    }
+
+    // Returns false indicating it is a read-only segment. It is used in
+    // the ZoneWriter tests.
+    virtual bool isWritable() const {
+        return (false);
+    }
+};
+
+TEST_F(ZoneWriterTest, constructForReadOnlySegment) {
+    MemorySegmentMock mem_sgmt;
+    ReadOnlySegment ztable_segment(RRClass::IN(), mem_sgmt);
+    EXPECT_THROW(ZoneWriter(ztable_segment,
+                            bind(&ZoneWriterTest::loadAction, this, _1),
+                            Name("example.org"), RRClass::IN()),
+                 isc::InvalidOperation);
+}
+
 // We call it the way we are supposed to, check every callback is called in the
 // right moment.
-TEST_F(ZoneWriterLocalTest, correctCall) {
+TEST_F(ZoneWriterTest, correctCall) {
     // Nothing called before we call it
     EXPECT_FALSE(load_called_);
+    EXPECT_FALSE(segment_->reset_header_called_);
 
     // Just the load gets called now
     EXPECT_NO_THROW(writer_->load());
     EXPECT_TRUE(load_called_);
+    EXPECT_TRUE(segment_->reset_header_called_);
     load_called_ = false;
+    segment_->reset_header_called_ = false;
 
     EXPECT_NO_THROW(writer_->install());
     EXPECT_FALSE(load_called_);
+    EXPECT_TRUE(segment_->reset_header_called_);
 
     // We don't check explicitly how this works, but call it to free memory. If
     // everything is freed should be checked inside the TearDown.
     EXPECT_NO_THROW(writer_->cleanup());
 }
 
-TEST_F(ZoneWriterLocalTest, loadTwice) {
+TEST_F(ZoneWriterTest, loadTwice) {
     // Load it the first time
     EXPECT_NO_THROW(writer_->load());
     EXPECT_TRUE(load_called_);
+    EXPECT_TRUE(segment_->reset_header_called_);
     load_called_ = false;
+    segment_->reset_header_called_ = false;
 
     // The second time, it should not be possible
     EXPECT_THROW(writer_->load(), isc::InvalidOperation);
     EXPECT_FALSE(load_called_);
+    EXPECT_FALSE(segment_->reset_header_called_);
 
     // The object should not be damaged, try installing and clearing now
     EXPECT_NO_THROW(writer_->install());
     EXPECT_FALSE(load_called_);
+    EXPECT_TRUE(segment_->reset_header_called_);
 
     // We don't check explicitly how this works, but call it to free memory. If
     // everything is freed should be checked inside the TearDown.
@@ -126,25 +182,28 @@ TEST_F(ZoneWriterLocalTest, loadTwice) {
 
 // Try loading after call to install and call to cleanup. Both is
 // forbidden.
-TEST_F(ZoneWriterLocalTest, loadLater) {
+TEST_F(ZoneWriterTest, loadLater) {
     // Load first, so we can install
     EXPECT_NO_THROW(writer_->load());
     EXPECT_NO_THROW(writer_->install());
     // Reset so we see nothing is called now
     load_called_ = false;
+    segment_->reset_header_called_ = false;
 
     EXPECT_THROW(writer_->load(), isc::InvalidOperation);
     EXPECT_FALSE(load_called_);
+    EXPECT_FALSE(segment_->reset_header_called_);
 
     // Cleanup and try loading again. Still shouldn't work.
     EXPECT_NO_THROW(writer_->cleanup());
 
     EXPECT_THROW(writer_->load(), isc::InvalidOperation);
     EXPECT_FALSE(load_called_);
+    EXPECT_FALSE(segment_->reset_header_called_);
 }
 
 // Try calling install at various bad times
-TEST_F(ZoneWriterLocalTest, invalidInstall) {
+TEST_F(ZoneWriterTest, invalidInstall) {
     // Nothing loaded yet
     EXPECT_THROW(writer_->install(), isc::InvalidOperation);
     EXPECT_FALSE(load_called_);
@@ -161,7 +220,7 @@ TEST_F(ZoneWriterLocalTest, invalidInstall) {
 // We check we can clean without installing first and nothing bad
 // happens. We also misuse the testcase to check we can't install
 // after cleanup.
-TEST_F(ZoneWriterLocalTest, cleanWithoutInstall) {
+TEST_F(ZoneWriterTest, cleanWithoutInstall) {
     EXPECT_NO_THROW(writer_->load());
     EXPECT_NO_THROW(writer_->cleanup());
 
@@ -172,7 +231,7 @@ TEST_F(ZoneWriterLocalTest, cleanWithoutInstall) {
 }
 
 // Test the case when load callback throws
-TEST_F(ZoneWriterLocalTest, loadThrows) {
+TEST_F(ZoneWriterTest, loadThrows) {
     load_throw_ = true;
     EXPECT_THROW(writer_->load(), TestException);
 
@@ -186,7 +245,7 @@ TEST_F(ZoneWriterLocalTest, loadThrows) {
 
 // Check the strong exception guarantee - if it throws, nothing happened
 // to the content.
-TEST_F(ZoneWriterLocalTest, retry) {
+TEST_F(ZoneWriterTest, retry) {
     // First attempt fails due to some exception.
     load_throw_ = true;
     EXPECT_THROW(writer_->load(), TestException);
@@ -214,7 +273,7 @@ TEST_F(ZoneWriterLocalTest, retry) {
 }
 
 // Check the writer defends itsefl when load action returns NULL
-TEST_F(ZoneWriterLocalTest, loadNull) {
+TEST_F(ZoneWriterTest, loadNull) {
     load_null_ = true;
     EXPECT_THROW(writer_->load(), isc::InvalidOperation);
 
@@ -226,7 +285,7 @@ TEST_F(ZoneWriterLocalTest, loadNull) {
 }
 
 // Check the object cleans up in case we forget it.
-TEST_F(ZoneWriterLocalTest, autoCleanUp) {
+TEST_F(ZoneWriterTest, autoCleanUp) {
     // Load data and forget about it. It should get released
     // when the writer itself is destroyed.
     EXPECT_NO_THROW(writer_->load());
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index f541fd8..fc08305 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -36,7 +36,6 @@
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 #include <boost/shared_ptr.hpp>
-#include <boost/scoped_ptr.hpp>
 
 #include <fstream>
 #include <sstream>
@@ -44,7 +43,6 @@
 
 using namespace std;
 using boost::shared_ptr;
-using boost::scoped_ptr;
 
 using namespace isc::data;
 using namespace isc::util;
@@ -79,12 +77,12 @@ createInMemoryClient(RRClass zclass, const Name& zname) {
             string(TEST_ZONE_FILE) + "\"}}"), true);
     shared_ptr<ZoneTableSegment> ztable_segment(
         ZoneTableSegment::create(zclass, cache_conf.getSegmentType()));
-    scoped_ptr<memory::ZoneWriter> writer(
-        ztable_segment->getZoneWriter(cache_conf.getLoadAction(zclass, zname),
-                                      zname, zclass));
-    writer->load();
-    writer->install();
-    writer->cleanup();
+    memory::ZoneWriter writer(*ztable_segment,
+                              cache_conf.getLoadAction(zclass, zname),
+                              zname, zclass);
+    writer.load();
+    writer.install();
+    writer.cleanup();
     shared_ptr<InMemoryClient> client(new InMemoryClient(ztable_segment,
                                                          zclass));
 
diff --git a/src/lib/datasrc/tests/zone_loader_unittest.cc b/src/lib/datasrc/tests/zone_loader_unittest.cc
index 4cf9e9a..80d23b7 100644
--- a/src/lib/datasrc/tests/zone_loader_unittest.cc
+++ b/src/lib/datasrc/tests/zone_loader_unittest.cc
@@ -319,9 +319,9 @@ protected:
                                   rrclass_, cache_conf.getSegmentType()));
         if (filename) {
             boost::scoped_ptr<memory::ZoneWriter> writer(
-                ztable_segment_->getZoneWriter(cache_conf.getLoadAction(
-                                                   rrclass_, zone),
-                                               zone, rrclass_));
+                new memory::ZoneWriter(*ztable_segment_,
+                                       cache_conf.getLoadAction(rrclass_, zone),
+                                       zone, rrclass_));
             writer->load();
             writer->install();
             writer->cleanup();
diff --git a/src/lib/util/memory_segment.h b/src/lib/util/memory_segment.h
index e62c9df..a613fd9 100644
--- a/src/lib/util/memory_segment.h
+++ b/src/lib/util/memory_segment.h
@@ -17,6 +17,8 @@
 
 #include <exceptions/exceptions.h>
 
+#include <utility>
+
 #include <stdlib.h>
 
 namespace isc {
@@ -116,6 +118,8 @@ public:
     /// requested storage.
     /// \throw MemorySegmentGrown The memory segment doesn't have sufficient
     /// space for the requested size and has grown internally.
+    /// \throw MemorySegmentError An attempt was made to allocate
+    /// storage on a read-only memory segment.
     ///
     /// \param size The size of the memory requested in bytes.
     /// \return Returns pointer to the memory allocated.
@@ -153,7 +157,7 @@ public:
     /// \return Returns <code>true</code> if all allocated memory (including
     /// names associated by memory addresses by \c setNamedAddress()) was
     /// deallocated, <code>false</code> otherwise.
-    virtual bool allMemoryDeallocated() const = 0;
+    virtual bool allMemoryDeallocated() = 0;
 
     /// \brief Associate specified address in the segment with a given name.
     ///
@@ -176,7 +180,8 @@ public:
     /// as \c addr even if it wouldn't be considered to "belong to" the
     /// segment in its normal sense; it can be used to indicate that memory
     /// has not been allocated for the specified name.  A subsequent call
-    /// to \c getNamedAddress() will return NULL for that name.
+    /// to \c getNamedAddress() will return NamedAddressResult(true, NULL)
+    /// for that name.
     ///
     /// \note Naming an address is intentionally separated from allocation
     /// so that, for example, one module of a program can name a memory
@@ -228,6 +233,9 @@ public:
         return (setNamedAddressImpl(name, addr));
     }
 
+    /// \brief Type definition for result returned by getNamedAddress()
+    typedef std::pair<bool, void*> NamedAddressResult;
+
     /// \brief Return the address in the segment that has the given name.
     ///
     /// This method returns the memory address in the segment corresponding
@@ -245,8 +253,10 @@ public:
     ///
     /// \param name A C string of which the segment memory address is to be
     /// returned.  Must not be NULL.
-    /// \return The address associated with the name, or NULL if not found.
-    void* getNamedAddress(const char* name) {
+    /// \return An std::pair containing a bool (set to true if the name
+    /// was found, or false otherwise) and the address associated with
+    /// the name (which is undefined if the name was not found).
+    NamedAddressResult getNamedAddress(const char* name) const {
         // This public method implements common validation.  The actual
         // work specific to the derived segment is delegated to the
         // corresponding protected method.
@@ -288,7 +298,7 @@ protected:
     virtual bool setNamedAddressImpl(const char* name, void* addr) = 0;
 
     /// \brief Implementation of getNamedAddress beyond common validation.
-    virtual void* getNamedAddressImpl(const char* name) = 0;
+    virtual NamedAddressResult getNamedAddressImpl(const char* name) const = 0;
 
     /// \brief Implementation of clearNamedAddress beyond common validation.
     virtual bool clearNamedAddressImpl(const char* name) = 0;
diff --git a/src/lib/util/memory_segment_local.cc b/src/lib/util/memory_segment_local.cc
index 81548fd..ec6ee66 100644
--- a/src/lib/util/memory_segment_local.cc
+++ b/src/lib/util/memory_segment_local.cc
@@ -47,17 +47,18 @@ MemorySegmentLocal::deallocate(void* ptr, size_t size) {
 }
 
 bool
-MemorySegmentLocal::allMemoryDeallocated() const {
+MemorySegmentLocal::allMemoryDeallocated() {
     return (allocated_size_ == 0 && named_addrs_.empty());
 }
 
-void*
-MemorySegmentLocal::getNamedAddressImpl(const char* name) {
-    std::map<std::string, void*>::iterator found = named_addrs_.find(name);
+MemorySegment::NamedAddressResult
+MemorySegmentLocal::getNamedAddressImpl(const char* name) const {
+    std::map<std::string, void*>::const_iterator found =
+        named_addrs_.find(name);
     if (found != named_addrs_.end()) {
-        return (found->second);
+        return (NamedAddressResult(true, found->second));
     }
-    return (0);
+    return (NamedAddressResult(false, NULL));
 }
 
 bool
diff --git a/src/lib/util/memory_segment_local.h b/src/lib/util/memory_segment_local.h
index 1db55a0..d3e556a 100644
--- a/src/lib/util/memory_segment_local.h
+++ b/src/lib/util/memory_segment_local.h
@@ -64,13 +64,13 @@ public:
     ///
     /// \return Returns <code>true</code> if all allocated memory was
     /// deallocated, <code>false</code> otherwise.
-    virtual bool allMemoryDeallocated() const;
+    virtual bool allMemoryDeallocated();
 
     /// \brief Local segment version of getNamedAddress.
     ///
     /// There's a small chance this method could throw std::bad_alloc.
     /// It should be considered a fatal error.
-    virtual void* getNamedAddressImpl(const char* name);
+    virtual NamedAddressResult getNamedAddressImpl(const char* name) const;
 
     /// \brief Local segment version of setNamedAddress.
     ///
diff --git a/src/lib/util/memory_segment_mapped.cc b/src/lib/util/memory_segment_mapped.cc
index e2ac944..0d82ffd 100644
--- a/src/lib/util/memory_segment_mapped.cc
+++ b/src/lib/util/memory_segment_mapped.cc
@@ -44,6 +44,15 @@ using boost::interprocess::offset_ptr;
 
 namespace isc {
 namespace util {
+
+namespace { // unnamed namespace
+
+const char* const RESERVED_NAMED_ADDRESS_STORAGE_NAME =
+    "_RESERVED_NAMED_ADDRESS_STORAGE";
+
+} // end of unnamed namespace
+
+
 // Definition of class static constant so it can be referenced by address
 // or reference.
 const size_t MemorySegmentMapped::INITIAL_SIZE;
@@ -98,6 +107,7 @@ struct MemorySegmentMapped::Impl {
         // confirm there's no other user and there won't either.
         lock_.reset(new boost::interprocess::file_lock(filename.c_str()));
         checkWriter();
+        reserveMemory();
     }
 
     // Constructor for open-or-write (and read-write) mode
@@ -108,6 +118,7 @@ struct MemorySegmentMapped::Impl {
         lock_(new boost::interprocess::file_lock(filename.c_str()))
     {
         checkWriter();
+        reserveMemory();
     }
 
     // Constructor for existing segment, either read-only or read-write
@@ -123,6 +134,37 @@ struct MemorySegmentMapped::Impl {
         } else {
             checkWriter();
         }
+        reserveMemory();
+    }
+
+    void reserveMemory() {
+        if (!read_only_) {
+            // Reserve a named address for use during
+            // setNamedAddress(). Though this will almost always succeed
+            // on the first try during construction, it may require
+            // multiple attempts later during a call from
+            // allMemoryDeallocated() when the segment has been in use
+            // for a while.
+            while (true) {
+                const offset_ptr<void>* reserved_storage =
+                    base_sgmt_->find_or_construct<offset_ptr<void> >(
+                        RESERVED_NAMED_ADDRESS_STORAGE_NAME, std::nothrow)();
+
+                if (reserved_storage) {
+                    break;
+                }
+
+                growSegment();
+            }
+        }
+    }
+
+    void freeReservedMemory() {
+        if (!read_only_) {
+            const bool deleted = base_sgmt_->destroy<offset_ptr<void> >
+                (RESERVED_NAMED_ADDRESS_STORAGE_NAME);
+            assert(deleted);
+        }
     }
 
     // Internal helper to grow the underlying mapped segment.
@@ -227,6 +269,7 @@ MemorySegmentMapped::MemorySegmentMapped(const std::string& filename,
 
 MemorySegmentMapped::~MemorySegmentMapped() {
     if (impl_->base_sgmt_ && !impl_->read_only_) {
+        impl_->freeReservedMemory();
         impl_->base_sgmt_->flush(); // note: this is exception free
     }
     delete impl_;
@@ -275,18 +318,22 @@ MemorySegmentMapped::deallocate(void* ptr, size_t) {
 }
 
 bool
-MemorySegmentMapped::allMemoryDeallocated() const {
-    return (impl_->base_sgmt_->all_memory_deallocated());
+MemorySegmentMapped::allMemoryDeallocated() {
+    impl_->freeReservedMemory();
+    const bool result = impl_->base_sgmt_->all_memory_deallocated();
+    impl_->reserveMemory();
+
+    return (result);
 }
 
-void*
-MemorySegmentMapped::getNamedAddressImpl(const char* name) {
+MemorySegment::NamedAddressResult
+MemorySegmentMapped::getNamedAddressImpl(const char* name) const {
     offset_ptr<void>* storage =
         impl_->base_sgmt_->find<offset_ptr<void> >(name).first;
     if (storage) {
-        return (storage->get());
+        return (NamedAddressResult(true, storage->get()));
     }
-    return (NULL);
+    return (NamedAddressResult(false, NULL));
 }
 
 bool
@@ -299,13 +346,27 @@ MemorySegmentMapped::setNamedAddressImpl(const char* name, void* addr) {
         isc_throw(MemorySegmentError, "address is out of segment: " << addr);
     }
 
+    // Temporarily save the passed addr into pre-allocated offset_ptr in
+    // case there are any relocations caused by allocations.
+    offset_ptr<void>* reserved_storage =
+        impl_->base_sgmt_->find<offset_ptr<void> >(
+            RESERVED_NAMED_ADDRESS_STORAGE_NAME).first;
+    assert(reserved_storage);
+    *reserved_storage = addr;
+
     bool grown = false;
     while (true) {
         offset_ptr<void>* storage =
             impl_->base_sgmt_->find_or_construct<offset_ptr<void> >(
                 name, std::nothrow)();
         if (storage) {
-            *storage = addr;
+            // Move the address from saved offset_ptr into the
+            // newly-allocated storage.
+            reserved_storage =
+                impl_->base_sgmt_->find<offset_ptr<void> >(
+                    RESERVED_NAMED_ADDRESS_STORAGE_NAME).first;
+            assert(reserved_storage);
+            *storage = *reserved_storage;
             return (grown);
         }
 
diff --git a/src/lib/util/memory_segment_mapped.h b/src/lib/util/memory_segment_mapped.h
index 7685e30..7702d88 100644
--- a/src/lib/util/memory_segment_mapped.h
+++ b/src/lib/util/memory_segment_mapped.h
@@ -175,7 +175,7 @@ public:
     /// read-only mode; in that case MemorySegmentError will be thrown.
     virtual void deallocate(void* ptr, size_t size);
 
-    virtual bool allMemoryDeallocated() const;
+    virtual bool allMemoryDeallocated();
 
     /// \brief Mapped segment version of setNamedAddress.
     ///
@@ -195,7 +195,7 @@ public:
     /// \brief Mapped segment version of getNamedAddress.
     ///
     /// This version never throws.
-    virtual void* getNamedAddressImpl(const char* name);
+    virtual NamedAddressResult getNamedAddressImpl(const char* name) const;
 
     /// \brief Mapped segment version of clearNamedAddress.
     ///
diff --git a/src/lib/util/random/random_number_generator.h b/src/lib/util/random/random_number_generator.h
index f0c0fb3..3f2a907 100644
--- a/src/lib/util/random/random_number_generator.h
+++ b/src/lib/util/random/random_number_generator.h
@@ -18,6 +18,7 @@
 #include <algorithm>
 #include <cmath>
 #include <numeric>
+#include <vector>
 
 #include <exceptions/exceptions.h>
 
@@ -59,7 +60,9 @@ public:
     ///
     /// \param min The minimum number in the range
     /// \param max The maximum number in the range
-    UniformRandomIntegerGenerator(int min, int max):
+    /// \param seed A seed for the RNG. If 0 is passed, the current time
+    /// is used.
+    UniformRandomIntegerGenerator(int min, int max, unsigned int seed = 0):
         min_(std::min(min, max)), max_(std::max(min, max)),
         dist_(min_, max_), generator_(rng_, dist_)
     {
@@ -72,7 +75,10 @@ public:
         }
 
         // Init with the current time
-        rng_.seed(time(NULL));
+        if (seed == 0) {
+            seed = time(NULL);
+        }
+        rng_.seed(seed);
     }
 
     /// \brief Generate uniformly distributed integer
diff --git a/src/lib/util/tests/memory_segment_common_unittest.cc b/src/lib/util/tests/memory_segment_common_unittest.cc
index 3810e0a..fac0559 100644
--- a/src/lib/util/tests/memory_segment_common_unittest.cc
+++ b/src/lib/util/tests/memory_segment_common_unittest.cc
@@ -30,9 +30,8 @@ checkSegmentNamedAddress(MemorySegment& segment, bool out_of_segment_ok) {
     // NULL name is not allowed.
     EXPECT_THROW(segment.getNamedAddress(NULL), InvalidParameter);
 
-    // If the name does not exist, NULL should be returned.
-    EXPECT_EQ(static_cast<void*>(NULL),
-              segment.getNamedAddress("test address"));
+    // If the name does not exist, false should be returned.
+    EXPECT_FALSE(segment.getNamedAddress("test address").first);
 
     // Now set it
     void* ptr32 = segment.allocate(sizeof(uint32_t));
@@ -44,29 +43,32 @@ checkSegmentNamedAddress(MemorySegment& segment, bool out_of_segment_ok) {
     EXPECT_THROW(segment.setNamedAddress(NULL, ptr32), InvalidParameter);
 
     // we can now get it; the stored value should be intact.
-    EXPECT_EQ(ptr32, segment.getNamedAddress("test address"));
-    EXPECT_EQ(test_val, *static_cast<const uint32_t*>(ptr32));
+    MemorySegment::NamedAddressResult result =
+        segment.getNamedAddress("test address");
+    EXPECT_TRUE(result.first);
+    EXPECT_EQ(test_val, *static_cast<const uint32_t*>(result.second));
 
     // Override it.
     void* ptr16 = segment.allocate(sizeof(uint16_t));
     const uint16_t test_val16 = 4200;
     *static_cast<uint16_t*>(ptr16) = test_val16;
     EXPECT_FALSE(segment.setNamedAddress("test address", ptr16));
-    EXPECT_EQ(ptr16, segment.getNamedAddress("test address"));
-    EXPECT_EQ(test_val16, *static_cast<const uint16_t*>(ptr16));
+    result = segment.getNamedAddress("test address");
+    EXPECT_TRUE(result.first);
+    EXPECT_EQ(test_val16, *static_cast<const uint16_t*>(result.second));
 
     // Clear it.  Then we won't be able to find it any more.
     EXPECT_TRUE(segment.clearNamedAddress("test address"));
-    EXPECT_EQ(static_cast<void*>(NULL),
-              segment.getNamedAddress("test address"));
+    EXPECT_FALSE(segment.getNamedAddress("test address").first);
 
     // duplicate attempt of clear will result in false as it doesn't exist.
     EXPECT_FALSE(segment.clearNamedAddress("test address"));
 
     // Setting NULL is okay.
     EXPECT_FALSE(segment.setNamedAddress("null address", NULL));
-    EXPECT_EQ(static_cast<void*>(NULL),
-              segment.getNamedAddress("null address"));
+    result = segment.getNamedAddress("null address");
+    EXPECT_TRUE(result.first);
+    EXPECT_FALSE(result.second);
 
     // If the underlying implementation performs explicit check against
     // out-of-segment address, confirm the behavior.
diff --git a/src/lib/util/tests/memory_segment_mapped_unittest.cc b/src/lib/util/tests/memory_segment_mapped_unittest.cc
index 1d9979d..dc8dffc 100644
--- a/src/lib/util/tests/memory_segment_mapped_unittest.cc
+++ b/src/lib/util/tests/memory_segment_mapped_unittest.cc
@@ -287,12 +287,14 @@ void
 checkNamedData(const std::string& name, const std::vector<uint8_t>& data,
                MemorySegment& sgmt, bool delete_after_check = false)
 {
-    void* dp = sgmt.getNamedAddress(name.c_str());
-    ASSERT_TRUE(dp);
-    EXPECT_EQ(0, std::memcmp(dp, &data[0], data.size()));
+    const MemorySegment::NamedAddressResult result =
+        sgmt.getNamedAddress(name.c_str());
+    ASSERT_TRUE(result.first);
+    ASSERT_TRUE(result.second);
+    EXPECT_EQ(0, std::memcmp(result.second, &data[0], data.size()));
 
     if (delete_after_check) {
-        sgmt.deallocate(dp, data.size());
+        sgmt.deallocate(result.second, data.size());
         sgmt.clearNamedAddress(name.c_str());
     }
 }
@@ -309,10 +311,10 @@ TEST_F(MemorySegmentMappedTest, namedAddress) {
     segment_.reset();           // close it before opening another one
 
     segment_.reset(new MemorySegmentMapped(mapped_file));
-    EXPECT_NE(static_cast<void*>(NULL),
-              segment_->getNamedAddress("test address"));
-    EXPECT_EQ(test_val16, *static_cast<const uint16_t*>(
-                  segment_->getNamedAddress("test address")));
+    MemorySegment::NamedAddressResult result =
+        segment_->getNamedAddress("test address");
+    ASSERT_TRUE(result.first);
+    EXPECT_EQ(test_val16, *static_cast<const uint16_t*>(result.second));
 
     // try to set an unusually long name.  We re-create the file so
     // creating the name would cause allocation failure and trigger internal
@@ -323,8 +325,9 @@ TEST_F(MemorySegmentMappedTest, namedAddress) {
     const std::string long_name(1025, 'x'); // definitely larger than segment
     // setNamedAddress should return true, indicating segment has grown.
     EXPECT_TRUE(segment_->setNamedAddress(long_name.c_str(), NULL));
-    EXPECT_EQ(static_cast<void*>(NULL),
-              segment_->getNamedAddress(long_name.c_str()));
+    result = segment_->getNamedAddress(long_name.c_str());
+    EXPECT_TRUE(result.first);
+    EXPECT_FALSE(result.second);
 
     // Check contents pointed by named addresses survive growing and
     // shrinking segment.
@@ -410,10 +413,12 @@ TEST_F(MemorySegmentMappedTest, multiProcess) {
         EXPECT_EQ(0, from_parent);
 
         MemorySegmentMapped sgmt(mapped_file);
-        void* ptr_child = sgmt.getNamedAddress("test address");
-        EXPECT_TRUE(ptr_child);
-        if (ptr_child) {
-            const uint32_t val = *static_cast<const uint32_t*>(ptr_child);
+        const MemorySegment::NamedAddressResult result =
+            sgmt.getNamedAddress("test address");
+        ASSERT_TRUE(result.first);
+        EXPECT_TRUE(result.second);
+        if (result.second) {
+            const uint32_t val = *static_cast<const uint32_t*>(result.second);
             EXPECT_EQ(424242, val);
             // tell the parent whether it succeeded. 0 means it did,
             // 0xff means it failed.
@@ -425,9 +430,11 @@ TEST_F(MemorySegmentMappedTest, multiProcess) {
     // parent: open another read-only segment, then tell the child to open
     // its own segment.
     segment_.reset(new MemorySegmentMapped(mapped_file));
-    ptr = segment_->getNamedAddress("test address");
-    ASSERT_TRUE(ptr);
-    EXPECT_EQ(424242, *static_cast<const uint32_t*>(ptr));
+    const MemorySegment::NamedAddressResult result =
+        segment_->getNamedAddress("test address");
+    ASSERT_TRUE(result.first);
+    ASSERT_TRUE(result.second);
+    EXPECT_EQ(424242, *static_cast<const uint32_t*>(result.second));
     const char some_data = 0;
     EXPECT_EQ(1, write(pipe_to_child.getWriteFD(), &some_data,
                        sizeof(some_data)));
@@ -460,7 +467,14 @@ TEST_F(MemorySegmentMappedTest, shrink) {
     EXPECT_EQ(shrinked_size, segment_->getSize());
 
     // Check that the segment is still usable after shrink.
-    void* p = segment_->allocate(sizeof(uint32_t));
+    void *p = NULL;
+    while (!p) {
+        try {
+            p = segment_->allocate(sizeof(uint32_t));
+        } catch (const MemorySegmentGrown&) {
+            // Do nothing. Just try again.
+        }
+    }
     segment_->deallocate(p, sizeof(uint32_t));
 }
 
@@ -477,9 +491,11 @@ TEST_F(MemorySegmentMappedTest, violateReadOnly) {
     if (!isc::util::unittests::runningOnValgrind()) {
         EXPECT_DEATH_IF_SUPPORTED({
                 MemorySegmentMapped segment_ro(mapped_file);
-                EXPECT_TRUE(segment_ro.getNamedAddress("test address"));
-                *static_cast<uint32_t*>(
-                    segment_ro.getNamedAddress("test address")) = 0;
+                const MemorySegment::NamedAddressResult result =
+                    segment_ro.getNamedAddress("test address");
+                ASSERT_TRUE(result.first);
+                ASSERT_TRUE(result.second);
+                *static_cast<uint32_t*>(result.second) = 0;
             }, "");
     }
 
@@ -487,10 +503,12 @@ TEST_F(MemorySegmentMappedTest, violateReadOnly) {
     // attempts are prohibited. When detectable it must result in an
     // exception.
     MemorySegmentMapped segment_ro(mapped_file);
-    ptr = segment_ro.getNamedAddress("test address");
-    EXPECT_NE(static_cast<void*>(NULL), ptr);
+    const MemorySegment::NamedAddressResult result =
+        segment_ro.getNamedAddress("test address");
+    ASSERT_TRUE(result.first);
+    EXPECT_NE(static_cast<void*>(NULL), result.second);
 
-    EXPECT_THROW(segment_ro.deallocate(ptr, 4), MemorySegmentError);
+    EXPECT_THROW(segment_ro.deallocate(result.second, 4), MemorySegmentError);
 
     EXPECT_THROW(segment_ro.allocate(16), MemorySegmentError);
     // allocation that would otherwise require growing the segment; permission
diff --git a/src/lib/util/tests/random_number_generator_unittest.cc b/src/lib/util/tests/random_number_generator_unittest.cc
index 23d5b88..2c6bec8 100644
--- a/src/lib/util/tests/random_number_generator_unittest.cc
+++ b/src/lib/util/tests/random_number_generator_unittest.cc
@@ -14,14 +14,16 @@
 
 #include <config.h>
 
+#include <util/random/random_number_generator.h>
+
 #include <gtest/gtest.h>
 #include <boost/shared_ptr.hpp>
 
-#include <algorithm>
 #include <iostream>
-#include <vector>
+#include <climits>
 
-#include <util/random/random_number_generator.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 namespace isc {
 namespace util {
@@ -42,9 +44,9 @@ public:
     }
     virtual ~UniformRandomIntegerGeneratorTest(){}
 
-    int gen() { return gen_(); }
-    int max() const { return max_; }
-    int min() const { return min_; }
+    int gen() { return (gen_()); }
+    int max() const { return (max_); }
+    int min() const { return (min_); }
 
 private:
     UniformRandomIntegerGenerator gen_;
@@ -82,7 +84,22 @@ TEST_F(UniformRandomIntegerGeneratorTest, IntegerRange) {
     vector<int>::iterator it = unique(numbers.begin(), numbers.end());
 
     // make sure the numbers are in range [min, max]
-    ASSERT_EQ(it - numbers.begin(), max() - min() + 1); 
+    ASSERT_EQ(it - numbers.begin(), max() - min() + 1);
+}
+
+TEST_F(UniformRandomIntegerGeneratorTest, withSeed) {
+    // Test that two generators with the same seed return the same
+    // sequence.
+    UniformRandomIntegerGenerator gen1(0, INT_MAX, getpid());
+    vector<int> numbers;
+    for (int i = 0; i < 1024; ++i) {
+        numbers.push_back(gen1());
+    }
+
+    UniformRandomIntegerGenerator gen2(0, INT_MAX, getpid());
+    for (int i = 0; i < 1024; ++i) {
+        EXPECT_EQ(numbers[i], gen2());
+    }
 }
 
 /// \brief Test Fixture Class for weighted random number generator
@@ -99,7 +116,8 @@ public:
 TEST_F(WeightedRandomIntegerGeneratorTest, Constructor) {
     vector<double> probabilities;
 
-    // If no probabilities is provided, the smallest integer will always be generated
+    // If no probabilities is provided, the smallest integer will always
+    // be generated
     WeightedRandomIntegerGenerator gen(probabilities, 123);
     for (int i = 0; i < 100; ++i) {
         ASSERT_EQ(gen(), 123);



More information about the bind10-changes mailing list