BIND 10 master, updated. bf60255cc1f000a7251436f2461cd8e9b31e52ff [master] Merge branch 'trac2834'

BIND 10 source code commits bind10-changes at lists.isc.org
Wed Apr 24 17:33:26 UTC 2013


The branch, master has been updated
       via  bf60255cc1f000a7251436f2461cd8e9b31e52ff (commit)
       via  2b67b0507c180a32d14f843d26b99614cb1a88ae (commit)
       via  fa304f6d472075939f45a1e59a45c6a6c82d8ac7 (commit)
       via  ad304b978c110bee6e97ef3010776bbd8733e813 (commit)
       via  44890bb7db4879313473787c726ae25dd6eac335 (commit)
       via  aef76a4ff2d463f09a2d82e304d6003025646a5a (commit)
       via  ba37fe42bf0e97653780bddc8ecb47a090c3ccc9 (commit)
       via  41a8bec7700a7792e1f24883add4e542977c111e (commit)
       via  c37383f57aa3d6b6cd4911279a143091912c0e32 (commit)
       via  d253c3c481194eff6ae52861624d0d0fdf44b4b3 (commit)
       via  854d608fd26a2b9c1cee43f5ce48d75ac7223e22 (commit)
       via  83652c539b9e0fc04202bef8c6abe6fffad1f58c (commit)
       via  bb5f0f9677e89c5fa45a6e54c2176a2496cfa6a8 (commit)
       via  97f58d9418e14b7076850c529619dcd1efa41145 (commit)
       via  4a27055866a0ec36350d20422713174d61543015 (commit)
       via  a5ec1487b162ef818186ae92b54e5c73d8757bd1 (commit)
       via  e7971923e90e58921feac425b7ec9073f4a22c95 (commit)
       via  962447aa16c4f4accd42fc326d9408cdf75d2dde (commit)
       via  b7a8ae05f15fb10c0e2215565f160889390c3c8d (commit)
      from  f85cdd324c2d51046c2030587d8d5053b4a0ebbd (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 bf60255cc1f000a7251436f2461cd8e9b31e52ff
Merge: f85cdd3 2b67b05
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Wed Apr 24 10:15:33 2013 -0700

    [master] Merge branch 'trac2834'

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

Summary of changes:
 src/bin/auth/auth_srv.cc                           |    2 +-
 src/bin/auth/datasrc_clients_mgr.h                 |    2 +-
 src/bin/auth/tests/config_unittest.cc              |    2 +-
 src/lib/datasrc/Makefile.am                        |    3 +-
 src/lib/datasrc/cache_config.cc                    |   85 ++++++
 src/lib/datasrc/cache_config.h                     |   58 +++-
 src/lib/datasrc/client_list.cc                     |  163 +++---------
 src/lib/datasrc/client_list.h                      |   10 +-
 src/lib/datasrc/data_source.h                      |   68 -----
 src/lib/datasrc/database.cc                        |    4 +-
 src/lib/datasrc/database.h                         |    2 +-
 src/lib/datasrc/datasrc_messages.mes               |   15 +-
 src/lib/datasrc/exceptions.h                       |   20 ++
 src/lib/datasrc/factory.cc                         |    2 +-
 src/lib/datasrc/factory.h                          |    2 +-
 src/lib/datasrc/memory/memory_client.cc            |  122 +--------
 src/lib/datasrc/memory/memory_client.h             |   79 +-----
 src/lib/datasrc/memory/memory_messages.mes         |    6 +-
 src/lib/datasrc/memory/zone_data_loader.cc         |    6 +
 src/lib/datasrc/memory/zone_finder.cc              |    2 +-
 src/lib/datasrc/memory/zone_table.cc               |   15 +-
 src/lib/datasrc/memory/zone_table.h                |    7 +
 src/lib/datasrc/sqlite3_accessor.cc                |    2 +-
 src/lib/datasrc/sqlite3_accessor.h                 |    2 +-
 src/lib/datasrc/tests/cache_config_unittest.cc     |   69 +++++
 src/lib/datasrc/tests/client_list_unittest.cc      |   83 ++++--
 src/lib/datasrc/tests/database_unittest.cc         |    2 +-
 src/lib/datasrc/tests/factory_unittest.cc          |    2 +-
 src/lib/datasrc/tests/memory/Makefile.am           |    1 +
 .../datasrc/tests/memory/memory_client_unittest.cc |  276 ++++++++++----------
 .../datasrc/tests/memory/zone_finder_unittest.cc   |   21 +-
 src/lib/datasrc/tests/memory/zone_loader_util.cc   |   93 +++++++
 src/lib/datasrc/tests/memory/zone_loader_util.h    |   57 ++++
 .../datasrc/tests/memory/zone_table_unittest.cc    |    8 +
 src/lib/datasrc/tests/mock_client.cc               |    2 +-
 src/lib/datasrc/tests/mock_client.h                |    5 +
 src/lib/datasrc/tests/sqlite3_accessor_unittest.cc |    2 +-
 .../datasrc/tests/zone_finder_context_unittest.cc  |   22 +-
 src/lib/datasrc/tests/zone_loader_unittest.cc      |   32 ++-
 src/lib/datasrc/zone_finder.cc                     |    3 +-
 src/lib/datasrc/zone_loader.cc                     |    2 +-
 src/lib/datasrc/zone_loader.h                      |    2 +-
 src/lib/python/isc/datasrc/client_python.cc        |    2 +-
 src/lib/python/isc/datasrc/finder_python.cc        |    2 +-
 src/lib/python/isc/datasrc/updater_python.cc       |    2 +-
 tests/lettuce/features/auth_badzone.feature        |    6 +-
 46 files changed, 764 insertions(+), 609 deletions(-)
 delete mode 100644 src/lib/datasrc/data_source.h
 create mode 100644 src/lib/datasrc/tests/memory/zone_loader_util.cc
 create mode 100644 src/lib/datasrc/tests/memory/zone_loader_util.h

-----------------------------------------------------------------------
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index 3fe9b9c..90efee7 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -42,7 +42,7 @@
 
 #include <asiodns/dns_service.h>
 
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/client_list.h>
 
 #include <xfr/xfrout_client.h>
diff --git a/src/bin/auth/datasrc_clients_mgr.h b/src/bin/auth/datasrc_clients_mgr.h
index 5bbdb99..f75b394 100644
--- a/src/bin/auth/datasrc_clients_mgr.h
+++ b/src/bin/auth/datasrc_clients_mgr.h
@@ -25,7 +25,7 @@
 
 #include <cc/data.h>
 
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/client_list.h>
 #include <datasrc/memory/zone_writer.h>
 
diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc
index 0d6cbf8..65b6539 100644
--- a/src/bin/auth/tests/config_unittest.cc
+++ b/src/bin/auth/tests/config_unittest.cc
@@ -21,7 +21,7 @@
 
 #include <cc/data.h>
 
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 
 #include <xfr/xfrout_client.h>
 
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index d7c5978..c048efa 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -24,8 +24,7 @@ CLEANFILES += datasrc_config.h
 CLEANFILES += static.zone
 
 lib_LTLIBRARIES = libb10-datasrc.la
-libb10_datasrc_la_SOURCES = data_source.h
-libb10_datasrc_la_SOURCES += exceptions.h
+libb10_datasrc_la_SOURCES = exceptions.h
 libb10_datasrc_la_SOURCES += zone.h zone_finder.h zone_finder.cc
 libb10_datasrc_la_SOURCES += zone_finder_context.cc
 libb10_datasrc_la_SOURCES += zone_iterator.h
diff --git a/src/lib/datasrc/cache_config.cc b/src/lib/datasrc/cache_config.cc
index 378e5e6..3896414 100644
--- a/src/lib/datasrc/cache_config.cc
+++ b/src/lib/datasrc/cache_config.cc
@@ -15,10 +15,19 @@
 #include <datasrc/cache_config.h>
 #include <datasrc/client.h>
 #include <datasrc/memory/load_action.h>
+#include <datasrc/memory/zone_data_loader.h>
+
+#include <util/memory_segment.h>
+
 #include <dns/name.h>
+#include <dns/rrclass.h>
+
 #include <cc/data.h>
 #include <exceptions/exceptions.h>
 
+#include <boost/bind.hpp>
+
+#include <cassert>
 #include <map>
 #include <string>
 
@@ -108,6 +117,82 @@ CacheConfig::CacheConfig(const std::string& datasrc_type,
     }
 }
 
+namespace {
+
+// We would like to use boost::bind for this. However, the loadZoneData takes
+// a reference, while we have a shared pointer to the iterator -- and we need
+// to keep it alive as long as the ZoneWriter is alive. Therefore we can't
+// really just dereference it and pass it, since it would get destroyed once
+// the getCachedZoneWriter would end. This class holds the shared pointer
+// alive, otherwise is mostly simple.
+//
+// It might be doable with nested boost::bind, but it would probably look
+// more awkward and complicated than this.
+class IteratorLoader {
+public:
+    IteratorLoader(const dns::RRClass& rrclass, const dns::Name& name,
+                   const ZoneIteratorPtr& iterator) :
+        rrclass_(rrclass),
+        name_(name),
+        iterator_(iterator)
+    {}
+    memory::ZoneData* operator()(util::MemorySegment& segment) {
+        return (memory::loadZoneData(segment, rrclass_, name_, *iterator_));
+    }
+private:
+    const dns::RRClass rrclass_;
+    const dns::Name name_;
+    ZoneIteratorPtr iterator_;
+};
+
+// We can't use the loadZoneData function directly in boost::bind, since
+// it is overloaded and the compiler can't choose the correct version
+// reliably and fails. So we simply wrap it into an unique name.
+memory::ZoneData*
+loadZoneDataFromFile(util::MemorySegment& segment, const dns::RRClass& rrclass,
+                     const dns::Name& name, const std::string& filename)
+{
+    return (memory::loadZoneData(segment, rrclass, name, filename));
+}
+
+} // unnamed namespace
+
+memory::LoadAction
+CacheConfig::getLoadAction(const dns::RRClass& rrclass,
+                           const dns::Name& zone_name) const
+{
+    // First, check if the specified zone is configured to be cached.
+    Zones::const_iterator found = zone_config_.find(zone_name);
+    if (found == zone_config_.end()) {
+        return (memory::LoadAction());
+    }
+
+    if (!found->second.empty()) {
+        // This is "MasterFiles" data source.
+        return (boost::bind(loadZoneDataFromFile, _1, rrclass, zone_name,
+                            found->second));
+    }
+
+    // Otherwise there must be a "source" data source (ensured by constructor)
+    assert(datasrc_client_);
+
+    // If the specified zone name does not exist in our client of the source,
+    // DataSourceError is thrown, which is exactly the result what we
+    // want, so no need to handle it.
+    ZoneIteratorPtr iterator(datasrc_client_->getIterator(zone_name));
+    if (!iterator) {
+        // This shouldn't happen for a compliant implementation of
+        // DataSourceClient, but we'll protect ourselves from buggy
+        // implementations.
+        isc_throw(Unexpected, "getting LoadAction for " << zone_name
+                  << "/" << rrclass << " resulted in Null zone iterator");
+    }
+
+    // Wrap the iterator into the correct functor (which keeps it alive as
+    // long as it is needed).
+    return (IteratorLoader(rrclass, zone_name, iterator));
+}
+
 } // namespace internal
 } // namespace datasrc
 } // namespace isc
diff --git a/src/lib/datasrc/cache_config.h b/src/lib/datasrc/cache_config.h
index a615b8a..7781f49 100644
--- a/src/lib/datasrc/cache_config.h
+++ b/src/lib/datasrc/cache_config.h
@@ -17,7 +17,7 @@
 
 #include <exceptions/exceptions.h>
 
-#include <dns/name.h>
+#include <dns/dns_fwd.h>
 #include <cc/data.h>
 #include <datasrc/memory/load_action.h>
 
@@ -53,7 +53,6 @@ public:
 /// object that can be used for loading zones, regardless of the underlying
 /// data source properties, i.e., whether it's special "MasterFiles" type
 /// or other generic data sources.
-/// NOTE: this part will be done in #2834.
 ///
 /// This class is publicly defined so it can be tested directly, but
 /// it's essentially private to the \c ConfigurableClientList class.
@@ -144,12 +143,56 @@ public:
     /// \throw None
     const std::string& getSegmentType() const { return (segment_type_); }
 
-    /// \todo the following definition is tentative, mainly for tests.
-    /// In #2834 we'll (probably) extend it to be a custom iterator so
-    /// the caller can iterate over the whole set of zones, loading the
-    /// content in memory.
+    /// \brief Return a \c LoadAction functor to load zone data into memory.
+    ///
+    /// This method returns an appropriate \c LoadAction functor that can be
+    /// passed to a \c memory::ZoneWriter object to load data of the specified
+    /// zone into memory.  The source of the zone data differs depending on
+    /// the cache configuration (either a master file or another data source),
+    /// but this method hides the details and works as a unified interface
+    /// for the caller.
+    ///
+    /// If the specified zone is not configured to be cached, it returns an
+    /// empty functor (which can be evaluated to be \c false as a boolean).
+    /// It doesn't throw an exception in this case because the expected caller
+    /// of this method would handle such a case internally.
+    ///
+    /// \throw DataSourceError error happens in the underlying data source
+    /// storing the cache data.  Most commonly it's because the specified zone
+    /// doesn't exist there.
+    /// \throw Unexpected Unexpected error happens in the underlying data
+    /// source storing the cache data.  This shouldn't happen as long as the
+    /// data source implementation meets the public API requirement.
+    ///
+    /// \param rrclass The RR class of the zone
+    /// \param zone_name The origin name of the zone
+    /// \return A \c LoadAction functor to load zone data or an empty functor
+    /// (see above).
+    memory::LoadAction getLoadAction(const dns::RRClass& rrlcass,
+                                     const dns::Name& zone_name) const;
+
+    /// \brief Read only iterator type over configured cached zones.
+    ///
+    /// \note This initial version exposes the internal data structure (i.e.
+    /// map from name to string) through this public iterator type for
+    /// simplicity.  In terms of data encapsulation it's better to introduce
+    /// a custom iterator type that only goes through the conceptual list
+    /// of zone names, but due to the limitation of the expected user of this
+    /// class that would probably be premature generalization.  In future,
+    /// we might want to allow getting the list of zones directly from the
+    /// underlying data source.  If and when that happens we should introduce
+    /// a custom type.  In any case, the user of this class should only
+    /// use the typedef, not the original map iterator.  It should also
+    /// use this iterator as a forward iterator (datasource-based iterator
+    /// wouldn't be able to be bidirectional), and it shouldn't use the
+    /// value of the map entry (a string, specifying a path to master file
+    /// for MasterFiles data source).
     typedef std::map<dns::Name, std::string>::const_iterator ConstZoneIterator;
+
+    /// \brief Return the beginning of cached zones in the form of iterator.
     ConstZoneIterator begin() const { return (zone_config_.begin()); }
+
+    /// \brief Return the end of cached zones in the form of iterator.
     ConstZoneIterator end() const { return (zone_config_.end()); }
 
 private:
@@ -158,6 +201,9 @@ private:
     // client of underlying data source, will be NULL for MasterFile datasrc
     const DataSourceClient* datasrc_client_;
 
+    // Maps each of zones to be cached to a string.  For "MasterFiles" type
+    // of data source, the string is a path to the master zone file; for
+    // others it's an empty string.
     typedef std::map<dns::Name, std::string> Zones;
     Zones zone_config_;
 };
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
index d366ac3..c9bdee0 100644
--- a/src/lib/datasrc/client_list.cc
+++ b/src/lib/datasrc/client_list.cc
@@ -31,6 +31,7 @@
 #include <set>
 #include <boost/foreach.hpp>
 #include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
 
 using namespace isc::data;
 using namespace isc::dns;
@@ -119,6 +120,9 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                 continue;
             }
 
+            // Build in-memory cache configuration, and create a set of
+            // related objects including the in-memory zone table for the
+            // cache.
             boost::shared_ptr<internal::CacheConfig> cache_conf(
                 new internal::CacheConfig(type, dsrc_pair.first, *dconf,
                                           allow_cache));
@@ -127,60 +131,38 @@ ConfigurableClientList::configure(const ConstElementPtr& config,
                                                       cache_conf, rrclass_,
                                                       name));
 
-            if (cache_conf->isEnabled()) {
-                // List the zones we are loading
-                vector<string> zones_origins;
-                if (type == "MasterFiles") {
-                    const map<string, ConstElementPtr>
-                        zones_files(paramConf->mapValue());
-                    for (map<string, ConstElementPtr>::const_iterator
-                         it(zones_files.begin()); it != zones_files.end();
-                         ++it) {
-                        zones_origins.push_back(it->first);
-                    }
-                } else {
-                    const ConstElementPtr zones(dconf->get("cache-zones"));
-                    for (size_t i(0); i < zones->size(); ++i) {
-                        zones_origins.push_back(zones->get(i)->stringValue());
-                    }
+            // If cache is disabled we are done for this data source.
+            // Otherwise load zones into the in-memory cache.
+            if (!cache_conf->isEnabled()) {
+                continue;
+            }
+            internal::CacheConfig::ConstZoneIterator end_of_zones =
+                cache_conf->end();
+            for (internal::CacheConfig::ConstZoneIterator zone_it =
+                     cache_conf->begin();
+                 zone_it != end_of_zones;
+                 ++zone_it)
+            {
+                const Name& zname = zone_it->first;
+                memory::LoadAction load_action;
+                try {
+                    load_action = cache_conf->getLoadAction(rrclass_, zname);
+                } catch (const DataSourceError&) {
+                    isc_throw(ConfigurationError, "Data source error for "
+                              "loading a zone (possibly non-existent) "
+                              << zname << "/" << rrclass_);
                 }
-
-                const shared_ptr<InMemoryClient>
-                    cache(new_data_sources.back().cache_);
-                const DataSourceClient* const
-                    client(new_data_sources.back().data_src_client_);
-
-                for (vector<string>::const_iterator it(zones_origins.begin());
-                     it != zones_origins.end(); ++it) {
-                    const Name origin(*it);
-                    if (type == "MasterFiles") {
-                        try {
-                            cache->load(origin,
-                                        paramConf->get(*it)->stringValue());
-                        } catch (const ZoneLoaderException& e) {
-                            LOG_ERROR(logger, DATASRC_LOAD_FROM_FILE_ERROR)
-                                .arg(origin).arg(e.what());
-                        }
-                    } else {
-                        ZoneIteratorPtr iterator;
-                        try {
-                            iterator = client->getIterator(origin);
-                        } catch (const DataSourceError&) {
-                            isc_throw(ConfigurationError, "Unable to "
-                                      "cache non-existent zone "
-                                      << origin);
-                        }
-                        if (!iterator) {
-                            isc_throw(isc::Unexpected, "Got NULL iterator "
-                                      "for zone " << origin);
-                        }
-                        try {
-                            cache->load(origin, *iterator);
-                        } catch (const ZoneLoaderException& e) {
-                            LOG_ERROR(logger, DATASRC_LOAD_FROM_ITERATOR_ERROR)
-                                .arg(origin).arg(e.what());
-                        }
-                    }
+                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();
+                } catch (const ZoneLoaderException& e) {
+                    LOG_ERROR(logger, DATASRC_LOAD_ZONE_ERROR)
+                        .arg(zname).arg(rrclass_).arg(name).arg(e.what());
                 }
             }
         }
@@ -344,46 +326,6 @@ ConfigurableClientList::reload(const Name& name) {
     return (ZONE_SUCCESS);
 }
 
-namespace {
-
-// We would like to use boost::bind for this. However, the loadZoneData takes
-// a reference, while we have a shared pointer to the iterator -- and we need
-// to keep it alive as long as the ZoneWriter is alive. Therefore we can't
-// really just dereference it and pass it, since it would get destroyed once
-// the getCachedZoneWriter would end. This class holds the shared pointer
-// alive, otherwise is mostly simple.
-//
-// It might be doable with nested boost::bind, but it would probably look
-// more awkward and complicated than this.
-class IteratorLoader {
-public:
-    IteratorLoader(const RRClass& rrclass, const Name& name,
-                   const ZoneIteratorPtr& iterator) :
-        rrclass_(rrclass),
-        name_(name),
-        iterator_(iterator)
-    {}
-    memory::ZoneData* operator()(util::MemorySegment& segment) {
-        return (memory::loadZoneData(segment, rrclass_, name_, *iterator_));
-    }
-private:
-    const RRClass rrclass_;
-    const Name name_;
-    ZoneIteratorPtr iterator_;
-};
-
-// We can't use the loadZoneData function directly in boost::bind, since
-// it is overloaded and the compiler can't choose the correct version
-// reliably and fails. So we simply wrap it into an unique name.
-memory::ZoneData*
-loadZoneDataFromFile(util::MemorySegment& segment, const RRClass& rrclass,
-                     const Name& name, const string& filename)
-{
-    return (memory::loadZoneData(segment, rrclass, name, filename));
-}
-
-}
-
 ConfigurableClientList::ZoneWriterPair
 ConfigurableClientList::getCachedZoneWriter(const Name& name) {
     if (!allow_cache_) {
@@ -395,36 +337,15 @@ ConfigurableClientList::getCachedZoneWriter(const Name& name) {
     if (!result.finder) {
         return (ZoneWriterPair(ZONE_NOT_FOUND, ZoneWriterPtr()));
     }
-    // Try to get the in-memory cache for the zone. If there's none,
-    // we can't provide the result.
-    if (!result.info->cache_) {
+
+    // Then get the appropriate load action and create a zone writer.
+    // Note that getCacheConfig() must return non NULL in this module (only
+    // tests could set it to a bogus value).
+    const memory::LoadAction load_action =
+        result.info->getCacheConfig()->getLoadAction(rrclass_, name);
+    if (!load_action) {
         return (ZoneWriterPair(ZONE_NOT_CACHED, ZoneWriterPtr()));
     }
-    memory::LoadAction load_action;
-    DataSourceClient* client(result.info->data_src_client_);
-    if (client != NULL) {
-        // Now finally provide the writer.
-        // If it does not exist in client,
-        // DataSourceError is thrown, which is exactly the result what we
-        // want, so no need to handle it.
-        ZoneIteratorPtr iterator(client->getIterator(name));
-        if (!iterator) {
-            isc_throw(isc::Unexpected, "Null iterator from " << name);
-        }
-        // And wrap the iterator into the correct functor (which
-        // keeps it alive as long as it is needed).
-        load_action = IteratorLoader(rrclass_, name, iterator);
-    } else {
-        // The MasterFiles special case
-        const string filename(result.info->cache_->getFileName(name));
-        if (filename.empty()) {
-            isc_throw(isc::Unexpected, "Confused about missing both filename "
-                      "and data source");
-        }
-        // boost::bind is enough here.
-        load_action = boost::bind(loadZoneDataFromFile, _1, rrclass_, name,
-                                  filename);
-    }
     return (ZoneWriterPair(ZONE_SUCCESS,
                            ZoneWriterPtr(
                                result.info->ztable_segment_->
diff --git a/src/lib/datasrc/client_list.h b/src/lib/datasrc/client_list.h
index 49e0779..a5a7488 100644
--- a/src/lib/datasrc/client_list.h
+++ b/src/lib/datasrc/client_list.h
@@ -342,8 +342,10 @@ public:
     /// \brief Result of the reload() method.
     enum ReloadResult {
         CACHE_DISABLED,     ///< The cache is not enabled in this list.
-        ZONE_NOT_CACHED,    ///< Zone is served directly, not from cache.
-        ZONE_NOT_FOUND,     ///< Zone does not exist or not cached.
+        ZONE_NOT_CACHED,    ///< Zone is served directly, not from cache
+                            ///  (including the case cache is disabled for
+                            ///  the specific data source).
+        ZONE_NOT_FOUND,     ///< Zone does not exist in this list.
         ZONE_SUCCESS        ///< The zone was successfully reloaded or
                             ///  the writer provided.
     };
@@ -418,6 +420,10 @@ public:
         boost::shared_ptr<memory::InMemoryClient> cache_;
         boost::shared_ptr<memory::ZoneTableSegment> ztable_segment_;
         std::string name_;
+
+        const internal::CacheConfig* getCacheConfig() const {
+            return (cache_conf_.get());
+        }
     private:
         // this is kept private for now.  When it needs to be accessed,
         // we'll add a read-only getter method.
diff --git a/src/lib/datasrc/data_source.h b/src/lib/datasrc/data_source.h
deleted file mode 100644
index bf5a7d7..0000000
--- a/src/lib/datasrc/data_source.h
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (C) 2009  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 DATA_SOURCE_H
-#define DATA_SOURCE_H
-
-#include <stdint.h>
-
-#include <vector>
-
-#include <boost/shared_ptr.hpp>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/name.h>
-#include <dns/rrclass.h>
-#include <cc/data.h>
-
-namespace isc {
-
-namespace dns {
-class Name;
-class RRType;
-class RRset;
-class RRsetList;
-}
-
-namespace datasrc {
-
-/// This exception represents Backend-independent errors relating to
-/// data source operations.
-class DataSourceError : public Exception {
-public:
-    DataSourceError(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-/// \brief No such serial number when obtaining difference iterator
-///
-/// Thrown if either the zone/start serial number or zone/end serial number
-/// combination does not exist in the differences table.  (Note that this
-/// includes the case where the differences table contains no records related
-/// to that zone.)
-class NoSuchSerial : public DataSourceError {
-public:
-    NoSuchSerial(const char* file, size_t line, const char* what) :
-        DataSourceError(file, line, what) {}
-};
-
-}
-}
-
-#endif
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index 2cff63e..70f4df0 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -17,7 +17,7 @@
 #include <vector>
 
 #include <datasrc/database.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/zone_iterator.h>
 #include <datasrc/rrset_collection_base.h>
 
@@ -30,7 +30,7 @@
 #include <dns/rdataclass.h>
 #include <dns/nsec3hash.h>
 
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/logger.h>
 
 #include <boost/foreach.hpp>
diff --git a/src/lib/datasrc/database.h b/src/lib/datasrc/database.h
index 61ee1e6..6e675e2 100644
--- a/src/lib/datasrc/database.h
+++ b/src/lib/datasrc/database.h
@@ -24,7 +24,7 @@
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
 
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/client.h>
 #include <datasrc/zone.h>
 #include <datasrc/logger.h>
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index f2a7eca..2c345c2 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -354,15 +354,12 @@ Therefore, the entire data source will not be available for this process. If
 this is a problem, you should configure the zones of that data source to some
 database backend (sqlite3, for example) and use it from there.
 
-% DATASRC_LOAD_FROM_FILE_ERROR Error loading zone %1: %2
-An error was found in the zone data when it was being loaded from a
-file. The zone was not loaded. The specific error is shown in the
-message, and should be addressed.
-
-% DATASRC_LOAD_FROM_ITERATOR_ERROR Error loading zone %1: %2
-An error was found in the zone data when it was being loaded from
-another data source. The zone was not loaded. The specific error is
-shown in the message, and should be addressed.
+% DATASRC_LOAD_ZONE_ERROR Error loading zone %1/%2 on data source %3: %4
+During data source configuration, an error was found in the zone data
+when it was being loaded in to memory on the shown data source.  This
+particular zone was not loaded, but data source configuration
+continues, possibly loading other zones into memory. The specific
+error is shown in the message, and should be addressed.
 
 % DATASRC_MASTER_LOAD_ERROR %1:%2: Zone '%3/%4' contains error: %5
 There's an error in the given master file. The zone won't be loaded for
diff --git a/src/lib/datasrc/exceptions.h b/src/lib/datasrc/exceptions.h
index 749b955..f9c5655 100644
--- a/src/lib/datasrc/exceptions.h
+++ b/src/lib/datasrc/exceptions.h
@@ -20,6 +20,26 @@
 namespace isc {
 namespace datasrc {
 
+/// This exception represents Backend-independent errors relating to
+/// data source operations.
+class DataSourceError : public Exception {
+public:
+    DataSourceError(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+/// \brief No such serial number when obtaining difference iterator
+///
+/// Thrown if either the zone/start serial number or zone/end serial number
+/// combination does not exist in the differences table.  (Note that this
+/// includes the case where the differences table contains no records related
+/// to that zone.)
+class NoSuchSerial : public DataSourceError {
+public:
+    NoSuchSerial(const char* file, size_t line, const char* what) :
+        DataSourceError(file, line, what) {}
+};
+
 /// Base class for a number of exceptions that are thrown while working
 /// with zones.
 struct ZoneException : public Exception {
diff --git a/src/lib/datasrc/factory.cc b/src/lib/datasrc/factory.cc
index 33338db..73f7e4a 100644
--- a/src/lib/datasrc/factory.cc
+++ b/src/lib/datasrc/factory.cc
@@ -14,7 +14,7 @@
 
 #include "factory.h"
 
-#include "data_source.h"
+#include "exceptions.h"
 #include "database.h"
 #include "sqlite3_accessor.h"
 
diff --git a/src/lib/datasrc/factory.h b/src/lib/datasrc/factory.h
index 45e4f9b..4e669ec 100644
--- a/src/lib/datasrc/factory.h
+++ b/src/lib/datasrc/factory.h
@@ -15,7 +15,7 @@
 #ifndef DATA_SOURCE_FACTORY_H
 #define DATA_SOURCE_FACTORY_H 1
 
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/client.h>
 
 #include <cc/data.h>
diff --git a/src/lib/datasrc/memory/memory_client.cc b/src/lib/datasrc/memory/memory_client.cc
index 66e61a2..d49359a 100644
--- a/src/lib/datasrc/memory/memory_client.cc
+++ b/src/lib/datasrc/memory/memory_client.cc
@@ -18,15 +18,11 @@
 #include <datasrc/memory/logger.h>
 #include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/rdataset.h>
-#include <datasrc/memory/segment_object_holder.h>
 #include <datasrc/memory/treenode_rrset.h>
 #include <datasrc/memory/zone_finder.h>
-#include <datasrc/memory/zone_data_loader.h>
 #include <datasrc/memory/zone_table_segment.h>
 
-#include <util/memory_segment_local.h>
-
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/factory.h>
 #include <datasrc/result.h>
 
@@ -34,12 +30,8 @@
 #include <dns/rdataclass.h>
 #include <dns/rrclass.h>
 
-#include <algorithm>
 #include <utility>
-#include <cctype>
-#include <cassert>
 
-using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 using namespace isc::datasrc::memory;
@@ -49,86 +41,14 @@ namespace isc {
 namespace datasrc {
 namespace memory {
 
-using detail::SegmentObjectHolder;
 using boost::shared_ptr;
 
-namespace { // unnamed namespace
-
-// A helper internal class used by the memory client, used for deleting
-// filenames stored in an internal tree.
-class FileNameDeleter {
-public:
-    FileNameDeleter() {}
-
-    void operator()(std::string* filename) const {
-        delete filename;
-    }
-};
-
-} // end of unnamed namespace
-
 InMemoryClient::InMemoryClient(shared_ptr<ZoneTableSegment> ztable_segment,
                                RRClass rrclass) :
     ztable_segment_(ztable_segment),
-    rrclass_(rrclass),
-    zone_count_(0),
-    file_name_tree_(FileNameTree::create(
-        ztable_segment_->getMemorySegment(), false))
+    rrclass_(rrclass)
 {}
 
-InMemoryClient::~InMemoryClient() {
-    MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
-    FileNameDeleter deleter;
-    FileNameTree::destroy(mem_sgmt, file_name_tree_, deleter);
-}
-
-result::Result
-InMemoryClient::loadInternal(const isc::dns::Name& zone_name,
-                             const std::string& filename,
-                             ZoneData* zone_data)
-{
-    MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
-    SegmentObjectHolder<ZoneData, RRClass> holder(
-        mem_sgmt, zone_data, rrclass_);
-
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
-        arg(zone_name).arg(rrclass_);
-
-    // Set the filename in file_name_tree_ now, so that getFileName()
-    // can use it (during zone reloading).
-    FileNameNode* node(NULL);
-    switch (file_name_tree_->insert(mem_sgmt, zone_name, &node)) {
-    case FileNameTree::SUCCESS:
-    case FileNameTree::ALREADYEXISTS:
-        // These are OK
-        break;
-    default:
-        // Can Not Happen
-        assert(false);
-    }
-    // node must point to a valid node now
-    assert(node != NULL);
-
-    const std::string* tstr = node->setData(new std::string(filename));
-    delete tstr;
-
-    ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
-    const ZoneTable::AddResult result(zone_table->addZone(mem_sgmt, rrclass_,
-                                                          zone_name,
-                                                          holder.release()));
-    if (result.code == result::SUCCESS) {
-        // Only increment the zone count if the zone doesn't already
-        // exist.
-        ++zone_count_;
-    }
-    // Destroy the old instance of the zone if there was any
-    if (result.zone_data != NULL) {
-        ZoneData::destroy(mem_sgmt, result.zone_data, rrclass_);
-    }
-
-    return (result.code);
-}
-
 RRClass
 InMemoryClient::getClass() const {
     return (rrclass_);
@@ -136,7 +56,8 @@ InMemoryClient::getClass() const {
 
 unsigned int
 InMemoryClient::getZoneCount() const {
-    return (zone_count_);
+    const ZoneTable* zone_table = ztable_segment_->getHeader().getTable();
+    return (zone_table->getZoneCount());
 }
 
 isc::datasrc::DataSourceClient::FindResult
@@ -162,39 +83,6 @@ InMemoryClient::findZoneData(const isc::dns::Name& zone_name) {
     return (result.zone_data);
 }
 
-result::Result
-InMemoryClient::load(const isc::dns::Name& zone_name,
-                     const std::string& filename)
-{
-    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD).arg(zone_name).
-        arg(filename);
-
-    MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
-    ZoneData* zone_data = loadZoneData(mem_sgmt, rrclass_, zone_name,
-                                       filename);
-    return (loadInternal(zone_name, filename, zone_data));
-}
-
-result::Result
-InMemoryClient::load(const isc::dns::Name& zone_name, ZoneIterator& iterator) {
-    MemorySegment& mem_sgmt = ztable_segment_->getMemorySegment();
-    ZoneData* zone_data = loadZoneData(mem_sgmt, rrclass_, zone_name,
-                                       iterator);
-    return (loadInternal(zone_name, string(), zone_data));
-}
-
-const std::string
-InMemoryClient::getFileName(const isc::dns::Name& zone_name) const {
-    const FileNameNode* node(NULL);
-    const FileNameTree::Result result = file_name_tree_->find(zone_name,
-                                                              &node);
-    if (result == FileNameTree::EXACTMATCH) {
-        return (*node->getData());
-    } else {
-        return (std::string());
-    }
-}
-
 namespace {
 
 class MemoryIterator : public ZoneIterator {
@@ -369,7 +257,7 @@ InMemoryClient::getUpdater(const isc::dns::Name&, bool, bool) const {
     isc_throw(isc::NotImplemented, "Update attempt on in memory data source");
 }
 
-pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
+std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
 InMemoryClient::getJournalReader(const isc::dns::Name&, uint32_t,
                                  uint32_t) const
 {
diff --git a/src/lib/datasrc/memory/memory_client.h b/src/lib/datasrc/memory/memory_client.h
index 10e8a81..45f0b77 100644
--- a/src/lib/datasrc/memory/memory_client.h
+++ b/src/lib/datasrc/memory/memory_client.h
@@ -55,7 +55,7 @@ class ZoneTableSegment;
 class InMemoryClient : public DataSourceClient {
 public:
     ///
-    /// \name Constructors and Destructor.
+    /// \name Constructor.
     ///
     //@{
 
@@ -66,9 +66,6 @@ public:
     /// It never throws an exception otherwise.
     InMemoryClient(boost::shared_ptr<ZoneTableSegment> ztable_segment,
                    isc::dns::RRClass rrclass);
-
-    /// The destructor.
-    ~InMemoryClient();
     //@}
 
     /// \brief Returns the class of the data source client.
@@ -81,68 +78,6 @@ public:
     /// \return The number of zones stored in the client.
     virtual unsigned int getZoneCount() const;
 
-    /// \brief Load zone from masterfile.
-    ///
-    /// This loads data from masterfile specified by filename. It replaces
-    /// current content. The masterfile parsing ability is kind of limited,
-    /// see isc::dns::masterLoad.
-    ///
-    /// This throws isc::dns::MasterLoadError or AddError if there are
-    /// problems with loading (missing file, malformed data, unexpected
-    /// zone, etc. - see isc::dns::masterLoad for details).
-    ///
-    /// In case of internal problems, NullRRset or AssertError could
-    /// be thrown, but they should not be expected. Exceptions caused by
-    /// allocation may be thrown as well.
-    ///
-    /// If anything is thrown, the previous content is preserved (so it can
-    /// be used to update the data, but if user makes a typo, the old one
-    /// is kept).
-    ///
-    /// \param filename The master file to load.
-    ///
-    /// \todo We may need to split it to some kind of build and commit/abort.
-    ///     This will probably be needed when a better implementation of
-    ///     configuration reloading is written.
-    result::Result load(const isc::dns::Name& zone_name,
-                        const std::string& filename);
-
-    /// \brief Load zone from another data source.
-    ///
-    /// This is similar to the other version, but zone's RRsets are provided
-    /// by an iterator of another data source.  On successful load, the
-    /// internal filename will be cleared.
-    ///
-    /// This implementation assumes the iterator produces combined RRsets,
-    /// that is, there should exactly one RRset for the same owner name and
-    /// RR type.  This means the caller is expected to create the iterator
-    /// with \c separate_rrs being \c false.  This implementation also assumes
-    /// RRsets of different names are not mixed; so if the iterator produces
-    /// an RRset of a different name than that of the previous RRset, that
-    /// previous name must never appear in the subsequent sequence of RRsets.
-    /// Note that the iterator API does not ensure this.  If the underlying
-    /// implementation does not follow it, load() will fail.  Note, however,
-    /// that this whole interface is tentative.  in-memory zone loading will
-    /// have to be revisited fundamentally, and at that point this restriction
-    /// probably won't matter.
-    result::Result load(const isc::dns::Name& zone_name,
-                        ZoneIterator& iterator);
-
-    /// Return the master file name of the zone
-    ///
-    /// This method returns the name of the zone's master file to be loaded.
-    /// The returned string will be an empty unless the data source client has
-    /// successfully loaded the \c zone_name zone from a file before.
-    ///
-    /// This method should normally not throw an exception.  But the creation
-    /// of the return string may involve a resource allocation, and if it
-    /// fails, the corresponding standard exception will be thrown.
-    ///
-    /// \return The name of the zone file corresponding to the zone, or
-    /// an empty string if the client hasn't loaded the \c zone_name
-    /// zone from a file before.
-    const std::string getFileName(const isc::dns::Name& zone_name) const;
-
     /// Returns a \c ZoneFinder result that best matches the given name.
     ///
     /// This derived version of the method never throws an exception.
@@ -180,20 +115,8 @@ public:
                      uint32_t end_serial) const;
 
 private:
-    // Some type aliases
-    typedef DomainTree<std::string> FileNameTree;
-    typedef DomainTreeNode<std::string> FileNameNode;
-
-    // Common process for zone load. Registers filename internally and
-    // adds the ZoneData to the ZoneTable.
-    result::Result loadInternal(const isc::dns::Name& zone_name,
-                                const std::string& filename,
-                                ZoneData* zone_data);
-
     boost::shared_ptr<ZoneTableSegment> ztable_segment_;
     const isc::dns::RRClass rrclass_;
-    unsigned int zone_count_;
-    FileNameTree* file_name_tree_;
 };
 
 } // namespace memory
diff --git a/src/lib/datasrc/memory/memory_messages.mes b/src/lib/datasrc/memory/memory_messages.mes
index 1b312bb..8580c8e 100644
--- a/src/lib/datasrc/memory/memory_messages.mes
+++ b/src/lib/datasrc/memory/memory_messages.mes
@@ -126,9 +126,13 @@ RRset is split into multiple locations is not supported yet.
 Debug information. A zone object for this zone is being searched for in the
 in-memory data source.
 
-% DATASRC_MEMORY_MEM_LOAD loading zone '%1' from file '%2'
+% DATASRC_MEMORY_MEM_LOAD_FROM_FILE loading zone '%1/%2' from file '%3'
 Debug information. The content of master file is being loaded into the memory.
 
+% DATASRC_MEMORY_MEM_LOAD_FROM_DATASRC loading zone '%1/%2' from other data source
+Debug information. The content of another  data source is being loaded
+into the memory.
+
 % DATASRC_MEMORY_MEM_NO_NSEC3PARAM NSEC3PARAM is missing for NSEC3-signed zone %1/%2
 The in-memory data source has loaded a zone signed with NSEC3 RRs,
 but it doesn't have a NSEC3PARAM RR at the zone origin.  It's likely that
diff --git a/src/lib/datasrc/memory/zone_data_loader.cc b/src/lib/datasrc/memory/zone_data_loader.cc
index de3a749..d66fb3b 100644
--- a/src/lib/datasrc/memory/zone_data_loader.cc
+++ b/src/lib/datasrc/memory/zone_data_loader.cc
@@ -253,6 +253,9 @@ loadZoneData(util::MemorySegment& mem_sgmt,
              const isc::dns::Name& zone_name,
              const std::string& zone_file)
 {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD_FROM_FILE).
+        arg(zone_name).arg(rrclass).arg(zone_file);
+
      return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
                                  boost::bind(masterLoaderWrapper,
                                              zone_file.c_str(),
@@ -266,6 +269,9 @@ loadZoneData(util::MemorySegment& mem_sgmt,
              const isc::dns::Name& zone_name,
              ZoneIterator& iterator)
 {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_LOAD_FROM_DATASRC).
+        arg(zone_name).arg(rrclass);
+
     return (loadZoneDataInternal(mem_sgmt, rrclass, zone_name,
                                  boost::bind(generateRRsetFromIterator,
                                              &iterator, _1)));
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
index 4f9183e..3f61b89 100644
--- a/src/lib/datasrc/memory/zone_finder.cc
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -18,7 +18,7 @@
 #include <datasrc/memory/rdata_serialization.h>
 
 #include <datasrc/zone_finder.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <dns/labelsequence.h>
 #include <dns/name.h>
 #include <dns/rrset.h>
diff --git a/src/lib/datasrc/memory/zone_table.cc b/src/lib/datasrc/memory/zone_table.cc
index c0237f5..77071f4 100644
--- a/src/lib/datasrc/memory/zone_table.cc
+++ b/src/lib/datasrc/memory/zone_table.cc
@@ -12,14 +12,15 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include <util/memory_segment.h>
-
-#include <dns/name.h>
-
-#include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/zone_table.h>
+#include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/domaintree.h>
 #include <datasrc/memory/segment_object_holder.h>
+#include <datasrc/memory/logger.h>
+
+#include <util/memory_segment.h>
+
+#include <dns/name.h>
 
 #include <boost/function.hpp>
 #include <boost/bind.hpp>
@@ -70,6 +71,9 @@ ZoneTable::AddResult
 ZoneTable::addZone(util::MemorySegment& mem_sgmt, RRClass zone_class,
                    const Name& zone_name, ZoneData* content)
 {
+    LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_MEMORY_MEM_ADD_ZONE).
+        arg(zone_name).arg(rrclass_);
+
     if (content == NULL) {
         isc_throw(isc::BadValue, "Zone content must not be NULL");
     }
@@ -94,6 +98,7 @@ ZoneTable::addZone(util::MemorySegment& mem_sgmt, RRClass zone_class,
     if (old != NULL) {
         return (AddResult(result::EXIST, old));
     } else {
+        ++zone_count_;
         return (AddResult(result::SUCCESS, NULL));
     }
 }
diff --git a/src/lib/datasrc/memory/zone_table.h b/src/lib/datasrc/memory/zone_table.h
index 1b369b9..2774df3 100644
--- a/src/lib/datasrc/memory/zone_table.h
+++ b/src/lib/datasrc/memory/zone_table.h
@@ -104,6 +104,7 @@ private:
     /// It never throws an exception otherwise.
     ZoneTable(const dns::RRClass& rrclass, ZoneTableTree* zones) :
         rrclass_(rrclass),
+        zone_count_(0),
         zones_(zones)
     {}
 
@@ -139,6 +140,11 @@ public:
     /// is undefined if this condition isn't met).
     static void destroy(util::MemorySegment& mem_sgmt, ZoneTable* ztable);
 
+    /// \brief Return the number of zones contained in the zone table.
+    ///
+    /// \throw None.
+    size_t getZoneCount() const { return (zone_count_); }
+
     /// Add a new zone to the \c ZoneTable.
     ///
     /// This method adds a given zone data to the internal table.
@@ -187,6 +193,7 @@ public:
 
 private:
     const dns::RRClass rrclass_;
+    size_t zone_count_;
     boost::interprocess::offset_ptr<ZoneTableTree> zones_;
 };
 }
diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc
index 1a90fa0..93f468c 100644
--- a/src/lib/datasrc/sqlite3_accessor.cc
+++ b/src/lib/datasrc/sqlite3_accessor.cc
@@ -25,7 +25,7 @@
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/sqlite3_datasrc_messages.h>
 #include <datasrc/logger.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/factory.h>
 #include <datasrc/database.h>
 #include <util/filename.h>
diff --git a/src/lib/datasrc/sqlite3_accessor.h b/src/lib/datasrc/sqlite3_accessor.h
index 3d457b3..f8c4138 100644
--- a/src/lib/datasrc/sqlite3_accessor.h
+++ b/src/lib/datasrc/sqlite3_accessor.h
@@ -17,7 +17,7 @@
 #define DATASRC_SQLITE3_ACCESSOR_H
 
 #include <datasrc/database.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 
 #include <exceptions/exceptions.h>
 
diff --git a/src/lib/datasrc/tests/cache_config_unittest.cc b/src/lib/datasrc/tests/cache_config_unittest.cc
index 8c266ec..e73b06d 100644
--- a/src/lib/datasrc/tests/cache_config_unittest.cc
+++ b/src/lib/datasrc/tests/cache_config_unittest.cc
@@ -13,10 +13,15 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <datasrc/cache_config.h>
+#include <datasrc/exceptions.h>
+#include <datasrc/memory/load_action.h>
+#include <datasrc/memory/zone_data.h>
 #include <datasrc/tests/mock_client.h>
 
 #include <cc/data.h>
+#include <util/memory_segment_local.h>
 #include <dns/name.h>
+#include <dns/rrclass.h>
 
 #include <gtest/gtest.h>
 
@@ -28,12 +33,15 @@ using namespace isc::dns;
 using isc::datasrc::unittest::MockDataSourceClient;
 using isc::datasrc::internal::CacheConfig;
 using isc::datasrc::internal::CacheConfigError;
+using isc::datasrc::memory::LoadAction;
+using isc::datasrc::memory::ZoneData;
 
 namespace {
 
 const char* zones[] = {
     "example.org.",
     "example.com.",
+    "null.org",                 // test for bad iterator case
     NULL
 };
 
@@ -50,9 +58,14 @@ protected:
                                        " \"cache-zones\": [\".\"]}"))
     {}
 
+    virtual void TearDown() {
+        EXPECT_TRUE(msgmt_.allMemoryDeallocated());
+    }
+
     MockDataSourceClient mock_client_;
     const ConstElementPtr master_config_; // valid config for MasterFiles
     const ConstElementPtr mock_config_; // valid config for MasterFiles
+    isc::util::MemorySegmentLocal msgmt_;
 };
 
 size_t
@@ -140,6 +153,28 @@ TEST_F(CacheConfigTest, badConstructMasterFiles) {
                  isc::InvalidParameter);
 }
 
+TEST_F(CacheConfigTest, getLoadActionWithMasterFiles) {
+    uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+
+    const CacheConfig cache_conf("MasterFiles", 0, *master_config_, true);
+
+    // Check getLoadAction.  Since it returns a mere functor, we can only
+    // check the behavior by actually calling it.  For the purpose of this
+    // test, it should suffice if we confirm the call succeeds and shows
+    // some reasonably valid behavior (we'll check the origin name for that).
+    LoadAction action = cache_conf.getLoadAction(RRClass::IN(),
+                                                 Name::ROOT_NAME());
+    ZoneData* zone_data = action(msgmt_);
+    ASSERT_TRUE(zone_data);
+    EXPECT_EQ(".", zone_data->getOriginNode()->
+              getAbsoluteLabels(labels_buf).toText());
+    ZoneData::destroy(msgmt_, zone_data, RRClass::IN());
+
+    // If the specified zone name is not configured to be cached,
+    // getLoadAction returns empty (false) functor.
+    EXPECT_FALSE(cache_conf.getLoadAction(RRClass::IN(), Name("example.com")));
+}
+
 TEST_F(CacheConfigTest, constructWithMock) {
     // Performing equivalent set of tests as constructMasterFiles
 
@@ -219,6 +254,40 @@ TEST_F(CacheConfigTest, badConstructWithMock) {
                  isc::InvalidParameter);
 }
 
+TEST_F(CacheConfigTest, getLoadActionWithMock) {
+    uint8_t labels_buf[LabelSequence::MAX_SERIALIZED_LENGTH];
+
+    // Similar to MasterFiles counterpart, but using underlying source
+    // data source.
+
+    // Note: there's a mismatch between this configuration and the actual
+    // mock data source content: example.net doesn't exist in the data source.
+    const ConstElementPtr config(Element::fromJSON(
+                                     "{\"cache-enable\": true,"
+                                     " \"cache-zones\": [\"example.org\","
+                                     " \"example.net\", \"null.org\"]}"));
+    const CacheConfig cache_conf("mock", &mock_client_, *config, true);
+    LoadAction action = cache_conf.getLoadAction(RRClass::IN(),
+                                                 Name("example.org"));
+    ZoneData* zone_data = action(msgmt_);
+    ASSERT_TRUE(zone_data);
+    EXPECT_EQ("example.org.", zone_data->getOriginNode()->
+              getAbsoluteLabels(labels_buf).toText());
+    ZoneData::destroy(msgmt_, zone_data, RRClass::IN());
+
+    // Zone not configured for the cache
+    EXPECT_FALSE(cache_conf.getLoadAction(RRClass::IN(), Name("example.com")));
+
+    // Zone configured for the cache but doesn't exist in the underling data
+    // source.
+    EXPECT_THROW(cache_conf.getLoadAction(RRClass::IN(), Name("example.net")),
+                 DataSourceError);
+
+    // buggy data source client: it returns a null pointer from getIterator.
+    EXPECT_THROW(cache_conf.getLoadAction(RRClass::IN(), Name("null.org")),
+                 isc::Unexpected);
+}
+
 TEST_F(CacheConfigTest, getSegmentType) {
     // Default type
     EXPECT_EQ("local",
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index ab553cb..8013f01 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -14,8 +14,9 @@
 
 #include <datasrc/client_list.h>
 #include <datasrc/client.h>
+#include <datasrc/cache_config.h>
 #include <datasrc/zone_iterator.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/memory/memory_client.h>
 #include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/memory/zone_finder.h>
@@ -133,29 +134,50 @@ public:
     }
 
     // Install a "fake" cached zone using a temporary underlying data source
-    // client.
-    void prepareCache(size_t index, const Name& zone) {
-        // Prepare the temporary data source client
-        const char* zones[2];
-        const std::string zonename_txt = zone.toText();
-        zones[0] = zonename_txt.c_str();
-        zones[1] = NULL;
-        MockDataSourceClient mock_client(zones);
+    // client.  If 'enabled' is set to false, emulate a disabled cache, in
+    // which case there will be no data in memory.
+    void prepareCache(size_t index, const Name& zone, bool enabled = true) {
+        ConfigurableClientList::DataSourceInfo& dsrc_info =
+                list_->getDataSources()[index];
+        MockDataSourceClient* mock_client =
+            static_cast<MockDataSourceClient*>(dsrc_info.data_src_client_);
+
         // Disable some default features of the mock to distinguish the
         // temporary case from normal case.
-        mock_client.disableA();
-        mock_client.disableBadIterator();
-
-        // Create cache from the temporary data source, and push it to the
-        // client list.
-        const shared_ptr<InMemoryClient> cache(
-            new InMemoryClient(ztable_segment_, rrclass_));
-        cache->load(zone, *mock_client.getIterator(zone, false));
+        mock_client->disableA();
+        mock_client->disableBadIterator();
+
+        // Build new cache config to load the specified zone, and replace
+        // the data source info with the new config.
+        ConstElementPtr cache_conf_elem =
+            Element::fromJSON("{\"type\": \"mock\","
+                              " \"cache-enable\": " +
+                              string(enabled ? "true," : "false,") +
+                              " \"cache-zones\": "
+                              "   [\"" + zone.toText() + "\"]}");
+        boost::shared_ptr<internal::CacheConfig> cache_conf(
+            new internal::CacheConfig("mock", mock_client, *cache_conf_elem,
+                                      true));
+        dsrc_info = ConfigurableClientList::DataSourceInfo(
+            dsrc_info.data_src_client_,
+            dsrc_info.container_,
+            cache_conf, rrclass_, dsrc_info.name_);
+
+        // Load the data into the zone table.
+        if (enabled) {
+            boost::scoped_ptr<memory::ZoneWriter> writer(
+                dsrc_info.ztable_segment_->getZoneWriter(
+                    cache_conf->getLoadAction(rrclass_, zone),
+                    zone, rrclass_));
+            writer->load();
+            writer->install();
+            writer->cleanup(); // not absolutely necessary, but just in case
+        }
 
-        ConfigurableClientList::DataSourceInfo& dsrc_info =
-                list_->getDataSources()[index];
-        dsrc_info.cache_ = cache;
-        dsrc_info.ztable_segment_ = ztable_segment_;
+        // On completion of load revert to the previous state of underlying
+        // data source.
+        mock_client->enableA();
+        mock_client->enableBadIterator();
     }
     // Check the positive result is as we expect it.
     void positiveResult(const ClientList::FindResult& result,
@@ -874,7 +896,7 @@ TYPED_TEST(ReloadTest, reloadSuccess) {
 }
 
 // The cache is not enabled. The load should be rejected.
-TYPED_TEST(ReloadTest, reloadNotEnabled) {
+TYPED_TEST(ReloadTest, reloadNotAllowed) {
     this->list_->configure(this->config_elem_zones_, false);
     const Name name("example.org");
     // We put the cache in even when not enabled. This won't confuse the thing.
@@ -893,6 +915,17 @@ TYPED_TEST(ReloadTest, reloadNotEnabled) {
                        RRType::A())->code);
 }
 
+// Similar to the previous case, but the cache is disabled in config.
+TYPED_TEST(ReloadTest, reloadNotEnabled) {
+    this->list_->configure(this->config_elem_zones_, true);
+    const Name name("example.org");
+    // We put the cache, actually disabling it.
+    this->prepareCache(0, name, false);
+    // In this case we cannot really look up due to the limitation of
+    // the mock implementation.  We only check reload fails.
+    EXPECT_EQ(ConfigurableClientList::ZONE_NOT_CACHED, this->doReload(name));
+}
+
 // Test several cases when the zone does not exist
 TYPED_TEST(ReloadTest, reloadNoSuchZone) {
     this->list_->configure(this->config_elem_zones_, true);
@@ -926,7 +959,7 @@ TYPED_TEST(ReloadTest, reloadNoSuchZone) {
 // Check we gracefuly throw an exception when a zone disappeared in
 // the underlying data source when we want to reload it
 TYPED_TEST(ReloadTest, reloadZoneGone) {
-    this->list_->configure(this->config_elem_, true);
+    this->list_->configure(this->config_elem_zones_, true);
     const Name name("example.org");
     // We put in a cache for non-existent zone. This emulates being loaded
     // and then the zone disappearing. We prefill the cache, so we can check
@@ -936,6 +969,10 @@ TYPED_TEST(ReloadTest, reloadZoneGone) {
     EXPECT_EQ(ZoneFinder::SUCCESS,
               this->list_->find(name).finder_->find(name,
                                                     RRType::SOA())->code);
+    // Remove the zone from the data source.
+    static_cast<MockDataSourceClient*>(
+        this->list_->getDataSources()[0].data_src_client_)->eraseZone(name);
+
     // The zone is not there, so abort the reload.
     EXPECT_THROW(this->doReload(name), DataSourceError);
     // The (cached) zone is not hurt.
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index c67e7fe..16b0627 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -25,7 +25,7 @@
 #include <datasrc/database.h>
 #include <datasrc/zone.h>
 #include <datasrc/zone_finder.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/zone_iterator.h>
 
 #include <testutils/dnsmessage_test.h>
diff --git a/src/lib/datasrc/tests/factory_unittest.cc b/src/lib/datasrc/tests/factory_unittest.cc
index 58d6029..5a01a27 100644
--- a/src/lib/datasrc/tests/factory_unittest.cc
+++ b/src/lib/datasrc/tests/factory_unittest.cc
@@ -16,7 +16,7 @@
 
 #include <datasrc/datasrc_config.h>
 #include <datasrc/factory.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/sqlite3_accessor.h>
 
 #include <dns/rrclass.h>
diff --git a/src/lib/datasrc/tests/memory/Makefile.am b/src/lib/datasrc/tests/memory/Makefile.am
index f77d212..e0fc0f5 100644
--- a/src/lib/datasrc/tests/memory/Makefile.am
+++ b/src/lib/datasrc/tests/memory/Makefile.am
@@ -21,6 +21,7 @@ if HAVE_GTEST
 TESTS += run_unittests
 
 run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += zone_loader_util.h zone_loader_util.cc
 run_unittests_SOURCES += rdata_serialization_unittest.cc
 run_unittests_SOURCES += rdataset_unittest.cc
 run_unittests_SOURCES += domaintree_unittest.cc
diff --git a/src/lib/datasrc/tests/memory/memory_client_unittest.cc b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
index 5984de5..f5b72a0 100644
--- a/src/lib/datasrc/tests/memory/memory_client_unittest.cc
+++ b/src/lib/datasrc/tests/memory/memory_client_unittest.cc
@@ -12,6 +12,8 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <datasrc/tests/memory/zone_loader_util.h>
+
 #include <exceptions/exceptions.h>
 
 #include <util/memory_segment_local.h>
@@ -26,7 +28,7 @@
 #include <dns/masterload.h>
 
 #include <datasrc/result.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/zone_table.h>
 #include <datasrc/memory/zone_data_updater.h>
@@ -42,6 +44,7 @@
 
 #include <boost/lexical_cast.hpp>
 #include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
 
 #include <new>                  // for bad_alloc
 
@@ -53,6 +56,7 @@ using namespace isc::datasrc::memory;
 using namespace isc::testutils;
 using boost::shared_ptr;
 using std::vector;
+using isc::datasrc::memory::test::loadZoneIntoTable;
 
 namespace {
 
@@ -169,26 +173,22 @@ protected:
                              zclass_, mem_sgmt_)),
                          client_(new InMemoryClient(ztable_segment_, zclass_))
     {}
-    ~MemoryClientTest() {
-        delete client_;
-    }
     void TearDown() {
-        delete client_;
-        client_ = NULL;
+        client_.reset();
         ztable_segment_.reset();
         EXPECT_TRUE(mem_sgmt_.allMemoryDeallocated()); // catch any leak here.
     }
     const RRClass zclass_;
     test::MemorySegmentTest mem_sgmt_;
     shared_ptr<ZoneTableSegment> ztable_segment_;
-    InMemoryClient* client_;
+    boost::scoped_ptr<InMemoryClient> client_;
 };
 
 TEST_F(MemoryClientTest, loadRRsetDoesntMatchOrigin) {
     // Attempting to load example.org to example.com zone should result
     // in an exception.
-    EXPECT_THROW(client_->load(Name("example.com"),
-                               TEST_DATA_DIR "/example.org-empty.zone"),
+    EXPECT_THROW(loadZoneData(mem_sgmt_, zclass_, Name("example.com"),
+                              TEST_DATA_DIR "/example.org-empty.zone"),
                  ZoneLoaderException);
 }
 
@@ -196,8 +196,8 @@ TEST_F(MemoryClientTest, loadErrorsInParsingZoneMustNotLeak1) {
     // Attempting to load broken example.org zone should result in an
     // exception. This should not leak ZoneData and other such
     // allocations.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR "/example.org-broken1.zone"),
+    EXPECT_THROW(loadZoneData(mem_sgmt_, zclass_, Name("example.org"),
+                              TEST_DATA_DIR "/example.org-broken1.zone"),
                  ZoneLoaderException);
     // Teardown checks for memory segment leaks
 }
@@ -206,50 +206,45 @@ TEST_F(MemoryClientTest, loadErrorsInParsingZoneMustNotLeak2) {
     // Attempting to load broken example.org zone should result in an
     // exception. This should not leak ZoneData and other such
     // allocations.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR "/example.org-broken2.zone"),
+    EXPECT_THROW(loadZoneData(mem_sgmt_, zclass_, Name("example.org"),
+                              TEST_DATA_DIR "/example.org-broken2.zone"),
                  ZoneLoaderException);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadNonExistentZoneFile) {
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR "/somerandomfilename"),
+    EXPECT_THROW(loadZoneData(mem_sgmt_, zclass_, Name("example.org"),
+                              TEST_DATA_DIR "/somerandomfilename"),
                  ZoneLoaderException);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadEmptyZoneFileThrows) {
     // When an empty zone file is loaded, the origin doesn't even have
-    // an SOA RR. This condition should be avoided, and hence load()
-    // should throw when an empty zone is loaded.
-
-    EXPECT_EQ(0, client_->getZoneCount());
-
-    EXPECT_THROW(client_->load(Name("."),
-                               TEST_DATA_DIR "/empty.zone"),
+    // an SOA RR. This condition should be avoided, and hence it results in
+    // an exception.
+    EXPECT_THROW(loadZoneData(mem_sgmt_, zclass_, Name("."),
+                              TEST_DATA_DIR "/empty.zone"),
                  ZoneValidationError);
-
-    EXPECT_EQ(0, client_->getZoneCount());
-
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, load) {
     // This is a simple load check for a "full" and correct zone that
     // should not result in any exceptions.
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org.zone");
-    const ZoneData* zone_data =
-        client_->findZoneData(Name("example.org"));
+    ZoneData* zone_data = loadZoneData(mem_sgmt_, zclass_,
+                                       Name("example.org"),
+                                       TEST_DATA_DIR
+                                       "/example.org.zone");
     ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
     EXPECT_FALSE(zone_data->isSigned());
     EXPECT_FALSE(zone_data->isNSEC3Signed());
+    ZoneData::destroy(mem_sgmt_, zone_data, zclass_);
 }
 
 TEST_F(MemoryClientTest, loadFromIterator) {
-    client_->load(Name("example.org"),
-                  *MockIterator::makeIterator(rrset_data));
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      *MockIterator::makeIterator(rrset_data));
 
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
 
@@ -281,21 +276,23 @@ TEST_F(MemoryClientTest, loadFromIterator) {
     // Iterating past the end should result in an exception
     EXPECT_THROW(iterator->getNextRRset(), isc::Unexpected);
 
+    // NOTE: The rest of the tests is not actually about InMemoryClient
+
     // Loading the zone with an iterator separating RRs of the same
     // RRset should not fail. It is acceptable to load RRs of the same
     // type again.
-    client_->load(Name("example.org"),
-                  *MockIterator::makeIterator(
-                      rrset_data_separated));
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      *MockIterator::makeIterator(rrset_data_separated));
 
     // Similar to the previous case, but with separated RRSIGs.
-    client_->load(Name("example.org"),
-                  *MockIterator::makeIterator(
-                      rrset_data_sigseparated));
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      *MockIterator::makeIterator(rrset_data_sigseparated));
 
     // Emulating bogus iterator implementation that passes empty RRSIGs.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               *MockIterator::makeIterator(rrset_data, true)),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   *MockIterator::makeIterator(rrset_data,
+                                                               true)),
                  isc::Unexpected);
 }
 
@@ -316,16 +313,16 @@ TEST_F(MemoryClientTest, loadMemoryAllocationFailures) {
             // fail (due to MemorySegmentTest throwing) and we check for
             // leaks when this happens.
             InMemoryClient client2(ztable_segment, zclass_);
-            client2.load(Name("example.org"),
-                         TEST_DATA_DIR "/example.org.zone");
+            loadZoneIntoTable(*ztable_segment, Name("example.org"), zclass_,
+                              TEST_DATA_DIR "/example.org.zone");
         }, std::bad_alloc);
     }
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadNSEC3Signed) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-nsec3-signed.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-nsec3-signed.zone");
     const ZoneData* zone_data =
         client_->findZoneData(Name("example.org"));
     ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
@@ -336,8 +333,8 @@ TEST_F(MemoryClientTest, loadNSEC3Signed) {
 TEST_F(MemoryClientTest, loadNSEC3EmptySalt) {
     // Load NSEC3 with empty ("-") salt. This should not throw or crash
     // or anything.
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-nsec3-empty-salt.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-nsec3-empty-salt.zone");
     const ZoneData* zone_data =
         client_->findZoneData(Name("example.org"));
     ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
@@ -346,8 +343,8 @@ TEST_F(MemoryClientTest, loadNSEC3EmptySalt) {
 }
 
 TEST_F(MemoryClientTest, loadNSEC3SignedNoParam) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-nsec3-signed-no-param.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-nsec3-signed-no-param.zone");
     const ZoneData* zone_data =
         client_->findZoneData(Name("example.org"));
     ASSERT_NE(static_cast<const ZoneData*>(NULL), zone_data);
@@ -360,14 +357,14 @@ TEST_F(MemoryClientTest, loadReloadZone) {
     // doesn't increase.
     EXPECT_EQ(0, client_->getZoneCount());
 
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-empty.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-empty.zone");
     EXPECT_EQ(1, client_->getZoneCount());
 
     // Reload zone with same data
 
-    client_->load(Name("example.org"),
-                  client_->getFileName(Name("example.org")));
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-empty.zone");
     EXPECT_EQ(1, client_->getZoneCount());
 
     const ZoneData* zone_data =
@@ -396,8 +393,8 @@ TEST_F(MemoryClientTest, loadReloadZone) {
 
     // Reload zone with different data
 
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-rrsigs.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-rrsigs.zone");
     EXPECT_EQ(1, client_->getZoneCount());
 
     zone_data = client_->findZoneData(Name("example.org"));
@@ -441,15 +438,14 @@ TEST_F(MemoryClientTest, loadReloadZone) {
 TEST_F(MemoryClientTest, loadDuplicateType) {
     // This should not result in any exceptions (multiple records of the
     // same name, type are present, one after another in sequence).
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-duplicate-type.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-duplicate-type.zone");
 
     // This should not result in any exceptions (multiple records of the
     // same name, type are present, but not one after another in
     // sequence).
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR
-                  "/example.org-duplicate-type-bad.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-duplicate-type-bad.zone");
 
     const ZoneData* zone_data =
         client_->findZoneData(Name("example.org"));
@@ -479,104 +475,116 @@ TEST_F(MemoryClientTest, loadDuplicateType) {
 
 TEST_F(MemoryClientTest, loadMultipleCNAMEThrows) {
     // Multiple CNAME RRs should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-multiple-cname.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-multiple-cname.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadMultipleDNAMEThrows) {
     // Multiple DNAME RRs should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-multiple-dname.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-multiple-dname.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadMultipleNSEC3Throws) {
     // Multiple NSEC3 RRs should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-multiple-nsec3.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-multiple-nsec3.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadMultipleNSEC3PARAMThrows) {
     // Multiple NSEC3PARAM RRs should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-multiple-nsec3param.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-multiple-nsec3param.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadOutOfZoneThrows) {
     // Out of zone names should throw.
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-out-of-zone.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-out-of-zone.zone"),
                  ZoneLoaderException);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadWildcardNSThrows) {
     // Wildcard NS names should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-wildcard-ns.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-wildcard-ns.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadWildcardDNAMEThrows) {
     // Wildcard DNAME names should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-wildcard-dname.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-wildcard-dname.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadWildcardNSEC3Throws) {
     // Wildcard NSEC3 names should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-wildcard-nsec3.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-wildcard-nsec3.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadNSEC3WithFewerLabelsThrows) {
     // NSEC3 names with labels != (origin_labels + 1) should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-nsec3-fewer-labels.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-nsec3-fewer-labels.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadNSEC3WithMoreLabelsThrows) {
     // NSEC3 names with labels != (origin_labels + 1) should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-nsec3-more-labels.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-nsec3-more-labels.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadCNAMEAndNotNSECThrows) {
     // CNAME and not NSEC should throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-cname-and-not-nsec-1.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-cname-and-not-nsec-1.zone"),
                  ZoneDataUpdater::AddError);
 
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-cname-and-not-nsec-2.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-cname-and-not-nsec-2.zone"),
                  ZoneDataUpdater::AddError);
 
     // Teardown checks for memory segment leaks
@@ -584,41 +592,41 @@ TEST_F(MemoryClientTest, loadCNAMEAndNotNSECThrows) {
 
 TEST_F(MemoryClientTest, loadDNAMEAndNSApex1) {
     // DNAME + NS (apex) is OK
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR
-                  "/example.org-dname-ns-apex-1.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-dname-ns-apex-1.zone");
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadDNAMEAndNSApex2) {
     // DNAME + NS (apex) is OK (reverse order)
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR
-                  "/example.org-dname-ns-apex-2.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-dname-ns-apex-2.zone");
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex1) {
     // DNAME + NS (non-apex) must throw
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-dname-ns-nonapex-1.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-dname-ns-nonapex-1.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadDNAMEAndNSNonApex2) {
     // DNAME + NS (non-apex) must throw (reverse order)
-    EXPECT_THROW(client_->load(Name("example.org"),
-                               TEST_DATA_DIR
-                               "/example.org-dname-ns-nonapex-2.zone"),
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   TEST_DATA_DIR
+                                   "/example.org-dname-ns-nonapex-2.zone"),
                  ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, loadRRSIGs) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-rrsigs.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-rrsigs.zone");
     EXPECT_EQ(1, client_->getZoneCount());
 }
 
@@ -642,37 +650,31 @@ TEST_F(MemoryClientTest, loadRRSIGsRdataMixedCoveredTypes) {
 
     rrsets_vec.push_back(rrset);
 
-    EXPECT_THROW(
-        client_->load(Name("example.org"),
-                      *MockVectorIterator::makeIterator(rrsets_vec)),
-        ZoneDataUpdater::AddError);
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   *MockVectorIterator::makeIterator(
+                                       rrsets_vec)),
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, getZoneCount) {
     EXPECT_EQ(0, client_->getZoneCount());
-    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-empty.zone");
+    // We've updated the zone table already in the client, so the count
+    // should also be incremented indirectly.
     EXPECT_EQ(1, client_->getZoneCount());
 }
 
-TEST_F(MemoryClientTest, getFileNameForNonExistentZone) {
-    // Zone "example.org." doesn't exist
-    EXPECT_TRUE(client_->getFileName(Name("example.org.")).empty());
-}
-
-TEST_F(MemoryClientTest, getFileName) {
-    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
-    EXPECT_EQ(TEST_DATA_DIR "/example.org-empty.zone",
-              client_->getFileName(Name("example.org")));
-}
-
 TEST_F(MemoryClientTest, getIteratorForNonExistentZone) {
     // Zone "." doesn't exist
     EXPECT_THROW(client_->getIterator(Name(".")), DataSourceError);
 }
 
 TEST_F(MemoryClientTest, getIterator) {
-    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-empty.zone");
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
 
     // First we have the SOA
@@ -693,8 +695,8 @@ TEST_F(MemoryClientTest, getIterator) {
 }
 
 TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-multiple.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-multiple.zone");
 
     // separate_rrs = false
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
@@ -746,8 +748,8 @@ TEST_F(MemoryClientTest, getIteratorSeparateRRs) {
 
 // Test we get RRSIGs and NSEC3s too for iterating with separate RRs
 TEST_F(MemoryClientTest, getIteratorSeparateSigned) {
-    client_->load(Name("example.org"),
-                       TEST_DATA_DIR "/example.org-nsec3-signed.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-nsec3-signed.zone");
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org"), true));
     bool seen_rrsig = false, seen_nsec3 = false;
     for (ConstRRsetPtr rrset = iterator->getNextRRset();
@@ -764,7 +766,8 @@ TEST_F(MemoryClientTest, getIteratorSeparateSigned) {
 }
 
 TEST_F(MemoryClientTest, getIteratorGetSOAThrowsNotImplemented) {
-    client_->load(Name("example.org"), TEST_DATA_DIR "/example.org-empty.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-empty.zone");
     ZoneIteratorPtr iterator(client_->getIterator(Name("example.org")));
 
     // This method is not implemented.
@@ -780,16 +783,17 @@ TEST_F(MemoryClientTest, addEmptyRRsetThrows) {
     rrsets_vec.push_back(RRsetPtr(new RRset(Name("example.org"), zclass_,
                                             RRType::A(), RRTTL(3600))));
 
-    EXPECT_THROW(
-        client_->load(Name("example.org"),
-                      *MockVectorIterator::makeIterator(rrsets_vec)),
-        ZoneDataUpdater::AddError);
+    EXPECT_THROW(loadZoneIntoTable(*ztable_segment_, Name("example.org"),
+                                   zclass_,
+                                   *MockVectorIterator::makeIterator(
+                                       rrsets_vec)),
+                 ZoneDataUpdater::AddError);
     // Teardown checks for memory segment leaks
 }
 
 TEST_F(MemoryClientTest, findZoneData) {
-    client_->load(Name("example.org"),
-                  TEST_DATA_DIR "/example.org-rrsigs.zone");
+    loadZoneIntoTable(*ztable_segment_, Name("example.org"), zclass_,
+                      TEST_DATA_DIR "/example.org-rrsigs.zone");
 
     const ZoneData* zone_data = client_->findZoneData(Name("example.com"));
     EXPECT_EQ(static_cast<const ZoneData*>(NULL), zone_data);
diff --git a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
index 02c8a09..0350ed9 100644
--- a/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_finder_unittest.cc
@@ -12,8 +12,9 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
-#include "memory_segment_test.h"
-#include "zone_table_segment_test.h"
+#include <datasrc/tests/memory/memory_segment_test.h>
+#include <datasrc/tests/memory/zone_table_segment_test.h>
+#include <datasrc/tests/memory/zone_loader_util.h>
 
 // NOTE: this faked_nsec3 inclusion (and all related code below)
 // was ported during #2109 for the convenience of implementing #2218
@@ -21,14 +22,14 @@
 // In #2219 the original is expected to be removed, and this file should
 // probably be moved here (and any leftover code not handled in #2218 should
 // be cleaned up)
-#include "../../tests/faked_nsec3.h"
+#include <datasrc/tests/faked_nsec3.h>
 
 #include <datasrc/memory/zone_finder.h>
 #include <datasrc/memory/zone_data_updater.h>
 #include <datasrc/memory/rdata_serialization.h>
 #include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/memory/memory_client.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/client.h>
 #include <testutils/dnsmessage_test.h>
 
@@ -1610,12 +1611,13 @@ TEST_F(InMemoryZoneFinderTest, findOrphanRRSIG) {
 // \brief testcase for #2504 (Problem in inmem NSEC denial of existence
 // handling)
 TEST_F(InMemoryZoneFinderTest, NSECNonExistentTest) {
+    const Name name("example.com.");
     shared_ptr<ZoneTableSegment> ztable_segment(
          new ZoneTableSegmentTest(class_, mem_sgmt_));
+    loadZoneIntoTable(*ztable_segment, name, class_,
+                      TEST_DATA_DIR "/2504-test.zone");
     InMemoryClient client(ztable_segment, class_);
-    Name name("example.com.");
 
-    client.load(name, TEST_DATA_DIR "/2504-test.zone");
     DataSourceClient::FindResult result(client.findZone(name));
 
     // Check for a non-existing name
@@ -1771,16 +1773,17 @@ TEST_F(InMemoryZoneFinderNSEC3Test, findNSEC3MissingOrigin) {
      DefaultNSEC3HashCreator creator;
      setNSEC3HashCreator(&creator);
 
+     const Name name("example.com.");
      shared_ptr<ZoneTableSegment> ztable_segment(
           new ZoneTableSegmentTest(class_, mem_sgmt_));
+     loadZoneIntoTable(*ztable_segment, name, class_,
+                       TEST_DATA_DIR "/2503-test.zone");
      InMemoryClient client(ztable_segment, class_);
-     Name name("example.com.");
 
-     client.load(name, TEST_DATA_DIR "/2503-test.zone");
      DataSourceClient::FindResult result(client.findZone(name));
 
      // Check for a non-existing name
-     Name search_name("nonexist.example.com.");
+     const Name search_name("nonexist.example.com.");
      ZoneFinder::FindNSEC3Result find_result(
           result.zone_finder->findNSEC3(search_name, true));
      // findNSEC3() must have completed (not throw or assert). Because
diff --git a/src/lib/datasrc/tests/memory/zone_loader_util.cc b/src/lib/datasrc/tests/memory/zone_loader_util.cc
new file mode 100644
index 0000000..1bf9cfa
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_loader_util.cc
@@ -0,0 +1,93 @@
+// 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/tests/memory/zone_loader_util.h>
+
+#include <datasrc/zone_iterator.h>
+#include <datasrc/cache_config.h>
+#include <datasrc/memory/zone_table_segment.h>
+#include <datasrc/memory/zone_data_loader.h>
+#include <datasrc/memory/zone_writer.h>
+
+#include <dns/dns_fwd.h>
+
+#include <cc/data.h>
+
+#include <boost/bind.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include <string>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+namespace test {
+
+void
+loadZoneIntoTable(ZoneTableSegment& zt_sgmt, const dns::Name& zname,
+                  const dns::RRClass& zclass, const std::string& zone_file)
+{
+    const isc::datasrc::internal::CacheConfig cache_conf(
+        "MasterFiles", NULL, *data::Element::fromJSON(
+            "{\"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();
+}
+
+namespace {
+// borrowed from CacheConfig's internal
+class IteratorLoader {
+public:
+    IteratorLoader(const dns::RRClass& rrclass, const dns::Name& name,
+                   ZoneIterator& iterator) :
+        rrclass_(rrclass),
+        name_(name),
+        iterator_(iterator)
+    {}
+    memory::ZoneData* operator()(util::MemorySegment& segment) {
+        return (memory::loadZoneData(segment, rrclass_, name_, iterator_));
+    }
+private:
+    const dns::RRClass rrclass_;
+    const dns::Name name_;
+    ZoneIterator& iterator_;
+};
+}
+
+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();
+}
+
+} // namespace test
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/memory/zone_loader_util.h b/src/lib/datasrc/tests/memory/zone_loader_util.h
new file mode 100644
index 0000000..06eba87
--- /dev/null
+++ b/src/lib/datasrc/tests/memory/zone_loader_util.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_MEMORY_TEST_ZONE_LOADER_UTIL_H
+#define DATASRC_MEMORY_TEST_ZONE_LOADER_UTIL_H 1
+
+#include <datasrc/memory/zone_table_segment.h>
+#include <datasrc/memory/zone_data_loader.h>
+
+#include <dns/dns_fwd.h>
+
+#include <string>
+
+namespace isc {
+namespace datasrc {
+namespace memory {
+namespace test {
+
+/// \brief A shortcut utility to load a specified zone into ZoneTableSegment
+/// from a file.
+///
+/// This function does nothing special, simply provides a shortcut for commonly
+/// used pattern that would be used in tests with a ZoneTableSegment loading
+/// a zone from file into it.
+void
+loadZoneIntoTable(ZoneTableSegment& zt_sgmt, const dns::Name& zname,
+                  const dns::RRClass& zclass, const std::string& zone_file);
+
+/// \brief A shortcut utility to load a specified zone into ZoneTableSegment
+/// from a zone iterator.
+///
+/// This is similar to the other version, but use a zone iterator as the
+/// source of the zone data.
+void
+loadZoneIntoTable(ZoneTableSegment& zt_sgmt, const dns::Name& zname,
+                  const dns::RRClass& zclass, ZoneIterator& iterator);
+} // namespace test
+} // namespace memory
+} // namespace datasrc
+} // namespace isc
+
+#endif // DATASRC_MEMORY_TEST_ZONE_LOADER_UTIL_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/tests/memory/zone_table_unittest.cc b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
index 3c53a59..0109793 100644
--- a/src/lib/datasrc/tests/memory/zone_table_unittest.cc
+++ b/src/lib/datasrc/tests/memory/zone_table_unittest.cc
@@ -70,9 +70,13 @@ TEST_F(ZoneTableTest, create) {
 }
 
 TEST_F(ZoneTableTest, addZone) {
+    // By default there's no zone contained.
+    EXPECT_EQ(0, zone_table->getZoneCount());
+
     // It doesn't accept empty (NULL) zones
     EXPECT_THROW(zone_table->addZone(mem_sgmt_, zclass_, zname1, NULL),
                  isc::BadValue);
+    EXPECT_EQ(0, zone_table->getZoneCount()); // count is still 0
 
     SegmentObjectHolder<ZoneData, RRClass> holder1(
         mem_sgmt_, ZoneData::create(mem_sgmt_, zname1), zclass_);
@@ -85,6 +89,7 @@ TEST_F(ZoneTableTest, addZone) {
     EXPECT_EQ(static_cast<const ZoneData*>(NULL), result1.zone_data);
     // It got released by it
     EXPECT_EQ(static_cast<const ZoneData*>(NULL), holder1.get());
+    EXPECT_EQ(1, zone_table->getZoneCount()); // count is now incremented
 
     // Duplicate add doesn't replace the existing data.
     SegmentObjectHolder<ZoneData, RRClass> holder2(
@@ -99,6 +104,7 @@ TEST_F(ZoneTableTest, addZone) {
     EXPECT_EQ(static_cast<const ZoneData*>(NULL), holder2.get());
     // We need to release the old one manually
     ZoneData::destroy(mem_sgmt_, result2.zone_data, zclass_);
+    EXPECT_EQ(1, zone_table->getZoneCount()); // count doesn't change.
 
     SegmentObjectHolder<ZoneData, RRClass> holder3(
         mem_sgmt_, ZoneData::create(mem_sgmt_, Name("EXAMPLE.COM")),
@@ -115,11 +121,13 @@ TEST_F(ZoneTableTest, addZone) {
     EXPECT_EQ(result::SUCCESS,
               zone_table->addZone(mem_sgmt_, zclass_, zname2,
                                   holder4.release()).code);
+    EXPECT_EQ(2, zone_table->getZoneCount());
     SegmentObjectHolder<ZoneData, RRClass> holder5(
         mem_sgmt_, ZoneData::create(mem_sgmt_, zname3), zclass_);
     EXPECT_EQ(result::SUCCESS,
               zone_table->addZone(mem_sgmt_, zclass_, zname3,
                                   holder5.release()).code);
+    EXPECT_EQ(3, zone_table->getZoneCount());
 
     // Have the memory segment throw an exception in extending the internal
     // tree.  It still shouldn't cause memory leak (which would be detected
diff --git a/src/lib/datasrc/tests/mock_client.cc b/src/lib/datasrc/tests/mock_client.cc
index 90e0a66..fd3916d 100644
--- a/src/lib/datasrc/tests/mock_client.cc
+++ b/src/lib/datasrc/tests/mock_client.cc
@@ -16,7 +16,7 @@
 #include <datasrc/client.h>
 #include <datasrc/result.h>
 #include <datasrc/zone_iterator.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 
 #include <dns/name.h>
 #include <dns/rrclass.h>
diff --git a/src/lib/datasrc/tests/mock_client.h b/src/lib/datasrc/tests/mock_client.h
index ae7a0bf..c51e9a1 100644
--- a/src/lib/datasrc/tests/mock_client.h
+++ b/src/lib/datasrc/tests/mock_client.h
@@ -52,7 +52,12 @@ public:
     }
     virtual ZoneIteratorPtr getIterator(const dns::Name& name, bool) const;
     void disableA() { have_a_ = false; }
+    void enableA() { have_a_ = true; }
     void disableBadIterator() { use_baditerator_ = false; }
+    void enableBadIterator() { use_baditerator_ = true; }
+    void eraseZone(const dns::Name& zone_name) {
+        zones.erase(zone_name);
+    }
     const std::string type_;
     const data::ConstElementPtr configuration_;
 
diff --git a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
index 786218a..ce34d25 100644
--- a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
+++ b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
@@ -16,7 +16,7 @@
 
 #include <datasrc/sqlite3_accessor.h>
 
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 
 #include <dns/rrclass.h>
 
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index 1ce1cee..f541fd8 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -18,9 +18,13 @@
 #include <dns/name.h>
 #include <dns/rrclass.h>
 
+#include <cc/data.h>
+
 #include <datasrc/zone_finder.h>
+#include <datasrc/cache_config.h>
 #include <datasrc/memory/memory_client.h>
 #include <datasrc/memory/zone_table_segment.h>
+#include <datasrc/memory/zone_writer.h>
 #include <datasrc/database.h>
 #include <datasrc/sqlite3_accessor.h>
 
@@ -32,6 +36,7 @@
 #include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 #include <boost/shared_ptr.hpp>
+#include <boost/scoped_ptr.hpp>
 
 #include <fstream>
 #include <sstream>
@@ -39,11 +44,13 @@
 
 using namespace std;
 using boost::shared_ptr;
+using boost::scoped_ptr;
 
 using namespace isc::data;
 using namespace isc::util;
 using namespace isc::dns;
 using namespace isc::datasrc;
+using isc::data::Element;
 using isc::datasrc::memory::InMemoryClient;
 using isc::datasrc::memory::ZoneTableSegment;
 using namespace isc::testutils;
@@ -64,11 +71,22 @@ typedef DataSourceClientPtr (*ClientCreator)(RRClass, const Name&);
 // Creator for the in-memory client to be tested
 DataSourceClientPtr
 createInMemoryClient(RRClass zclass, const Name& zname) {
+    const internal::CacheConfig cache_conf(
+        "MasterFiles", NULL, *Element::fromJSON(
+            "{\"cache-enable\": true,"
+            " \"params\":"
+            "  {\"" + zname.toText() + "\": \"" +
+            string(TEST_ZONE_FILE) + "\"}}"), true);
     shared_ptr<ZoneTableSegment> ztable_segment(
-        ZoneTableSegment::create(zclass, "local"));
+        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();
     shared_ptr<InMemoryClient> client(new InMemoryClient(ztable_segment,
                                                          zclass));
-    client->load(zname, TEST_ZONE_FILE);
 
     return (client);
 }
diff --git a/src/lib/datasrc/tests/zone_loader_unittest.cc b/src/lib/datasrc/tests/zone_loader_unittest.cc
index eabcd65..4cf9e9a 100644
--- a/src/lib/datasrc/tests/zone_loader_unittest.cc
+++ b/src/lib/datasrc/tests/zone_loader_unittest.cc
@@ -13,11 +13,13 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <datasrc/zone_loader.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/rrset_collection_base.h>
+#include <datasrc/cache_config.h>
 
 #include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/memory/memory_client.h>
+#include <datasrc/memory/zone_writer.h>
 
 #include <dns/rrclass.h>
 #include <dns/name.h>
@@ -26,6 +28,8 @@
 #include <util/memory_segment_local.h>
 #include <exceptions/exceptions.h>
 
+#include <cc/data.h>
+
 #include <gtest/gtest.h>
 
 #include <boost/shared_ptr.hpp>
@@ -37,6 +41,7 @@
 
 using namespace isc::dns;
 using namespace isc::datasrc;
+using isc::data::Element;
 using boost::shared_ptr;
 using std::string;
 using std::vector;
@@ -301,13 +306,28 @@ protected:
 
         // (re)configure zone table, then (re)construct the in-memory client
         // with it.
-        ztable_segment_.reset(memory::ZoneTableSegment::create(rrclass_,
-                                                               "local"));
-        source_client_.reset(new memory::InMemoryClient(ztable_segment_,
-                                                        rrclass_));
+        string param_data;
         if (filename) {
-            source_client_->load(zone, string(TEST_DATA_DIR) + "/" + filename);
+            param_data = "\"" + zone.toText() + "\": \"" +
+                string(TEST_DATA_DIR) + "/" + filename + "\"";
         }
+        const internal::CacheConfig cache_conf(
+            "MasterFiles", NULL, *Element::fromJSON(
+                "{\"cache-enable\": true,"
+                " \"params\": {" + param_data + "}}"), true);
+        ztable_segment_.reset(memory::ZoneTableSegment::create(
+                                  rrclass_, cache_conf.getSegmentType()));
+        if (filename) {
+            boost::scoped_ptr<memory::ZoneWriter> writer(
+                ztable_segment_->getZoneWriter(cache_conf.getLoadAction(
+                                                   rrclass_, zone),
+                                               zone, rrclass_));
+            writer->load();
+            writer->install();
+            writer->cleanup();
+        }
+        source_client_.reset(new memory::InMemoryClient(ztable_segment_,
+                                                        rrclass_));
     }
 private:
     const RRClass rrclass_;
diff --git a/src/lib/datasrc/zone_finder.cc b/src/lib/datasrc/zone_finder.cc
index b4240c0..70cb8bf 100644
--- a/src/lib/datasrc/zone_finder.cc
+++ b/src/lib/datasrc/zone_finder.cc
@@ -13,8 +13,9 @@
 // PERFORMANCE OF THIS SOFTWARE.
 
 #include <datasrc/zone_finder.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 
+#include <dns/rrclass.h>
 #include <dns/rdata.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
diff --git a/src/lib/datasrc/zone_loader.cc b/src/lib/datasrc/zone_loader.cc
index d0f4a64..8044bc0 100644
--- a/src/lib/datasrc/zone_loader.cc
+++ b/src/lib/datasrc/zone_loader.cc
@@ -16,7 +16,7 @@
 #include <datasrc/master_loader_callbacks.h>
 
 #include <datasrc/client.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/zone_iterator.h>
 #include <datasrc/zone.h>
 #include <datasrc/logger.h>
diff --git a/src/lib/datasrc/zone_loader.h b/src/lib/datasrc/zone_loader.h
index 2a4559e..068dc35 100644
--- a/src/lib/datasrc/zone_loader.h
+++ b/src/lib/datasrc/zone_loader.h
@@ -15,7 +15,7 @@
 #ifndef DATASRC_ZONE_LOADER_H
 #define DATASRC_ZONE_LOADER_H
 
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 
 #include <dns/master_loader.h>
 
diff --git a/src/lib/python/isc/datasrc/client_python.cc b/src/lib/python/isc/datasrc/client_python.cc
index df19492..3eed80e 100644
--- a/src/lib/python/isc/datasrc/client_python.cc
+++ b/src/lib/python/isc/datasrc/client_python.cc
@@ -25,7 +25,7 @@
 #include <datasrc/client.h>
 #include <datasrc/factory.h>
 #include <datasrc/database.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/zone_iterator.h>
 #include <datasrc/client_list.h>
diff --git a/src/lib/python/isc/datasrc/finder_python.cc b/src/lib/python/isc/datasrc/finder_python.cc
index 05c44c9..ef1bcc1 100644
--- a/src/lib/python/isc/datasrc/finder_python.cc
+++ b/src/lib/python/isc/datasrc/finder_python.cc
@@ -24,7 +24,7 @@
 
 #include <datasrc/client.h>
 #include <datasrc/database.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/zone_iterator.h>
 #include <datasrc/zone.h>
diff --git a/src/lib/python/isc/datasrc/updater_python.cc b/src/lib/python/isc/datasrc/updater_python.cc
index e61db75..331eafa 100644
--- a/src/lib/python/isc/datasrc/updater_python.cc
+++ b/src/lib/python/isc/datasrc/updater_python.cc
@@ -24,7 +24,7 @@
 
 #include <datasrc/client.h>
 #include <datasrc/database.h>
-#include <datasrc/data_source.h>
+#include <datasrc/exceptions.h>
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/zone.h>
 
diff --git a/tests/lettuce/features/auth_badzone.feature b/tests/lettuce/features/auth_badzone.feature
index edc1a64..5448b6e 100644
--- a/tests/lettuce/features/auth_badzone.feature
+++ b/tests/lettuce/features/auth_badzone.feature
@@ -12,9 +12,9 @@ Feature: Authoritative DNS server with a bad zone
         # will be logged and we cannot use the 'new' keyword to wait for
         # 3 different log messages. *There could still be a race here if
         # auth starts very quickly.*
-        And wait for new bind10 stderr message DATASRC_LOAD_FROM_FILE_ERROR
-        And wait for new bind10 stderr message DATASRC_LOAD_FROM_FILE_ERROR
-        And wait for new bind10 stderr message DATASRC_LOAD_FROM_FILE_ERROR
+        And wait for new bind10 stderr message DATASRC_LOAD_ZONE_ERROR
+        And wait for new bind10 stderr message DATASRC_LOAD_ZONE_ERROR
+        And wait for new bind10 stderr message DATASRC_LOAD_ZONE_ERROR
 
         And wait for bind10 stderr message BIND10_STARTED_CC
         And wait for bind10 stderr message CMDCTL_STARTED



More information about the bind10-changes mailing list