Browse Source

[master] Merge branch 'trac2834'

JINMEI Tatuya 12 years ago
parent
commit
bf60255cc1
46 changed files with 764 additions and 609 deletions
  1. 1 1
      src/bin/auth/auth_srv.cc
  2. 1 1
      src/bin/auth/datasrc_clients_mgr.h
  3. 1 1
      src/bin/auth/tests/config_unittest.cc
  4. 1 2
      src/lib/datasrc/Makefile.am
  5. 85 0
      src/lib/datasrc/cache_config.cc
  6. 52 6
      src/lib/datasrc/cache_config.h
  7. 42 121
      src/lib/datasrc/client_list.cc
  8. 8 2
      src/lib/datasrc/client_list.h
  9. 0 68
      src/lib/datasrc/data_source.h
  10. 2 2
      src/lib/datasrc/database.cc
  11. 1 1
      src/lib/datasrc/database.h
  12. 6 9
      src/lib/datasrc/datasrc_messages.mes
  13. 20 0
      src/lib/datasrc/exceptions.h
  14. 1 1
      src/lib/datasrc/factory.cc
  15. 1 1
      src/lib/datasrc/factory.h
  16. 5 117
      src/lib/datasrc/memory/memory_client.cc
  17. 1 78
      src/lib/datasrc/memory/memory_client.h
  18. 5 1
      src/lib/datasrc/memory/memory_messages.mes
  19. 6 0
      src/lib/datasrc/memory/zone_data_loader.cc
  20. 1 1
      src/lib/datasrc/memory/zone_finder.cc
  21. 10 5
      src/lib/datasrc/memory/zone_table.cc
  22. 7 0
      src/lib/datasrc/memory/zone_table.h
  23. 1 1
      src/lib/datasrc/sqlite3_accessor.cc
  24. 1 1
      src/lib/datasrc/sqlite3_accessor.h
  25. 69 0
      src/lib/datasrc/tests/cache_config_unittest.cc
  26. 60 23
      src/lib/datasrc/tests/client_list_unittest.cc
  27. 1 1
      src/lib/datasrc/tests/database_unittest.cc
  28. 1 1
      src/lib/datasrc/tests/factory_unittest.cc
  29. 1 0
      src/lib/datasrc/tests/memory/Makefile.am
  30. 140 136
      src/lib/datasrc/tests/memory/memory_client_unittest.cc
  31. 12 9
      src/lib/datasrc/tests/memory/zone_finder_unittest.cc
  32. 93 0
      src/lib/datasrc/tests/memory/zone_loader_util.cc
  33. 57 0
      src/lib/datasrc/tests/memory/zone_loader_util.h
  34. 8 0
      src/lib/datasrc/tests/memory/zone_table_unittest.cc
  35. 1 1
      src/lib/datasrc/tests/mock_client.cc
  36. 5 0
      src/lib/datasrc/tests/mock_client.h
  37. 1 1
      src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
  38. 20 2
      src/lib/datasrc/tests/zone_finder_context_unittest.cc
  39. 26 6
      src/lib/datasrc/tests/zone_loader_unittest.cc
  40. 2 1
      src/lib/datasrc/zone_finder.cc
  41. 1 1
      src/lib/datasrc/zone_loader.cc
  42. 1 1
      src/lib/datasrc/zone_loader.h
  43. 1 1
      src/lib/python/isc/datasrc/client_python.cc
  44. 1 1
      src/lib/python/isc/datasrc/finder_python.cc
  45. 1 1
      src/lib/python/isc/datasrc/updater_python.cc
  46. 3 3
      tests/lettuce/features/auth_badzone.feature

+ 1 - 1
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>

+ 1 - 1
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>
 

+ 1 - 1
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>
 

+ 1 - 2
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

+ 85 - 0
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

+ 52 - 6
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_;
 };

+ 42 - 121
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_->

+ 8 - 2
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.

+ 0 - 68
src/lib/datasrc/data_source.h

@@ -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:

+ 2 - 2
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>

+ 1 - 1
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>

+ 6 - 9
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

+ 20 - 0
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 {

+ 1 - 1
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"
 

+ 1 - 1
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>

+ 5 - 117
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
 {

+ 1 - 78
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

+ 5 - 1
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

+ 6 - 0
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)));

+ 1 - 1
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>

+ 10 - 5
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));
     }
 }

+ 7 - 0
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_;
 };
 }

+ 1 - 1
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>

+ 1 - 1
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>
 

+ 69 - 0
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",

+ 60 - 23
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.

+ 1 - 1
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>

+ 1 - 1
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>

+ 1 - 0
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

+ 140 - 136
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);

+ 12 - 9
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

+ 93 - 0
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:

+ 57 - 0
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:

+ 8 - 0
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

+ 1 - 1
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>

+ 5 - 0
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_;
 

+ 1 - 1
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>
 

+ 20 - 2
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);
 }

+ 26 - 6
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_;

+ 2 - 1
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>

+ 1 - 1
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>

+ 1 - 1
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>
 

+ 1 - 1
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>

+ 1 - 1
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>

+ 1 - 1
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>
 

+ 3 - 3
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