BIND 10 master, updated. f9e512d246f51641cd9089694926edbd3be14fe8 Changelog for #1976

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Jul 24 11:35:00 UTC 2012


The branch, master has been updated
       via  f9e512d246f51641cd9089694926edbd3be14fe8 (commit)
       via  0d4685b3e7603585afde1b587cbfefdfaf6a1bb3 (commit)
       via  19df22ab0570f7299ff142243119cc9cc07d4d48 (commit)
       via  7d5399cb039d854dc9d816735d0854f1ff5babc8 (commit)
       via  9cef6836cd9198c1a8f20574fc07cf632ef82d1b (commit)
       via  3359259cabddd159f85f6c9d16fbc261fb94ceda (commit)
       via  9c128152d15049af019ad58e20be23810b518141 (commit)
       via  4a972b4645aa694071027e0685e61a6e993cac4a (commit)
       via  64d096e98b2f1803e0e5f5f36986a59c4cd90dff (commit)
       via  65a9d49f2f80d46fd1852a9ebc789a7c1367a398 (commit)
       via  c7462ec728933bfc3fcbc143f37f2284cabc0ab7 (commit)
       via  6adec616524f9cc43a399d58f38d14907b19cc79 (commit)
       via  eecbfe1f68e76f43ee01105112a5f4e7fc99006d (commit)
       via  a9e6753cf15e6df9639e012744c3422cfc212827 (commit)
       via  441ea8549d43504d2b53a7090ebc5c16ba299d77 (commit)
       via  9a7b53ca18ede76274bab50c3bd45c248cd65c52 (commit)
       via  78d6dcd302295dc106b6cb6de2c995b724f9f05f (commit)
       via  cbb514313e63277f7e4b8fb0ccc22748b8d36e32 (commit)
       via  0e63a2cbf64f3f5a3b11bc2cdfb1f5e3289c3d02 (commit)
       via  bd426afdde14c8ae8e6b2cd781cac216e882ad84 (commit)
       via  9164b2999c49e604753127082eb3eb6d1d557940 (commit)
       via  68c6c03be3d3e656b376581f5df623cff67bb473 (commit)
       via  e0b54d0fc6f3208033134fdc0b3b98def9415a95 (commit)
       via  5566bd5d3b8dbc511a37755f04a158908ce5e4c5 (commit)
       via  3b2d6d62493592c5ec09557ae653bb9ea127e6a0 (commit)
       via  16f8257f2564999f32cfef6cf87640e0275c5f92 (commit)
       via  899ef652280b56e0974fd78c5f0b160c538ae952 (commit)
       via  e675dc75b6fbe186980798b8e3c7106a17de40dd (commit)
       via  77cc51898582ef249035a5ea3b99501d76143bde (commit)
       via  d31754477ab0136864aa6d85ce2936e5a5e02ffc (commit)
       via  be031e34e7fc50522908b39f897cb7865a055b0e (commit)
       via  eabb375e7dfc94f67aab7e4d8e372d71db9885c1 (commit)
       via  a0607f2c1a78586f6f54490c5a0c9e284a2caefc (commit)
       via  95833885795b723c5c1586d23827ea42c37b1789 (commit)
       via  97659d0862864670a3b45e8ae2c672b0d7029b2b (commit)
       via  b7c8ced3bac54e5e4560bdc39d15a74f4636fd88 (commit)
       via  90593cc3f05fbd272f11fc57c876487f9dbc3813 (commit)
       via  5fba01f28ca9b4a07417b40c0fc016eed2cdc7fa (commit)
       via  4f90ffd6c73b67efc830da23a101f9095b2540f8 (commit)
       via  6dc6d1f5d551d833a86b38297b9e209271fbdea3 (commit)
       via  af4e7787d37b951f9a48e992f0e2c6f4e4a28c22 (commit)
       via  27b68b4cbeb6ed397baf40221b9dda915230dcf6 (commit)
       via  be542e8e2c04b89bc6788112e4006e91bcff2418 (commit)
       via  5ed0c62ab3febe9f5310006fe3dedf52928fa79f (commit)
       via  f5db3a25bbac60c241acc36ba9869f72b4db18a9 (commit)
       via  1af29fce7c3ed236d2db21289f8fcf76af15724c (commit)
       via  6a56ac9b0e5bd227af1730fe4cd8adbd36d03d00 (commit)
       via  6107757547e99687e84c8c19f412801ac926a342 (commit)
       via  c3badfe37d74047f7b6b1f7f4ec03d30e7164296 (commit)
       via  327c71c61633f0d60163ac0cf38ce3954547c60f (commit)
       via  1124a637dfa3b123519bbd0e5e28d3b370c0bf4e (commit)
       via  59a8af594d8c0a0ea672dece5d10cd995fb4c0c2 (commit)
       via  9d269c5437c03247628e8d73ebda85a2e1e7ef72 (commit)
       via  18da2727080b2f1c4fbac21fb46371fb11311264 (commit)
       via  0e5ceb2ea0871dfd07db2eb8548ba7454df0fa02 (commit)
       via  343dc8e1fefc65298ddf3cc7d82adf8b6b9a60bf (commit)
       via  2536cfbce01e0fdd5b3d891beeedf2105ec8178c (commit)
       via  7ef59689d4277f0fa9fa43996c7c19ac509e741d (commit)
       via  07236d6cc1068f21d8362c5bb47c4928741d5421 (commit)
       via  f7de4b58b26e102920ce67597be8dfa8908f1a1e (commit)
       via  8fa13ec3115f58573bc2fd6213a99be1c8435462 (commit)
       via  c558fd6d7a67fa70d3ba78f43c6536f5c006fd3d (commit)
      from  1318187d1f3536922d396937de0cca535eb228bf (commit)

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

- Log -----------------------------------------------------------------
commit f9e512d246f51641cd9089694926edbd3be14fe8
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Jul 24 13:34:37 2012 +0200

    Changelog for #1976

commit 0d4685b3e7603585afde1b587cbfefdfaf6a1bb3
Merge: 1318187 19df22a
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Jul 24 11:32:53 2012 +0200

    Merge #1976
    
    Finally! This one was big.
    
    With some minor updates to catch up to the changes after merge.
    
    Conflicts:
    	src/bin/auth/auth_srv.cc
    	src/bin/auth/auth_srv.h
    	src/bin/auth/tests/auth_srv_unittest.cc
    	src/lib/datasrc/client_list.cc
    	src/lib/datasrc/tests/client_list_unittest.cc

commit 19df22ab0570f7299ff142243119cc9cc07d4d48
Merge: 7d5399c 3359259
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Jul 24 11:02:07 2012 +0200

    Merge remote-tracking branch 'origin/trac1976-cont-3' into work/merge

commit 7d5399cb039d854dc9d816735d0854f1ff5babc8
Merge: 9cef683 e0b54d0
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Jul 24 11:01:41 2012 +0200

    Merge remote-tracking branch 'origin/trac1976-cont-2' into work/merge

commit 9cef6836cd9198c1a8f20574fc07cf632ef82d1b
Merge: 3b2d6d6 d317544
Author: Michal 'vorner' Vaner <michal.vaner at nic.cz>
Date:   Tue Jul 24 11:00:25 2012 +0200

    Merge remote-tracking branch 'origin/trac1976-cont' into work/merge
    
    Conflicts:
    	src/bin/auth/tests/datasrc_configurator_unittest.cc

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

Summary of changes:
 ChangeLog                                          |    6 +
 configure.ac                                       |    1 +
 src/bin/auth/Makefile.am                           |    1 +
 src/bin/auth/auth.spec.pre.in                      |    4 -
 src/bin/auth/auth_config.cc                        |   99 +---
 src/bin/auth/auth_srv.cc                           |  197 ++------
 src/bin/auth/auth_srv.h                            |  132 ++----
 src/bin/auth/b10-auth.xml                          |   13 -
 src/bin/auth/benchmarks/query_bench.cc             |   38 +-
 src/bin/auth/command.cc                            |  167 ++-----
 src/bin/auth/datasrc_configurator.h                |  223 +++++++++
 src/bin/auth/main.cc                               |   20 +-
 src/bin/auth/query.cc                              |   54 +--
 src/bin/auth/query.h                               |   20 +-
 src/bin/auth/tests/Makefile.am                     |    5 +
 src/bin/auth/tests/auth_srv_unittest.cc            |  497 +++++++++++---------
 src/bin/auth/tests/command_unittest.cc             |  263 +++--------
 src/bin/auth/tests/config_unittest.cc              |  388 +--------------
 .../auth/tests/datasrc_configurator_unittest.cc    |  298 ++++++++++++
 src/bin/auth/tests/query_unittest.cc               |  208 ++++----
 src/bin/auth/tests/testdata/Makefile.am            |    1 +
 .../auth}/tests/testdata/spec.spec                 |    0
 src/bin/bind10/bind10.xml                          |   11 -
 src/bin/bind10/bind10_src.py.in                    |    9 +-
 src/bin/bind10/tests/bind10_test.py.in             |    2 -
 src/bin/cfgmgr/plugins/Makefile.am                 |    9 +-
 src/bin/cfgmgr/plugins/datasrc.spec.pre.in         |   66 +++
 .../bin/cfgmgr/plugins/datasrc_config_plugin.py    |   31 +-
 src/bin/cfgmgr/plugins/tests/Makefile.am           |    2 +-
 .../cfgmgr/plugins/tests/datasrc_test.py}          |   28 +-
 src/bin/ddns/tests/ddns_test.py                    |   38 +-
 src/bin/xfrin/tests/xfrin_test.py                  |  150 +-----
 src/bin/xfrin/xfrin.py.in                          |    2 +-
 src/bin/xfrin/xfrin_messages.mes                   |    7 +-
 src/lib/config/module_spec.cc                      |    2 +-
 src/lib/config/tests/module_spec_unittests.cc      |    1 +
 src/lib/config/tests/testdata/Makefile.am          |    1 +
 .../tests/testdata/{spec9.spec => spec40.spec}     |    4 +-
 src/lib/datasrc/client_list.cc                     |  132 ++++--
 src/lib/datasrc/client_list.h                      |   56 ++-
 src/lib/datasrc/static.zone.pre                    |    2 +
 src/lib/datasrc/tests/client_list_unittest.cc      |  219 ++++++++-
 .../isc/datasrc/configurableclientlist_python.cc   |    2 +-
 src/lib/python/isc/server_common/auth_command.py   |   53 +--
 .../isc/server_common/server_common_messages.mes   |    6 -
 tests/lettuce/configurations/ddns/ddns.config.orig |   12 +
 .../lettuce/configurations/ddns/noddns.config.orig |   29 +-
 .../lettuce/configurations/example.org.config.orig |   12 +
 .../configurations/example.org.inmem.config        |   29 +-
 tests/lettuce/configurations/example2.org.config   |   12 +
 .../inmemory_over_sqlite3/secondary.conf           |   24 +-
 .../configurations/ixfr-out/testset1-config.db     |   54 ++-
 .../multi_instance/multi_auth.config.orig          |   10 +
 tests/lettuce/configurations/no_db_file.config     |   12 +
 .../lettuce/configurations/nsec3/nsec3_auth.config |   37 +-
 .../lettuce/configurations/xfrin/inmem_slave.conf  |   25 +-
 .../configurations/xfrin/retransfer_master.conf    |   10 +
 .../configurations/xfrin/retransfer_slave.conf     |   10 +
 .../xfrin/retransfer_slave_notify.conf             |   10 +
 tests/lettuce/features/example.feature             |   12 +-
 tests/lettuce/features/terrain/bind10_control.py   |    2 +-
 .../system/bindctl/nsx1/b10-config.db.template.in  |   20 +
 tests/system/bindctl/tests.sh                      |    6 +-
 tests/system/glue/example.good                     |    7 +-
 tests/system/glue/nsx1/b10-config.db.in            |   20 +
 tests/system/glue/nsx1/root.db                     |    2 -
 tests/system/glue/tests.sh                         |   10 +-
 tests/system/ixfr/b10-config.db.in                 |   18 +
 68 files changed, 2039 insertions(+), 1812 deletions(-)
 create mode 100644 src/bin/auth/datasrc_configurator.h
 create mode 100644 src/bin/auth/tests/datasrc_configurator_unittest.cc
 copy src/{lib/server_common => bin/auth}/tests/testdata/spec.spec (100%)
 create mode 100644 src/bin/cfgmgr/plugins/datasrc.spec.pre.in
 copy tests/lettuce/run_lettuce.sh => src/bin/cfgmgr/plugins/datasrc_config_plugin.py (51%)
 mode change 100755 => 100644
 copy src/{lib/dns/python/tests/tsig_rdata_python_test.py => bin/cfgmgr/plugins/tests/datasrc_test.py} (59%)
 copy src/lib/config/tests/testdata/{spec9.spec => spec40.spec} (72%)

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index bd58aeb..ddcfb77 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+455.	[func]*		vorner
+	The server now uses never API for data sources. This would be an internal
+	change, however, the data sources are now configured differently. Please,
+	migrate your configuration to the top-level "data_sources" module.
+	(Trac #1976, git 0d4685b3e7603585afde1b587cbfefdfaf6a1bb3)
+
 454.	[bug]		jelte
 	b10-cfgmgr now loads its configuration check plugins directly from
 	the plugin search path, as opposed to importing them from the
diff --git a/configure.ac b/configure.ac
index 352c5c9..624530a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1142,6 +1142,7 @@ AC_CONFIG_FILES([Makefile
 AC_OUTPUT([doc/version.ent
            src/bin/cfgmgr/b10-cfgmgr.py
            src/bin/cfgmgr/tests/b10-cfgmgr_test.py
+           src/bin/cfgmgr/plugins/datasrc.spec.pre
            src/bin/cmdctl/cmdctl.py
            src/bin/cmdctl/run_b10-cmdctl.sh
            src/bin/cmdctl/tests/cmdctl_test
diff --git a/src/bin/auth/Makefile.am b/src/bin/auth/Makefile.am
index 34b5155..1f0fbbf 100644
--- a/src/bin/auth/Makefile.am
+++ b/src/bin/auth/Makefile.am
@@ -48,6 +48,7 @@ b10_auth_SOURCES += auth_config.cc auth_config.h
 b10_auth_SOURCES += command.cc command.h
 b10_auth_SOURCES += common.h common.cc
 b10_auth_SOURCES += statistics.cc statistics.h
+b10_auth_SOURCES += datasrc_configurator.h
 b10_auth_SOURCES += main.cc
 # This is a temporary workaround for #1206, where the InMemoryClient has been
 # moved to an ldopened library. We could add that library to LDADD, but that
diff --git a/src/bin/auth/auth.spec.pre.in b/src/bin/auth/auth.spec.pre.in
index 7606be4..a0b5a3d 100644
--- a/src/bin/auth/auth.spec.pre.in
+++ b/src/bin/auth/auth.spec.pre.in
@@ -125,10 +125,6 @@
 	  {
             "item_name": "origin", "item_type": "string",
             "item_optional": false, "item_default": ""
-          },
-	  {
-            "item_name": "datasrc", "item_type": "string",
-            "item_optional": true, "item_default": "memory"
           }
         ]
       },
diff --git a/src/bin/auth/auth_config.cc b/src/bin/auth/auth_config.cc
index c85a4ee..d7266e5 100644
--- a/src/bin/auth/auth_config.cc
+++ b/src/bin/auth/auth_config.cc
@@ -43,20 +43,6 @@ using namespace isc::datasrc;
 using namespace isc::server_common::portconfig;
 
 namespace {
-/// A derived \c AuthConfigParser class for the "datasources" configuration
-/// identifier.
-class DatasourcesConfig : public AuthConfigParser {
-public:
-    DatasourcesConfig(AuthSrv& server) : server_(server)
-    {}
-    virtual void build(ConstElementPtr config_value);
-    virtual void commit();
-private:
-    AuthSrv& server_;
-    vector<boost::shared_ptr<AuthConfigParser> > datasources_;
-    set<string> configured_sources_;
-    vector<pair<RRClass, DataSourceClientContainerPtr> > clients_;
-};
 
 /// A derived \c AuthConfigParser for the version value
 /// (which is not used at this moment)
@@ -67,79 +53,6 @@ public:
     virtual void commit() {};
 };
 
-void
-DatasourcesConfig::build(ConstElementPtr config_value) {
-    BOOST_FOREACH(ConstElementPtr datasrc_elem, config_value->listValue()) {
-        // The caller is supposed to perform syntax-level checks, but we'll
-        // do minimum level of validation ourselves so that we won't crash due
-        // to a buggy application.
-        ConstElementPtr datasrc_type = datasrc_elem->get("type");
-        if (!datasrc_type) {
-            isc_throw(AuthConfigError, "Missing data source type");
-        }
-
-        if (configured_sources_.find(datasrc_type->stringValue()) !=
-            configured_sources_.end()) {
-            isc_throw(AuthConfigError, "Data source type '" <<
-                      datasrc_type->stringValue() << "' already configured");
-        }
-
-        // Apart from that it's not really easy to get at the default
-        // class value for the class here, it should probably really
-        // be a property of the instantiated data source. For now
-        // use hardcoded default IN.
-        const RRClass rrclass =
-            datasrc_elem->contains("class") ?
-            RRClass(datasrc_elem->get("class")->stringValue()) : RRClass::IN();
-
-        // Right now, we only support the in-memory data source for the
-        // RR class of IN.  We reject other cases explicitly by hardcoded
-        // checks.  This will soon be generalized, at which point these
-        // checks will also have to be cleaned up.
-        if (rrclass != RRClass::IN()) {
-            isc_throw(isc::InvalidParameter, "Unsupported data source class: "
-                      << rrclass);
-        }
-        if (datasrc_type->stringValue() != "memory") {
-            isc_throw(AuthConfigError, "Unsupported data source type: "
-                      << datasrc_type->stringValue());
-        }
-
-        // Create a new client for the specified data source and store it
-        // in the local vector.  For now, we always build a new client
-        // from the scratch, and replace any existing ones with the new ones.
-        // We might eventually want to optimize building zones (in case of
-        // reloading) by selectively loading fresh zones for data source
-        // where zone loading is expensive (such as in-memory).
-        clients_.push_back(
-            pair<RRClass, DataSourceClientContainerPtr>(
-                rrclass,
-                DataSourceClientContainerPtr(new DataSourceClientContainer(
-                                                 datasrc_type->stringValue(),
-                                                 datasrc_elem))));
-
-        configured_sources_.insert(datasrc_type->stringValue());
-    }
-}
-
-void
-DatasourcesConfig::commit() {
-    // As noted in build(), the current implementation only supports the
-    // in-memory data source for class IN, and build() should have ensured
-    // it.  So, depending on the vector is empty or not, we either clear
-    // or install an in-memory data source for the server.
-    //
-    // When we generalize it, we'll somehow install all data source clients
-    // built in the vector, clearing deleted ones from the server.
-    if (clients_.empty()) {
-        server_.setInMemoryClient(RRClass::IN(),
-                                  DataSourceClientContainerPtr());
-    } else {
-        server_.setInMemoryClient(clients_.front().first,
-                                  clients_.front().second);
-    }
-}
-
 /// A derived \c AuthConfigParser class for the "statistics-internal"
 /// configuration identifier.
 class StatisticsIntervalConfig : public AuthConfigParser {
@@ -242,9 +155,7 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
     // simplicity.  In future we'll probably generalize it using map-like
     // data structure, and may even provide external register interface so
     // that it can be dynamically customized.
-    if (config_id == "datasources") {
-        return (new DatasourcesConfig(server));
-    } else if (config_id == "statistics-interval") {
+    if (config_id == "statistics-interval") {
         return (new StatisticsIntervalConfig(server));
     } else if (config_id == "listen_on") {
         return (new ListenAddressConfig(server));
@@ -261,6 +172,14 @@ createAuthConfigParser(AuthSrv& server, const std::string& config_id) {
         // later be used to mark backwards incompatible changes in the
         // config data
         return (new VersionConfig());
+    } else if (config_id == "datasources") {
+        // TODO: Ignored for now, since the value is probably used by
+        // other modules. Once they have been removed from there, remove
+        // it from here and the spec file.
+
+        // We need to return something. The VersionConfig is empty now,
+        // so we may abuse that one, as it is a short-term solution only.
+        return (new VersionConfig());
     } else {
         isc_throw(AuthConfigError, "Unknown configuration identifier: " <<
                   config_id);
diff --git a/src/bin/auth/auth_srv.cc b/src/bin/auth/auth_srv.cc
index e8176c3..32d36a5 100644
--- a/src/bin/auth/auth_srv.cc
+++ b/src/bin/auth/auth_srv.cc
@@ -43,9 +43,9 @@
 
 #include <datasrc/query.h>
 #include <datasrc/data_source.h>
-#include <datasrc/memory_datasrc.h>
 #include <datasrc/static_datasrc.h>
 #include <datasrc/sqlite3_datasrc.h>
+#include <datasrc/client_list.h>
 
 #include <xfr/xfrout_client.h>
 
@@ -222,10 +222,9 @@ private:
     AuthSrvImpl(const AuthSrvImpl& source);
     AuthSrvImpl& operator=(const AuthSrvImpl& source);
 public:
-    AuthSrvImpl(const bool use_cache, AbstractXfroutClient& xfrout_client,
+    AuthSrvImpl(AbstractXfroutClient& xfrout_client,
                 BaseSocketSessionForwarder& ddns_forwarder);
     ~AuthSrvImpl();
-    isc::data::ConstElementPtr setDbFile(isc::data::ConstElementPtr config);
 
     bool processNormalQuery(const IOMessage& io_message, Message& message,
                             OutputBuffer& buffer,
@@ -248,13 +247,6 @@ public:
     ModuleCCSession* config_session_;
     AbstractSession* xfrin_session_;
 
-    /// In-memory data source.  Currently class IN only for simplicity.
-    const RRClass memory_client_class_;
-    isc::datasrc::DataSourceClientContainerPtr memory_client_container_;
-
-    /// Hot spot cache
-    isc::datasrc::HotCache cache_;
-
     /// Interval timer for periodic submission of statistics counters.
     IntervalTimer statistics_timer_;
 
@@ -267,6 +259,21 @@ public:
     /// The TSIG keyring
     const boost::shared_ptr<TSIGKeyRing>* keyring_;
 
+    /// The client list
+    map<RRClass, boost::shared_ptr<ConfigurableClientList> > client_lists_;
+
+    boost::shared_ptr<ConfigurableClientList> getClientList(const RRClass&
+                                                            rrclass)
+    {
+        const map<RRClass, boost::shared_ptr<ConfigurableClientList> >::
+            const_iterator it(client_lists_.find(rrclass));
+        if (it == client_lists_.end()) {
+            return (boost::shared_ptr<ConfigurableClientList>());
+        } else {
+            return (it->second);
+        }
+    }
+
     /// Bind the ModuleSpec object in config_session_ with
     /// isc:config::ModuleSpec::validateStatistics.
     void registerStatisticsValidator();
@@ -296,14 +303,6 @@ public:
                       bool done);
 
 private:
-    std::string db_file_;
-
-    MetaDataSrc data_sources_;
-    /// We keep a pointer to the currently running sqlite datasource
-    /// so that we can specifically remove that one should the database
-    /// file change
-    ConstDataSrcPtr cur_datasrc_;
-
     bool xfrout_connected_;
     AbstractXfroutClient& xfrout_client_;
 
@@ -316,12 +315,10 @@ private:
     auth::Query query_;
 };
 
-AuthSrvImpl::AuthSrvImpl(const bool use_cache,
-                         AbstractXfroutClient& xfrout_client,
+AuthSrvImpl::AuthSrvImpl(AbstractXfroutClient& xfrout_client,
                          BaseSocketSessionForwarder& ddns_forwarder) :
     config_session_(NULL),
     xfrin_session_(NULL),
-    memory_client_class_(RRClass::IN()),
     statistics_timer_(io_service_),
     counters_(),
     keyring_(NULL),
@@ -329,17 +326,7 @@ AuthSrvImpl::AuthSrvImpl(const bool use_cache,
     ddns_forwarder_(NULL),
     xfrout_connected_(false),
     xfrout_client_(xfrout_client)
-{
-    // cur_datasrc_ is automatically initialized by the default constructor,
-    // effectively being an empty (sqlite) data source.  once ccsession is up
-    // the datasource will be set by the configuration setting
-
-    // add static data source
-    data_sources_.addDataSrc(ConstDataSrcPtr(new StaticDataSrc));
-
-    // enable or disable the cache
-    cache_.setEnabled(use_cache);
-}
+{}
 
 AuthSrvImpl::~AuthSrvImpl() {
     if (xfrout_connected_) {
@@ -398,11 +385,10 @@ private:
     AuthSrv* server_;
 };
 
-AuthSrv::AuthSrv(const bool use_cache,
-                 isc::xfr::AbstractXfroutClient& xfrout_client,
+AuthSrv::AuthSrv(isc::xfr::AbstractXfroutClient& xfrout_client,
                  isc::util::io::BaseSocketSessionForwarder& ddns_forwarder)
 {
-    impl_ = new AuthSrvImpl(use_cache, xfrout_client, ddns_forwarder);
+    impl_ = new AuthSrvImpl(xfrout_client, ddns_forwarder);
     checkin_ = new ConfigChecker(this);
     dns_lookup_ = new MessageLookup(this);
     dns_answer_ = new MessageAnswer(this);
@@ -482,16 +468,6 @@ AuthSrv::getIOService() {
 }
 
 void
-AuthSrv::setCacheSlots(const size_t slots) {
-    impl_->cache_.setSlots(slots);
-}
-
-size_t
-AuthSrv::getCacheSlots() const {
-    return (impl_->cache_.getSlots());
-}
-
-void
 AuthSrv::setXfrinSession(AbstractSession* xfrin_session) {
     impl_->xfrin_session_ = xfrin_session;
 }
@@ -512,48 +488,6 @@ AuthSrv::getConfigSession() const {
     return (impl_->config_session_);
 }
 
-isc::datasrc::DataSourceClientContainerPtr
-AuthSrv::getInMemoryClientContainer(const RRClass& rrclass) {
-    if (rrclass != impl_->memory_client_class_) {
-        isc_throw(InvalidParameter,
-                  "Memory data source is not supported for RR class "
-                  << rrclass);
-    }
-    return (impl_->memory_client_container_);
-}
-
-isc::datasrc::DataSourceClient*
-AuthSrv::getInMemoryClient(const RRClass& rrclass) {
-    if (hasInMemoryClient()) {
-        return (&getInMemoryClientContainer(rrclass)->getInstance());
-    } else {
-        return (NULL);
-    }
-}
-
-bool
-AuthSrv::hasInMemoryClient() const {
-    return (impl_->memory_client_container_);
-}
-
-void
-AuthSrv::setInMemoryClient(const isc::dns::RRClass& rrclass,
-                           DataSourceClientContainerPtr memory_client)
-{
-    if (rrclass != impl_->memory_client_class_) {
-        isc_throw(InvalidParameter,
-                  "Memory data source is not supported for RR class "
-                  << rrclass);
-    } else if (!impl_->memory_client_container_ && memory_client) {
-        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_MEM_DATASRC_ENABLED)
-                  .arg(rrclass);
-    } else if (impl_->memory_client_container_ && !memory_client) {
-        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_MEM_DATASRC_DISABLED)
-                  .arg(rrclass);
-    }
-    impl_->memory_client_container_ = memory_client;
-}
-
 uint32_t
 AuthSrv::getStatisticsTimerInterval() const {
     return (impl_->statistics_timer_.getInterval() / 1000);
@@ -725,18 +659,16 @@ AuthSrvImpl::processNormalQuery(const IOMessage& io_message, Message& message,
     }
 
     try {
-        // If a memory data source is configured call the separate
-        // Query::process()
         const ConstQuestionPtr question = *message.beginQuestion();
-        if (memory_client_container_ &&
-            memory_client_class_ == question->getClass()) {
+        const boost::shared_ptr<datasrc::ClientList>
+            list(getClientList(question->getClass()));
+        if (list) {
             const RRType& qtype = question->getType();
             const Name& qname = question->getName();
-            query_.process(memory_client_container_->getInstance(),
-                           qname, qtype, message, dnssec_ok);
+            query_.process(*list, qname, qtype, message, dnssec_ok);
         } else {
-            datasrc::Query query(message, cache_, dnssec_ok);
-            data_sources_.doQuery(query);
+            makeErrorMessage(renderer_, message, buffer, Rcode::REFUSED());
+            return (true);
         }
     } catch (const Exception& ex) {
         LOG_ERROR(auth_logger, AUTH_PROCESS_FAIL).arg(ex.what());
@@ -926,56 +858,6 @@ AuthSrvImpl::validateStatistics(isc::data::ConstElementPtr data) const {
             data, true));
 }
 
-ConstElementPtr
-AuthSrvImpl::setDbFile(ConstElementPtr config) {
-    ConstElementPtr answer = isc::config::createAnswer();
-
-    if (config && config->contains("database_file")) {
-        db_file_ = config->get("database_file")->stringValue();
-    } else if (config_session_ != NULL) {
-        bool is_default;
-        string item("database_file");
-        ConstElementPtr value = config_session_->getValue(is_default, item);
-        ElementPtr final = Element::createMap();
-
-        // If the value is the default, and we are running from
-        // a specific directory ('from build'), we need to use
-        // a different value than the default (which may not exist)
-        // (btw, this should not be done here in the end, i think
-        //  the from-source script should have a check for this,
-        //  but for that we need offline access to config, so for
-        //  now this is a decent solution)
-        if (is_default && getenv("B10_FROM_BUILD")) {
-            value = Element::create(string(getenv("B10_FROM_BUILD")) +
-                                    "/bind10_zones.sqlite3");
-        }
-        final->set(item, value);
-        config = final;
-
-        db_file_ = value->stringValue();
-    } else {
-        return (answer);
-    }
-    LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_DATA_SOURCE).arg(db_file_);
-
-    // create SQL data source
-    // Note: the following step is tricky to be exception-safe and to ensure
-    // exception guarantee: We first need to perform all operations that can
-    // fail, while acquiring resources in the RAII manner.  We then perform
-    // delete and swap operations which should not fail.
-    DataSrcPtr datasrc_ptr(DataSrcPtr(new Sqlite3DataSrc));
-    datasrc_ptr->init(config);
-    data_sources_.addDataSrc(datasrc_ptr);
-
-    // The following code should be exception free.
-    if (cur_datasrc_ != NULL) {
-        data_sources_.removeDataSrc(cur_datasrc_);
-    }
-    cur_datasrc_ = datasrc_ptr;
-
-    return (answer);
-}
-
 void
 AuthSrvImpl::resumeServer(DNSServer* server, Message& message, bool done) {
     if (done) {
@@ -992,7 +874,7 @@ AuthSrv::updateConfig(ConstElementPtr new_config) {
         if (new_config) {
             configureAuthServer(*this, new_config);
         }
-        return (impl_->setDbFile(new_config));
+        return (isc::config::createAnswer());
     } catch (const isc::Exception& error) {
         LOG_ERROR(auth_logger, AUTH_CONFIG_UPDATE_FAIL).arg(error.what());
         return (isc::config::createAnswer(1, error.what()));
@@ -1056,4 +938,27 @@ AuthSrv::destroyDDNSForwarder() {
     }
 }
 
+void
+AuthSrv::setClientList(const RRClass& rrclass,
+                       const boost::shared_ptr<ConfigurableClientList>& list) {
+    if (list) {
+        impl_->client_lists_[rrclass] = list;
+    } else {
+        impl_->client_lists_.erase(rrclass);
+    }
+}
+boost::shared_ptr<ConfigurableClientList>
+AuthSrv::getClientList(const RRClass& rrclass) {
+    return (impl_->getClientList(rrclass));
+}
 
+vector<RRClass>
+AuthSrv::getClientListClasses() const {
+    vector<RRClass> result;
+    for (map<RRClass, boost::shared_ptr<ConfigurableClientList> >::
+         const_iterator it(impl_->client_lists_.begin());
+         it != impl_->client_lists_.end(); ++it) {
+        result.push_back(it->first);
+    }
+    return (result);
+}
diff --git a/src/bin/auth/auth_srv.h b/src/bin/auth/auth_srv.h
index d40a490..c1835e6 100644
--- a/src/bin/auth/auth_srv.h
+++ b/src/bin/auth/auth_srv.h
@@ -43,7 +43,7 @@ class BaseSocketSessionForwarder;
 }
 }
 namespace datasrc {
-class InMemoryClient;
+class ConfigurableClientList;
 }
 namespace xfr {
 class AbstractXfroutClient;
@@ -92,13 +92,11 @@ private:
 public:
     /// The constructor.
     ///
-    /// \param use_cache Whether to enable hot spot cache for lookup results.
     /// \param xfrout_client Communication interface with a separate xfrout
     /// process.  It's normally a reference to an xfr::XfroutClient object,
     /// but can refer to a local mock object for testing (or other
     /// experimental) purposes.
-    AuthSrv(const bool use_cache,
-            isc::xfr::AbstractXfroutClient& xfrout_client,
+    AuthSrv(isc::xfr::AbstractXfroutClient& xfrout_client,
             isc::util::io::BaseSocketSessionForwarder& ddns_forwarder);
     ~AuthSrv();
     //@}
@@ -129,20 +127,7 @@ public:
                         isc::util::OutputBuffer& buffer,
                         isc::asiodns::DNSServer* server);
 
-    /// \brief Updates the data source for the \c AuthSrv object.
-    ///
-    /// This method installs or replaces the data source that the \c AuthSrv
-    /// object refers to for query processing.
-    /// Although the method name is generic, the only thing it does is to
-    /// update the data source information.
-    /// If there is a data source installed, it will be replaced with the
-    /// new one.
-    ///
-    /// In the current implementation, the SQLite data source and InMemoryClient
-    /// are assumed.
-    /// We can enable memory data source and get the path of SQLite database by
-    /// the \c config parameter.  If we disabled memory data source, the SQLite
-    /// data source will be used.
+    /// \brief Updates the configuration for the \c AuthSrv object.
     ///
     /// On success this method returns a data \c Element (in the form of a
     /// pointer like object) indicating the successful result,
@@ -200,26 +185,6 @@ public:
     /// \brief Return pointer to the Checkin callback function
     isc::asiolink::SimpleCallback* getCheckinProvider() const { return (checkin_); }
 
-    /// \brief Set or update the size (number of slots) of hot spot cache.
-    ///
-    /// If the specified size is 0, it means the size will be unlimited.
-    /// The specified size is recorded even if the cache is disabled; the
-    /// new size will be effective when the cache is enabled.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \param slots The number of cache slots.
-    void setCacheSlots(const size_t slots);
-
-    /// \brief Get the current size (number of slots) of hot spot cache.
-    ///
-    /// It always returns the recorded size regardless of the cache is enabled.
-    ///
-    /// This method never throws an exception.
-    ///
-    /// \return The current number of cache slots.
-    size_t getCacheSlots() const;
-
     /// \brief Set the communication session with a separate process for
     /// outgoing zone transfers.
     ///
@@ -238,71 +203,6 @@ public:
     ///
     void setXfrinSession(isc::cc::AbstractSession* xfrin_session);
 
-    /// Returns the in-memory data source configured for the \c AuthSrv,
-    /// if any, as a pointer.
-    ///
-    /// This is mostly a convenience function around
-    /// \c getInMemoryClientContainer, which saves the caller the step
-    /// of having to call getInstance().
-    /// The pointer is of course only valid as long as the container
-    /// exists.
-    ///
-    /// The in-memory data source is configured per RR class.  However,
-    /// the data source may not be available for all RR classes.
-    /// If it is not available for the specified RR class, an exception of
-    /// class \c InvalidParameter will be thrown.
-    /// This method never throws an exception otherwise.
-    ///
-    /// Even for supported RR classes, the in-memory data source is not
-    /// configured by default.  In that case a NULL (shared) pointer will
-    /// be returned.
-    ///
-    /// \param rrclass The RR class of the requested in-memory data source.
-    /// \return A pointer to the in-memory data source, if configured;
-    /// otherwise NULL.
-    isc::datasrc::DataSourceClient* getInMemoryClient(
-        const isc::dns::RRClass& rrclass);
-
-    /// Returns the DataSourceClientContainer of the in-memory datasource
-    ///
-    /// \exception InvalidParameter if the given class does not match
-    ///            the one in the memory data source, or if the memory
-    ///            datasource has not been set (callers can check with
-    ///            \c hasMemoryDataSource())
-    ///
-    /// \param rrclass The RR class of the requested in-memory data source.
-    /// \return A shared pointer to the in-memory data source, if configured;
-    /// otherwise an empty shared pointer.
-    isc::datasrc::DataSourceClientContainerPtr getInMemoryClientContainer(
-        const isc::dns::RRClass& rrclass);
-
-    /// Checks if the in-memory data source has been set.
-    ///
-    /// Right now, only one datasource at a time is effectively supported.
-    /// This is a helper method to check whether it is the in-memory one.
-    /// This is mostly useful for current testing, and is expected to be
-    /// removed (or changed in behaviour) soon, when the general
-    /// multi-data-source framework is completed.
-    ///
-    /// \return True if the in-memory datasource has been set.
-    bool hasInMemoryClient() const;
-
-    /// Sets or replaces the in-memory data source of the specified RR class.
-    ///
-    /// Some RR classes may not be supported, in which case an exception
-    /// of class \c InvalidParameter will be thrown.
-    /// This method never throws an exception otherwise.
-    ///
-    /// If there is already an in memory data source configured, it will be
-    /// replaced with the newly specified one.
-    /// \c memory_client can be an empty shared pointer, in which case it
-    /// will (re)disable the in-memory data source.
-    ///
-    /// \param rrclass The RR class of the in-memory data source to be set.
-    /// \param memory_client A (shared) pointer to \c InMemoryClient to be set.
-    void setInMemoryClient(const isc::dns::RRClass& rrclass,
-        isc::datasrc::DataSourceClientContainerPtr memory_client);
-
     /// \brief Set the communication session with Statistics.
     ///
     /// This function never throws an exception as far as
@@ -437,6 +337,32 @@ public:
     /// If there was no forwarder yet, this method does nothing.
     void destroyDDNSForwarder();
 
+    /// \brief Sets the currently used list for data sources of given
+    ///     class.
+    ///
+    /// Replaces the internally used client list with a new one. Other
+    /// classes are not changed.
+    ///
+    /// \param rrclass The class to modify.
+    /// \param list Shared pointer to the client list. If it is NULL,
+    ///     the list is removed instead.
+    void setClientList(const isc::dns::RRClass& rrclass, const
+                       boost::shared_ptr<isc::datasrc::ConfigurableClientList>&
+                       list);
+
+    /// \brief Returns the currently used client list for the class.
+    ///
+    /// \param rrclass The class for which to get the list.
+    /// \return The list, or NULL if no list is set for the class.
+    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        getClientList(const isc::dns::RRClass& rrclass);
+
+    /// \brief Returns a list of classes that have a client list.
+    ///
+    /// \return List of classes for which a non-NULL client list
+    ///     has been set by setClientList.
+    std::vector<isc::dns::RRClass> getClientListClasses() const;
+
 private:
     AuthSrvImpl* impl_;
     isc::asiolink::SimpleCallback* checkin_;
diff --git a/src/bin/auth/b10-auth.xml b/src/bin/auth/b10-auth.xml
index 44c036f..37843e3 100644
--- a/src/bin/auth/b10-auth.xml
+++ b/src/bin/auth/b10-auth.xml
@@ -44,7 +44,6 @@
   <refsynopsisdiv>
     <cmdsynopsis>
       <command>b10-auth</command>
-      <arg><option>-n</option></arg>
       <arg><option>-v</option></arg>
     </cmdsynopsis>
   </refsynopsisdiv>
@@ -80,18 +79,6 @@
 
     <variablelist>
       <varlistentry>
-        <term><option>-n</option></term>
-        <listitem><para>
-          Do not cache answers in memory.
-          The default is to use the cache for faster responses.
-	  The cache keeps the most recent 30,000 answers (positive
-	  and negative) in memory for 30 seconds (instead of querying
-	  the data source, such as SQLite3 database, each time).
-        </para></listitem>
-<!-- TODO: this is SQLite3 only -->
-      </varlistentry>
-
-      <varlistentry>
         <term><option>-v</option></term>
         <listitem><para>
 	  Enable verbose logging mode. This enables logging of
diff --git a/src/bin/auth/benchmarks/query_bench.cc b/src/bin/auth/benchmarks/query_bench.cc
index 2e705e4..6314ab9 100644
--- a/src/bin/auth/benchmarks/query_bench.cc
+++ b/src/bin/auth/benchmarks/query_bench.cc
@@ -77,10 +77,9 @@ protected:
 private:
     typedef boost::shared_ptr<const IOEndpoint> IOEndpointPtr;
 protected:
-    QueryBenchMark(const bool enable_cache,
-                   const BenchQueries& queries, Message& query_message,
+    QueryBenchMark(const BenchQueries& queries, Message& query_message,
                    OutputBuffer& buffer) :
-        server_(new AuthSrv(enable_cache, xfrout_client, ddns_forwarder)),
+        server_(new AuthSrv(xfrout_client, ddns_forwarder)),
         queries_(queries),
         query_message_(query_message),
         buffer_(buffer),
@@ -119,17 +118,12 @@ private:
 
 class Sqlite3QueryBenchMark  : public QueryBenchMark {
 public:
-    Sqlite3QueryBenchMark(const int cache_slots,
-                          const char* const datasrc_file,
+    Sqlite3QueryBenchMark(const char* const datasrc_file,
                           const BenchQueries& queries,
                           Message& query_message,
                           OutputBuffer& buffer) :
-        QueryBenchMark(cache_slots >= 0 ? true : false, queries,
-                       query_message, buffer)
+        QueryBenchMark(queries, query_message, buffer)
     {
-        if (cache_slots >= 0) {
-            server_->setCacheSlots(cache_slots);
-        }
         server_->updateConfig(Element::fromJSON("{\"database_file\": \"" +
                                                 string(datasrc_file) + "\"}"));
     }
@@ -142,7 +136,7 @@ public:
                           const BenchQueries& queries,
                           Message& query_message,
                           OutputBuffer& buffer) :
-        QueryBenchMark(false, queries, query_message, buffer)
+        QueryBenchMark(queries, query_message, buffer)
     {
         configureAuthServer(*server_,
                             Element::fromJSON(
@@ -274,27 +268,9 @@ main(int argc, char* argv[]) {
 
     switch (datasrc_type) {
     case SQLITE3:
-        cout << "Benchmark enabling Hot Spot Cache with unlimited slots "
-             << endl;
-        BenchMark<Sqlite3QueryBenchMark>(
-            iteration, Sqlite3QueryBenchMark(0, datasrc_file, queries,
-                                             message, buffer));
-
-        cout << "Benchmark enabling Hot Spot Cache with 10*#queries slots "
-             << endl;
-        BenchMark<Sqlite3QueryBenchMark>(
-            iteration, Sqlite3QueryBenchMark(10 * queries.size(), datasrc_file,
-                                             queries, message, buffer));
-
-        cout << "Benchmark enabling Hot Spot Cache with #queries/2 slots "
-             << endl;
-        BenchMark<Sqlite3QueryBenchMark>(
-            iteration, Sqlite3QueryBenchMark(queries.size() / 2, datasrc_file,
-                                             queries, message, buffer));
-
-        cout << "Benchmark disabling Hot Spot Cache" << endl;
+        cout << "Benchmark with SQLite3" << endl;
         BenchMark<Sqlite3QueryBenchMark>(
-            iteration, Sqlite3QueryBenchMark(-1, datasrc_file, queries,
+            iteration, Sqlite3QueryBenchMark(datasrc_file, queries,
                                              message, buffer));
         break;
     case MEMORY:
diff --git a/src/bin/auth/command.cc b/src/bin/auth/command.cc
index aaaa5b6..f3cc260 100644
--- a/src/bin/auth/command.cc
+++ b/src/bin/auth/command.cc
@@ -17,8 +17,7 @@
 #include <auth/auth_srv.h>
 
 #include <cc/data.h>
-#include <datasrc/memory_datasrc.h>
-#include <datasrc/factory.h>
+#include <datasrc/client_list.h>
 #include <config/ccsession.h>
 #include <exceptions/exceptions.h>
 #include <dns/rrclass.h>
@@ -159,156 +158,50 @@ public:
 class LoadZoneCommand : public AuthCommand {
 public:
     virtual void exec(AuthSrv& server, isc::data::ConstElementPtr args) {
-        // parse and validate the args.
-        if (!validate(server, args)) {
-            return;
-        }
-
-        const ConstElementPtr zone_config = getZoneConfig(server);
-
-        // Load a new zone and replace the current zone with the new one.
-        // TODO: eventually this should be incremental or done in some way
-        // that doesn't block other server operations.
-        // TODO: we may (should?) want to check the "last load time" and
-        // the timestamp of the file and skip loading if the file isn't newer.
-        const ConstElementPtr type(zone_config->get("filetype"));
-        boost::shared_ptr<InMemoryZoneFinder> zone_finder(
-            new InMemoryZoneFinder(old_zone_finder_->getClass(),
-                                   old_zone_finder_->getOrigin()));
-        if (type && type->stringValue() == "sqlite3") {
-            scoped_ptr<DataSourceClientContainer>
-                container(new DataSourceClientContainer("sqlite3",
-                                                        Element::fromJSON(
-                    "{\"database_file\": \"" +
-                    zone_config->get("file")->stringValue() + "\"}")));
-            zone_finder->load(*container->getInstance().getIterator(
-                old_zone_finder_->getOrigin()));
-        } else {
-            zone_finder->load(old_zone_finder_->getFileName());
-        }
-        old_zone_finder_->swap(*zone_finder);
-        LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_LOAD_ZONE)
-                  .arg(zone_finder->getOrigin()).arg(zone_finder->getClass());
-    }
-
-private:
-    // zone finder to be updated with the new file.
-    boost::shared_ptr<InMemoryZoneFinder> old_zone_finder_;
-
-    // A helper private method to parse and validate command parameters.
-    // On success, it sets 'old_zone_finder_' to the zone to be updated.
-    // It returns true if everything is okay; and false if the command is
-    // valid but there's no need for further process.
-    bool validate(AuthSrv& server, isc::data::ConstElementPtr args) {
         if (args == NULL) {
             isc_throw(AuthCommandError, "Null argument");
         }
 
-        // In this initial implementation, we assume memory data source
-        // for class IN by default.
-        ConstElementPtr datasrc_elem = args->get("datasrc");
-        if (datasrc_elem) {
-            if (datasrc_elem->stringValue() == "sqlite3") {
-                LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_SQLITE3);
-                return (false);
-            } else if (datasrc_elem->stringValue() != "memory") {
-                // (note: at this point it's guaranteed that datasrc_elem
-                // is of string type)
-                isc_throw(AuthCommandError,
-                          "Data source type " << datasrc_elem->stringValue()
-                          << " is not supported");
-            }
-        }
-
         ConstElementPtr class_elem = args->get("class");
-        const RRClass zone_class =
-            class_elem ? RRClass(class_elem->stringValue()) : RRClass::IN();
-
-        isc::datasrc::DataSourceClient* datasrc(
-            server.getInMemoryClient(zone_class));
-        if (datasrc == NULL) {
-            isc_throw(AuthCommandError, "Memory data source is disabled");
-        }
+        RRClass zone_class(class_elem ? RRClass(class_elem->stringValue()) :
+            RRClass::IN());
 
         ConstElementPtr origin_elem = args->get("origin");
         if (!origin_elem) {
             isc_throw(AuthCommandError, "Zone origin is missing");
         }
-        const Name origin = Name(origin_elem->stringValue());
+        Name origin(origin_elem->stringValue());
 
-        // Get the current zone
-        const DataSourceClient::FindResult result = datasrc->findZone(origin);
-        if (result.code != result::SUCCESS) {
-            isc_throw(AuthCommandError, "Zone " << origin <<
-                      " is not found in data source");
-        }
-
-        // It would appear that dynamic_cast does not work on all systems;
-        // it seems to confuse the RTTI system, resulting in NULL return
-        // values. So we use the more dangerous static_pointer_cast here.
-        old_zone_finder_ = boost::static_pointer_cast<InMemoryZoneFinder>(
-            result.zone_finder);
-
-        return (true);
-    }
+        const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+            list(server.getClientList(zone_class));
 
-    ConstElementPtr getZoneConfig(const AuthSrv &server) {
-        if (!server.getConfigSession()) {
-            // FIXME: This is a hack to make older tests pass. We should
-            // update these tests as well sometime and remove this hack.
-            // (note that under normal situation, the
-            // server.getConfigSession() does not return NULL)
-
-            // We provide an empty map, which means no configuration --
-            // defaults.
-            return (ConstElementPtr(new MapElement()));
+        if (!list) {
+            isc_throw(AuthCommandError, "There's no client list for "
+                      "class " << zone_class);
         }
 
-        // Find the config corresponding to the zone.
-        // We expect the configuration to be valid, as we have it and we
-        // accepted it before, therefore it must be validated.
-        const ConstElementPtr config(server.getConfigSession()->
-                                     getValue("datasources"));
-        ConstElementPtr zone_list;
-        // Unfortunately, we need to walk the list to find the correct data
-        // source.
-        // TODO: Make it named sets. These lists are uncomfortable.
-        for (size_t i(0); i < config->size(); ++i) {
-            // We use the getValue to get defaults as well
-            const ConstElementPtr dsrc_config(config->get(i));
-            const ConstElementPtr class_config(dsrc_config->get("class"));
-            const string class_type(class_config ?
-                                    class_config->stringValue() : "IN");
-            // It is in-memory and our class matches.
-            // FIXME: Is it allowed to have two datasources for the same
-            // type and class at once? It probably would not work now
-            // anyway and we may want to change the configuration of
-            // datasources somehow.
-            if (dsrc_config->get("type")->stringValue() == "memory" &&
-                RRClass(class_type) == old_zone_finder_->getClass()) {
-                zone_list = dsrc_config->get("zones");
-                break;
-            }
-        }
-
-        if (!zone_list) {
-            isc_throw(AuthCommandError,
-                      "Corresponding data source configuration was not found");
-        }
-
-        // Now we need to walk the zones and find the correct one.
-        for (size_t i(0); i < zone_list->size(); ++i) {
-            const ConstElementPtr zone_config(zone_list->get(i));
-            if (Name(zone_config->get("origin")->stringValue()) ==
-                old_zone_finder_->getOrigin()) {
-                // The origins are the same, so we consider this config to be
-                // for the zone.
-                return (zone_config);
-            }
+        switch (list->reload(origin)) {
+            case ConfigurableClientList::ZONE_RELOADED:
+                // Everything worked fine.
+                LOG_DEBUG(auth_logger, DBG_AUTH_OPS, AUTH_LOAD_ZONE)
+                    .arg(zone_class).arg(origin);
+                return;
+            case ConfigurableClientList::ZONE_NOT_FOUND:
+                isc_throw(AuthCommandError, "Zone " << origin << "/" <<
+                          zone_class << " was not found in any configured "
+                          "data source. Configure it first.");
+            case ConfigurableClientList::ZONE_NOT_CACHED:
+                isc_throw(AuthCommandError, "Zone " << origin << "/" <<
+                          zone_class << " is not served from memory, but "
+                          "direcly from the data source. It is not possible "
+                          "to reload it into memory. Configure it to be cached "
+                          "first.");
+            case ConfigurableClientList::CACHE_DISABLED:
+                // This is an internal error. Auth server must have the cache
+                // enabled.
+                isc_throw(isc::Unexpected, "Cache disabled in client list of "
+                          "class " << zone_class);
         }
-
-        isc_throw(AuthCommandError,
-                  "Corresponding zone configuration was not found");
     }
 };
 
diff --git a/src/bin/auth/datasrc_configurator.h b/src/bin/auth/datasrc_configurator.h
new file mode 100644
index 0000000..810d433
--- /dev/null
+++ b/src/bin/auth/datasrc_configurator.h
@@ -0,0 +1,223 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef DATASRC_CONFIGURATOR_H
+#define DATASRC_CONFIGURATOR_H
+
+#include "auth_srv.h"
+
+#include <datasrc/client_list.h>
+#include <config/ccsession.h>
+#include <cc/data.h>
+
+#include <set>
+
+/// \brief A class to configure the authoritative server's data source lists
+///
+/// This will hook into the data_sources module configuration and it will
+/// keep the local copy of data source clients in the list in the authoritative
+/// server.
+///
+/// The class is slightly unusual. Due to some technical limitations, the hook
+/// needs to be static method. Therefore it is not possible to create instances
+/// of the class.
+///
+/// Also, the class is a template. This is simply because of easier testing.
+/// You don't need to pay attention to it, use the DataSourceConfigurator
+/// type alias instead.
+template<class Server, class List>
+class DataSourceConfiguratorGeneric {
+private:
+    /// \brief Disallow creation of instances
+    DataSourceConfiguratorGeneric();
+    /// \brief Internal method to hook into the ModuleCCSession
+    ///
+    /// It simply calls reconfigure.
+    static void reconfigureInternal(const std::string&,
+                                    isc::data::ConstElementPtr config,
+                                    const isc::config::ConfigData&)
+    {
+        if (config->contains("classes")) {
+            reconfigure(config->get("classes"));
+        }
+    }
+    static Server* server_;
+    static isc::config::ModuleCCSession* session_;
+    typedef boost::shared_ptr<List> ListPtr;
+public:
+    /// \brief Initializes the class.
+    ///
+    /// This configures which session and server should be used.
+    /// It hooks to the session now and downloads the configuration.
+    /// It is synchronous (it may block for some time).
+    ///
+    /// Note that you need to call cleanup before the server or
+    /// session dies, otherwise it might access them after they
+    /// are destroyed.
+    ///
+    /// \param session The session to hook into and to access the configuration
+    ///     through.
+    /// \param server It is the server to configure.
+    /// \throw isc::InvalidOperation if this is called when already initialized.
+    /// \throw isc::InvalidParameter if any of the parameters is NULL
+    /// \throw isc::config::ModuleCCError if the remote configuration is not
+    ///     available for some reason.
+    static void init(isc::config::ModuleCCSession *session,
+                     Server *server)
+    {
+        if (session == NULL) {
+            isc_throw(isc::InvalidParameter, "The session must not be NULL");
+        }
+        if (server == NULL) {
+            isc_throw(isc::InvalidParameter, "The server must not be NULL");
+        }
+        if (server_ != NULL) {
+            isc_throw(isc::InvalidOperation,
+                      "The configurator is already initialized");
+        }
+        server_ = server;
+        session_ = session;
+        session->addRemoteConfig("data_sources", reconfigureInternal, false);
+    }
+    /// \brief Deinitializes the class.
+    ///
+    /// This detaches from the session and removes the server from internal
+    /// storage. The current configuration in the server is preserved.
+    ///
+    /// This can be called even if it is not initialized currently. You
+    /// can initialize it again after this.
+    static void cleanup() {
+        if (session_ != NULL) {
+            session_->removeRemoteConfig("data_sources");
+        }
+        session_ = NULL;
+        server_ = NULL;
+    }
+    /// \brief Reads new configuration and replaces the old one.
+    ///
+    /// It instructs the server to replace the lists with new ones as needed.
+    /// You don't need to call it directly (but you could, though the benefit
+    /// is unknown and it would be questionable at least). It is called
+    /// automatically on normal updates.
+    ///
+    /// \param config The configuration value to parse. It is in the form
+    ///     as an update from the config manager.
+    /// \throw InvalidOperation if it is called when not initialized.
+    static void reconfigure(const isc::data::ConstElementPtr& config) {
+        if (server_ == NULL) {
+            isc_throw(isc::InvalidOperation,
+                      "Can't reconfigure while not initialized by init()");
+        }
+        typedef std::map<std::string, isc::data::ConstElementPtr> Map;
+        typedef std::pair<isc::dns::RRClass, ListPtr> RollbackPair;
+        typedef std::pair<isc::dns::RRClass, isc::data::ConstElementPtr>
+            RollbackConfiguration;
+        // Some structures to be able to perform a rollback
+        std::vector<RollbackPair> rollback_sets;
+        std::vector<RollbackConfiguration> rollback_configurations;
+        try {
+            // Get the configuration and current state.
+            const Map& map(config->mapValue());
+            const std::vector<isc::dns::RRClass>
+                activeVector(server_->getClientListClasses());
+            std::set<isc::dns::RRClass> active(activeVector.begin(),
+                                               activeVector.end());
+            // Go through the configuration and change everything.
+            for (Map::const_iterator it(map.begin()); it != map.end(); ++it) {
+                isc::dns::RRClass rrclass(it->first);
+                active.erase(rrclass);
+                ListPtr list(server_->getClientList(rrclass));
+                bool need_set(false);
+                if (list) {
+                    rollback_configurations.
+                        push_back(RollbackConfiguration(rrclass,
+                            list->getConfiguration()));
+                } else {
+                    list.reset(new List(rrclass));
+                    need_set = true;
+                    rollback_sets.push_back(RollbackPair(rrclass, ListPtr()));
+                }
+                list->configure(it->second, true);
+                if (need_set) {
+                    server_->setClientList(rrclass, list);
+                }
+            }
+            // Remove the ones that are not in the configuration.
+            for (std::set<isc::dns::RRClass>::iterator it(active.begin());
+                 it != active.end(); ++it) {
+                // There seems to be no way the setClientList could throw.
+                // But this is just to make sure in case it did to restore
+                // the original.
+                rollback_sets.push_back(
+                    RollbackPair(*it, server_->getClientList(*it)));
+                server_->setClientList(*it, ListPtr());
+            }
+        } catch (...) {
+            // Perform a rollback of the changes. The old configuration should
+            // work.
+            for (typename std::vector<RollbackPair>::const_iterator
+                 it(rollback_sets.begin()); it != rollback_sets.end(); ++it) {
+                server_->setClientList(it->first, it->second);
+            }
+            for (typename std::vector<RollbackConfiguration>::const_iterator
+                 it(rollback_configurations.begin());
+                 it != rollback_configurations.end(); ++it) {
+                server_->getClientList(it->first)->configure(it->second, true);
+            }
+            throw;
+        }
+    }
+    /// \brief Version of reconfigure for easier testing.
+    ///
+    /// This method can be used to reconfigure a server without first
+    /// initializing the configurator. This does not need a session.
+    /// Otherwise, it acts the same as reconfigure.
+    ///
+    /// This is not meant for production code. Do not use there.
+    ///
+    /// \param server The server to configure.
+    /// \param config The config to use.
+    /// \throw isc::InvalidOperation if the configurator is initialized.
+    /// \throw anything that reconfigure does.
+    static void testReconfigure(Server* server,
+                                const isc::data::ConstElementPtr& config)
+    {
+        if (server_ != NULL) {
+            isc_throw(isc::InvalidOperation, "Currently initialized.");
+        }
+        try {
+            server_ = server;
+            reconfigure(config);
+            server_ = NULL;
+        } catch (...) {
+            server_ = NULL;
+            throw;
+        }
+    }
+};
+
+template<class Server, class List>
+isc::config::ModuleCCSession*
+DataSourceConfiguratorGeneric<Server, List>::session_(NULL);
+
+template<class Server, class List>
+Server* DataSourceConfiguratorGeneric<Server, List>::server_(NULL);
+
+/// \brief Concrete version of DataSourceConfiguratorGeneric for the
+///     use in authoritative server.
+typedef DataSourceConfiguratorGeneric<AuthSrv,
+        isc::datasrc::ConfigurableClientList>
+    DataSourceConfigurator;
+
+#endif
diff --git a/src/bin/auth/main.cc b/src/bin/auth/main.cc
index fc3b6b6..0bf24f2 100644
--- a/src/bin/auth/main.cc
+++ b/src/bin/auth/main.cc
@@ -45,6 +45,7 @@
 #include <auth/command.h>
 #include <auth/auth_srv.h>
 #include <auth/auth_log.h>
+#include <auth/datasrc_configurator.h>
 #include <asiodns/asiodns.h>
 #include <asiolink/asiolink.h>
 #include <log/logger_support.h>
@@ -84,9 +85,8 @@ my_command_handler(const string& command, ConstElementPtr args) {
 
 void
 usage() {
-    cerr << "Usage:  b10-auth [-u user] [-nv]"
+    cerr << "Usage:  b10-auth [-v]"
          << endl;
-    cerr << "\t-n: do not cache answers in memory" << endl;
     cerr << "\t-v: verbose logging (debug-level)" << endl;
     exit(1);
 }
@@ -96,14 +96,10 @@ usage() {
 int
 main(int argc, char* argv[]) {
     int ch;
-    bool cache = true;
     bool verbose = false;
 
     while ((ch = getopt(argc, argv, ":nu:v")) != -1) {
         switch (ch) {
-        case 'n':
-            cache = false;
-            break;
         case 'v':
             verbose = true;
             break;
@@ -142,7 +138,7 @@ main(int argc, char* argv[]) {
             specfile = string(AUTH_SPECFILE_LOCATION);
         }
 
-        auth_server = new AuthSrv(cache, xfrout_client, ddns_forwarder);
+        auth_server = new AuthSrv(xfrout_client, ddns_forwarder);
         LOG_INFO(auth_logger, AUTH_SERVER_CREATED);
 
         SimpleCallback* checkin = auth_server->getCheckinProvider();
@@ -204,6 +200,14 @@ main(int argc, char* argv[]) {
         isc::server_common::initKeyring(*config_session);
         auth_server->setTSIGKeyRing(&isc::server_common::keyring);
 
+        // Start the data source configuration
+        DataSourceConfigurator::init(config_session, auth_server);
+        // HACK: The default is not passed to the handler. This one will
+        // get the default (or, current value). Further updates will work
+        // the usual way.
+        DataSourceConfigurator::reconfigure(
+            config_session->getRemoteConfigValue("data_sources", "classes"));
+
         // Now start asynchronous read.
         config_session->start();
         LOG_DEBUG(auth_logger, DBG_AUTH_START, AUTH_CONFIG_CHANNEL_STARTED);
@@ -217,7 +221,6 @@ main(int argc, char* argv[]) {
         cc_session->group_sendmsg(
             isc::config::createCommand(AUTH_STARTED_NOTIFICATION), "DDNS");
         io_service.run();
-
     } catch (const std::exception& ex) {
         LOG_FATAL(auth_logger, AUTH_SERVER_FAILED).arg(ex.what());
         ret = 1;
@@ -231,6 +234,7 @@ main(int argc, char* argv[]) {
         xfrin_session->disconnect();
     }
 
+    DataSourceConfigurator::cleanup();
     delete statistics_session;
     delete xfrin_session;
     delete config_session;
diff --git a/src/bin/auth/query.cc b/src/bin/auth/query.cc
index f215c04..1eb6228 100644
--- a/src/bin/auth/query.cc
+++ b/src/bin/auth/query.cc
@@ -19,6 +19,7 @@
 #include <dns/rdataclass.h>
 
 #include <datasrc/client.h>
+#include <datasrc/client_list.h>
 
 #include <auth/query.h>
 
@@ -341,17 +342,17 @@ namespace {
 // the qname consists of a single label, which also means it's the root name),
 // we should search the deepest zone we have (which should be the root zone;
 // otherwise it's a query error).
-DataSourceClient::FindResult
-findZone(const DataSourceClient& client, const Name& qname, RRType qtype) {
+ClientList::FindResult
+findZone(const ClientList& list, const Name& qname, RRType qtype) {
     if (qtype != RRType::DS() || qname.getLabelCount() == 1) {
-        return (client.findZone(qname));
+        return (list.find(qname));
     }
-    return (client.findZone(qname.split(1)));
+    return (list.find(qname.split(1)));
 }
 }
 
 void
-Query::process(datasrc::DataSourceClient& datasrc_client,
+Query::process(datasrc::ClientList& client_list,
                const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                isc::dns::Message& response, bool dnssec)
 {
@@ -360,19 +361,18 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
     QueryCleaner cleaner(*this);
 
     // Set up query parameters for the rest of the (internal) methods
-    initialize(datasrc_client, qname, qtype, response, dnssec);
+    initialize(client_list, qname, qtype, response, dnssec);
 
     // Found a zone which is the nearest ancestor to QNAME
-    const DataSourceClient::FindResult result = findZone(*datasrc_client_,
-                                                         *qname_, *qtype_);
+    const ClientList::FindResult result = findZone(*client_list_, *qname_,
+                                                   *qtype_);
 
     // If we have no matching authoritative zone for the query name, return
     // REFUSED.  In short, this is to be compatible with BIND 9, but the
     // background discussion is not that simple.  See the relevant topic
     // at the BIND 10 developers's ML:
     // https://lists.isc.org/mailman/htdig/bind10-dev/2010-December/001633.html
-    if (result.code != result::SUCCESS &&
-        result.code != result::PARTIALMATCH) {
+    if (result.dsrc_client_ == NULL) {
         // If we tried to find a "parent zone" for a DS query and failed,
         // we may still have authority at the child side.  If we do, the query
         // has to be handled there.
@@ -384,7 +384,7 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
         response_->setRcode(Rcode::REFUSED());
         return;
     }
-    ZoneFinder& zfinder = *result.zone_finder;
+    ZoneFinder& zfinder = *result.finder_;
 
     // We have authority for a zone that contain the query name (possibly
     // indirectly via delegation).  Look into the zone.
@@ -457,7 +457,7 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
             // If the answer is a result of wildcard substitution,
             // add a proof that there's no closer name.
             if (dnssec_ && db_context->isWildcard()) {
-                addWildcardProof(*result.zone_finder, *db_context);
+                addWildcardProof(*result.finder_, *db_context);
             }
             break;
         case ZoneFinder::SUCCESS:
@@ -475,17 +475,17 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
             // section.
             // Checking the findZone() is a lightweight check to see if
             // qname is the zone origin.
-            if (result.code != result::SUCCESS ||
+            if (!result.exact_match_ ||
                 db_context->code != ZoneFinder::SUCCESS ||
                 (*qtype_ != RRType::NS() && !qtype_is_any))
             {
-                addAuthAdditional(*result.zone_finder, additionals_);
+                addAuthAdditional(*result.finder_, additionals_);
             }
 
             // If the answer is a result of wildcard substitution,
             // add a proof that there's no closer name.
             if (dnssec_ && db_context->isWildcard()) {
-                addWildcardProof(*result.zone_finder, *db_context);
+                addWildcardProof(*result.finder_, *db_context);
             }
             break;
         case ZoneFinder::DELEGATION:
@@ -505,12 +505,12 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
             // If DNSSEC is requested, see whether there is a DS
             // record for this delegation.
             if (dnssec_) {
-                addDS(*result.zone_finder, db_context->rrset->getName());
+                addDS(*result.finder_, db_context->rrset->getName());
             }
             break;
         case ZoneFinder::NXDOMAIN:
             response_->setRcode(Rcode::NXDOMAIN());
-            addSOA(*result.zone_finder);
+            addSOA(*result.finder_);
             if (dnssec_) {
                 if (db_context->isNSECSigned() && db_context->rrset) {
                     addNXDOMAINProofByNSEC(zfinder, db_context->rrset);
@@ -520,7 +520,7 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
             }
             break;
         case ZoneFinder::NXRRSET:
-            addSOA(*result.zone_finder);
+            addSOA(*result.finder_);
             if (dnssec_) {
                 addNXRRsetProof(zfinder, *db_context);
             }
@@ -538,11 +538,11 @@ Query::process(datasrc::DataSourceClient& datasrc_client,
 }
 
 void
-Query::initialize(datasrc::DataSourceClient& datasrc_client,
+Query::initialize(datasrc::ClientList& client_list,
                   const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                   isc::dns::Message& response, bool dnssec)
 {
-    datasrc_client_ = &datasrc_client;
+    client_list_ = &client_list;
     qname_ = &qname;
     qtype_ = &qtype;
     response_ = &response;
@@ -553,7 +553,7 @@ Query::initialize(datasrc::DataSourceClient& datasrc_client,
 
 void
 Query::reset() {
-    datasrc_client_ = NULL;
+    client_list_ = NULL;
     qname_ = NULL;
     qtype_ = NULL;
     response_ = NULL;
@@ -565,10 +565,10 @@ Query::reset() {
 
 bool
 Query::processDSAtChild() {
-    const DataSourceClient::FindResult zresult =
-        datasrc_client_->findZone(*qname_);
+    const ClientList::FindResult zresult =
+        client_list_->find(*qname_, true);
 
-    if (zresult.code != result::SUCCESS) {
+    if (zresult.dsrc_client_ == NULL) {
         return (false);
     }
 
@@ -583,12 +583,12 @@ Query::processDSAtChild() {
     // by seeing the SOA.
     response_->setHeaderFlag(Message::HEADERFLAG_AA);
     response_->setRcode(Rcode::NOERROR());
-    addSOA(*zresult.zone_finder);
+    addSOA(*zresult.finder_);
     ConstZoneFinderContextPtr ds_context =
-        zresult.zone_finder->find(*qname_, RRType::DS(), dnssec_opt_);
+        zresult.finder_->find(*qname_, RRType::DS(), dnssec_opt_);
     if (ds_context->code == ZoneFinder::NXRRSET) {
         if (dnssec_) {
-            addNXRRsetProof(*zresult.zone_finder, *ds_context);
+            addNXRRsetProof(*zresult.finder_, *ds_context);
         }
     }
 
diff --git a/src/bin/auth/query.h b/src/bin/auth/query.h
index dce19f7..1dc5ec0 100644
--- a/src/bin/auth/query.h
+++ b/src/bin/auth/query.h
@@ -32,7 +32,7 @@ class RRset;
 }
 
 namespace datasrc {
-class DataSourceClient;
+class ClientList;
 }
 
 namespace auth {
@@ -55,8 +55,6 @@ namespace auth {
 ///   separate attribute setter.
 /// - likewise, we'll eventually need to do per zone access control, for which
 ///   we need querier's information such as its IP address.
-/// - datasrc_client and response may better be parameters to process() instead
-///   of the constructor.
 ///
 /// <b>Note:</b> The class name is intentionally the same as the one used in
 /// the datasrc library.  This is because the plan is to eventually merge
@@ -240,14 +238,14 @@ private:
     /// This is the first step of the process() method, and initializes
     /// the member data
     ///
-    /// \param datasrc_client The datasource wherein the answer to the query is
-    /// to be found.
+    /// \param client_list The datasource list wherein the answer to the query
+    /// is to be found.
     /// \param qname The query name
     /// \param qtype The RR type of the query
     /// \param response The response message to store the answer to the query.
     /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
     ///     possible.
-    void initialize(datasrc::DataSourceClient& datasrc_client,
+    void initialize(datasrc::ClientList& client_list,
                     const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                     isc::dns::Message& response, bool dnssec = false);
 
@@ -281,7 +279,7 @@ public:
     /// Query parameters will be set by the call to process()
     ///
     Query() :
-        datasrc_client_(NULL), qname_(NULL), qtype_(NULL),
+        client_list_(NULL), qname_(NULL), qtype_(NULL),
         dnssec_(false), dnssec_opt_(isc::datasrc::ZoneFinder::FIND_DEFAULT),
         response_(NULL)
     {
@@ -318,14 +316,14 @@ public:
     /// shouldn't happen in real-life (as BadZone means wrong data, it should
     /// have been rejected upon loading).
     ///
-    /// \param datasrc_client The datasource wherein the answer to the query is
-    /// to be found.
+    /// \param client_list The datasource list wherein the answer to the query
+    /// is to be found.
     /// \param qname The query name
     /// \param qtype The RR type of the query
     /// \param response The response message to store the answer to the query.
     /// \param dnssec If the answer should include signatures and NSEC/NSEC3 if
     ///     possible.
-    void process(datasrc::DataSourceClient& datasrc_client,
+    void process(datasrc::ClientList& client_list,
                  const isc::dns::Name& qname, const isc::dns::RRType& qtype,
                  isc::dns::Message& response, bool dnssec = false);
 
@@ -483,7 +481,7 @@ public:
     };
 
 private:
-    const isc::datasrc::DataSourceClient* datasrc_client_;
+    const isc::datasrc::ClientList* client_list_;
     const isc::dns::Name* qname_;
     const isc::dns::RRType* qtype_;
     bool dnssec_;
diff --git a/src/bin/auth/tests/Makefile.am b/src/bin/auth/tests/Makefile.am
index 1a5836b..c6b199a 100644
--- a/src/bin/auth/tests/Makefile.am
+++ b/src/bin/auth/tests/Makefile.am
@@ -5,7 +5,10 @@ AM_CPPFLAGS += -I$(top_builddir)/src/lib/cc
 AM_CPPFLAGS += $(BOOST_INCLUDES)
 AM_CPPFLAGS += -DAUTH_OBJ_DIR=\"$(abs_top_builddir)/src/bin/auth\"
 AM_CPPFLAGS += -DTEST_DATA_DIR=\"$(abs_top_srcdir)/src/lib/testutils/testdata\"
+AM_CPPFLAGS += -DTEST_OWN_DATA_DIR=\"$(abs_top_srcdir)/src/bin/auth/tests/testdata\"
 AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/testutils/testdata\"
+AM_CPPFLAGS += -DDSRC_DIR=\"$(abs_top_builddir)/src/lib/datasrc\"
+AM_CPPFLAGS += -DPLUGIN_DATA_PATH=\"$(abs_top_srcdir)/src/bin/cfgmgr/plugins\"
 AM_CPPFLAGS += -DINSTALL_PROG=\"$(abs_top_srcdir)/install-sh\"
 
 AM_CXXFLAGS = $(B10_CXXFLAGS)
@@ -44,6 +47,7 @@ run_unittests_SOURCES += command_unittest.cc
 run_unittests_SOURCES += common_unittest.cc
 run_unittests_SOURCES += query_unittest.cc
 run_unittests_SOURCES += statistics_unittest.cc
+run_unittests_SOURCES += datasrc_configurator_unittest.cc
 run_unittests_SOURCES += run_unittests.cc
 # This is a temporary workaround for #1206, where the InMemoryClient has been
 # moved to an ldopened library. We could add that library to LDADD, but that
@@ -72,6 +76,7 @@ run_unittests_LDADD += $(top_builddir)/src/lib/server_common/libserver_common.la
 run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
 run_unittests_LDADD += $(top_builddir)/src/lib/util/unittests/libutil_unittests.la
 run_unittests_LDADD += $(top_builddir)/src/lib/statistics/libstatistics.la
+run_unittests_LDADD += $(top_builddir)/src/lib/config/tests/libfake_session.la
 run_unittests_LDADD += $(GTEST_LDADD)
 run_unittests_LDADD += $(SQLITE_LIBS)
 
diff --git a/src/bin/auth/tests/auth_srv_unittest.cc b/src/bin/auth/tests/auth_srv_unittest.cc
index 0a9efe1..1324a4f 100644
--- a/src/bin/auth/tests/auth_srv_unittest.cc
+++ b/src/bin/auth/tests/auth_srv_unittest.cc
@@ -30,10 +30,12 @@
 #include <server_common/keyring.h>
 
 #include <datasrc/memory_datasrc.h>
+#include <datasrc/client_list.h>
 #include <auth/auth_srv.h>
 #include <auth/command.h>
 #include <auth/common.h>
 #include <auth/statistics.h>
+#include <auth/datasrc_configurator.h>
 
 #include <util/unittests/mock_socketsession.h>
 #include <dns/tests/unittest_util.h>
@@ -48,6 +50,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/shared_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
+#include <boost/foreach.hpp>
 
 #include <vector>
 
@@ -79,19 +82,17 @@ const char* const CONFIG_TESTDB =
 const char* const BADCONFIG_TESTDB =
     "{ \"database_file\": \"" TEST_DATA_DIR "/nodir/notexist\"}";
 
+const char* const STATIC_DSRC_FILE = DSRC_DIR "/static.zone";
+
 // This is a configuration that uses the in-memory data source containing
 // a signed example zone.
-const char* const CONFIG_INMEMORY_EXAMPLE =
-    "{\"datasources\": [{\"type\": \"memory\","
-    "\"zones\": [{\"origin\": \"example\","
-    "\"file\": \"" TEST_DATA_DIR "/rfc5155-example.zone.signed\"}]}]}";
+const char* const CONFIG_INMEMORY_EXAMPLE = TEST_DATA_DIR "/rfc5155-example.zone.signed";
 
 class AuthSrvTest : public SrvTestBase {
 protected:
     AuthSrvTest() :
         dnss_(),
-        server(true, xfrout, ddns_forwarder),
-        rrclass(RRClass::IN()),
+        server(xfrout, ddns_forwarder),
         // The empty string is expected value of the parameter of
         // requestSocket, not the app_name (there's no fallback, it checks
         // the empty string is passed).
@@ -183,7 +184,6 @@ protected:
     MockXfroutClient xfrout;
     MockSocketSessionForwarder ddns_forwarder;
     AuthSrv server;
-    const RRClass rrclass;
     vector<uint8_t> response_data;
     AddressList address_store_;
     TestSocketRequestor sock_requestor_;
@@ -194,7 +194,8 @@ protected:
 // by default.  The resulting wire-format data will be stored in 'data'.
 void
 createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
-    const Name version_name("version.bind");
+    const Name version_name("VERSION.BIND.");
+    const Name apex_name("BIND.");
     Message message(Message::RENDER);
 
     UnitTestUtil::createRequestMessage(message, Opcode::QUERY(),
@@ -207,9 +208,9 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
     rrset_version->addRdata(generic::TXT(PACKAGE_STRING));
     message.addRRset(Message::SECTION_ANSWER, rrset_version);
 
-    RRsetPtr rrset_version_ns = RRsetPtr(new RRset(version_name, RRClass::CH(),
+    RRsetPtr rrset_version_ns = RRsetPtr(new RRset(apex_name, RRClass::CH(),
                                                    RRType::NS(), RRTTL(0)));
-    rrset_version_ns->addRdata(generic::NS(version_name));
+    rrset_version_ns->addRdata(generic::NS(apex_name));
     message.addRRset(Message::SECTION_AUTHORITY, rrset_version_ns);
 
     MessageRenderer renderer;
@@ -221,69 +222,18 @@ createBuiltinVersionResponse(const qid_t qid, vector<uint8_t>& data) {
                 renderer.getLength());
 }
 
-// In the following tests we confirm the response data is rendered in
-// wire format in the expected way.
-
-// The most primitive check: checking the result of the processMessage()
-// method
-TEST_F(AuthSrvTest, builtInQuery) {
+// We did not configure any client lists. Therefore it should be REFUSED
+TEST_F(AuthSrvTest, noClientList) {
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
                                        default_qid, Name("version.bind"),
                                        RRClass::CH(), RRType::TXT());
     createRequestPacket(request_message, IPPROTO_UDP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
-    createBuiltinVersionResponse(default_qid, response_data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        response_obuffer->getData(),
-                        response_obuffer->getLength(),
-                        &response_data[0], response_data.size());
-    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
-}
-
-// Same test emulating the UDPServer class behavior (defined in libasiolink).
-// This is not a good test in that it assumes internal implementation details
-// of UDPServer, but we've encountered a regression due to the introduction
-// of that class, so we add a test for that case to prevent such a regression
-// in future.
-// Besides, the generalization of UDPServer is probably too much for the
-// authoritative only server in terms of performance, and it's quite likely
-// we need to drop it for the authoritative server implementation.
-// At that point we can drop this test, too.
-TEST_F(AuthSrvTest, builtInQueryViaDNSServer) {
-    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
-                                       default_qid, Name("version.bind"),
-                                       RRClass::CH(), RRType::TXT());
-    createRequestPacket(request_message, IPPROTO_UDP);
-
-    (*server.getDNSLookupProvider())(*io_message, parse_message,
-                                     response_message,
-                                     response_obuffer, &dnsserv);
-    (*server.getDNSAnswerProvider())(*io_message, parse_message,
-                                     response_message, response_obuffer);
-
-    createBuiltinVersionResponse(default_qid, response_data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        response_obuffer->getData(),
-                        response_obuffer->getLength(),
-                        &response_data[0], response_data.size());
-}
-
-// Same type of test as builtInQueryViaDNSServer but for an error response.
-TEST_F(AuthSrvTest, iqueryViaDNSServer) {
-    createDataFromFile("iquery_fromWire.wire");
-    (*server.getDNSLookupProvider())(*io_message, parse_message,
-                                     response_message,
-                                     response_obuffer, &dnsserv);
-    (*server.getDNSAnswerProvider())(*io_message, parse_message,
-                                     response_message, response_obuffer);
 
-    UnitTestUtil::readWireData("iquery_response_fromWire.wire",
-                               response_data);
-    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
-                        response_obuffer->getData(),
-                        response_obuffer->getLength(),
-                        &response_data[0], response_data.size());
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::REFUSED(),
+                opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 
 // Unsupported requests.  Should result in NOTIMP.
@@ -350,43 +300,6 @@ TEST_F(AuthSrvTest, AXFRSuccess) {
     checkAllRcodeCountersZero();
 }
 
-// Try giving the server a TSIG signed request and see it can anwer signed as
-// well
-TEST_F(AuthSrvTest, TSIGSigned) {
-    // Prepare key, the client message, etc
-    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
-    TSIGContext context(key);
-    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
-                                       Name("version.bind"), RRClass::CH(),
-                                       RRType::TXT());
-    createRequestPacket(request_message, IPPROTO_UDP, &context);
-
-    // Run the message through the server
-    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
-    keyring->add(key);
-    server.setTSIGKeyRing(&keyring);
-    server.processMessage(*io_message, *parse_message, *response_obuffer,
-                          &dnsserv);
-
-    // What did we get?
-    EXPECT_TRUE(dnsserv.hasAnswer());
-    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
-                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
-    // We need to parse the message ourself, or getTSIGRecord won't work
-    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
-    Message m(Message::PARSE);
-    m.fromWire(ib);
-
-    const TSIGRecord* tsig = m.getTSIGRecord();
-    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
-    TSIGError error(context.verify(tsig, response_obuffer->getData(),
-                                   response_obuffer->getLength()));
-    EXPECT_EQ(TSIGError::NOERROR(), error) <<
-        "The server signed the response, but it doesn't seem to be valid";
-
-    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
-}
-
 // Give the server a signed request, but don't give it the key. It will
 // not be able to verify it, returning BADKEY
 TEST_F(AuthSrvTest, TSIGSignedBadKey) {
@@ -827,9 +740,172 @@ updateConfig(AuthSrv* server, const char* const config_data,
         "Bad result from updateConfig: " << result->str();
 }
 
+void
+updateDatabase(AuthSrv* server, const char* params) {
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "    \"type\": \"sqlite3\","
+        "    \"params\": " + string(params) +
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(server, config);
+}
+
+void
+updateInMemory(AuthSrv* server, const char* origin, const char* filename) {
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "   \"type\": \"MasterFiles\","
+        "   \"params\": {"
+        "       \"" + string(origin) + "\": \"" + string(filename) + "\""
+        "   },"
+        "   \"cache-enable\": true"
+        "}],"
+        "\"CH\": [{"
+        "   \"type\": \"static\","
+        "   \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(server, config);
+}
+
+void
+updateBuiltin(AuthSrv* server) {
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"CH\": [{"
+        "   \"type\": \"static\","
+        "   \"params\": \"" + string(STATIC_DSRC_FILE) + "\""
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(server, config);
+}
+
+// Try giving the server a TSIG signed request and see it can anwer signed as
+// well
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_TSIGSigned) { // Needs builtin
+#else
+TEST_F(AuthSrvTest, TSIGSigned) {
+#endif
+    // Prepare key, the client message, etc
+    updateBuiltin(&server);
+    const TSIGKey key("key:c2VjcmV0Cg==:hmac-sha1");
+    TSIGContext context(key);
+    UnitTestUtil::createRequestMessage(request_message, opcode, default_qid,
+                                       Name("VERSION.BIND."), RRClass::CH(),
+                                       RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP, &context);
+
+    // Run the message through the server
+    boost::shared_ptr<TSIGKeyRing> keyring(new TSIGKeyRing);
+    keyring->add(key);
+    server.setTSIGKeyRing(&keyring);
+    server.processMessage(*io_message, *parse_message, *response_obuffer,
+                          &dnsserv);
+
+    // What did we get?
+    EXPECT_TRUE(dnsserv.hasAnswer());
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
+                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
+    // We need to parse the message ourself, or getTSIGRecord won't work
+    InputBuffer ib(response_obuffer->getData(), response_obuffer->getLength());
+    Message m(Message::PARSE);
+    m.fromWire(ib);
+
+    const TSIGRecord* tsig = m.getTSIGRecord();
+    ASSERT_TRUE(tsig != NULL) << "Missing TSIG signature";
+    TSIGError error(context.verify(tsig, response_obuffer->getData(),
+                                   response_obuffer->getLength()));
+    EXPECT_EQ(TSIGError::NOERROR(), error) <<
+        "The server signed the response, but it doesn't seem to be valid";
+
+    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
+}
+
+// Same test emulating the UDPServer class behavior (defined in libasiolink).
+// This is not a good test in that it assumes internal implementation details
+// of UDPServer, but we've encountered a regression due to the introduction
+// of that class, so we add a test for that case to prevent such a regression
+// in future.
+// Besides, the generalization of UDPServer is probably too much for the
+// authoritative only server in terms of performance, and it's quite likely
+// we need to drop it for the authoritative server implementation.
+// At that point we can drop this test, too.
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_builtInQueryViaDNSServer) {
+#else
+TEST_F(AuthSrvTest, builtInQueryViaDNSServer) {
+#endif
+    updateBuiltin(&server);
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("VERSION.BIND."),
+                                       RRClass::CH(), RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP);
+
+    (*server.getDNSLookupProvider())(*io_message, parse_message,
+                                     response_message,
+                                     response_obuffer, &dnsserv);
+    (*server.getDNSAnswerProvider())(*io_message, parse_message,
+                                     response_message, response_obuffer);
+
+    createBuiltinVersionResponse(default_qid, response_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        response_obuffer->getData(),
+                        response_obuffer->getLength(),
+                        &response_data[0], response_data.size());
+}
+
+// In the following tests we confirm the response data is rendered in
+// wire format in the expected way.
+
+// The most primitive check: checking the result of the processMessage()
+// method
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_builtInQuery) {
+#else
+TEST_F(AuthSrvTest, builtInQuery) {
+#endif
+    updateBuiltin(&server);
+    UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
+                                       default_qid, Name("VERSION.BIND."),
+                                       RRClass::CH(), RRType::TXT());
+    createRequestPacket(request_message, IPPROTO_UDP);
+    server.processMessage(*io_message, *parse_message, *response_obuffer,
+                          &dnsserv);
+    createBuiltinVersionResponse(default_qid, response_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        response_obuffer->getData(),
+                        response_obuffer->getLength(),
+                        &response_data[0], response_data.size());
+    checkAllRcodeCountersZeroExcept(Rcode::NOERROR(), 1);
+}
+
+// Same type of test as builtInQueryViaDNSServer but for an error response.
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_iqueryViaDNSServer) { // Needs builtin
+#else
+TEST_F(AuthSrvTest, iqueryViaDNSServer) { // Needs builtin
+#endif
+    updateBuiltin(&server);
+    createDataFromFile("iquery_fromWire.wire");
+    (*server.getDNSLookupProvider())(*io_message, parse_message,
+                                     response_message,
+                                     response_obuffer, &dnsserv);
+    (*server.getDNSAnswerProvider())(*io_message, parse_message,
+                                     response_message, response_obuffer);
+
+    UnitTestUtil::readWireData("iquery_response_fromWire.wire",
+                               response_data);
+    EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+                        response_obuffer->getData(),
+                        response_obuffer->getLength(),
+                        &response_data[0], response_data.size());
+}
+
 // Install a Sqlite3 data source with testing data.
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_updateConfig) {
+#else
 TEST_F(AuthSrvTest, updateConfig) {
-    updateConfig(&server, CONFIG_TESTDB, true);
+#endif
+    updateDatabase(&server, CONFIG_TESTDB);
 
     // query for existent data in the installed data source.  The resulting
     // response should have the AA flag on, and have an RR in each answer
@@ -842,8 +918,12 @@ TEST_F(AuthSrvTest, updateConfig) {
                 QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_datasourceFail) {
+#else
 TEST_F(AuthSrvTest, datasourceFail) {
-    updateConfig(&server, CONFIG_TESTDB, true);
+#endif
+    updateDatabase(&server, CONFIG_TESTDB);
 
     // This query will hit a corrupted entry of the data source (the zoneload
     // tool and the data source itself naively accept it).  This will result
@@ -857,40 +937,40 @@ TEST_F(AuthSrvTest, datasourceFail) {
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 
+#ifdef USE_STATIC_LINK
+TEST_F(AuthSrvTest, DISABLED_updateConfigFail) {
+#else
 TEST_F(AuthSrvTest, updateConfigFail) {
+#endif
     // First, load a valid data source.
-    updateConfig(&server, CONFIG_TESTDB, true);
+    updateDatabase(&server, CONFIG_TESTDB);
 
     // Next, try to update it with a non-existent one.  This should fail.
-    updateConfig(&server, BADCONFIG_TESTDB, false);
+    EXPECT_THROW(updateDatabase(&server, BADCONFIG_TESTDB),
+                 isc::datasrc::DataSourceError);
 
     // The original data source should still exist.
     createDataFromFile("examplequery_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
                           &dnsserv);
     EXPECT_TRUE(dnsserv.hasAnswer());
-    headerCheck(*parse_message, default_qid, Rcode::NOERROR(), opcode.getCode(),
-                QR_FLAG | AA_FLAG, 1, 1, 1, 0);
+    headerCheck(*parse_message, default_qid, Rcode::NOERROR(),
+                opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
-TEST_F(AuthSrvTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_updateWithInMemoryClient
-#else
-       updateWithInMemoryClient
-#endif
-    )
-{
+TEST_F(AuthSrvTest, updateWithInMemoryClient) {
     // Test configuring memory data source.  Detailed test cases are covered
     // in the configuration tests.  We only check the AuthSrv interface here.
 
-    // By default memory data source isn't enabled
-    EXPECT_FALSE(server.hasInMemoryClient());
-    updateConfig(&server,
-                 "{\"datasources\": [{\"type\": \"memory\"}]}", true);
+    // Create an empty in-memory
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "   \"type\": \"MasterFiles\","
+        "   \"params\": {},"
+        "   \"cache-enable\": true"
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(&server, config);
     // after successful configuration, we should have one (with empty zoneset).
-    EXPECT_TRUE(server.hasInMemoryClient());
-    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
 
     // The memory data source is empty, should return REFUSED rcode.
     createDataFromFile("examplequery_fromWire.wire");
@@ -901,21 +981,12 @@ TEST_F(AuthSrvTest,
                 opcode.getCode(), QR_FLAG, 1, 0, 0, 0);
 }
 
-TEST_F(AuthSrvTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_queryWithInMemoryClientNoDNSSEC
-#else
-       queryWithInMemoryClientNoDNSSEC
-#endif
-    )
-{
+TEST_F(AuthSrvTest, queryWithInMemoryClientNoDNSSEC) {
     // In this example, we do simple check that query is handled from the
     // query handler class, and confirm it returns no error and a non empty
     // answer section.  Detailed examination on the response content
     // for various types of queries are tested in the query tests.
-    updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
-    EXPECT_TRUE(server.hasInMemoryClient());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
 
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -926,20 +997,11 @@ TEST_F(AuthSrvTest,
                 opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 2, 1);
 }
 
-TEST_F(AuthSrvTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_queryWithInMemoryClientDNSSEC
-#else
-       queryWithInMemoryClientDNSSEC
-#endif
-    )
-{
+TEST_F(AuthSrvTest, queryWithInMemoryClientDNSSEC) {
     // Similar to the previous test, but the query has the DO bit on.
     // The response should contain RRSIGs, and should have more RRs than
     // the previous case.
-    updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
-    EXPECT_TRUE(server.hasInMemoryClient());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
+    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
 
     createDataFromFile("nsec3query_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -958,13 +1020,12 @@ TEST_F(AuthSrvTest,
 #endif
     )
 {
-    // Configure memory data source for class IN
-    updateConfig(&server, "{\"datasources\": "
-                 "[{\"class\": \"IN\", \"type\": \"memory\"}]}", true);
+    // Set up the in-memory
+    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
 
     // This shouldn't affect the result of class CH query
     UnitTestUtil::createRequestMessage(request_message, Opcode::QUERY(),
-                                       default_qid, Name("version.bind"),
+                                       default_qid, Name("VERSION.BIND."),
                                        RRClass::CH(), RRType::TXT());
     createRequestPacket(request_message, IPPROTO_UDP);
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -974,16 +1035,6 @@ TEST_F(AuthSrvTest,
                 opcode.getCode(), QR_FLAG | AA_FLAG, 1, 1, 1, 0);
 }
 
-TEST_F(AuthSrvTest, cacheSlots) {
-    // simple check for the get/set operations
-    server.setCacheSlots(10);    // 10 = arbitrary choice
-    EXPECT_EQ(10, server.getCacheSlots());
-
-    // 0 is a valid size
-    server.setCacheSlots(0);
-    EXPECT_EQ(00, server.getCacheSlots());
-}
-
 // Submit UDP normal query and check query counter
 TEST_F(AuthSrvTest, queryCounterUDPNormal) {
     // The counter should be initialized to 0.
@@ -1290,7 +1341,7 @@ public:
     ///                      throw std::exception
     /// \param fake_rrset If non NULL, it will be used as an answer to
     /// find() for that name and type.
-    FakeClient(isc::datasrc::DataSourceClientContainerPtr real_client,
+    FakeClient(const DataSourceClient* real_client,
                ThrowWhen throw_when, bool isc_exception,
                ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
         real_client_ptr_(real_client),
@@ -1309,7 +1360,7 @@ public:
     findZone(const isc::dns::Name& name) const {
         checkThrow(THROW_AT_FIND_ZONE, throw_when_, isc_exception_);
         const FindResult result =
-            real_client_ptr_->getInstance().findZone(name);
+            real_client_ptr_->findZone(name);
         return (FindResult(result.code, isc::datasrc::ZoneFinderPtr(
                                         new FakeZoneFinder(result.zone_finder,
                                                            throw_when_,
@@ -1329,38 +1380,39 @@ public:
                   "fake data source");
     }
 private:
-    const isc::datasrc::DataSourceClientContainerPtr real_client_ptr_;
+    const DataSourceClient* real_client_ptr_;
     ThrowWhen throw_when_;
     bool isc_exception_;
     ConstRRsetPtr fake_rrset_;
 };
 
-class FakeContainer : public isc::datasrc::DataSourceClientContainer {
+class FakeList : public isc::datasrc::ConfigurableClientList {
 public:
-    /// \brief Creates a fake container for the given in-memory client
-    ///
-    /// The initializer creates a fresh instance of a memory datasource,
-    /// which is ignored for the rest (but we do not allow 'null' containers
-    /// atm, and this is only needed in these tests, this may be changed
-    /// if we generalize the container class a bit more)
+    /// \brief Creates a fake list for the given in-memory client
     ///
-    /// It will also create a FakeClient, with the given arguments, which
-    /// is actually used when the instance is requested.
-    FakeContainer(isc::datasrc::DataSourceClientContainerPtr real_client,
-                  ThrowWhen throw_when, bool isc_exception,
-                  ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
-        DataSourceClientContainer("memory",
-                                  Element::fromJSON("{\"type\": \"memory\"}")),
-        client_(new FakeClient(real_client, throw_when, isc_exception,
-                               fake_rrset))
-    {}
-
-    isc::datasrc::DataSourceClient& getInstance() {
-        return (*client_);
+    /// It will create a FakeClient for each client in the original list,
+    /// with the given arguments, which is used when searching for the
+    /// corresponding data source.
+    FakeList(const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+             real_list, ThrowWhen throw_when, bool isc_exception,
+             ConstRRsetPtr fake_rrset = ConstRRsetPtr()) :
+        ConfigurableClientList(RRClass::IN()),
+        real_(real_list)
+    {
+        BOOST_FOREACH(const DataSourceInfo& info, real_->getDataSources()) {
+             const isc::datasrc::DataSourceClientPtr
+                 client(new FakeClient(info.data_src_client_ != NULL ?
+                                       info.data_src_client_ :
+                                       info.cache_.get(),
+                                       throw_when, isc_exception, fake_rrset));
+             clients_.push_back(client);
+             data_sources_.push_back(DataSourceInfo(client.get(),
+                 isc::datasrc::DataSourceClientContainerPtr(), false));
+        }
     }
-
 private:
-    const boost::scoped_ptr<isc::datasrc::DataSourceClient> client_;
+    const boost::shared_ptr<isc::datasrc::ConfigurableClientList> real_;
+    vector<isc::datasrc::DataSourceClientPtr> clients_;
 };
 
 } // end anonymous namespace for throwing proxy classes
@@ -1378,13 +1430,11 @@ TEST_F(AuthSrvTest,
     )
 {
     // Set real inmem client to proxy
-    updateConfig(&server, CONFIG_INMEMORY_EXAMPLE, true);
-    EXPECT_TRUE(server.hasInMemoryClient());
-
-    isc::datasrc::DataSourceClientContainerPtr fake_client_container(
-        new FakeContainer(server.getInMemoryClientContainer(rrclass),
-                          THROW_NEVER, false));
-    server.setInMemoryClient(rrclass, fake_client_container);
+    updateInMemory(&server, "example.", CONFIG_INMEMORY_EXAMPLE);
+    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        list(new FakeList(server.getClientList(RRClass::IN()), THROW_NEVER,
+                          false));
+    server.setClientList(RRClass::IN(), list);
 
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -1402,21 +1452,15 @@ TEST_F(AuthSrvTest,
 // If non null rrset is given, it will be passed to the proxy so it can
 // return some faked response.
 void
-setupThrow(AuthSrv* server, const char *config, ThrowWhen throw_when,
-           bool isc_exception, ConstRRsetPtr rrset = ConstRRsetPtr())
+setupThrow(AuthSrv* server, ThrowWhen throw_when, bool isc_exception,
+           ConstRRsetPtr rrset = ConstRRsetPtr())
 {
-    // Set real inmem client to proxy
-    updateConfig(server, config, true);
-
-    // Set it to throw on findZone(), this should result in
-    // SERVFAIL on any exception
-    isc::datasrc::DataSourceClientContainerPtr fake_client_container(
-        new FakeContainer(
-            server->getInMemoryClientContainer(isc::dns::RRClass::IN()),
-            throw_when, isc_exception, rrset));
+    updateInMemory(server, "example.", CONFIG_INMEMORY_EXAMPLE);
 
-    ASSERT_TRUE(server->hasInMemoryClient());
-    server->setInMemoryClient(isc::dns::RRClass::IN(), fake_client_container);
+    boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        list(new FakeList(server->getClientList(RRClass::IN()), throw_when,
+                          isc_exception, rrset));
+    server->setClientList(RRClass::IN(), list);
 }
 
 TEST_F(AuthSrvTest,
@@ -1439,11 +1483,11 @@ TEST_F(AuthSrvTest,
                                              RRClass::IN(), RRType::TXT());
     for (ThrowWhen* when(throws); *when != THROW_NEVER; ++when) {
         createRequestPacket(request_message, IPPROTO_UDP);
-        setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, true);
+        setupThrow(&server, *when, true);
         processAndCheckSERVFAIL();
         // To be sure, check same for non-isc-exceptions
         createRequestPacket(request_message, IPPROTO_UDP);
-        setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, *when, false);
+        setupThrow(&server, *when, false);
         processAndCheckSERVFAIL();
     }
 }
@@ -1459,7 +1503,7 @@ TEST_F(AuthSrvTest,
     )
 {
     createDataFromFile("nsec3query_nodnssec_fromWire.wire");
-    setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_AT_GET_CLASS, true);
+    setupThrow(&server, THROW_AT_GET_CLASS, true);
 
     // getClass is not called so it should just answer
     server.processMessage(*io_message, *parse_message, *response_obuffer,
@@ -1483,8 +1527,7 @@ TEST_F(AuthSrvTest,
     ConstRRsetPtr empty_rrset(new RRset(Name("foo.example"),
                                         RRClass::IN(), RRType::TXT(),
                                         RRTTL(0)));
-    setupThrow(&server, CONFIG_INMEMORY_EXAMPLE, THROW_NEVER, true,
-               empty_rrset);
+    setupThrow(&server, THROW_NEVER, true, empty_rrset);
 
     // Repeat the query processing two times.  Due to the faked RRset,
     // toWire() should throw, and it should result in SERVFAIL.
@@ -1627,7 +1670,7 @@ TEST_F(AuthSrvTest, DDNSForwardPushFail) {
 }
 
 TEST_F(AuthSrvTest, DDNSForwardClose) {
-    scoped_ptr<AuthSrv> tmp_server(new AuthSrv(true, xfrout, ddns_forwarder));
+    scoped_ptr<AuthSrv> tmp_server(new AuthSrv(xfrout, ddns_forwarder));
     tmp_server->createDDNSForwarder();
     UnitTestUtil::createRequestMessage(request_message, Opcode::UPDATE(),
                                        default_qid, Name("example.com"),
@@ -1660,7 +1703,7 @@ TEST_F(AuthSrvTest, DDNSForwardCreateDestroy) {
     // that the ddns_forwarder is connected when the 'start_ddns_forwarder'
     // command has been sent, and that it is no longer connected and auth
     // returns NOTIMP after the stop_ddns_forwarding command is sent.
-    scoped_ptr<AuthSrv> tmp_server(new AuthSrv(true, xfrout, ddns_forwarder));
+    scoped_ptr<AuthSrv> tmp_server(new AuthSrv(xfrout, ddns_forwarder));
 
     // Prepare update message to send
     UnitTestUtil::createRequestMessage(request_message, Opcode::UPDATE(),
@@ -1724,4 +1767,36 @@ TEST_F(AuthSrvTest, DDNSForwardCreateDestroy) {
                 Opcode::UPDATE().getCode(), QR_FLAG, 0, 0, 0, 0);
 }
 
+// Check the client list accessors
+TEST_F(AuthSrvTest, clientList) {
+    // The lists don't exist. Therefore, the list of RRClasses is empty.
+    // We also have no IN list.
+    EXPECT_TRUE(server.getClientListClasses().empty());
+    EXPECT_EQ(boost::shared_ptr<const isc::datasrc::ClientList>(),
+              server.getClientList(RRClass::IN()));
+    // Put something in.
+    const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        list(new isc::datasrc::ConfigurableClientList(RRClass::IN()));
+    const boost::shared_ptr<isc::datasrc::ConfigurableClientList>
+        list2(new isc::datasrc::ConfigurableClientList(RRClass::CH()));
+    server.setClientList(RRClass::IN(), list);
+    server.setClientList(RRClass::CH(), list2);
+    // There are two things in the list and they are IN and CH
+    vector<RRClass> classes(server.getClientListClasses());
+    ASSERT_EQ(2, classes.size());
+    EXPECT_EQ(RRClass::IN(), classes[0]);
+    EXPECT_EQ(RRClass::CH(), classes[1]);
+    // And the lists can be retrieved.
+    EXPECT_EQ(list, server.getClientList(RRClass::IN()));
+    EXPECT_EQ(list2, server.getClientList(RRClass::CH()));
+    // Remove one of them
+    server.setClientList(RRClass::CH(),
+        boost::shared_ptr<isc::datasrc::ConfigurableClientList>());
+    // This really got deleted, including the class.
+    classes = server.getClientListClasses();
+    ASSERT_EQ(1, classes.size());
+    EXPECT_EQ(RRClass::IN(), classes[0]);
+    EXPECT_EQ(list, server.getClientList(RRClass::IN()));
+}
+
 }
diff --git a/src/bin/auth/tests/command_unittest.cc b/src/bin/auth/tests/command_unittest.cc
index ec00d11..bb2e7c3 100644
--- a/src/bin/auth/tests/command_unittest.cc
+++ b/src/bin/auth/tests/command_unittest.cc
@@ -19,6 +19,7 @@
 #include <auth/auth_srv.h>
 #include <auth/auth_config.h>
 #include <auth/command.h>
+#include <auth/datasrc_configurator.h>
 
 #include <dns/name.h>
 #include <dns/rrclass.h>
@@ -62,14 +63,16 @@ namespace {
 class AuthCommandTest : public ::testing::Test {
 protected:
     AuthCommandTest() :
-        server_(false, xfrout_, ddns_forwarder_),
+        server_(xfrout_, ddns_forwarder_),
         rcode_(-1),
         expect_rcode_(0),
         itimer_(server_.getIOService())
     {
         server_.setStatisticsSession(&statistics_session_);
     }
-    void checkAnswer(const int expected_code) {
+    void checkAnswer(const int expected_code, const char* name = "") {
+        SCOPED_TRACE(name);
+
         parseAnswer(rcode_, result_);
         EXPECT_EQ(expected_code, rcode_) << result_->str();
     }
@@ -182,18 +185,17 @@ TEST_F(AuthCommandTest, shutdownIncorrectPID) {
 // zones, and checks the zones are correctly loaded.
 void
 zoneChecks(AuthSrv& server) {
-    EXPECT_TRUE(server.getInMemoryClient(RRClass::IN()));
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test1.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test1.example")).finder_->
               find(Name("ns.test1.example"), RRType::A())->code);
-    EXPECT_EQ(ZoneFinder::NXRRSET, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test1.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXRRSET, server.getClientList(RRClass::IN())->
+              find(Name("ns.test1.example")).finder_->
               find(Name("ns.test1.example"), RRType::AAAA())->code);
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test2.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test2.example")).finder_->
               find(Name("ns.test2.example"), RRType::A())->code);
-    EXPECT_EQ(ZoneFinder::NXRRSET, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test2.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXRRSET, server.getClientList(RRClass::IN())->
+              find(Name("ns.test2.example")).finder_->
               find(Name("ns.test2.example"), RRType::AAAA())->code);
 }
 
@@ -203,48 +205,44 @@ configureZones(AuthSrv& server) {
                         TEST_DATA_BUILDDIR "/test1.zone.copied"));
     ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR "/test2.zone.in "
                         TEST_DATA_BUILDDIR "/test2.zone.copied"));
-    configureAuthServer(server, Element::fromJSON(
-                            "{\"datasources\": "
-                            " [{\"type\": \"memory\","
-                            "   \"zones\": "
-                            "[{\"origin\": \"test1.example\","
-                            "  \"file\": \""
-                               TEST_DATA_BUILDDIR "/test1.zone.copied\"},"
-                            " {\"origin\": \"test2.example\","
-                            "  \"file\": \""
-                               TEST_DATA_BUILDDIR "/test2.zone.copied\"}"
-                            "]}]}"));
+
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "   \"type\": \"MasterFiles\","
+        "   \"params\": {"
+        "       \"test1.example\": \"" +
+                string(TEST_DATA_BUILDDIR "/test1.zone.copied") + "\","
+        "       \"test2.example\": \"" +
+                string(TEST_DATA_BUILDDIR "/test2.zone.copied") + "\""
+        "   },"
+        "   \"cache-enable\": true"
+        "}]}"));
+
+    DataSourceConfigurator::testReconfigure(&server, config);
+
     zoneChecks(server);
 }
 
 void
 newZoneChecks(AuthSrv& server) {
-    EXPECT_TRUE(server.getInMemoryClient(RRClass::IN()));
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test1.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test1.example")).finder_->
               find(Name("ns.test1.example"), RRType::A())->code);
     // now test1.example should have ns/AAAA
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test1.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test1.example")).finder_->
               find(Name("ns.test1.example"), RRType::AAAA())->code);
 
     // test2.example shouldn't change
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test2.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server.getClientList(RRClass::IN())->
+              find(Name("ns.test2.example")).finder_->
               find(Name("ns.test2.example"), RRType::A())->code);
-    EXPECT_EQ(ZoneFinder::NXRRSET, server.getInMemoryClient(RRClass::IN())->
-              findZone(Name("ns.test2.example")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXRRSET, server.getClientList(RRClass::IN())->
+              find(Name("ns.test2.example")).finder_->
               find(Name("ns.test2.example"), RRType::AAAA())->code);
 }
 
-TEST_F(AuthCommandTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_loadZone
-#else
-       loadZone
-#endif
-    )
-{
+TEST_F(AuthCommandTest, loadZone) {
     configureZones(server_);
 
     ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
@@ -269,47 +267,24 @@ TEST_F(AuthCommandTest,
 #endif
     )
 {
-    const char* const SPEC_FILE = AUTH_OBJ_DIR "/auth.spec";
-
     // Prepare the database first
     const string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
     const string bad_db = TEST_DATA_BUILDDIR "/does-not-exist.sqlite3";
     stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n");
     createSQLite3DB(RRClass::IN(), Name("example.org"), test_db.c_str(), ss);
-
-    // Then store a config of the zone to the auth server
-    // This omits many config options of the auth server, but these are
-    // not read now.
-    isc::testutils::MockSession session;
-    // The session should not take care of anything or start anything, we
-    // need it only to hold the config we're going to put into it.
-    ModuleCCSession module_session(SPEC_FILE, session, NULL, NULL, false,
-                                  false);
     // This describes the data source in the configuration
-    const ElementPtr
-        map(Element::fromJSON("{\"datasources\": ["
-                              "  {"
-                              "    \"type\": \"memory\","
-                              "    \"zones\": ["
-                              "      {"
-                              "        \"origin\": \"example.org\","
-                              "        \"file\": \"" + test_db + "\","
-                              "        \"filetype\": \"sqlite3\""
-                              "      }"
-                              "    ]"
-                              "  }"
-                              "],"
-                              " \"database_file\": \"" + test_db + "\""
-                              "}"));
-    module_session.setLocalConfig(map);
-    server_.setConfigSession(&module_session);
-
-    server_.updateConfig(map);
+    const ConstElementPtr config(Element::fromJSON("{"
+        "\"IN\": [{"
+        "    \"type\": \"sqlite3\","
+        "    \"params\": {\"database_file\": \"" + test_db + "\"},"
+        "    \"cache-enable\": true,"
+        "    \"cache-zones\": [\"example.org\"]"
+        "}]}"));
+    DataSourceConfigurator::testReconfigure(&server_, config);
 
     // Check that the A record at www.example.org does not exist
-    ASSERT_TRUE(server_.hasInMemoryClient());
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("www.example.org"), RRType::A())->code);
 
     // Add the record to the underlying sqlite database, by loading
@@ -328,90 +303,52 @@ TEST_F(AuthCommandTest,
     sql_updater->addRRset(*rrset);
     sql_updater->commit();
 
-    // This new record is in the database now, but should not be in the
-    // memory-datasource yet, so check again
-    EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::NXDOMAIN, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("www.example.org"), RRType::A())->code);
 
     // Now send the command to reload it
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON(
                                         "{\"origin\": \"example.org\"}"));
-    checkAnswer(0);
+    checkAnswer(0, "Successful load");
 
     // And now it should be present too.
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("www.example.org"), RRType::A())->code);
 
     // Some error cases. First, the zone has no configuration. (note .com here)
     result_ = execAuthServerCommand(server_, "loadzone",
         Element::fromJSON("{\"origin\": \"example.com\"}"));
-    checkAnswer(1);
+    checkAnswer(1, "example.com");
+
     // The previous zone is not hurt in any way
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("example.org"), RRType::SOA())->code);
 
-    module_session.setLocalConfig(Element::fromJSON("{\"datasources\": []}"));
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"example.org\"}"));
-    checkAnswer(1);
+    const ConstElementPtr config2(Element::fromJSON("{"
+        "\"IN\": [{"
+        "    \"type\": \"sqlite3\","
+        "    \"params\": {\"database_file\": \"" + bad_db + "\"},"
+        "    \"cache-enable\": true,"
+        "    \"cache-zones\": [\"example.com\"]"
+        "}]}"));
+    EXPECT_THROW(DataSourceConfigurator::testReconfigure(&server_, config2),
+                 ConfigurableClientList::ConfigurationError);
 
-    // The previous zone is not hurt in any way
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
-              find(Name("example.org"), RRType::SOA())->code);
-    // Configure an unreadable zone. Should fail, but leave the original zone
-    // data there
-    const ElementPtr
-        mapBad(Element::fromJSON("{\"datasources\": ["
-                                 "  {"
-                                 "    \"type\": \"memory\","
-                                 "    \"zones\": ["
-                                 "      {"
-                                 "        \"origin\": \"example.org\","
-                                 "        \"file\": \"" + bad_db + "\","
-                                 "        \"filetype\": \"sqlite3\""
-                                 "      }"
-                                 "    ]"
-                                 "  }"
-                                 "]}"));
-    module_session.setLocalConfig(mapBad);
     result_ = execAuthServerCommand(server_, "loadzone",
         Element::fromJSON("{\"origin\": \"example.com\"}"));
-    checkAnswer(1);
-    // The previous zone is not hurt in any way
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
-              find(Name("example.org"), RRType::SOA())->code);
+    checkAnswer(1, "Unreadable");
 
-    // Broken configuration (not valid against the spec)
-    const ElementPtr
-        broken(Element::fromJSON("{\"datasources\": ["
-                                 "  {"
-                                 "    \"type\": \"memory\","
-                                 "    \"zones\": [[]]"
-                                 "  }"
-                                 "]}"));
-    module_session.setLocalConfig(broken);
-    checkAnswer(1);
     // The previous zone is not hurt in any way
-    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getInMemoryClient(RRClass::IN())->
-              findZone(Name("example.org")).zone_finder->
+    EXPECT_EQ(ZoneFinder::SUCCESS, server_.getClientList(RRClass::IN())->
+              find(Name("example.org")).finder_->
               find(Name("example.org"), RRType::SOA())->code);
 }
 
-TEST_F(AuthCommandTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_loadBrokenZone
-#else
-       loadBrokenZone
-#endif
-    )
-{
+TEST_F(AuthCommandTest, loadBrokenZone) {
     configureZones(server_);
 
     ASSERT_EQ(0, system(INSTALL_PROG " -c " TEST_DATA_DIR
@@ -424,14 +361,7 @@ TEST_F(AuthCommandTest,
     zoneChecks(server_);     // zone shouldn't be replaced
 }
 
-TEST_F(AuthCommandTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_loadUnreadableZone
-#else
-       loadUnreadableZone
-#endif
-    )
-{
+TEST_F(AuthCommandTest, loadUnreadableZone) {
     configureZones(server_);
 
     // install the zone file as unreadable
@@ -454,82 +384,45 @@ TEST_F(AuthCommandTest, loadZoneWithoutDataSrc) {
     checkAnswer(1);
 }
 
-TEST_F(AuthCommandTest, loadSqlite3DataSrc) {
-    // For sqlite3 data source we don't have to do anything (the data source
-    // (re)loads itself automatically)
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"datasrc\": \"sqlite3\"}"));
-    checkAnswer(0);
-}
-
-TEST_F(AuthCommandTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_loadZoneInvalidParams
-#else
-       loadZoneInvalidParams
-#endif
-    )
-{
+TEST_F(AuthCommandTest, loadZoneInvalidParams) {
     configureZones(server_);
 
     // null arg
     result_ = execAuthServerCommand(server_, "loadzone", ElementPtr());
-    checkAnswer(1);
+    checkAnswer(1, "Null arg");
 
     // zone class is bogus
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON(
                                         "{\"origin\": \"test1.example\","
                                         " \"class\": \"no_such_class\"}"));
-    checkAnswer(1);
+    checkAnswer(1, "No such class");
 
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON(
                                         "{\"origin\": \"test1.example\","
                                         " \"class\": 1}"));
-    checkAnswer(1);
+    checkAnswer(1, "Integral class");
 
-    // unsupported zone class
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"class\": \"CH\"}"));
-    checkAnswer(1);
-
-    // unsupported data source class
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"datasrc\": \"not supported\"}"));
-    checkAnswer(1);
-
-    // data source is bogus
-    result_ = execAuthServerCommand(server_, "loadzone",
-                                    Element::fromJSON(
-                                        "{\"origin\": \"test1.example\","
-                                        " \"datasrc\": 0}"));
-    checkAnswer(1);
 
     // origin is missing
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON("{}"));
-    checkAnswer(1);
+    checkAnswer(1, "Missing origin");
 
     // zone doesn't exist in the data source
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON("{\"origin\": \"xx\"}"));
-    checkAnswer(1);
+    checkAnswer(1, "No such zone");
 
     // origin is bogus
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON(
                                         "{\"origin\": \"...\"}"));
-    checkAnswer(1);
+    checkAnswer(1, "Wrong name");
 
     result_ = execAuthServerCommand(server_, "loadzone",
                                     Element::fromJSON("{\"origin\": 10}"));
-    checkAnswer(1);
+    checkAnswer(1, "Integral name");
 }
 }
diff --git a/src/bin/auth/tests/config_unittest.cc b/src/bin/auth/tests/config_unittest.cc
index e2d193a..c4d1db7 100644
--- a/src/bin/auth/tests/config_unittest.cc
+++ b/src/bin/auth/tests/config_unittest.cc
@@ -54,7 +54,7 @@ protected:
     AuthConfigTest() :
         dnss_(),
         rrclass(RRClass::IN()),
-        server(true, xfrout, ddns_forwarder),
+        server(xfrout, ddns_forwarder),
         // The empty string is expected value of the parameter of
         // requestSocket, not the app_name (there's no fallback, it checks
         // the empty string is passed).
@@ -72,32 +72,6 @@ private:
     isc::testutils::TestSocketRequestor sock_requestor_;
 };
 
-TEST_F(AuthConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_datasourceConfig
-#else
-       datasourceConfig
-#endif
-    )
-{
-    // By default, we don't have any in-memory data source.
-    EXPECT_FALSE(server.hasInMemoryClient());
-    configureAuthServer(server, Element::fromJSON(
-                            "{\"datasources\": [{\"type\": \"memory\"}]}"));
-    // after successful configuration, we should have one (with empty zoneset).
-    EXPECT_TRUE(server.hasInMemoryClient());
-    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(AuthConfigTest, databaseConfig) {
-    // right now, "database_file" is handled separately, so the parser
-    // doesn't recognize it, but it shouldn't throw an exception due to that.
-    EXPECT_NO_THROW(configureAuthServer(
-                        server,
-                        Element::fromJSON(
-                            "{\"database_file\": \"should_be_ignored\"}")));
-}
-
 TEST_F(AuthConfigTest, versionConfig) {
     // make sure it does not throw on 'version'
     EXPECT_NO_THROW(configureAuthServer(
@@ -106,32 +80,17 @@ TEST_F(AuthConfigTest, versionConfig) {
 }
 
 TEST_F(AuthConfigTest, exceptionGuarantee) {
-    EXPECT_FALSE(server.hasInMemoryClient());
+    server.setStatisticsTimerInterval(1234);
+    EXPECT_EQ(1234, server.getStatisticsTimerInterval());
     // This configuration contains an invalid item, which will trigger
     // an exception.
     EXPECT_THROW(configureAuthServer(
                      server,
                      Element::fromJSON(
-                         "{\"datasources\": [{\"type\": \"memory\"}], "
-                         " \"no_such_config_var\": 1}")),
+                         "{ \"no_such_config_var\": 1}")),
                  AuthConfigError);
     // The server state shouldn't change
-    EXPECT_FALSE(server.hasInMemoryClient());
-}
-
-TEST_F(AuthConfigTest, exceptionConversion) {
-    // This configuration contains a bogus RR class, which will trigger an
-    // exception from libdns++.  configureAuthServer() should convert this
-    // to AuthConfigError and rethrow the converted one.
-    EXPECT_THROW(configureAuthServer(
-                     server,
-                     Element::fromJSON(
-                         "{\"datasources\": "
-                         " [{\"type\": \"memory\","
-                         "   \"class\": \"BADCLASS\","
-                         "   \"zones\": [{\"origin\": \"example.com\","
-                         "                \"file\": \"example.zone\"}]}]}")),
-                 AuthConfigError);
+    EXPECT_EQ(1234, server.getStatisticsTimerInterval());
 }
 
 TEST_F(AuthConfigTest, badConfig) {
@@ -172,343 +131,6 @@ TEST_F(AuthConfigTest, listenAddressConfig) {
     EXPECT_EQ(DNSService::SERVER_SYNC_OK, dnss_.getUDPFdParams().at(1).options);
 }
 
-class MemoryDatasrcConfigTest : public AuthConfigTest {
-protected:
-    MemoryDatasrcConfigTest() :
-        parser(createAuthConfigParser(server, "datasources"))
-    {}
-    ~MemoryDatasrcConfigTest() {
-        delete parser;
-    }
-    AuthConfigParser* parser;
-};
-
-TEST_F(MemoryDatasrcConfigTest, addZeroDataSrc) {
-    parser->build(Element::fromJSON("[]"));
-    parser->commit();
-    EXPECT_FALSE(server.hasInMemoryClient());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addEmpty
-#else
-       addEmpty
-#endif
-    )
-{
-    // By default, we don't have any in-memory data source.
-    EXPECT_FALSE(server.hasInMemoryClient());
-    parser->build(Element::fromJSON("[{\"type\": \"memory\"}]"));
-    parser->commit();
-    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addZeroZone
-#else
-       addZeroZone
-#endif
-    )
-{
-    parser->build(Element::fromJSON("[{\"type\": \"memory\","
-                                    "  \"zones\": []}]"));
-    parser->commit();
-    EXPECT_EQ(0, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addOneZone
-#else
-       addOneZone
-#endif
-    )
-{
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-    // Check it actually loaded something
-    EXPECT_EQ(ZoneFinder::SUCCESS, server.getInMemoryClient(rrclass)->findZone(
-        Name("ns.example.com.")).zone_finder->find(Name("ns.example.com."),
-        RRType::A())->code);
-}
-
-// This test uses dynamic load of a data source module, and won't work when
-// statically linked.
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addOneWithFiletypeSQLite3
-#else
-       addOneWithFiletypeSQLite3
-#endif
-    )
-{
-    const string test_db = TEST_DATA_BUILDDIR "/auth_test.sqlite3.copied";
-    stringstream ss("example.org. 3600 IN SOA . . 0 0 0 0 0\n");
-    createSQLite3DB(rrclass, Name("example.org"), test_db.c_str(), ss);
-
-    // In-memory with an SQLite3 data source as the backend.
-    parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.org\","
-                      "               \"file\": \""
-                      + test_db +  "\","
-                      "               \"filetype\": \"sqlite3\"}]}]"));
-    parser->commit();
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-
-    // Failure case: the specified zone doesn't exist in the DB file.
-    delete parser;
-    parser = createAuthConfigParser(server, "datasources");
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"origin\": \"example.com\","
-                         "               \"file\": \""
-                         + test_db +  "\","
-                         "               \"filetype\": \"sqlite3\"}]}]")),
-                 DataSourceError);
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addOneWithFiletypeText
-#else
-       addOneWithFiletypeText
-#endif
-    )
-{
-    // Explicitly specifying "text" is okay.
-    parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \""
-                      TEST_DATA_DIR "/example.zone\","
-                      "               \"filetype\": \"text\"}]}]"));
-    parser->commit();
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_addMultiZones
-#else
-       addMultiZones
-#endif
-    )
-{
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"},"
-                      "              {\"origin\": \"example.org\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.org.zone\"},"
-                      "              {\"origin\": \"example.net\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.net.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(3, server.getInMemoryClient(rrclass)->getZoneCount());
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_replace
-#else
-       replace
-#endif
-    )
-{
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-    EXPECT_EQ(isc::datasrc::result::SUCCESS,
-              server.getInMemoryClient(rrclass)->findZone(
-                  Name("example.com")).code);
-
-    // create a new parser, and install a new set of configuration.  It
-    // should replace the old one.
-    delete parser;
-    parser = createAuthConfigParser(server, "datasources"); 
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.org\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.org.zone\"},"
-                      "              {\"origin\": \"example.net\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.net.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(2, server.getInMemoryClient(rrclass)->getZoneCount());
-    EXPECT_EQ(isc::datasrc::result::NOTFOUND,
-              server.getInMemoryClient(rrclass)->findZone(
-                  Name("example.com")).code);
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_exception
-#else
-       exception
-#endif
-    )
-{
-    // Load a zone
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-    EXPECT_EQ(isc::datasrc::result::SUCCESS,
-              server.getInMemoryClient(rrclass)->findZone(
-                  Name("example.com")).code);
-
-    // create a new parser, and try to load something. It will throw,
-    // the given master file should not exist
-    delete parser;
-    parser = createAuthConfigParser(server, "datasources");
-    EXPECT_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.org\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.org.zone\"},"
-                      "              {\"origin\": \"example.net\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/nonexistent.zone\"}]}]")),
-                 isc::datasrc::DataSourceError);
-    // As that one throwed exception, it is not expected from us to
-    // commit it
-
-    // The original should be untouched
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-    EXPECT_EQ(isc::datasrc::result::SUCCESS,
-              server.getInMemoryClient(rrclass)->findZone(
-                  Name("example.com")).code);
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_remove
-#else
-       remove
-#endif
-    )
-{
-    EXPECT_NO_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example.com\","
-                      "               \"file\": \"" TEST_DATA_DIR
-                      "/example.zone\"}]}]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_EQ(1, server.getInMemoryClient(rrclass)->getZoneCount());
-
-    delete parser;
-    parser = createAuthConfigParser(server, "datasources"); 
-    EXPECT_NO_THROW(parser->build(Element::fromJSON("[]")));
-    EXPECT_NO_THROW(parser->commit());
-    EXPECT_FALSE(server.hasInMemoryClient());
-}
-
-TEST_F(MemoryDatasrcConfigTest, addDuplicateZones) {
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"origin\": \"example.com\","
-                         "               \"file\": \"" TEST_DATA_DIR
-                         "/example.zone\"},"
-                         "              {\"origin\": \"example.com\","
-                         "               \"file\": \"" TEST_DATA_DIR
-                         "/example.com.zone\"}]}]")),
-                 DataSourceError);
-}
-
-TEST_F(MemoryDatasrcConfigTest, addBadZone) {
-    // origin and file are missing
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{}]}]")),
-                 DataSourceError);
-
-    // origin is missing
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"file\": \"example.zone\"}]}]")),
-                 DataSourceError);
-
-    // file is missing
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"origin\": \"example.com\"}]}]")),
-                 DataSourceError);
-
-    // missing zone file
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"zones\": [{\"origin\": \"example.com\"}]}]")),
-                 DataSourceError);
-
-    // bogus origin name
-    EXPECT_THROW(parser->build(Element::fromJSON(
-                      "[{\"type\": \"memory\","
-                      "  \"zones\": [{\"origin\": \"example..com\","
-                      "               \"file\": \"example.zone\"}]}]")),
-                 DataSourceError);
-
-    // bogus RR class name
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"class\": \"BADCLASS\","
-                         "  \"zones\": [{\"origin\": \"example.com\","
-                         "               \"file\": \"example.zone\"}]}]")),
-                 InvalidRRClass);
-
-    // valid RR class, but not currently supported
-    EXPECT_THROW(parser->build(
-                     Element::fromJSON(
-                         "[{\"type\": \"memory\","
-                         "  \"class\": \"CH\","
-                         "  \"zones\": [{\"origin\": \"example.com\","
-                         "               \"file\": \"example.zone\"}]}]")),
-                 isc::InvalidParameter);
-}
-
-TEST_F(MemoryDatasrcConfigTest,
-#ifdef USE_STATIC_LINK
-       DISABLED_badDatasrcType
-#else
-       badDatasrcType
-#endif
-    )
-{
-    EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": \"badsrc\"}]")),
-                 AuthConfigError);
-    EXPECT_THROW(parser->build(Element::fromJSON("[{\"notype\": \"memory\"}]")),
-                 AuthConfigError);
-    EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": 1}]")),
-                                      isc::data::TypeError);
-    EXPECT_THROW(parser->build(Element::fromJSON("[{\"type\": \"memory\"},"
-                                                 " {\"type\": \"memory\"}]")),
-                 AuthConfigError);
-}
-
 class StatisticsIntervalConfigTest : public AuthConfigTest {
 protected:
     StatisticsIntervalConfigTest() :
diff --git a/src/bin/auth/tests/datasrc_configurator_unittest.cc b/src/bin/auth/tests/datasrc_configurator_unittest.cc
new file mode 100644
index 0000000..12454f0
--- /dev/null
+++ b/src/bin/auth/tests/datasrc_configurator_unittest.cc
@@ -0,0 +1,298 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <auth/datasrc_configurator.h>
+
+#include <config/tests/fake_session.h>
+#include <config/ccsession.h>
+
+#include <gtest/gtest.h>
+#include <memory>
+#include <boost/shared_ptr.hpp>
+
+using namespace isc;
+using namespace isc::cc;
+using namespace isc::config;
+using namespace isc::data;
+using namespace isc::dns;
+using namespace std;
+using namespace boost;
+
+namespace {
+
+class DatasrcConfiguratorTest;
+
+class FakeList {
+public:
+    FakeList(const RRClass&) :
+        configuration_(new ListElement)
+    {}
+    void configure(const ConstElementPtr& configuration, bool allow_cache) {
+        EXPECT_TRUE(allow_cache);
+        conf_ = configuration->get(0)->get("type")->stringValue();
+        configuration_ = configuration;
+    }
+    const string& getConf() const {
+        return (conf_);
+    }
+    ConstElementPtr getConfiguration() const {
+        return (configuration_);
+    }
+private:
+    string conf_;
+    ConstElementPtr configuration_;
+};
+
+typedef shared_ptr<FakeList> ListPtr;
+
+// We use the test fixture as both parameters, this makes it possible
+// to easily fake all needed methods and look that they were called.
+typedef DataSourceConfiguratorGeneric<DatasrcConfiguratorTest,
+        FakeList> Configurator;
+
+class DatasrcConfiguratorTest : public ::testing::Test {
+public:
+    // These pretend to be the server
+    ListPtr getClientList(const RRClass& rrclass) {
+        log_ += "get " + rrclass.toText() + "\n";
+        return (lists_[rrclass]);
+    }
+    void setClientList(const RRClass& rrclass, const ListPtr& list) {
+        log_ += "set " + rrclass.toText() + " " +
+            (list ? list->getConf() : "") + "\n";
+        lists_[rrclass] = list;
+    }
+    vector<RRClass> getClientListClasses() const {
+        vector<RRClass> result;
+        for (map<RRClass, ListPtr>::const_iterator it(lists_.begin());
+             it != lists_.end(); ++it) {
+            result.push_back(it->first);
+        }
+        return (result);
+    }
+protected:
+    DatasrcConfiguratorTest() :
+        session(ElementPtr(new ListElement), ElementPtr(new ListElement),
+                ElementPtr(new ListElement)),
+        specfile(string(TEST_OWN_DATA_DIR) + "/spec.spec")
+    {
+        initSession();
+    }
+    void initSession() {
+        session.getMessages()->add(createAnswer());
+        mccs.reset(new ModuleCCSession(specfile, session, NULL, NULL, false,
+                                       false));
+    }
+    void TearDown() {
+        // Make sure no matter what we did, it is cleaned up.
+        Configurator::cleanup();
+    }
+    void init(const ElementPtr& config = ElementPtr()) {
+        session.getMessages()->
+            add(createAnswer(0,
+                             moduleSpecFromFile(string(PLUGIN_DATA_PATH) +
+                                                "/datasrc.spec").
+                             getFullSpec()));
+        if (config) {
+            session.getMessages()->add(createAnswer(0, config));
+        } else {
+            session.getMessages()->
+                add(createAnswer(0, ElementPtr(new MapElement)));
+        }
+        Configurator::init(mccs.get(), this);
+    }
+    void SetUp() {
+        init();
+    }
+    ElementPtr buildConfig(const string& config) const {
+        const ElementPtr internal(Element::fromJSON(config));
+        const ElementPtr external(Element::fromJSON("{\"version\": 1}"));
+        external->set("classes", internal);
+        return (external);
+    }
+    void initializeINList() {
+        const ElementPtr
+            config(buildConfig("{\"IN\": [{\"type\": \"xxx\"}]}"));
+        session.addMessage(createCommand("config_update", config), "data_sources",
+                           "*");
+        mccs->checkCommand();
+        // Check it called the correct things (check that there's no IN yet and
+        // set a new one.
+        EXPECT_EQ("get IN\nset IN xxx\n", log_);
+        EXPECT_EQ(1, lists_.size());
+    }
+    FakeSession session;
+    auto_ptr<ModuleCCSession> mccs;
+    const string specfile;
+    map<RRClass, ListPtr> lists_;
+    string log_;
+};
+
+// Check the initialization (and cleanup)
+TEST_F(DatasrcConfiguratorTest, initialization) {
+    // It can't be initialized again
+    EXPECT_THROW(init(), InvalidOperation);
+    EXPECT_TRUE(session.haveSubscription("data_sources", "*"));
+    // Deinitialize to make the tests reasonable
+    Configurator::cleanup();
+    EXPECT_FALSE(session.haveSubscription("data_sources", "*"));
+    // We can't reconfigure now (not even manually)
+    EXPECT_THROW(Configurator::reconfigure(ElementPtr(new MapElement())),
+                 InvalidOperation);
+    // If one of them is NULL, it does not work
+    EXPECT_THROW(Configurator::init(NULL, this), InvalidParameter);
+    EXPECT_FALSE(session.haveSubscription("data_sources", "*"));
+    EXPECT_THROW(Configurator::init(mccs.get(), NULL), InvalidParameter);
+    EXPECT_FALSE(session.haveSubscription("data_sources", "*"));
+    // But we can initialize it again now
+    EXPECT_NO_THROW(init());
+    EXPECT_TRUE(session.haveSubscription("data_sources", "*"));
+}
+
+// Push there a configuration with a single list.
+TEST_F(DatasrcConfiguratorTest, createList) {
+    initializeINList();
+}
+
+TEST_F(DatasrcConfiguratorTest, modifyList) {
+    // First, initialize the list
+    initializeINList();
+    // And now change the configuration of the list
+    const ElementPtr
+        config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}]}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    log_ = "";
+    mccs->checkCommand();
+    // This one does not set
+    EXPECT_EQ("get IN\n", log_);
+    // But this should contain the yyy configuration
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ(1, lists_.size());
+}
+
+// Check we can have multiple lists at once
+TEST_F(DatasrcConfiguratorTest, multiple) {
+    const ElementPtr
+        config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}], "
+                                 "\"CH\": [{\"type\": \"xxx\"}]}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    mccs->checkCommand();
+    // We have set commands for both classes.
+    EXPECT_EQ("get CH\nset CH xxx\nget IN\nset IN yyy\n", log_);
+    // We should have both there
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
+    EXPECT_EQ(2, lists_.size());
+}
+
+// Check we can add another one later and the old one does not get
+// overwritten.
+//
+// It's almost like above, but we initialize first with single-list
+// config.
+TEST_F(DatasrcConfiguratorTest, updateAdd) {
+    initializeINList();
+    const ElementPtr
+        config(buildConfig("{\"IN\": [{\"type\": \"yyy\"}], "
+                           "\"CH\": [{\"type\": \"xxx\"}]}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    log_ = "";
+    mccs->checkCommand();
+    // The CH is set, IN not
+    EXPECT_EQ("get CH\nset CH xxx\nget IN\n", log_);
+    // But this should contain the yyy configuration
+    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ(2, lists_.size());
+}
+
+// We delete a class list in this test.
+TEST_F(DatasrcConfiguratorTest, updateDelete) {
+    initializeINList();
+    const ElementPtr
+        config(buildConfig("{}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    log_ = "";
+    mccs->checkCommand();
+    EXPECT_EQ("get IN\nset IN \n", log_);
+    EXPECT_FALSE(lists_[RRClass::IN()]);
+    // In real auth server, the NULL one would be removed. However, we just
+    // store it, so the IN bucket is still in there. This checks there's nothing
+    // else.
+    EXPECT_EQ(1, lists_.size());
+}
+
+// Check that we can rollback an addition if something else fails
+TEST_F(DatasrcConfiguratorTest, rollbackAddition) {
+    initializeINList();
+    // The configuration is wrong. However, the CH one will get done first.
+    const ElementPtr
+        config(buildConfig("{\"IN\": [{\"type\": 13}], "
+                           "\"CH\": [{\"type\": \"xxx\"}]}"));
+    session.addMessage(createCommand("config_update", config), "data_sources",
+                       "*");
+    log_ = "";
+    // It does not throw, as it is handled in the ModuleCCSession.
+    // Throwing from the reconfigure is checked in other tests.
+    EXPECT_NO_THROW(mccs->checkCommand());
+    // Anyway, the result should not contain CH now and the original IN should
+    // be there.
+    EXPECT_EQ("xxx", lists_[RRClass::IN()]->getConf());
+    EXPECT_FALSE(lists_[RRClass::CH()]);
+}
+
+// Check that we can rollback a deletion if something else fails
+TEST_F(DatasrcConfiguratorTest, rollbackDeletion) {
+    initializeINList();
+    // Put the CH there
+    const ElementPtr
+        config1(Element::fromJSON("{\"IN\": [{\"type\": \"yyy\"}], "
+                                  "\"CH\": [{\"type\": \"xxx\"}]}"));
+    Configurator::reconfigure(config1);
+    const ElementPtr
+        config2(Element::fromJSON("{\"IN\": [{\"type\": 13}]}"));
+    // This would delete CH. However, the IN one fails.
+    // As the deletions happen after the additions/settings
+    // and there's no known way to cause an exception during the
+    // deletions, it is not a true rollback, but the result should
+    // be the same.
+    EXPECT_THROW(Configurator::reconfigure(config2), TypeError);
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
+}
+
+// Check that we can roll back configuration change if something
+// fails later on.
+TEST_F(DatasrcConfiguratorTest, rollbackConfiguration) {
+    initializeINList();
+    // Put the CH there
+    const ElementPtr
+        config1(Element::fromJSON("{\"IN\": [{\"type\": \"yyy\"}], "
+                                  "\"CH\": [{\"type\": \"xxx\"}]}"));
+    Configurator::reconfigure(config1);
+    // Now, the CH happens first. But nevertheless, it should be
+    // restored to the previoeus version.
+    const ElementPtr
+        config2(Element::fromJSON("{\"IN\": [{\"type\": 13}], "
+                                  "\"CH\": [{\"type\": \"yyy\"}]}"));
+    EXPECT_THROW(Configurator::reconfigure(config2), TypeError);
+    EXPECT_EQ("yyy", lists_[RRClass::IN()]->getConf());
+    EXPECT_EQ("xxx", lists_[RRClass::CH()]->getConf());
+}
+
+}
diff --git a/src/bin/auth/tests/query_unittest.cc b/src/bin/auth/tests/query_unittest.cc
index 4c404e6..69d6608 100644
--- a/src/bin/auth/tests/query_unittest.cc
+++ b/src/bin/auth/tests/query_unittest.cc
@@ -32,6 +32,7 @@
 #include <dns/rdataclass.h>
 
 #include <datasrc/memory_datasrc.h>
+#include <datasrc/client_list.h>
 
 #include <auth/query.h>
 
@@ -48,6 +49,37 @@ using namespace isc::testutils;
 
 namespace {
 
+// Simple wrapper for a sincle data source client.
+// The list simply delegates all the answers to the single
+// client.
+class SingletonList : public ClientList {
+public:
+    SingletonList(DataSourceClient& client) :
+        client_(client)
+    {}
+    virtual FindResult find(const Name& zone, bool exact, bool) const {
+        DataSourceClient::FindResult result(client_.findZone(zone));
+        // We don't complicate the tests with real life keepers, but we
+        // need to put something to the parameter anyway.
+        const boost::shared_ptr<ClientList::FindResult::LifeKeeper> keeper;
+        switch (result.code) {
+            case result::SUCCESS:
+                return (FindResult(&client_, result.zone_finder, true,
+                                   keeper));
+            case result::PARTIALMATCH:
+                if (!exact) {
+                    return (FindResult(&client_, result.zone_finder, false,
+                                       keeper));
+                }
+            default:
+                return (FindResult());
+        }
+    }
+private:
+    DataSourceClient& client_;
+};
+
+
 // This is the content of the mock zone (see below).
 // It's a sequence of textual RRs that is supposed to be parsed by
 // dns::masterLoad().  Some of the RRs are also used as the expected
@@ -875,6 +907,7 @@ MockZoneFinder::find(const Name& name, const RRType& type,
 class QueryTest : public ::testing::Test {
 protected:
     QueryTest() :
+        list(memory_client),
         qname(Name("www.example.com")), qclass(RRClass::IN()),
         qtype(RRType::A()), response(Message::RENDER),
         qid(response.getQid()), query_code(Opcode::QUERY().getCode()),
@@ -898,6 +931,8 @@ protected:
     // (originally named MemoryDataSrc) and was tested with it, so we keep
     // it like this for now.
     InMemoryClient memory_client;
+    // A wrapper client list to wrap the single data source.
+    SingletonList list;
     const Name qname;
     const RRClass qclass;
     const RRType qtype;
@@ -949,20 +984,21 @@ TEST_F(QueryTest, noZone) {
     // There's no zone in the memory datasource.  So the response should have
     // REFUSED.
     InMemoryClient empty_memory_client;
-    EXPECT_NO_THROW(query.process(empty_memory_client, qname, qtype,
+    SingletonList empty_list(empty_memory_client);
+    EXPECT_NO_THROW(query.process(empty_list, qname, qtype,
                                   response));
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 
 TEST_F(QueryTest, exactMatch) {
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
 }
 
 TEST_F(QueryTest, exactMatchMultipleQueries) {
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
@@ -971,7 +1007,7 @@ TEST_F(QueryTest, exactMatchMultipleQueries) {
     response.clear(isc::dns::Message::RENDER);
     response.setRcode(Rcode::NOERROR());
     response.setOpcode(Opcode::QUERY());
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
     // find match rrset
     SCOPED_TRACE("Second query");
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -982,7 +1018,7 @@ TEST_F(QueryTest, exactMatchIgnoreSIG) {
     // Check that we do not include the RRSIG when not requested even when
     // we receive it from the data source.
     mock_finder->setIncludeRRSIGAnyway(true);
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response));
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response));
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
                   www_a_txt, zone_ns_txt, ns_addrs_txt);
@@ -990,7 +1026,7 @@ TEST_F(QueryTest, exactMatchIgnoreSIG) {
 
 TEST_F(QueryTest, dnssecPositive) {
     // Just like exactMatch, but the signatures should be included as well
-    EXPECT_NO_THROW(query.process(memory_client, qname, qtype, response,
+    EXPECT_NO_THROW(query.process(list, qname, qtype, response,
                                   true));
     // find match rrset
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 4, 6,
@@ -1009,7 +1045,7 @@ TEST_F(QueryTest, dnssecPositive) {
 TEST_F(QueryTest, exactAddrMatch) {
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("noglue.example.com"),
                                   qtype, response));
 
@@ -1022,7 +1058,7 @@ TEST_F(QueryTest, exactAddrMatch) {
 TEST_F(QueryTest, apexNSMatch) {
     // find match rrset, omit authority data which has already been provided
     // in the answer section from the authority section.
-    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("example.com"),
                                   RRType::NS(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 0, 3,
@@ -1033,7 +1069,7 @@ TEST_F(QueryTest, apexNSMatch) {
 TEST_F(QueryTest, exactAnyMatch) {
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
-    EXPECT_NO_THROW(query.process(memory_client, Name("noglue.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("noglue.example.com"),
                                   RRType::ANY(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 3, 2,
@@ -1047,7 +1083,7 @@ TEST_F(QueryTest, exactAnyMatch) {
 TEST_F(QueryTest, apexAnyMatch) {
     // find match rrset, omit additional data which has already been provided
     // in the answer section from the additional.
-    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("example.com"),
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 5, 0, 3,
                   (string(soa_txt) + string(zone_ns_txt) +
@@ -1056,7 +1092,7 @@ TEST_F(QueryTest, apexAnyMatch) {
 }
 
 TEST_F(QueryTest, mxANYMatch) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("mx.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("mx.example.com"),
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 4, 3, 4,
                   (string(mx_txt) + string(nsec_mx_txt)).c_str(), zone_ns_txt,
@@ -1064,14 +1100,14 @@ TEST_F(QueryTest, mxANYMatch) {
 }
 
 TEST_F(QueryTest, glueANYMatch) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("delegation.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("delegation.example.com"),
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NOERROR(), 0, 0, 4, 3,
                   NULL, delegation_txt, ns_addrs_txt);
 }
 
 TEST_F(QueryTest, nodomainANY) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("nxdomain.example.com"),
                                   RRType::ANY(), response));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
                   NULL, soa_txt, NULL, mock_finder->getOrigin());
@@ -1084,13 +1120,13 @@ TEST_F(QueryTest, noApexNS) {
     // Disable apex NS record
     mock_finder->setApexNSFlag(false);
 
-    EXPECT_THROW(query.process(memory_client, Name("noglue.example.com"), qtype,
+    EXPECT_THROW(query.process(list, Name("noglue.example.com"), qtype,
                                response), Query::NoApexNS);
     // We don't look into the response, as it threw
 }
 
 TEST_F(QueryTest, delegation) {
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("delegation.example.com"),
                                   qtype, response));
 
@@ -1102,7 +1138,7 @@ TEST_F(QueryTest, delegationWithDNSSEC) {
     // Similar to the previous one, but with requesting DNSSEC.
     // In this case the parent zone would behave as unsigned, so the result
     // should be just like non DNSSEC delegation.
-    query.process(memory_client, Name("www.nosec-delegation.example.com"),
+    query.process(list, Name("www.nosec-delegation.example.com"),
                   qtype, response, true);
 
     responseCheck(response, Rcode::NOERROR(), 0, 0, 1, 0,
@@ -1110,7 +1146,7 @@ TEST_F(QueryTest, delegationWithDNSSEC) {
 }
 
 TEST_F(QueryTest, secureDelegation) {
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("foo.signed-delegation.example.com"),
                                   qtype, response, true));
 
@@ -1125,7 +1161,7 @@ TEST_F(QueryTest, secureDelegation) {
 }
 
 TEST_F(QueryTest, secureUnsignedDelegation) {
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("foo.unsigned-delegation.example.com"),
                                   qtype, response, true));
 
@@ -1146,7 +1182,7 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3) {
     mock_finder->setNSEC3Flag(true);
     mock_finder->addRecord(unsigned_delegation_nsec3_txt);
 
-    query.process(memory_client,
+    query.process(list,
                   Name("foo.unsigned-delegation.example.com"),
                   qtype, response, true);
 
@@ -1165,7 +1201,7 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3OptOut) {
     // Similar to the previous case, but the delegation is an optout.
     mock_finder->setNSEC3Flag(true);
 
-    query.process(memory_client,
+    query.process(list,
                   Name("foo.unsigned-delegation.example.com"),
                   qtype, response, true);
 
@@ -1190,20 +1226,20 @@ TEST_F(QueryTest, secureUnsignedDelegationWithNSEC3OptOut) {
 TEST_F(QueryTest, badSecureDelegation) {
     // Test whether exception is raised if DS query at delegation results in
     // something different than SUCCESS or NXRRSET
-    EXPECT_THROW(query.process(memory_client,
+    EXPECT_THROW(query.process(list,
                                Name("bad-delegation.example.com"),
                                qtype, response, true), Query::BadDS);
 
     // But only if DNSSEC is requested (it shouldn't even try to look for
     // the DS otherwise)
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("bad-delegation.example.com"),
                                   qtype, response));
 }
 
 
 TEST_F(QueryTest, nxdomain) {
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("nxdomain.example.com"), qtype,
                                   response));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
@@ -1214,7 +1250,7 @@ TEST_F(QueryTest, nxdomainWithNSEC) {
     // NXDOMAIN with DNSSEC proof.  We should have SOA, NSEC that proves
     // NXDOMAIN and NSEC that proves nonexistence of matching wildcard,
     // as well as their RRSIGs.
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("nxdomain.example.com"), qtype,
                                   response, true));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
@@ -1235,7 +1271,7 @@ TEST_F(QueryTest, nxdomainWithNSEC2) {
     // is derived from the next domain of the NSEC that proves NXDOMAIN, and
     // the NSEC to provide the non existence of wildcard is different from
     // the first NSEC.
-    query.process(memory_client, Name("(.no.example.com"), qtype, response,
+    query.process(list, Name("(.no.example.com"), qtype, response,
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
                   NULL, (string(soa_txt) +
@@ -1253,7 +1289,7 @@ TEST_F(QueryTest, nxdomainWithNSEC2) {
 TEST_F(QueryTest, nxdomainWithNSECDuplicate) {
     // See comments about nz_txt.  In this case we only need one NSEC,
     // which proves both NXDOMAIN and the non existence of wildcard.
-    query.process(memory_client, Name("nx.no.example.com"), qtype, response,
+    query.process(list, Name("nx.no.example.com"), qtype, response,
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 4, 0,
                   NULL, (string(soa_txt) +
@@ -1270,7 +1306,7 @@ TEST_F(QueryTest, nxdomainBadNSEC1) {
     mock_finder->setNSECResult(Name("badnsec.example.com"),
                                ZoneFinder::NXDOMAIN,
                                mock_finder->dname_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("badnsec.example.com"),
+    EXPECT_THROW(query.process(list, Name("badnsec.example.com"),
                                qtype, response, true),
                  std::bad_cast);
 }
@@ -1280,7 +1316,7 @@ TEST_F(QueryTest, nxdomainBadNSEC2) {
     mock_finder->setNSECResult(Name("emptynsec.example.com"),
                                ZoneFinder::NXDOMAIN,
                                mock_finder->empty_nsec_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("emptynsec.example.com"),
+    EXPECT_THROW(query.process(list, Name("emptynsec.example.com"),
                                qtype, response, true),
                  Query::BadNSEC);
 }
@@ -1290,7 +1326,7 @@ TEST_F(QueryTest, nxdomainBadNSEC3) {
     mock_finder->setNSECResult(Name("*.example.com"),
                                ZoneFinder::SUCCESS,
                                mock_finder->dname_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                qtype, response, true),
                  Query::BadNSEC);
 }
@@ -1299,7 +1335,7 @@ TEST_F(QueryTest, nxdomainBadNSEC4) {
     // "no-wildcard proof" doesn't return RRset.
     mock_finder->setNSECResult(Name("*.example.com"),
                                ZoneFinder::NXDOMAIN, ConstRRsetPtr());
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                qtype, response, true),
                  Query::BadNSEC);
 }
@@ -1310,7 +1346,7 @@ TEST_F(QueryTest, nxdomainBadNSEC5) {
                                ZoneFinder::NXDOMAIN,
                                mock_finder->dname_rrset_);
     // This is a bit odd, but we'll simply include the returned RRset.
-    query.process(memory_client, Name("nxdomain.example.com"), qtype,
+    query.process(list, Name("nxdomain.example.com"), qtype,
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
                   NULL, (string(soa_txt) +
@@ -1330,13 +1366,13 @@ TEST_F(QueryTest, nxdomainBadNSEC6) {
     mock_finder->setNSECResult(Name("*.example.com"),
                                ZoneFinder::NXDOMAIN,
                                mock_finder->empty_nsec_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                qtype, response, true),
                  Query::BadNSEC);
 }
 
 TEST_F(QueryTest, nxrrset) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("www.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("www.example.com"),
                                   RRType::TXT(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
@@ -1346,7 +1382,7 @@ TEST_F(QueryTest, nxrrset) {
 TEST_F(QueryTest, nxrrsetWithNSEC) {
     // NXRRSET with DNSSEC proof.  We should have SOA, NSEC that proves the
     // NXRRSET and their RRSIGs.
-    query.process(memory_client, Name("www.example.com"), RRType::TXT(),
+    query.process(list, Name("www.example.com"), RRType::TXT(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -1367,7 +1403,7 @@ TEST_F(QueryTest, emptyNameWithNSEC) {
     // exact match), so we only need one NSEC.
     // From the point of the Query::process(), this is actually no different
     // from the other NXRRSET case, but we check that explicitly just in case.
-    query.process(memory_client, Name("no.example.com"), RRType::A(),
+    query.process(list, Name("no.example.com"), RRType::A(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -1383,7 +1419,7 @@ TEST_F(QueryTest, nxrrsetWithoutNSEC) {
     // NXRRSET with DNSSEC proof requested, but there's no NSEC at that node.
     // This is an unexpected event (if the zone is supposed to be properly
     // signed with NSECs), but we accept and ignore the oddity.
-    query.process(memory_client, Name("nonsec.example.com"), RRType::TXT(),
+    query.process(list, Name("nonsec.example.com"), RRType::TXT(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
@@ -1395,7 +1431,7 @@ TEST_F(QueryTest, nxrrsetWithoutNSEC) {
 TEST_F(QueryTest, wildcardNSEC) {
     // The qname matches *.wild.example.com.  The response should contain
     // an NSEC that proves the non existence of a closer name.
-    query.process(memory_client, Name("www.wild.example.com"), RRType::A(),
+    query.process(list, Name("www.wild.example.com"), RRType::A(),
                   response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
                   (string(wild_txt).replace(0, 1, "www") +
@@ -1415,7 +1451,7 @@ TEST_F(QueryTest, wildcardNSEC) {
 TEST_F(QueryTest, CNAMEwildNSEC) {
     // Similar to the previous case, but the matching wildcard record is
     // CNAME.
-    query.process(memory_client, Name("www.cnamewild.example.com"),
+    query.process(list, Name("www.cnamewild.example.com"),
                   RRType::A(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
                   (string(cnamewild_txt).replace(0, 1, "www") +
@@ -1438,7 +1474,7 @@ TEST_F(QueryTest, wildcardNSEC3) {
     // of identifying the next closer name.
     mock_finder->addRecord(nsec3_atwild_txt);
 
-    query.process(memory_client, Name("x.y.wild.example.com"), RRType::A(),
+    query.process(list, Name("x.y.wild.example.com"), RRType::A(),
                   response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 6, 6,
                   (string(wild_txt).replace(0, 1, "x.y") +
@@ -1463,7 +1499,7 @@ TEST_F(QueryTest, CNAMEwildNSEC3) {
     mock_finder->setNSEC3Flag(true);
     mock_finder->addRecord(nsec3_atcnamewild_txt);
 
-    query.process(memory_client, Name("www.cnamewild.example.com"),
+    query.process(list, Name("www.cnamewild.example.com"),
                   RRType::A(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
                   (string(cnamewild_txt).replace(0, 1, "www") +
@@ -1486,7 +1522,7 @@ TEST_F(QueryTest, badWildcardNSEC3) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                  Query::BadNSEC3);
 }
@@ -1497,7 +1533,7 @@ TEST_F(QueryTest, badWildcardProof1) {
     mock_finder->setNSECResult(Name("www.wild.example.com"),
                                ZoneFinder::SUCCESS,
                                mock_finder->dname_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                  Query::BadNSEC);
 }
@@ -1506,7 +1542,7 @@ TEST_F(QueryTest, badWildcardProof2) {
     // "wildcard proof" doesn't return RRset.
     mock_finder->setNSECResult(Name("www.wild.example.com"),
                                ZoneFinder::NXDOMAIN, ConstRRsetPtr());
-    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                  Query::BadNSEC);
 }
@@ -1516,7 +1552,7 @@ TEST_F(QueryTest, badWildcardProof3) {
     mock_finder->setNSECResult(Name("www.wild.example.com"),
                                ZoneFinder::NXDOMAIN,
                                mock_finder->empty_nsec_rrset_);
-    EXPECT_THROW(query.process(memory_client, Name("www.wild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.wild.example.com"),
                                RRType::A(), response, true),
                  Query::BadNSEC);
 }
@@ -1525,7 +1561,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
     // NXRRSET on WILDCARD with DNSSEC proof.  We should have SOA, NSEC that
     // proves the NXRRSET and their RRSIGs. In this case we only need one NSEC,
     // which proves both NXDOMAIN and the non existence RRSETs of wildcard.
-    query.process(memory_client, Name("www.wild.example.com"), RRType::TXT(),
+    query.process(list, Name("www.wild.example.com"), RRType::TXT(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -1542,7 +1578,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC) {
     // proves the NXRRSET and their RRSIGs. In this case we need two NSEC RRs,
     // one proves NXDOMAIN and the other proves non existence RRSETs of
     // wildcard.
-    query.process(memory_client, Name("www1.uwild.example.com"),
+    query.process(list, Name("www1.uwild.example.com"),
                   RRType::TXT(), response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
@@ -1565,7 +1601,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3) {
     mock_finder->addRecord(nsec3_uwild_txt);
     mock_finder->setNSEC3Flag(true);
 
-    query.process(memory_client, Name("www1.uwild.example.com"),
+    query.process(list, Name("www1.uwild.example.com"),
                   RRType::TXT(), response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 8, 0, NULL,
@@ -1599,7 +1635,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Collision) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    EXPECT_THROW(query.process(memory_client, Name("www1.uwild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www1.uwild.example.com"),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
 }
@@ -1616,7 +1652,7 @@ TEST_F(QueryTest, wildcardNxrrsetWithNSEC3Broken) {
     mock_finder->addRecord(nsec3_wild_txt);
     mock_finder->addRecord(nsec3_uwild_txt);
 
-    EXPECT_THROW(query.process(memory_client, Name("www1.uwild.example.com"),
+    EXPECT_THROW(query.process(list, Name("www1.uwild.example.com"),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
 }
@@ -1625,7 +1661,7 @@ TEST_F(QueryTest, wildcardEmptyWithNSEC) {
     // Empty WILDCARD with DNSSEC proof.  We should have SOA, NSEC that proves
     // the NXDOMAIN and their RRSIGs. In this case we need two NSEC RRs,
     // one proves NXDOMAIN and the other proves non existence wildcard.
-    query.process(memory_client, Name("a.t.example.com"), RRType::A(),
+    query.process(list, Name("a.t.example.com"), RRType::A(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
@@ -1649,19 +1685,19 @@ TEST_F(QueryTest, noSOA) {
     mock_finder->setSOAFlag(false);
 
     // The NX Domain
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                qtype, response), Query::NoSOA);
     // Of course, we don't look into the response, as it throwed
 
     // NXRRSET
-    EXPECT_THROW(query.process(memory_client, Name("nxrrset.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxrrset.example.com"),
                                qtype, response), Query::NoSOA);
 }
 
 TEST_F(QueryTest, noMatchZone) {
     // there's a zone in the memory datasource but it doesn't match the qname.
     // should result in REFUSED.
-    query.process(memory_client, Name("example.org"), qtype, response);
+    query.process(list, Name("example.org"), qtype, response);
     EXPECT_EQ(Rcode::REFUSED(), response.getRcode());
 }
 
@@ -1672,7 +1708,7 @@ TEST_F(QueryTest, noMatchZone) {
  * A record, other to unknown out of zone one.
  */
 TEST_F(QueryTest, MX) {
-    query.process(memory_client, Name("mx.example.com"), RRType::MX(),
+    query.process(list, Name("mx.example.com"), RRType::MX(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 3, 3, 4,
@@ -1686,7 +1722,7 @@ TEST_F(QueryTest, MX) {
  * This should not trigger the additional processing for the exchange.
  */
 TEST_F(QueryTest, MXAlias) {
-    query.process(memory_client, Name("cnamemx.example.com"), RRType::MX(),
+    query.process(list, Name("cnamemx.example.com"), RRType::MX(),
                   response);
 
     // there shouldn't be no additional RRs for the exchanges (we have 3
@@ -1706,7 +1742,7 @@ TEST_F(QueryTest, MXAlias) {
  * returned.
  */
 TEST_F(QueryTest, CNAME) {
-    query.process(memory_client, Name("cname.example.com"), RRType::A(),
+    query.process(list, Name("cname.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1716,7 +1752,7 @@ TEST_F(QueryTest, CNAME) {
 TEST_F(QueryTest, explicitCNAME) {
     // same owner name as the CNAME test but explicitly query for CNAME RR.
     // expect the same response as we don't provide a full chain yet.
-    query.process(memory_client, Name("cname.example.com"), RRType::CNAME(),
+    query.process(list, Name("cname.example.com"), RRType::CNAME(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1728,7 +1764,7 @@ TEST_F(QueryTest, CNAME_NX_RRSET) {
     // note: with chaining, what should be expected is not trivial:
     // BIND 9 returns the CNAME in answer and SOA in authority, no additional.
     // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional.
-    query.process(memory_client, Name("cname.example.com"), RRType::TXT(),
+    query.process(list, Name("cname.example.com"), RRType::TXT(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1737,7 +1773,7 @@ TEST_F(QueryTest, CNAME_NX_RRSET) {
 
 TEST_F(QueryTest, explicitCNAME_NX_RRSET) {
     // same owner name as the NXRRSET test but explicitly query for CNAME RR.
-    query.process(memory_client, Name("cname.example.com"), RRType::CNAME(),
+    query.process(list, Name("cname.example.com"), RRType::CNAME(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1751,7 +1787,7 @@ TEST_F(QueryTest, CNAME_NX_DOMAIN) {
     // RCODE being NXDOMAIN.
     // NSD returns the CNAME, NS in authority, A/AAAA for NS in additional,
     // RCODE being NOERROR.
-    query.process(memory_client, Name("cnamenxdom.example.com"), RRType::A(),
+    query.process(list, Name("cnamenxdom.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1760,7 +1796,7 @@ TEST_F(QueryTest, CNAME_NX_DOMAIN) {
 
 TEST_F(QueryTest, explicitCNAME_NX_DOMAIN) {
     // same owner name as the NXDOMAIN test but explicitly query for CNAME RR.
-    query.process(memory_client, Name("cnamenxdom.example.com"),
+    query.process(list, Name("cnamenxdom.example.com"),
                   RRType::CNAME(), response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1776,7 +1812,7 @@ TEST_F(QueryTest, CNAME_OUT) {
      * Then the same test should be done with .org included there and
      * see what it does (depends on what we want to do)
      */
-    query.process(memory_client, Name("cnameout.example.com"), RRType::A(),
+    query.process(list, Name("cnameout.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 0, 0,
@@ -1785,7 +1821,7 @@ TEST_F(QueryTest, CNAME_OUT) {
 
 TEST_F(QueryTest, explicitCNAME_OUT) {
     // same owner name as the OUT test but explicitly query for CNAME RR.
-    query.process(memory_client, Name("cnameout.example.com"), RRType::CNAME(),
+    query.process(list, Name("cnameout.example.com"), RRType::CNAME(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1801,7 +1837,7 @@ TEST_F(QueryTest, explicitCNAME_OUT) {
  * pointing to NXRRSET and NXDOMAIN cases (similarly as with CNAME).
  */
 TEST_F(QueryTest, DNAME) {
-    query.process(memory_client, Name("www.dname.example.com"), RRType::A(),
+    query.process(list, Name("www.dname.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
@@ -1817,7 +1853,7 @@ TEST_F(QueryTest, DNAME) {
  * DNAME.
  */
 TEST_F(QueryTest, DNAME_ANY) {
-    query.process(memory_client, Name("www.dname.example.com"), RRType::ANY(),
+    query.process(list, Name("www.dname.example.com"), RRType::ANY(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 0, 0,
@@ -1826,7 +1862,7 @@ TEST_F(QueryTest, DNAME_ANY) {
 
 // Test when we ask for DNAME explicitly, it does no synthetizing.
 TEST_F(QueryTest, explicitDNAME) {
-    query.process(memory_client, Name("dname.example.com"), RRType::DNAME(),
+    query.process(list, Name("dname.example.com"), RRType::DNAME(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1838,7 +1874,7 @@ TEST_F(QueryTest, explicitDNAME) {
  * the CNAME, it should return the RRset.
  */
 TEST_F(QueryTest, DNAME_A) {
-    query.process(memory_client, Name("dname.example.com"), RRType::A(),
+    query.process(list, Name("dname.example.com"), RRType::A(),
                   response);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 1, 3, 3,
@@ -1850,7 +1886,7 @@ TEST_F(QueryTest, DNAME_A) {
  * It should not synthetize the CNAME.
  */
 TEST_F(QueryTest, DNAME_NX_RRSET) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("dname.example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("dname.example.com"),
                     RRType::TXT(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
@@ -1870,7 +1906,7 @@ TEST_F(QueryTest, LongDNAME) {
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "dname.example.com.");
-    EXPECT_NO_THROW(query.process(memory_client, longname, RRType::A(),
+    EXPECT_NO_THROW(query.process(list, longname, RRType::A(),
                     response));
 
     responseCheck(response, Rcode::YXDOMAIN(), AA_FLAG, 1, 0, 0,
@@ -1889,7 +1925,7 @@ TEST_F(QueryTest, MaxLenDNAME) {
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
         "dname.example.com.");
-    EXPECT_NO_THROW(query.process(memory_client, longname, RRType::A(),
+    EXPECT_NO_THROW(query.process(list, longname, RRType::A(),
                     response));
 
     // Check the answer is OK
@@ -2075,7 +2111,7 @@ TEST_F(QueryTest, dsAboveDelegation) {
 
     // The following will succeed only if the search goes to the parent
     // zone, not the child one we added above.
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("delegation.example.com"),
                                   RRType::DS(), response, true));
 
@@ -2099,7 +2135,7 @@ TEST_F(QueryTest, dsAboveDelegationNoData) {
 
     // The following will succeed only if the search goes to the parent
     // zone, not the child one we added above.
-    EXPECT_NO_THROW(query.process(memory_client,
+    EXPECT_NO_THROW(query.process(list,
                                   Name("unsigned-delegation.example.com"),
                                   RRType::DS(), response, true));
 
@@ -2117,7 +2153,7 @@ TEST_F(QueryTest, dsAboveDelegationNoData) {
 // when it happens to be sent to the child zone, as described in RFC 4035,
 // section 3.1.4.1. The example is inspired by the B.8. example from the RFC.
 TEST_F(QueryTest, dsBelowDelegation) {
-    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("example.com"),
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -2134,7 +2170,7 @@ TEST_F(QueryTest, dsBelowDelegation) {
 // In our implementation NSEC/NSEC3 isn't attached in this case.
 TEST_F(QueryTest, dsBelowDelegationWithDS) {
     mock_finder->addRecord(zone_ds_txt); // add the DS to the child's apex
-    EXPECT_NO_THROW(query.process(memory_client, Name("example.com"),
+    EXPECT_NO_THROW(query.process(list, Name("example.com"),
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
@@ -2147,7 +2183,7 @@ TEST_F(QueryTest, dsBelowDelegationWithDS) {
 // server.  It should just like the "noZone" test case, but DS query involves
 // special processing, so we test it explicitly.
 TEST_F(QueryTest, dsNoZone) {
-    query.process(memory_client, Name("example"), RRType::DS(), response,
+    query.process(list, Name("example"), RRType::DS(), response,
                   true);
     responseCheck(response, Rcode::REFUSED(), 0, 0, 0, 0, NULL, NULL, NULL);
 }
@@ -2155,7 +2191,7 @@ TEST_F(QueryTest, dsNoZone) {
 // DS query for a "grandchild" zone.  This should result in normal
 // delegation (unless this server also has authority of the grandchild zone).
 TEST_F(QueryTest, dsAtGrandParent) {
-    query.process(memory_client, Name("grand.delegation.example.com"),
+    query.process(list, Name("grand.delegation.example.com"),
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), 0, 0, 6, 6, NULL,
                   (string(delegation_txt) + string(delegation_ds_txt) +
@@ -2174,7 +2210,7 @@ TEST_F(QueryTest, dsAtGrandParentAndChild) {
     const Name childname("grand.delegation.example.com");
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(childname)));
-    query.process(memory_client, childname, RRType::DS(), response, true);
+    query.process(list, childname, RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (childname.toText() + " 3600 IN SOA . . 0 0 0 0 0\n" +
                    childname.toText() + " 3600 IN RRSIG " +
@@ -2192,7 +2228,7 @@ TEST_F(QueryTest, dsAtRoot) {
     // Pretend to be a root server.
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(Name::ROOT_NAME())));
-    query.process(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
+    query.process(list, Name::ROOT_NAME(), RRType::DS(), response,
                   true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (string(". 3600 IN SOA . . 0 0 0 0 0\n") +
@@ -2209,7 +2245,7 @@ TEST_F(QueryTest, dsAtRootWithDS) {
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(Name::ROOT_NAME(),
                                                       true)));
-    query.process(memory_client, Name::ROOT_NAME(), RRType::DS(), response,
+    query.process(list, Name::ROOT_NAME(), RRType::DS(), response,
                   true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 2, 2, 0,
                   (string(". 3600 IN DS 57855 5 1 49FD46E6C4B45C55D4AC69CBD"
@@ -2226,7 +2262,7 @@ TEST_F(QueryTest, nxrrsetWithNSEC3) {
 
     // NXRRSET with DNSSEC proof.  We should have SOA, NSEC3 that proves the
     // NXRRSET and their RRSIGs.
-    query.process(memory_client, Name("www.example.com"), RRType::TXT(),
+    query.process(list, Name("www.example.com"), RRType::TXT(),
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
@@ -2249,7 +2285,7 @@ TEST_F(QueryTest, nxrrsetMissingNSEC3) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    EXPECT_THROW(query.process(memory_client, Name("www.example.com"),
+    EXPECT_THROW(query.process(list, Name("www.example.com"),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
 }
@@ -2260,7 +2296,7 @@ TEST_F(QueryTest, nxrrsetWithNSEC3_ds_exact) {
 
     // This delegation has no DS, but does have a matching NSEC3 record
     // (See RFC5155 section 7.2.4)
-    query.process(memory_client, Name("unsigned-delegation.example.com."),
+    query.process(list, Name("unsigned-delegation.example.com."),
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
                   (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -2282,7 +2318,7 @@ TEST_F(QueryTest, nxrrsetWithNSEC3_ds_no_exact) {
     // 'next closer' should have opt-out set, though that is not
     // actually checked)
     // (See RFC5155 section 7.2.4)
-    query.process(memory_client, Name("unsigned-delegation-optout.example.com."),
+    query.process(list, Name("unsigned-delegation-optout.example.com."),
                   RRType::DS(), response, true);
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
                   (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
@@ -2309,7 +2345,7 @@ TEST_F(QueryTest, nxdomainWithNSEC3Proof) {
     // This will be the covering NSEC3 for the possible wildcard
     mock_finder->addRecord(unsigned_delegation_nsec3_txt);
 
-    query.process(memory_client, Name("nxdomain.example.com"), qtype,
+    query.process(list, Name("nxdomain.example.com"), qtype,
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 8, 0, NULL,
                   // SOA + its RRSIG
@@ -2344,7 +2380,7 @@ TEST_F(QueryTest, nxdomainWithBadNextNSEC3Proof) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3);
 
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"),
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"),
                                RRType::TXT(), response, true),
                  Query::BadNSEC3);
 }
@@ -2363,7 +2399,7 @@ TEST_F(QueryTest, nxdomainWithBadWildcardNSEC3Proof) {
                                       ConstRRsetPtr());
     mock_finder->setNSEC3Result(&nsec3, &wname);
 
-    EXPECT_THROW(query.process(memory_client, Name("nxdomain.example.com"), qtype,
+    EXPECT_THROW(query.process(list, Name("nxdomain.example.com"), qtype,
                                response, true),
                  Query::BadNSEC3);
 }
diff --git a/src/bin/auth/tests/testdata/Makefile.am b/src/bin/auth/tests/testdata/Makefile.am
index c86722f..7e42b70 100644
--- a/src/bin/auth/tests/testdata/Makefile.am
+++ b/src/bin/auth/tests/testdata/Makefile.am
@@ -18,6 +18,7 @@ EXTRA_DIST += shortquestion_fromWire
 EXTRA_DIST += shortresponse_fromWire
 EXTRA_DIST += simplequery_fromWire.spec
 EXTRA_DIST += simpleresponse_fromWire.spec
+EXTRA_DIST += spec.spec
 
 EXTRA_DIST += example.com
 EXTRA_DIST += example.sqlite3
diff --git a/src/bin/auth/tests/testdata/spec.spec b/src/bin/auth/tests/testdata/spec.spec
new file mode 100644
index 0000000..3e0a822
--- /dev/null
+++ b/src/bin/auth/tests/testdata/spec.spec
@@ -0,0 +1,6 @@
+{
+    "module_spec": {
+        "module_name": "test"
+    }
+}
+
diff --git a/src/bin/bind10/bind10.xml b/src/bin/bind10/bind10.xml
index 4053783..cfd5b52 100644
--- a/src/bin/bind10/bind10.xml
+++ b/src/bin/bind10/bind10.xml
@@ -47,7 +47,6 @@
       <arg><option>-c <replaceable>config-filename</replaceable></option></arg>
       <arg><option>-i</option></arg>
       <arg><option>-m <replaceable>file</replaceable></option></arg>
-      <arg><option>-n</option></arg>
       <arg><option>-p <replaceable>data_path</replaceable></option></arg>
       <arg><option>-u <replaceable>user</replaceable></option></arg>
       <arg><option>-v</option></arg>
@@ -57,7 +56,6 @@
       <arg><option>--config-file</option> <replaceable>config-filename</replaceable></arg>
       <arg><option>--data-path</option> <replaceable>directory</replaceable></arg>
       <arg><option>--msgq-socket-file <replaceable>file</replaceable></option></arg>
-      <arg><option>--no-cache</option></arg>
       <arg><option>--no-kill</option></arg>
       <arg><option>--pid-file</option> <replaceable>filename</replaceable></arg>
       <arg><option>--pretty-name <replaceable>name</replaceable></option></arg>
@@ -169,15 +167,6 @@
       </varlistentry>
 
       <varlistentry>
-        <term><option>-n</option>, <option>--no-cache</option></term>
-        <listitem>
-	  <para>Disables the hot-spot caching used by the
-	    <citerefentry><refentrytitle>b10-auth</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-	  daemon.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
         <term><option>-i</option>, <option>--no-kill</option></term>
         <listitem>
 	  <para>When this option is passed, <command>bind10</command>
diff --git a/src/bin/bind10/bind10_src.py.in b/src/bin/bind10/bind10_src.py.in
index b9dbc36..7b71737 100755
--- a/src/bin/bind10/bind10_src.py.in
+++ b/src/bin/bind10/bind10_src.py.in
@@ -168,7 +168,7 @@ class BoB:
     """Boss of BIND class."""
     
     def __init__(self, msgq_socket_file=None, data_path=None,
-                 config_filename=None, clear_config=False, nocache=False,
+                 config_filename=None, clear_config=False,
                  verbose=False, nokill=False, setuid=None, setgid=None,
                  username=None, cmdctl_port=None, wait_time=10):
         """
@@ -192,7 +192,6 @@ class BoB:
         self.ccs = None
         self.curproc = None
         self.msgq_socket_file = msgq_socket_file
-        self.nocache = nocache
         self.component_config = {}
         # Some time in future, it may happen that a single component has
         # multple processes (like a pipeline-like component). If so happens,
@@ -568,8 +567,6 @@ class BoB:
         if self.uid is not None and self.__started:
             logger.warn(BIND10_START_AS_NON_ROOT_AUTH)
         authargs = ['b10-auth']
-        if self.nocache:
-            authargs += ['-n']
         if self.verbose:
             authargs += ['-v']
 
@@ -1052,8 +1049,6 @@ def parse_args(args=sys.argv[1:], Parser=OptionParser):
     parser.add_option("-m", "--msgq-socket-file", dest="msgq_socket_file",
                       type="string", default=None,
                       help="UNIX domain socket file the b10-msgq daemon will use")
-    parser.add_option("-n", "--no-cache", action="store_true", dest="nocache",
-                      default=False, help="disable hot-spot cache in authoritative DNS server")
     parser.add_option("-i", "--no-kill", action="store_true", dest="nokill",
                       default=False, help="do not send SIGTERM and SIGKILL signals to modules during shutdown")
     parser.add_option("-u", "--user", dest="user", type="string", default=None,
@@ -1208,7 +1203,7 @@ def main():
         # Go bob!
         boss_of_bind = BoB(options.msgq_socket_file, options.data_path,
                            options.config_file, options.clear_config,
-                           options.nocache, options.verbose, options.nokill,
+                           options.verbose, options.nokill,
                            setuid, setgid, username, options.cmdctl_port,
                            options.wait_time)
         startup_result = boss_of_bind.startup()
diff --git a/src/bin/bind10/tests/bind10_test.py.in b/src/bin/bind10/tests/bind10_test.py.in
index 6ed7411..0a17230 100644
--- a/src/bin/bind10/tests/bind10_test.py.in
+++ b/src/bin/bind10/tests/bind10_test.py.in
@@ -349,7 +349,6 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.runnable, False)
         self.assertEqual(bob.uid, None)
         self.assertEqual(bob.username, None)
-        self.assertEqual(bob.nocache, False)
         self.assertIsNone(bob._socket_cache)
 
     def test_set_creator(self):
@@ -377,7 +376,6 @@ class TestBoB(unittest.TestCase):
         self.assertEqual(bob.runnable, False)
         self.assertEqual(bob.uid, None)
         self.assertEqual(bob.username, None)
-        self.assertEqual(bob.nocache, False)
 
     def test_command_handler(self):
         class DummySession():
diff --git a/src/bin/cfgmgr/plugins/Makefile.am b/src/bin/cfgmgr/plugins/Makefile.am
index 5a4cfef..eb7809c 100644
--- a/src/bin/cfgmgr/plugins/Makefile.am
+++ b/src/bin/cfgmgr/plugins/Makefile.am
@@ -2,13 +2,16 @@ SUBDIRS = tests
 
 EXTRA_DIST = README logging.spec tsig_keys.spec
 
+datasrc.spec: datasrc.spec.pre
+	$(SED) -e "s|@@PKGDATADIR@@|$(pkgdatadir)|" datasrc.spec.pre >$@
+
 config_plugindir = @prefix@/share/@PACKAGE@/config_plugins
-config_plugin_DATA = logging.spec tsig_keys.spec
+config_plugin_DATA = logging.spec tsig_keys.spec datasrc.spec
 
-python_PYTHON = b10logging.py tsig_keys.py
+python_PYTHON = b10logging.py tsig_keys.py datasrc_config_plugin.py
 pythondir = $(config_plugindir)
 
-CLEANFILES = b10logging.pyc tsig_keys.pyc
+CLEANFILES = b10logging.pyc tsig_keys.pyc datasrc.spec
 CLEANDIRS = __pycache__
 
 clean-local:
diff --git a/src/bin/cfgmgr/plugins/datasrc.spec.pre.in b/src/bin/cfgmgr/plugins/datasrc.spec.pre.in
new file mode 100644
index 0000000..5bd20bb
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/datasrc.spec.pre.in
@@ -0,0 +1,66 @@
+{
+    "module_spec": {
+        "module_name": "data_sources",
+        "module_description": "The sources of authoritative DNS data",
+        "config_data": [
+            {
+                "item_name": "classes",
+                "item_type": "named_set",
+                "item_optional": false,
+                "item_default": {
+                    "CH": [
+                        {
+                            "type": "static",
+                            "cache-enable": false,
+                            "params": "@@PKGDATADIR@@/static.zone"
+                        }
+                    ]
+                },
+                "named_set_item_spec": {
+                    "item_name": "class",
+                    "item_type": "list",
+                    "item_optional": false,
+                    "item_default": [],
+                    "list_item_spec": {
+                        "item_name": "source",
+                        "item_type": "map",
+                        "item_optional": false,
+                        "item_default": {},
+                        "map_item_spec": [
+                            {
+                                "item_name": "type",
+                                "item_type": "string",
+                                "item_optional": false,
+                                "item_default": ""
+                            },
+                            {
+                                "item_name": "params",
+                                "item_type": "any",
+                                "item_optional": false,
+                                "item_default": null
+                            },
+                            {
+                                "item_name": "cache-enable",
+                                "item_type": "boolean",
+                                "item_optional": false,
+                                "item_default": false
+                            },
+                            {
+                                "item_name": "cache-zones",
+                                "item_type": "list",
+                                "item_optional": true,
+                                "list_item_spec": {
+                                    "item_name": "zone",
+                                    "item_type": "string",
+                                    "item_optional": false,
+                                    "item_default": ""
+                                }
+                            }
+                        ]
+                    }
+                }
+            }
+        ],
+        "commands": []
+    }
+}
diff --git a/src/bin/cfgmgr/plugins/datasrc_config_plugin.py b/src/bin/cfgmgr/plugins/datasrc_config_plugin.py
new file mode 100644
index 0000000..f675aba
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/datasrc_config_plugin.py
@@ -0,0 +1,36 @@
+# Copyright (C) 2012  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM 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.
+
+from isc.config.module_spec import module_spec_from_file
+from isc.util.file import path_search
+from bind10_config import PLUGIN_PATHS
+spec = module_spec_from_file(path_search('datasrc.spec', PLUGIN_PATHS))
+
+def check(config):
+    """
+    Check the configuration.
+    """
+    # TODO: Once we have solved ticket #2051, create the list and
+    # fill it with the configuration. We probably want to have some way
+    # to not load the data sources, just the configuration. It could
+    # be hacked together by subclassing ConfigurableClientList and
+    # having empty getDataSource method. But it looks like a hack and it
+    # won't really check the params configuration.
+    #
+    # For now, we let everything pass.
+    return None
+
+def load():
+    return (spec, check)
diff --git a/src/bin/cfgmgr/plugins/tests/Makefile.am b/src/bin/cfgmgr/plugins/tests/Makefile.am
index ffea2d7..9b8b925 100644
--- a/src/bin/cfgmgr/plugins/tests/Makefile.am
+++ b/src/bin/cfgmgr/plugins/tests/Makefile.am
@@ -1,5 +1,5 @@
 PYCOVERAGE_RUN = @PYCOVERAGE_RUN@
-PYTESTS = tsig_keys_test.py logging_test.py
+PYTESTS = tsig_keys_test.py logging_test.py datasrc_test.py
 
 EXTRA_DIST = $(PYTESTS)
 
diff --git a/src/bin/cfgmgr/plugins/tests/datasrc_test.py b/src/bin/cfgmgr/plugins/tests/datasrc_test.py
new file mode 100644
index 0000000..f88ef87
--- /dev/null
+++ b/src/bin/cfgmgr/plugins/tests/datasrc_test.py
@@ -0,0 +1,36 @@
+# Copyright (C) 2011  Internet Systems Consortium.
+#
+# Permission to use, copy, modify, and 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 INTERNET SYSTEMS CONSORTIUM
+# DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+# INTERNET SYSTEMS CONSORTIUM 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.
+
+# Make sure we can load the module, put it into path
+import sys
+import os
+sys.path.extend(os.environ["B10_TEST_PLUGIN_DIR"].split(':'))
+
+import datasrc_config_plugin
+import unittest
+
+class DatasrcTest(unittest.TestCase):
+    def test_load(self):
+        """
+        Checks the entry point returns the correct values.
+        """
+        (spec, check) = datasrc_config_plugin.load()
+        # It returns the checking function
+        self.assertEqual(check, datasrc_config_plugin.check)
+        # The plugin stores it's spec
+        self.assertEqual(spec, datasrc_config_plugin.spec)
+
+if __name__ == '__main__':
+        unittest.main()
diff --git a/src/bin/ddns/tests/ddns_test.py b/src/bin/ddns/tests/ddns_test.py
index b634415..0f5ca9b 100755
--- a/src/bin/ddns/tests/ddns_test.py
+++ b/src/bin/ddns/tests/ddns_test.py
@@ -1136,7 +1136,7 @@ class TestDDNSSession(unittest.TestCase):
         num_rrsets = len(self.__req_message.get_section(SECTION_PREREQUISITE))
         self.assertEqual(2, num_rrsets)
 
-    def check_session_msg(self, result, expect_recv=1, notify_auth=False):
+    def check_session_msg(self, result, expect_recv=2):
         '''Check post update communication with other modules.'''
         # iff the update succeeds, b10-ddns should tell interested other
         # modules the information about the update zone.  Possible modules
@@ -1145,32 +1145,28 @@ class TestDDNSSession(unittest.TestCase):
         #                         'zone_class', <updated_zone_class>}]}
         # for auth, it should be:
         # {'command': ['loadzone', {'origin': <updated_zone_name>,
-        #                           'class', <updated_zone_class>,
-        #                           'datasrc', <datasrc type, should be
-        #                                       "memory" in practice>}]}
+        #                           'class', <updated_zone_class>}]}
         # and expect an answer by calling group_recvmsg().
         #
         # expect_recv indicates the expected number of calls to
-        # group_recvmsg(), which is normally 1, but can be 0 if send fails;
+        # group_recvmsg(), which is normally 2, but can be 0 if send fails;
         # if the message is to be sent
         if result == UPDATE_SUCCESS:
-            expected_sentmsg = 2 if notify_auth else 1
+            expected_sentmsg = 2
             self.assertEqual(expected_sentmsg,
                              len(self.__cc_session._sent_msg))
             self.assertEqual(expect_recv, self.__cc_session._recvmsg_called)
             msg_cnt = 0
-            if notify_auth:
-                sent_msg, sent_group = self.__cc_session._sent_msg[msg_cnt]
-                sent_cmd = sent_msg['command']
-                self.assertEqual('Auth', sent_group)
-                self.assertEqual('loadzone', sent_cmd[0])
-                self.assertEqual(3, len(sent_cmd[1]))
-                self.assertEqual(TEST_ZONE_NAME.to_text(),
-                                 sent_cmd[1]['origin'])
-                self.assertEqual(TEST_RRCLASS.to_text(),
-                                 sent_cmd[1]['class'])
-                self.assertEqual('memory', sent_cmd[1]['datasrc'])
-                msg_cnt += 1
+            sent_msg, sent_group = self.__cc_session._sent_msg[msg_cnt]
+            sent_cmd = sent_msg['command']
+            self.assertEqual('Auth', sent_group)
+            self.assertEqual('loadzone', sent_cmd[0])
+            self.assertEqual(2, len(sent_cmd[1]))
+            self.assertEqual(TEST_ZONE_NAME.to_text(),
+                             sent_cmd[1]['origin'])
+            self.assertEqual(TEST_RRCLASS.to_text(),
+                             sent_cmd[1]['class'])
+            msg_cnt += 1
             sent_msg, sent_group = self.__cc_session._sent_msg[msg_cnt]
             sent_cmd = sent_msg['command']
             self.assertEqual('Xfrout', sent_group)
@@ -1267,21 +1263,21 @@ class TestDDNSSession(unittest.TestCase):
             [{'type': 'memory', 'class': 'IN', 'zones': [
                     {'origin': TEST_ZONE_NAME_STR, 'filetype': 'sqlite3'}]}]
         self.check_session()
-        self.check_session_msg(UPDATE_SUCCESS, expect_recv=2, notify_auth=True)
+        self.check_session_msg(UPDATE_SUCCESS)
 
         # Let sendmsg() raise an exception.  The first exception shouldn't
         # stop sending the second message.  There's just no recv calls.
         self.__cc_session.clear_msg()
         self.__cc_session._sendmsg_exception = SessionError('send error')
         self.check_session()
-        self.check_session_msg(UPDATE_SUCCESS, expect_recv=0, notify_auth=True)
+        self.check_session_msg(UPDATE_SUCCESS, expect_recv=0)
 
         # Likewise, in the case recvmsg() raises (and there should be recv
         # calls in this case)
         self.__cc_session.clear_msg()
         self.__cc_session._recvmsg_exception = SessionError('recv error')
         self.check_session()
-        self.check_session_msg(UPDATE_SUCCESS, expect_recv=2, notify_auth=True)
+        self.check_session_msg(UPDATE_SUCCESS)
 
     def test_session_with_config(self):
         '''Check a session with more realistic config setups.
diff --git a/src/bin/xfrin/tests/xfrin_test.py b/src/bin/xfrin/tests/xfrin_test.py
index a1f4d28..a3818a6 100644
--- a/src/bin/xfrin/tests/xfrin_test.py
+++ b/src/bin/xfrin/tests/xfrin_test.py
@@ -2739,18 +2739,8 @@ class TestMain(unittest.TestCase):
 
 class TestXfrinProcessMockCC:
     def __init__(self):
-        self.get_called = False
-        self.get_called_correctly = False
         self.config = []
 
-    def get_remote_config_value(self, module, identifier):
-        self.get_called = True
-        if module == 'Auth' and identifier == 'datasources':
-            self.get_called_correctly = True
-            return (self.config, False)
-        else:
-            return (None, True)
-
 class TestXfrinProcessMockCCSession:
     def __init__(self):
         self.send_called = False
@@ -2869,22 +2859,17 @@ class TestXfrinProcess(unittest.TestCase):
         # Create a connection for each attempt
         self.assertEqual(len(transfers), self.__created_connections)
         self.assertEqual([published], self.__published)
-        if published == XFRIN_OK:
-            self.assertTrue(self._module_cc.get_called)
-            self.assertTrue(self._module_cc.get_called_correctly)
-        else:
-            self.assertFalse(self._module_cc.get_called)
-            self.assertFalse(self._module_cc.get_called_correctly)
 
     def test_ixfr_ok(self):
         """
         Everything OK the first time, over IXFR.
         """
         self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
+        # Check there was loadzone command
+        self.assertTrue(self._send_cc_session.send_called)
+        self.assertTrue(self._send_cc_session.send_called_correctly)
+        self.assertTrue(self._send_cc_session.recv_called)
+        self.assertTrue(self._send_cc_session.recv_called_correctly)
 
     def test_axfr_ok(self):
         """
@@ -2916,137 +2901,16 @@ class TestXfrinProcess(unittest.TestCase):
         self.__do_test([XFRIN_FAIL, XFRIN_FAIL],
                        [RRType.IXFR(), RRType.AXFR()], RRType.IXFR())
 
-    def test_inmem_ok(self):
+    def test_send_loadzone(self):
         """
-        Inmem configuration where all the configuration is just right
-        for loadzone to be sent to b10-auth (origin is the name received
-        by xfrin, filetype is sqlite3, type is memory and class is the
-        one received by xfrin).
+        Check the loadzone command is sent after successful transfer.
         """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory', 'class': 'IN'}]
         self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
         self.assertTrue(self._send_cc_session.send_called)
         self.assertTrue(self._send_cc_session.send_called_correctly)
         self.assertTrue(self._send_cc_session.recv_called)
         self.assertTrue(self._send_cc_session.recv_called_correctly)
 
-    def test_inmem_datasource_type_not_memory(self):
-        """
-        Inmem configuration where the datasource type is not memory. In
-        this case, loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'punched-card', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_datasource_type_is_missing(self):
-        """
-        Inmem configuration where the datasource type is missing. In
-        this case, loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_backend_type_not_sqlite3(self):
-        """
-        Inmem configuration where the datasource backing file is not of
-        type sqlite3. In this case, loadzone should not be sent to
-        b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'postgresql',
-                                              'file': 'data/inmem-xfrin.db'}],
-                                   'type': 'memory', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_backend_type_is_missing(self):
-        """
-        Inmem configuration where the datasource backing file type is
-        not set. In this case, loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org',
-                                              'file': 'data/inmem-xfrin'}],
-                                   'type': 'memory', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_class_is_different(self):
-        """
-        Inmem configuration where the datasource class does not match
-        the received class. In this case, loadzone should not be sent to
-        b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory', 'class': 'XX'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_class_is_missing(self):
-        """
-        Inmem configuration where the datasource class is missing. In
-        this case, we assume the IN class and loadzone may be sent to
-        b10-auth if everything else matches.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'example.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertTrue(self._send_cc_session.send_called)
-        self.assertTrue(self._send_cc_session.send_called_correctly)
-        self.assertTrue(self._send_cc_session.recv_called)
-        self.assertTrue(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_name_doesnt_match(self):
-        """
-        Inmem configuration where the origin does not match the received
-        name. In this case, loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'origin': 'isc.org', 'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
-    def test_inmem_name_is_missing(self):
-        """
-        Inmem configuration where the origin is missing. In this case,
-        loadzone should not be sent to b10-auth.
-        """
-        self._module_cc.config = [{'zones': [{'filetype': 'sqlite3',
-                                              'file': 'data/inmem-xfrin.sqlite3'}],
-                                   'type': 'memory', 'class': 'IN'}]
-        self.__do_test([XFRIN_OK], [RRType.IXFR()], RRType.IXFR())
-        self.assertFalse(self._send_cc_session.send_called)
-        self.assertFalse(self._send_cc_session.send_called_correctly)
-        self.assertFalse(self._send_cc_session.recv_called)
-        self.assertFalse(self._send_cc_session.recv_called_correctly)
-
 class TestFormatting(unittest.TestCase):
     # If the formatting functions are moved to a more general library
     # (ticket #1379), these tests should be moved with them.
diff --git a/src/bin/xfrin/xfrin.py.in b/src/bin/xfrin/xfrin.py.in
index 1f04bee..b4a4cf9 100755
--- a/src/bin/xfrin/xfrin.py.in
+++ b/src/bin/xfrin/xfrin.py.in
@@ -1256,7 +1256,7 @@ def _do_auth_loadzone(server, zone_name, zone_class):
     if msg is not None:
         param = msg['command'][1]
         logger.debug(DBG_XFRIN_TRACE, XFRIN_AUTH_LOADZONE, param["origin"],
-                     param["class"], param["datasrc"])
+                     param["class"])
         seq = server._send_cc_session.group_sendmsg(msg, AUTH_MODULE_NAME)
         answer, env = server._send_cc_session.group_recvmsg(False, seq)
 
diff --git a/src/bin/xfrin/xfrin_messages.mes b/src/bin/xfrin/xfrin_messages.mes
index ffea249..554a195 100644
--- a/src/bin/xfrin/xfrin_messages.mes
+++ b/src/bin/xfrin/xfrin_messages.mes
@@ -15,10 +15,9 @@
 # No namespace declaration - these constants go in the global namespace
 # of the xfrin messages python module.
 
-% XFRIN_AUTH_LOADZONE sending Auth loadzone for origin=%1, class=%2, datasrc=%3
-There was a successful zone transfer, and the zone is served by b10-auth
-in the in-memory data source using sqlite3 as a backend. We send the
-"loadzone" command for the zone to b10-auth.
+% XFRIN_AUTH_LOADZONE sending Auth loadzone for origin=%1, class=%2
+There was a successful zone transfer.  We send the "loadzone" command for the
+zone to b10-auth.
 
 % XFRIN_AXFR_INCONSISTENT_SOA AXFR SOAs are inconsistent for %1: %2 expected, %3 received
 The serial fields of the first and last SOAs of AXFR (including AXFR-style
diff --git a/src/lib/config/module_spec.cc b/src/lib/config/module_spec.cc
index 781fed2..da42a5e 100644
--- a/src/lib/config/module_spec.cc
+++ b/src/lib/config/module_spec.cc
@@ -37,7 +37,7 @@ check_leaf_item(ConstElementPtr spec, const std::string& name,
                 Element::types type, bool mandatory)
 {
     if (spec->contains(name)) {
-        if (spec->get(name)->getType() == type) {
+        if (type == Element::any || spec->get(name)->getType() == type) {
             return;
         } else {
             isc_throw(ModuleSpecError,
diff --git a/src/lib/config/tests/module_spec_unittests.cc b/src/lib/config/tests/module_spec_unittests.cc
index b2ca7b4..d6b9a76 100644
--- a/src/lib/config/tests/module_spec_unittests.cc
+++ b/src/lib/config/tests/module_spec_unittests.cc
@@ -110,6 +110,7 @@ TEST(ModuleSpec, SpecfileItems) {
                    "item_default not of type map");
     moduleSpecError("spec15.spec",
                    "badname is not a valid type name");
+    EXPECT_NO_THROW(moduleSpecFromFile(specfile("spec40.spec")));
 }
 
 TEST(ModuleSpec, SpecfileConfigData) {
diff --git a/src/lib/config/tests/testdata/Makefile.am b/src/lib/config/tests/testdata/Makefile.am
index 1bf9496..6b66005 100644
--- a/src/lib/config/tests/testdata/Makefile.am
+++ b/src/lib/config/tests/testdata/Makefile.am
@@ -66,3 +66,4 @@ EXTRA_DIST += spec36.spec
 EXTRA_DIST += spec37.spec
 EXTRA_DIST += spec38.spec
 EXTRA_DIST += spec39.spec
+EXTRA_DIST += spec40.spec
diff --git a/src/lib/config/tests/testdata/spec40.spec b/src/lib/config/tests/testdata/spec40.spec
new file mode 100644
index 0000000..8e64fa9
--- /dev/null
+++ b/src/lib/config/tests/testdata/spec40.spec
@@ -0,0 +1,13 @@
+{
+  "module_spec": {
+    "module_name": "Spec40",
+    "config_data": [
+      { "item_name": "item1",
+        "item_type": "any",
+        "item_optional": false,
+        "item_default": "asdf"
+      }
+    ]
+  }
+}
+
diff --git a/src/lib/datasrc/client_list.cc b/src/lib/datasrc/client_list.cc
index 2ed4f44..38ab5cc 100644
--- a/src/lib/datasrc/client_list.cc
+++ b/src/lib/datasrc/client_list.cc
@@ -49,14 +49,19 @@ ConfigurableClientList::DataSourceInfo::DataSourceInfo(bool has_cache) :
 }
 
 void
-ConfigurableClientList::configure(const Element& config, bool allow_cache) {
+ConfigurableClientList::configure(const ConstElementPtr& config,
+                                  bool allow_cache)
+{
+    if (!config) {
+        isc_throw(isc::BadValue, "NULL configuration passed");
+    }
     // TODO: Implement recycling from the old configuration.
     size_t i(0); // Outside of the try to be able to access it in the catch
     try {
         vector<DataSourceInfo> new_data_sources;
-        for (; i < config.size(); ++i) {
+        for (; i < config->size(); ++i) {
             // Extract the parameters
-            const ConstElementPtr dconf(config.get(i));
+            const ConstElementPtr dconf(config->get(i));
             const ConstElementPtr typeElem(dconf->get("type"));
             if (typeElem == ConstElementPtr()) {
                 isc_throw(ConfigurationError, "Missing the type option in "
@@ -161,6 +166,8 @@ ConfigurableClientList::configure(const Element& config, bool allow_cache) {
         // ready. So just put it there and let the old one die when we exit
         // the scope.
         data_sources_.swap(new_data_sources);
+        configuration_ = config;
+        allow_cache_ = allow_cache;
     } catch (const TypeError& te) {
         isc_throw(ConfigurationError, "Malformed configuration at data source "
                   "no. " << i << ": " << te.what());
@@ -188,44 +195,57 @@ private:
 };
 
 boost::shared_ptr<ClientList::FindResult::LifeKeeper>
-genKeeper(const ConfigurableClientList::DataSourceInfo& info) {
-    if (info.cache_) {
+genKeeper(const ConfigurableClientList::DataSourceInfo* info) {
+    if (info == NULL) {
+        return (boost::shared_ptr<ClientList::FindResult::LifeKeeper>());
+    }
+    if (info->cache_) {
         return (boost::shared_ptr<ClientList::FindResult::LifeKeeper>(
-            new CacheKeeper(info.cache_)));
+            new CacheKeeper(info->cache_)));
     } else {
         return (boost::shared_ptr<ClientList::FindResult::LifeKeeper>(
-            new ContainerKeeper(info.container_)));
+            new ContainerKeeper(info->container_)));
     }
 }
 
 }
 
+// We have this class as a temporary storage, as the FindResult can't be
+// assigned.
+struct ConfigurableClientList::MutableResult {
+    MutableResult() :
+        datasrc_client(NULL),
+        matched_labels(0),
+        matched(false),
+        exact(false),
+        info(NULL)
+    {}
+    DataSourceClient* datasrc_client;
+    ZoneFinderPtr finder;
+    uint8_t matched_labels;
+    bool matched;
+    bool exact;
+    const DataSourceInfo* info;
+    operator FindResult() const {
+        // Conversion to the right result.
+        return (FindResult(datasrc_client, finder, exact, genKeeper(info)));
+    }
+};
+
 ClientList::FindResult
 ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
-                            bool) const
+                             bool want_finder) const
 {
-    // Nothing found yet.
-    //
-    // We have this class as a temporary storage, as the FindResult can't be
-    // assigned.
-    struct MutableResult {
-        MutableResult() :
-            datasrc_client(NULL),
-            matched_labels(0),
-            matched(false)
-        {}
-        DataSourceClient* datasrc_client;
-        ZoneFinderPtr finder;
-        uint8_t matched_labels;
-        bool matched;
-        boost::shared_ptr<FindResult::LifeKeeper> keeper;
-        operator FindResult() const {
-            // Conversion to the right result. If we return this, there was
-            // a partial match at best.
-            return (FindResult(datasrc_client, finder, false, keeper));
-        }
-    } candidate;
+    MutableResult result;
+    findInternal(result, name, want_exact_match, want_finder);
+    return (result);
+}
 
+void
+ConfigurableClientList::findInternal(MutableResult& candidate,
+                                     const dns::Name& name,
+                                     bool want_exact_match, bool) const
+{
     BOOST_FOREACH(const DataSourceInfo& info, data_sources_) {
         DataSourceClient* client(info.cache_ ? info.cache_.get() :
                                  info.data_src_client_);
@@ -239,8 +259,12 @@ ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
 
                 // TODO: In case we have only the datasource and not the finder
                 // and the need_updater parameter is true, get the zone there.
-                return (FindResult(client, result.zone_finder,
-                                   true, genKeeper(info)));
+                candidate.datasrc_client = client;
+                candidate.finder = result.zone_finder;
+                candidate.matched = true;
+                candidate.exact = true;
+                candidate.info = &info;
+                return;
             case result::PARTIALMATCH:
                 if (!want_exact_match) {
                     // In case we have a partial match, check if it is better
@@ -264,7 +288,7 @@ ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
                         candidate.finder = result.zone_finder;
                         candidate.matched_labels = labels;
                         candidate.matched = true;
-                        candidate.keeper = genKeeper(info);
+                        candidate.info = &info;
                     }
                 }
                 break;
@@ -276,10 +300,48 @@ ConfigurableClientList::find(const dns::Name& name, bool want_exact_match,
 
     // TODO: In case we have only the datasource and not the finder
     // and the need_updater parameter is true, get the zone there.
+}
 
-    // Return the partial match we have. In case we didn't want a partial
-    // match, this surely contains the original empty result.
-    return (candidate);
+ConfigurableClientList::ReloadResult
+ConfigurableClientList::reload(const Name& name) {
+    if (!allow_cache_) {
+        return (CACHE_DISABLED);
+    }
+    // Try to find the correct zone.
+    MutableResult result;
+    findInternal(result, name, true, true);
+    if (!result.finder) {
+        return (ZONE_NOT_FOUND);
+    }
+    // Try to convert the finder to in-memory one. If it is the cache,
+    // it should work.
+    shared_ptr<InMemoryZoneFinder>
+        finder(dynamic_pointer_cast<InMemoryZoneFinder>(result.finder));
+    const DataSourceInfo* info(result.info);
+    // It is of a different type or there's no cache.
+    if (!info->cache_ || !finder) {
+        return (ZONE_NOT_CACHED);
+    }
+    DataSourceClient* client(info->data_src_client_);
+    if (client) {
+        // Now do the final reload. 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);
+        }
+        finder->load(*iterator);
+    } else {
+        // The MasterFiles special case
+        const string filename(finder->getFileName());
+        if (filename.empty()) {
+            isc_throw(isc::Unexpected, "Confused about missing both filename "
+                      "and data source");
+        }
+        finder->load(filename);
+    }
+    return (ZONE_RELOADED);
 }
 
 // NOTE: This function is not tested, it would be complicated. However, the
diff --git a/src/lib/datasrc/client_list.h b/src/lib/datasrc/client_list.h
index f943c4f..0dd522f 100644
--- a/src/lib/datasrc/client_list.h
+++ b/src/lib/datasrc/client_list.h
@@ -210,7 +210,9 @@ public:
     ///
     /// \param rrclass For which class the list should work.
     ConfigurableClientList(const isc::dns::RRClass &rrclass) :
-        rrclass_(rrclass)
+        rrclass_(rrclass),
+        configuration_(new isc::data::ListElement),
+        allow_cache_(false)
     {}
     /// \brief Exception thrown when there's an error in configuration.
     class ConfigurationError : public Exception {
@@ -239,12 +241,44 @@ public:
     ///     client.
     /// \throw ConfigurationError if the configuration is invalid in some
     ///     sense.
+    /// \throw BadValue if configuration is NULL
     /// \throw Unexpected if something misbehaves (like the data source
     ///     returning NULL iterator).
     /// \throw NotImplemented if the auto-detection of list of zones is
     ///     needed.
     /// \throw Whatever is propagated from within the data source.
-    void configure(const data::Element& configuration, bool allow_cache);
+    void configure(const isc::data::ConstElementPtr& configuration,
+                   bool allow_cache);
+
+    /// \brief Returns the currently active configuration.
+    ///
+    /// In case configure was not called yet, it returns an empty
+    /// list, which corresponds to the default content.
+    const isc::data::ConstElementPtr& getConfiguration() const {
+        return (configuration_);
+    }
+
+    /// \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_RELOADED       ///< The zone was successfully reloaded.
+    };
+
+    /// \brief Reloads a cached zone.
+    ///
+    /// This method finds a zone which is loaded into a cache and reloads it.
+    /// This may be used to renew the cache when the underlying data source
+    /// changes.
+    ///
+    /// \param zone The origin of the zone to reload.
+    /// \return A status if the command worked.
+    /// \throw DataSourceError or anything else that the data source
+    ///      containing the zone might throw is propagated.
+    /// \throw DataSourceError if something unexpected happens, like when
+    ///      the original data source no longer contains the cached zone.
+    ReloadResult reload(const dns::Name& zone);
 
     /// \brief Implementation of the ClientList::find.
     virtual FindResult find(const dns::Name& zone,
@@ -308,7 +342,25 @@ public:
     /// hide it).
     const DataSources& getDataSources() const { return (data_sources_); }
 private:
+    struct MutableResult;
+    /// \brief Internal implementation of find.
+    ///
+    /// The class itself needs to do some internal searches in other methods,
+    /// so the implementation is shared.
+    ///
+    /// The result is returned as parameter because MutableResult is not
+    /// defined in the header file.
+    ///
+    /// If there's no match, the result is not modified. Therefore, this
+    /// expects to get a fresh result object each time it is called, not
+    /// to reuse it.
+    void findInternal(MutableResult& result, const dns::Name& name,
+                      bool want_exact_match, bool want_finder) const;
     const isc::dns::RRClass rrclass_;
+    /// \brief Currently active configuration.
+    isc::data::ConstElementPtr configuration_;
+    /// \brief The last set value of allow_cache.
+    bool allow_cache_;
 };
 
 } // namespace datasrc
diff --git a/src/lib/datasrc/static.zone.pre b/src/lib/datasrc/static.zone.pre
index 16a7379..13c0c9d 100644
--- a/src/lib/datasrc/static.zone.pre
+++ b/src/lib/datasrc/static.zone.pre
@@ -6,7 +6,9 @@
 ;;
 ;; in the bindctl.
 
+;; This is here mostly for technical reasons.
 BIND.           0   CH  SOA bind. authors.bind. 0 28800 7200 604800 86400
+BIND.           0   CH  NS  BIND.
 
 VERSION.BIND.   0   CH  TXT "@@VERSION_STRING@@"
 ;; HOSTNAME.BIND    0   CH  TXT "localhost"
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index 2f5e24d..64eb347 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -25,6 +25,7 @@
 #include <gtest/gtest.h>
 
 #include <set>
+#include <fstream>
 
 using namespace isc::datasrc;
 using namespace isc::data;
@@ -225,6 +226,12 @@ public:
             "{"
             "   \"type\": \"test_type\","
             "   \"params\": {}"
+            "}]")),
+        config_elem_zones_(Element::fromJSON("["
+            "{"
+            "   \"type\": \"test_type\","
+            "   \"params\": [\"example.org\", \"example.com\", "
+            "                \"noiter.org\", \"null.org\"]"
             "}]"))
     {
         for (size_t i(0); i < ds_count; ++ i) {
@@ -235,6 +242,25 @@ public:
                 DataSourceClientContainerPtr(), false));
         }
     }
+    void prepareCache(size_t index, const Name& zone, bool prefill = false) {
+        const shared_ptr<InMemoryClient> cache(new InMemoryClient());
+        const shared_ptr<InMemoryZoneFinder>
+            finder(new InMemoryZoneFinder(RRClass::IN(), zone));
+        if (prefill) {
+            RRsetPtr soa(new RRset(zone, RRClass::IN(), RRType::SOA(),
+                                   RRTTL(3600)));
+            // The RData here is bogus, but it is not used to anything. There
+            // just needs to be some.
+            soa->addRdata(rdata::generic::SOA(Name::ROOT_NAME(),
+                                              Name::ROOT_NAME(),
+                                              0, 0, 0, 0, 0));
+            finder->add(soa);
+        }
+        // If we don't do prefill, we leave the zone empty. This way,
+        // we can check when it was reloaded.
+        cache->addZone(finder);
+        list_->getDataSources()[index].cache_ = cache;
+    }
     // Check the positive result is as we expect it.
     void positiveResult(const ClientList::FindResult& result,
                         const shared_ptr<MockDataSourceClient>& dsrc,
@@ -309,7 +335,7 @@ public:
     const ClientList::FindResult negativeResult_;
     vector<shared_ptr<MockDataSourceClient> > ds_;
     vector<ConfigurableClientList::DataSourceInfo> ds_info_;
-    const ConstElementPtr config_elem_;
+    const ConstElementPtr config_elem_, config_elem_zones_;
 };
 
 // Test the test itself
@@ -427,8 +453,10 @@ TEST_F(ListTest, multiBestMatch) {
 // Check the configuration is empty when the list is empty
 TEST_F(ListTest, configureEmpty) {
     const ConstElementPtr elem(new ListElement);
-    list_->configure(*elem, true);
+    list_->configure(elem, true);
     EXPECT_TRUE(list_->getDataSources().empty());
+    // Check the exact configuration is preserved
+    EXPECT_EQ(elem, list_->getConfiguration());
 }
 
 // Check we can get multiple data sources and they are in the right order.
@@ -445,10 +473,12 @@ TEST_F(ListTest, configureMulti) {
         "   \"params\": {}"
         "}]"
     ));
-    list_->configure(*elem, true);
+    list_->configure(elem, true);
     EXPECT_EQ(2, list_->getDataSources().size());
     checkDS(0, "type1", "{}", false);
     checkDS(1, "type2", "{}", false);
+    // Check the exact configuration is preserved
+    EXPECT_EQ(elem, list_->getConfiguration());
 }
 
 // Check we can pass whatever we want to the params
@@ -471,7 +501,7 @@ TEST_F(ListTest, configureParams) {
             "   \"cache\": \"off\","
             "   \"params\": ") + *param +
             "}]"));
-        list_->configure(*elem, true);
+        list_->configure(elem, true);
         EXPECT_EQ(1, list_->getDataSources().size());
         checkDS(0, "t", *param, false);
     }
@@ -561,12 +591,12 @@ TEST_F(ListTest, wrongConfig) {
         NULL
     };
     // Put something inside to see it survives the exception
-    list_->configure(*config_elem_, true);
+    list_->configure(config_elem_, true);
     checkDS(0, "test_type", "{}", false);
     for (const char** config(configs); *config; ++config) {
         SCOPED_TRACE(*config);
         ConstElementPtr elem(Element::fromJSON(*config));
-        EXPECT_THROW(list_->configure(*elem, true),
+        EXPECT_THROW(list_->configure(elem, true),
                      ConfigurableClientList::ConfigurationError);
         // Still untouched
         checkDS(0, "test_type", "{}", false);
@@ -580,7 +610,7 @@ TEST_F(ListTest, defaults) {
         "{"
         "   \"type\": \"type1\""
         "}]"));
-    list_->configure(*elem, true);
+    list_->configure(elem, true);
     EXPECT_EQ(1, list_->getDataSources().size());
     checkDS(0, "type1", "null", false);
 }
@@ -588,11 +618,11 @@ TEST_F(ListTest, defaults) {
 // Check we can call the configure multiple times, to change the configuration
 TEST_F(ListTest, reconfigure) {
     const ConstElementPtr empty(new ListElement);
-    list_->configure(*config_elem_, true);
+    list_->configure(config_elem_, true);
     checkDS(0, "test_type", "{}", false);
-    list_->configure(*empty, true);
+    list_->configure(empty, true);
     EXPECT_TRUE(list_->getDataSources().empty());
-    list_->configure(*config_elem_, true);
+    list_->configure(config_elem_, true);
     checkDS(0, "test_type", "{}", false);
 }
 
@@ -602,9 +632,9 @@ TEST_F(ListTest, dataSrcError) {
         "{"
         "   \"type\": \"error\""
         "}]"));
-    list_->configure(*config_elem_, true);
+    list_->configure(config_elem_, true);
     checkDS(0, "test_type", "{}", false);
-    EXPECT_THROW(list_->configure(*elem, true), DataSourceError);
+    EXPECT_THROW(list_->configure(elem, true), DataSourceError);
     checkDS(0, "test_type", "{}", false);
 }
 
@@ -624,7 +654,7 @@ TEST_F(ListTest, configureCacheEmpty) {
         "   \"params\": {}"
         "}]"
     ));
-    list_->configure(*elem, true);
+    list_->configure(elem, true);
     EXPECT_EQ(2, list_->getDataSources().size());
     checkDS(0, "type1", "{}", true);
     checkDS(1, "type2", "{}", false);
@@ -646,7 +676,7 @@ TEST_F(ListTest, configureCacheDisabled) {
         "   \"params\": {}"
         "}]"
     ));
-    list_->configure(*elem, false);
+    list_->configure(elem, false);
     EXPECT_EQ(2, list_->getDataSources().size());
     checkDS(0, "type1", "{}", false);
     checkDS(1, "type2", "{}", false);
@@ -661,7 +691,7 @@ TEST_F(ListTest, cacheZones) {
         "   \"cache-zones\": [\"example.org\", \"example.com\"],"
         "   \"params\": [\"example.org\", \"example.com\", \"exmaple.cz\"]"
         "}]"));
-    list_->configure(*elem, true);
+    list_->configure(elem, true);
     checkDS(0, "type1", "[\"example.org\", \"example.com\", \"exmaple.cz\"]",
             true);
 
@@ -688,7 +718,7 @@ TEST_F(ListTest, cacheZones) {
 // Check the caching handles misbehaviour from the data source and
 // misconfiguration gracefully
 TEST_F(ListTest, badCache) {
-    list_->configure(*config_elem_, true);
+    list_->configure(config_elem_, true);
     checkDS(0, "test_type", "{}", false);
     // First, the zone is not in the data source
     const ConstElementPtr elem1(Element::fromJSON("["
@@ -698,7 +728,7 @@ TEST_F(ListTest, badCache) {
         "   \"cache-zones\": [\"example.org\"],"
         "   \"params\": []"
         "}]"));
-    EXPECT_THROW(list_->configure(*elem1, true),
+    EXPECT_THROW(list_->configure(elem1, true),
                  ConfigurableClientList::ConfigurationError);
     checkDS(0, "test_type", "{}", false);
     // Now, the zone doesn't give an iterator
@@ -709,7 +739,7 @@ TEST_F(ListTest, badCache) {
         "   \"cache-zones\": [\"noiter.org\"],"
         "   \"params\": [\"noiter.org\"]"
         "}]"));
-    EXPECT_THROW(list_->configure(*elem2, true), isc::NotImplemented);
+    EXPECT_THROW(list_->configure(elem2, true), isc::NotImplemented);
     checkDS(0, "test_type", "{}", false);
     // Now, the zone returns NULL iterator
     const ConstElementPtr elem3(Element::fromJSON("["
@@ -719,7 +749,7 @@ TEST_F(ListTest, badCache) {
         "   \"cache-zones\": [\"null.org\"],"
         "   \"params\": [\"null.org\"]"
         "}]"));
-    EXPECT_THROW(list_->configure(*elem3, true), isc::Unexpected);
+    EXPECT_THROW(list_->configure(elem3, true), isc::Unexpected);
     checkDS(0, "test_type", "{}", false);
     // The autodetection of zones is not enabled
     const ConstElementPtr elem4(Element::fromJSON("["
@@ -728,7 +758,7 @@ TEST_F(ListTest, badCache) {
         "   \"cache-enable\": true,"
         "   \"params\": [\"example.org\"]"
         "}]"));
-    EXPECT_THROW(list_->configure(*elem4, true), isc::NotImplemented);
+    EXPECT_THROW(list_->configure(elem4, true), isc::NotImplemented);
     checkDS(0, "test_type", "{}", false);
 }
 
@@ -741,7 +771,7 @@ TEST_F(ListTest, masterFiles) {
         "       \".\": \"" TEST_DATA_DIR "/root.zone\""
         "   }"
         "}]"));
-    list_->configure(*elem, true);
+    list_->configure(elem, true);
 
     // It has only the cache
     EXPECT_EQ(static_cast<const DataSourceClient*>(NULL),
@@ -752,8 +782,153 @@ TEST_F(ListTest, masterFiles) {
                    true);
 
     // If cache is not enabled, nothing is loaded
-    list_->configure(*elem, false);
+    list_->configure(elem, false);
     EXPECT_EQ(0, list_->getDataSources().size());
 }
 
+// Test we can reload a zone
+TEST_F(ListTest, reloadSuccess) {
+    list_->configure(config_elem_zones_, true);
+    Name name("example.org");
+    prepareCache(0, name);
+    // Not there yet. It would be NXDOMAIN, but it is in apex and
+    // it returns NXRRSET instead.
+    EXPECT_EQ(ZoneFinder::NXRRSET,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+    // Now reload. It should be there now.
+    EXPECT_EQ(ConfigurableClientList::ZONE_RELOADED, list_->reload(name));
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
+// The cache is not enabled. The load should be rejected.
+TEST_F(ListTest, reloadNotEnabled) {
+    list_->configure(config_elem_zones_, false);
+    Name name("example.org");
+    // We put the cache in even when not enabled. This won't confuse the thing.
+    prepareCache(0, name);
+    // Not there yet. It would be NXDOMAIN, but it is in apex and
+    // it returns NXRRSET instead.
+    EXPECT_EQ(ZoneFinder::NXRRSET,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+    // Now reload. It should reject it.
+    EXPECT_EQ(ConfigurableClientList::CACHE_DISABLED, list_->reload(name));
+    // Nothing changed here
+    EXPECT_EQ(ZoneFinder::NXRRSET,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
+// Test several cases when the zone does not exist
+TEST_F(ListTest, reloadNoSuchZone) {
+    list_->configure(config_elem_zones_, true);
+    Name name("example.org");
+    // We put the cache in even when not enabled. This won't confuse the
+    // reload method, as that one looks at the real state of things, not
+    // at the configuration.
+    prepareCache(0, Name("example.com"));
+    // Not in the data sources
+    EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
+              list_->reload(Name("example.cz")));
+    // Not cached
+    EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND, list_->reload(name));
+    // Partial match
+    EXPECT_EQ(ConfigurableClientList::ZONE_NOT_FOUND,
+              list_->reload(Name("sub.example.com")));
+    // Nothing changed here - these zones don't exist
+    EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
+              list_->find(name).dsrc_client_);
+    EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
+              list_->find(Name("example.cz")).dsrc_client_);
+    EXPECT_EQ(static_cast<isc::datasrc::DataSourceClient*>(NULL),
+              list_->find(Name("sub.example.com"), true).dsrc_client_);
+    // Not reloaded
+    EXPECT_EQ(ZoneFinder::NXRRSET,
+              list_->find(Name("example.com")).finder_->
+              find(Name("example.com"), RRType::SOA())->code);
+}
+
+// Check we gracefuly throw an exception when a zone disappeared in
+// the underlying data source when we want to reload it
+TEST_F(ListTest, reloadZoneGone) {
+    list_->configure(config_elem_, true);
+    Name name("example.org");
+    // We put in a cache for non-existant zone. This emulates being loaded
+    // and then the zone disappearing. We prefill the cache, so we can check
+    // it.
+    prepareCache(0, name, true);
+    // The zone contains something
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+    // The zone is not there, so abort the reload.
+    EXPECT_THROW(list_->reload(name), DataSourceError);
+    // The zone is not hurt.
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
+// The underlying data source throws. Check we don't modify the state.
+TEST_F(ListTest, reloadZoneThrow) {
+    list_->configure(config_elem_zones_, true);
+    Name name("noiter.org");
+    prepareCache(0, name, true);
+    // The zone contains stuff now
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+    // The iterator throws, so abort the reload.
+    EXPECT_THROW(list_->reload(name), isc::NotImplemented);
+    // The zone is not hurt.
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
+TEST_F(ListTest, reloadNullIterator) {
+    list_->configure(config_elem_zones_, true);
+    Name name("null.org");
+    prepareCache(0, name, true);
+    // The zone contains stuff now
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+    // The iterator throws, so abort the reload.
+    EXPECT_THROW(list_->reload(name), isc::Unexpected);
+    // The zone is not hurt.
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              list_->find(name).finder_->find(name, RRType::SOA())->code);
+}
+
+// Test we can reload the master files too (special-cased)
+TEST_F(ListTest, reloadMasterFile) {
+    const char* const install_cmd = INSTALL_PROG " -c " TEST_DATA_DIR
+        "/root.zone " TEST_DATA_BUILDDIR "/root.zone.copied";
+    if (system(install_cmd) != 0) {
+        // any exception will do, this is failure in test setup, but
+        // nice to show the command that fails, and shouldn't be caught
+        isc_throw(isc::Exception,
+          "Error setting up; command failed: " << install_cmd);
+    }
+
+    const ConstElementPtr elem(Element::fromJSON("["
+        "{"
+        "   \"type\": \"MasterFiles\","
+        "   \"cache-enable\": true,"
+        "   \"params\": {"
+        "       \".\": \"" TEST_DATA_BUILDDIR "/root.zone.copied\""
+        "   }"
+        "}]"));
+    list_->configure(elem, true);
+    // Add a record that is not in the zone
+    EXPECT_EQ(ZoneFinder::NXDOMAIN,
+              list_->find(Name(".")).finder_->find(Name("nosuchdomain"),
+                                                   RRType::TXT())->code);
+    ofstream f;
+    f.open(TEST_DATA_BUILDDIR "/root.zone.copied", ios::out | ios::app);
+    f << "nosuchdomain.\t\t3600\tIN\tTXT\ttest" << std::endl;
+    f.close();
+    // Do the reload.
+    EXPECT_EQ(ConfigurableClientList::ZONE_RELOADED, list_->reload(Name(".")));
+    // It is here now.
+    EXPECT_EQ(ZoneFinder::SUCCESS,
+              list_->find(Name(".")).finder_->find(Name("nosuchdomain"),
+                                                   RRType::TXT())->code);
+}
+
 }
diff --git a/src/lib/python/isc/datasrc/configurableclientlist_python.cc b/src/lib/python/isc/datasrc/configurableclientlist_python.cc
index 5db3a5a..81da7d8 100644
--- a/src/lib/python/isc/datasrc/configurableclientlist_python.cc
+++ b/src/lib/python/isc/datasrc/configurableclientlist_python.cc
@@ -95,7 +95,7 @@ ConfigurableClientList_configure(PyObject* po_self, PyObject* args) {
         if (PyArg_ParseTuple(args, "si", &configuration, &allow_cache)) {
             const isc::data::ConstElementPtr
                 element(isc::data::Element::fromJSON(string(configuration)));
-            self->cppobj->configure(*element, allow_cache);
+            self->cppobj->configure(element, allow_cache);
             Py_RETURN_NONE;
         } else {
             return (NULL);
diff --git a/src/lib/python/isc/server_common/auth_command.py b/src/lib/python/isc/server_common/auth_command.py
index eb9c892..493d5fb 100644
--- a/src/lib/python/isc/server_common/auth_command.py
+++ b/src/lib/python/isc/server_common/auth_command.py
@@ -26,9 +26,7 @@ AUTH_MODULE_NAME = 'Auth'
 def auth_loadzone_command(module_cc, zone_name, zone_class):
     '''Create a 'loadzone' command with a given zone for Auth server.
 
-    This function checks the Auth module configuration to see if it
-    servers a given zone via an in-memory data source on top of SQLite3
-    data source, and, if so, generate an inter-module command for Auth
+    This function generates an inter-module command for Auth
     to force it to reload the zone.
 
     Parameters:
@@ -38,9 +36,7 @@ def auth_loadzone_command(module_cc, zone_name, zone_class):
     zone_class (isc.dns.RRClass): the RR class of the zone to be possibly
       reloaded.
 
-    Return: a CC command message for the reload if the zone is found;
-      otherwise None.
-
+    Return: a CC command message for the reload.
     '''
     # Note: this function was originally a dedicated subroutine of xfrin,
     # but was moved here so it can be shared by some other modules
@@ -50,41 +46,12 @@ def auth_loadzone_command(module_cc, zone_name, zone_class):
     # deprecated (which is a more likely scenario).  For this reason, the
     # corresponding tests were still kept in xfrin.
 
-    datasources, is_default =\
-        module_cc.get_remote_config_value(AUTH_MODULE_NAME, "datasources")
-    if is_default:
-        return None
-    for d in datasources:
-        if "type" not in d:
-            continue
-        try:
-            if "class" in d:
-                dclass = RRClass(d["class"])
-            else:
-                dclass = RRClass("IN")
-        except InvalidRRClass as err:
-            logger.info(PYSERVER_COMMON_AUTH_CONFIG_RRCLASS_ERROR, err)
-            continue
-
-        if d["type"].lower() == "memory" and dclass == zone_class:
-            for zone in d["zones"]:
-                if "filetype" not in zone:
-                    continue
-                if "origin" not in zone:
-                    continue
-                if "filetype" not in zone:
-                    continue
-                try:
-                    name = Name(zone["origin"])
-                except (EmptyLabel, TooLongLabel, BadLabelType, BadEscape,
-                        TooLongName, IncompleteName):
-                    logger.info(PYSERVER_COMMON_AUTH_CONFIG_NAME_PARSER_ERROR,
-                                err)
-                    continue
+    # Note: The function got very simplified by #1976. There's plan to move
+    # to notification-driven approach, at which point the function would
+    # be changed a lot.
 
-                if zone["filetype"].lower() == "sqlite3" and name == zone_name:
-                    param = {"origin": zone_name.to_text(),
-                             "class": zone_class.to_text(),
-                             "datasrc": d["type"]}
-                    return create_command("loadzone", param)
-    return None
+    param = {
+        "origin": zone_name.to_text(),
+        "class": zone_class.to_text()
+    }
+    return create_command("loadzone", param)
diff --git a/src/lib/python/isc/server_common/server_common_messages.mes b/src/lib/python/isc/server_common/server_common_messages.mes
index 9eab129..bd4e3cc 100644
--- a/src/lib/python/isc/server_common/server_common_messages.mes
+++ b/src/lib/python/isc/server_common/server_common_messages.mes
@@ -21,12 +21,6 @@
 # have that at this moment. So when adding a message, make sure that
 # the name is not already used in src/lib/config/config_messages.mes
 
-% PYSERVER_COMMON_AUTH_CONFIG_NAME_PARSER_ERROR Invalid name when parsing Auth configuration: %1
-There was an invalid name when parsing Auth configuration.
-
-% PYSERVER_COMMON_AUTH_CONFIG_RRCLASS_ERROR Invalid RRClass when parsing Auth configuration: %1
-There was an invalid RR class when parsing Auth configuration.
-
 % PYSERVER_COMMON_DNS_TCP_SEND_DONE completed sending TCP message to %1 (%2 bytes in total)
 Debug message.  A complete DNS message has been successfully
 transmitted over a TCP connection, possibly after multiple send
diff --git a/tests/lettuce/configurations/ddns/ddns.config.orig b/tests/lettuce/configurations/ddns/ddns.config.orig
index 80b92f7..93e7c1c 100644
--- a/tests/lettuce/configurations/ddns/ddns.config.orig
+++ b/tests/lettuce/configurations/ddns/ddns.config.orig
@@ -27,6 +27,18 @@
             }
         ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "sqlite3",
+                    "params": {
+                        "database_file": "data/ddns/example.org.sqlite3"
+                    }
+                }
+            ]
+        }
+    },
     "Boss": {
         "components": {
             "b10-xfrout": {
diff --git a/tests/lettuce/configurations/ddns/noddns.config.orig b/tests/lettuce/configurations/ddns/noddns.config.orig
index bf89537..7a9a947 100644
--- a/tests/lettuce/configurations/ddns/noddns.config.orig
+++ b/tests/lettuce/configurations/ddns/noddns.config.orig
@@ -17,21 +17,24 @@
                 "port": 47806,
                 "address": "127.0.0.1"
             }
-        ],
-        "datasources": [
-            {
-                "type": "memory",
-                "class": "IN",
-                "zones": [
-                    {
-                        "origin": "example.org",
-                        "filetype": "sqlite3",
-                        "file": "data/ddns/example.org.sqlite3"
-                    }
-                ]
-            }
         ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "sqlite3",
+                    "params": {
+                        "database_file": "data/ddns/example.org.sqlite3"
+                    },
+                    "cache-enable": true,
+                    "cache-zones": [
+                        "example.org"
+                    ]
+                }
+            ]
+        }
+    },
     "Boss": {
         "components": {
             "b10-xfrout": {"kind": "dispensable"},
diff --git a/tests/lettuce/configurations/example.org.config.orig b/tests/lettuce/configurations/example.org.config.orig
index fadb3e2..c5545ed 100644
--- a/tests/lettuce/configurations/example.org.config.orig
+++ b/tests/lettuce/configurations/example.org.config.orig
@@ -14,6 +14,18 @@
             "address": "127.0.0.1"
         } ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "sqlite3",
+                    "params": {
+                        "database_file": "data/example.org.sqlite3"
+                    }
+                }
+            ]
+        }
+    },
     "Boss": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
diff --git a/tests/lettuce/configurations/example.org.inmem.config b/tests/lettuce/configurations/example.org.inmem.config
index 6418c65..7ea34b3 100644
--- a/tests/lettuce/configurations/example.org.inmem.config
+++ b/tests/lettuce/configurations/example.org.inmem.config
@@ -1,4 +1,31 @@
-{"version": 2, "Logging": {"loggers": [{"severity": "DEBUG", "name": "*", "debuglevel": 99}]}, "Auth": {"database_file": "", "listen_on": [{"port": 47806, "address": "127.0.0.1"}], "datasources": [{"zones": [{"origin": "example.org", "file": "data/example.org"}], "type": "memory"}]},
+{
+    "version": 2,
+    "Logging": {
+        "loggers": [{
+            "severity": "DEBUG",
+            "name": "*",
+            "debuglevel": 99
+        }]
+    },
+    "Auth": {
+        "listen_on": [{
+            "port": 47806,
+            "address": "127.0.0.1"
+        }]
+    },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "MasterFiles",
+                    "cache-enable": true,
+                    "params": {
+                        "example.org": "data/example.org"
+                    }
+                }
+            ]
+        }
+    },
     "Boss": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
diff --git a/tests/lettuce/configurations/example2.org.config b/tests/lettuce/configurations/example2.org.config
index 25314dc..eeb9733 100644
--- a/tests/lettuce/configurations/example2.org.config
+++ b/tests/lettuce/configurations/example2.org.config
@@ -15,6 +15,18 @@
             "address": "::1"
         } ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "sqlite3",
+                    "params": {
+                        "database_file": "data/example.org.sqlite3"
+                    }
+                }
+            ]
+        }
+    },
     "Boss": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
diff --git a/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf b/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf
index 8571015..107c53f 100644
--- a/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf
+++ b/tests/lettuce/configurations/inmemory_over_sqlite3/secondary.conf
@@ -8,19 +8,27 @@
         } ]
     },
     "Auth": {
-        "datasources": [ {
-            "type": "memory",
-            "zones": [ {
-                "origin": "example.org",
-                "file": "data/example.org.sqlite3",
-	        "filetype": "sqlite3"
-            } ]
-	} ],
         "listen_on": [ {
             "port": 47806,
             "address": "127.0.0.1"
         } ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "sqlite3",
+                    "params": {
+                        "database_file": "data/example.org.sqlite3"
+                    },
+                    "cache-enable": true,
+                    "cache-zones": [
+                        "example.org"
+                    ]
+                }
+            ]
+        }
+    },
     "Boss": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
diff --git a/tests/lettuce/configurations/ixfr-out/testset1-config.db b/tests/lettuce/configurations/ixfr-out/testset1-config.db
index 1c1b990..e78c84a 100644
--- a/tests/lettuce/configurations/ixfr-out/testset1-config.db
+++ b/tests/lettuce/configurations/ixfr-out/testset1-config.db
@@ -1,4 +1,56 @@
-{"Xfrin": {"zones": [{"use_ixfr": true, "class": "IN", "name": "example.com.", "master_addr": "178.18.82.80"}]}, "version": 2, "Logging": {"loggers": [{"debuglevel": 99, "severity": "DEBUG", "output_options": [{"output": "stderr", "flush": true}], "name": "*"}]}, "Auth": {"database_file": "data/ixfr-out/zones.sqlite3", "listen_on": [{"port": 47806, "address": "::"}, {"port": 47806, "address": "0.0.0.0"}]},
+{
+    "Xfrin": {
+        "zones": [
+            {
+                "use_ixfr": true,
+                "class": "IN",
+                "name": "example.com.",
+                "master_addr": "178.18.82.80"
+            }
+        ]
+    },
+    "version": 2,
+    "Logging": {
+        "loggers":
+            [
+                {
+                    "debuglevel": 99,
+                    "severity": "DEBUG",
+                    "output_options": [
+                        {
+                            "output": "stderr",
+                            "flush": true
+                        }
+                    ],
+                    "name": "*"
+                }
+        ]
+    },
+    "Auth": {
+        "database_file": "data/ixfr-out/zones.sqlite3",
+        "listen_on": [
+            {
+                "port": 47806,
+                "address": "::"
+            },
+            {
+                "port": 47806,
+                "address": "0.0.0.0"
+            }
+        ]
+    },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "sqlite3",
+                    "params": {
+                        "database_file": "data/ixfr-out/zones.sqlite3"
+                    }
+                }
+            ]
+        }
+    },
     "Boss": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
diff --git a/tests/lettuce/configurations/multi_instance/multi_auth.config.orig b/tests/lettuce/configurations/multi_instance/multi_auth.config.orig
index 35b8e72..fe482f9 100644
--- a/tests/lettuce/configurations/multi_instance/multi_auth.config.orig
+++ b/tests/lettuce/configurations/multi_instance/multi_auth.config.orig
@@ -14,6 +14,16 @@
             "address": "127.0.0.1"
         } ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [{
+                "type": "sqlite3",
+                "params": {
+                    "database_file": "data/test_nonexistent_db.sqlite3"
+                }
+            }]
+        }
+    },
     "Boss": {
         "components": {
             "b10-auth-2": {"kind": "dispensable", "special": "auth"},
diff --git a/tests/lettuce/configurations/no_db_file.config b/tests/lettuce/configurations/no_db_file.config
index fc0a25d..bc4ff5f 100644
--- a/tests/lettuce/configurations/no_db_file.config
+++ b/tests/lettuce/configurations/no_db_file.config
@@ -15,6 +15,18 @@
             "address": "127.0.0.1"
         } ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "sqlite3",
+                    "params": {
+                        "database_file": "data/test_nonexistent_db.sqlite3"
+                    }
+                }
+            ]
+        }
+    },
     "Boss": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
diff --git a/tests/lettuce/configurations/nsec3/nsec3_auth.config b/tests/lettuce/configurations/nsec3/nsec3_auth.config
index 94514c0..618c5ef 100644
--- a/tests/lettuce/configurations/nsec3/nsec3_auth.config
+++ b/tests/lettuce/configurations/nsec3/nsec3_auth.config
@@ -1 +1,36 @@
-{"version": 2, "Logging": {"loggers": [{"severity": "DEBUG", "name": "*", "debuglevel": 99}]}, "Auth": {"datasources": [{"zones": [{"origin": "example.", "file": "configurations/nsec3/rfc5155-example.zone.signed"}], "type": "memory"}], "listen_on": [{"port": 47806, "address": "0.0.0.0"}]}, "Boss": {"components": {"b10-auth": {"kind": "needed", "special": "auth"}, "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}}}}
+{
+    "version": 2,
+    "Logging": {
+        "loggers": [
+            {
+                "severity": "DEBUG",
+                "name": "*", "debuglevel": 99
+            }
+        ]
+    },
+    "Auth": {
+        "datasources": [
+            {"zones": [{"origin": "example.", "file": "configurations/nsec3/rfc5155-example.zone.signed"}], "type": "memory"}],
+            "listen_on": [{"port": 47806, "address": "0.0.0.0"}
+        ]
+    },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "MasterFiles",
+                    "cache-enable": true,
+                    "params": {
+                        "example.": "configurations/nsec3/rfc5155-example.zone.signed"
+                    }
+                }
+            ]
+        }
+    },
+    "Boss": {
+        "components": {
+            "b10-auth": {"kind": "needed", "special": "auth"},
+            "b10-cmdctl": {"kind": "needed", "special": "cmdctl"}
+        }
+    }
+}
diff --git a/tests/lettuce/configurations/xfrin/inmem_slave.conf b/tests/lettuce/configurations/xfrin/inmem_slave.conf
index 9b69300..cc1c997 100644
--- a/tests/lettuce/configurations/xfrin/inmem_slave.conf
+++ b/tests/lettuce/configurations/xfrin/inmem_slave.conf
@@ -9,20 +9,27 @@
     },
     "Auth": {
         "database_file": "data/inmem-xfrin.sqlite3",
-        "datasources": [ {
-            "type": "memory",
-            "class": "IN",
-            "zones": [ {
-                "origin": "example.org",
-                "file": "data/inmem-xfrin.sqlite3",
-                "filetype": "sqlite3"
-            } ]
-        } ],
         "listen_on": [ {
             "address": "::1",
             "port": 47806
         } ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [
+                {
+                    "type": "sqlite3",
+                    "params": {
+                        "database_file": "data/inmem-xfrin.sqlite3"
+                    },
+                    "cache-enable": true,
+                    "cache-zones": [
+                        "example.org"
+                    ]
+                }
+            ]
+        }
+    },
     "Boss": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
diff --git a/tests/lettuce/configurations/xfrin/retransfer_master.conf b/tests/lettuce/configurations/xfrin/retransfer_master.conf
index 378cff9..dd29ac8 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_master.conf
+++ b/tests/lettuce/configurations/xfrin/retransfer_master.conf
@@ -14,6 +14,16 @@
             "port": 47807
         } ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [{
+                "type": "sqlite3",
+                "params": {
+                    "database_file": "data/example.org.sqlite3"
+                }
+            }]
+        }
+    },
     "Xfrout": {
         "zone_config": [ {
             "origin": "example.org"
diff --git a/tests/lettuce/configurations/xfrin/retransfer_slave.conf b/tests/lettuce/configurations/xfrin/retransfer_slave.conf
index 260147d..cef04cf 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_slave.conf
+++ b/tests/lettuce/configurations/xfrin/retransfer_slave.conf
@@ -14,6 +14,16 @@
             "port": 47806
         } ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [{
+                "type": "sqlite3",
+                "params": {
+                    "database_file": "data/test_nonexistent_db.sqlite3"
+                }
+            }]
+        }
+    },
     "Boss": {
         "components": {
             "b10-auth": { "kind": "needed", "special": "auth" },
diff --git a/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf b/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf
index 57244a4..d977c58 100644
--- a/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf
+++ b/tests/lettuce/configurations/xfrin/retransfer_slave_notify.conf
@@ -14,6 +14,16 @@
             "port": 47806
         } ]
     },
+    "data_sources": {
+        "classes": {
+            "IN": [{
+                "type": "sqlite3",
+                "params": {
+                    "database_file": "data/xfrin-notify.sqlite3"
+                }
+            }]
+        }
+    },
     "Xfrin": {
         "zones": [ {
             "name": "example.org",
diff --git a/tests/lettuce/features/example.feature b/tests/lettuce/features/example.feature
index 685cf8b..ecfdcc3 100644
--- a/tests/lettuce/features/example.feature
+++ b/tests/lettuce/features/example.feature
@@ -160,12 +160,12 @@ Feature: Example feature
 
         A query for www.example.org should have rcode NOERROR
         Wait for new bind10 stderr message AUTH_SEND_NORMAL_RESPONSE
-        Then set bind10 configuration Auth/database_file to data/empty_db.sqlite3
-        And wait for new bind10 stderr message DATASRC_SQLITE_OPEN
+        Then set bind10 configuration data_sources/classes/IN[0]/params to {"database_file": "data/empty_db.sqlite3"}
+        And wait for new bind10 stderr message DATASRC_SQLITE_CONNOPEN
         A query for www.example.org should have rcode REFUSED
         Wait for new bind10 stderr message AUTH_SEND_NORMAL_RESPONSE
-        Then set bind10 configuration Auth/database_file to data/example.org.sqlite3
-        And wait for new bind10 stderr message DATASRC_SQLITE_OPEN
+        Then set bind10 configuration data_sources/classes/IN[0]/params to {"database_file": "data/example.org.sqlite3"}
+        And wait for new bind10 stderr message DATASRC_SQLITE_CONNOPEN
         A query for www.example.org should have rcode NOERROR
 
     Scenario: two bind10 instances
@@ -186,8 +186,8 @@ Feature: Example feature
         The SOA serial for example.org at 127.0.0.1:47806 should be 1234
         The SOA serial for example.org at ::1:47807 should be 1234
 
-        Then set bind10 configuration Auth/database_file to data/empty_db.sqlite3
-        And wait for bind10_one stderr message DATASRC_SQLITE_OPEN
+        Then set bind10 configuration data_sources/classes/IN[0]/params to {"database_file": "data/empty_db.sqlite3"}
+        And wait for bind10_one stderr message DATASRC_SQLITE_CONNOPEN
 
         A query for www.example.org to 127.0.0.1:47806 should have rcode REFUSED
         A query for www.example.org to [::1]:47807 should have rcode NOERROR
diff --git a/tests/lettuce/features/terrain/bind10_control.py b/tests/lettuce/features/terrain/bind10_control.py
index 248c6ec..5829339 100644
--- a/tests/lettuce/features/terrain/bind10_control.py
+++ b/tests/lettuce/features/terrain/bind10_control.py
@@ -52,7 +52,7 @@ def start_bind10(step, config_file, cmdctl_port, msgq_sockfile, process_name):
     It will also fail if there is a running process with the given process_name
     already.
     """
-    args = [ 'bind10', '-n', '-v' ]
+    args = [ 'bind10', '-v' ]
     if config_file is not None:
         args.append('-p')
         args.append("configurations/")
diff --git a/tests/system/bindctl/nsx1/b10-config.db.template.in b/tests/system/bindctl/nsx1/b10-config.db.template.in
index 7a3647c..4c0b6dc 100644
--- a/tests/system/bindctl/nsx1/b10-config.db.template.in
+++ b/tests/system/bindctl/nsx1/b10-config.db.template.in
@@ -3,5 +3,25 @@
    "listen_on": [{"address": "10.53.0.1", "port": 53210}],
    "database_file": "@abs_builddir@/zone.sqlite3",
    "statistics-interval": 1
+ },
+ "data_sources": {
+    "classes": {
+        "IN": [{
+            "type": "sqlite3",
+            "params": {
+                "database_file": "@abs_builddir@/zone.sqlite3"
+            }
+        }]
+    }
+ },
+ "Logging": {
+     "loggers": [
+        {
+            "name": "*",
+            "severity": "DEBUG",
+            "output_options": [],
+            "debuglevel": 99
+        }
+     ]
  }
 }
diff --git a/tests/system/bindctl/tests.sh b/tests/system/bindctl/tests.sh
index 352642e..a49043b 100755
--- a/tests/system/bindctl/tests.sh
+++ b/tests/system/bindctl/tests.sh
@@ -108,9 +108,9 @@ if [ $status != 0 ]; then echo "I:failed"; fi
 n=`expr $n + 1`
 
 echo "I:Changing the data source from sqlite3 to in-memory ($n)"
-DATASRC_SPEC='[{"type": "memory", "zones": [{"origin": "com","file":'
-DATASRC_SPEC="${DATASRC_SPEC} \"${TEST_TOP}/bindctl/nsx1/example-normalized.db\"}]}]"
-echo "config set Auth/datasources ${DATASRC_SPEC}
+DATASRC_SPEC='{"type": "MasterFiles", "cache-enable": true, "params": {"com":'
+DATASRC_SPEC="${DATASRC_SPEC} \"${TEST_TOP}/bindctl/nsx1/example-normalized.db\"}}"
+echo "config set data_sources/classes/IN[0] ${DATASRC_SPEC}
 config commit
 quit
 " | $RUN_BINDCTL \
diff --git a/tests/system/glue/example.good b/tests/system/glue/example.good
index 3b7bbb8..b6d5708 100644
--- a/tests/system/glue/example.good
+++ b/tests/system/glue/example.good
@@ -15,5 +15,8 @@ example.			172800	IN	NS	NS.example.
 ;; ADDITIONAL SECTION:
 NS.example.		172800	IN	A	192.0.2.1
 NS.example.		172800	IN	A	192.0.2.2
-NS1.example.COM.	172800	IN	A	192.0.2.101
-NS1.example.COM.		172800	IN	AAAA	2001:db8::1
+NS1.example.COM.	172800	IN	A	192.0.2.3
+;; These are not used now - they are in a different master file
+;; than the answer.
+; NS1.example.COM.	172800	IN	A	192.0.2.101
+; NS1.example.COM.		172800	IN	AAAA	2001:db8::1
diff --git a/tests/system/glue/nsx1/b10-config.db.in b/tests/system/glue/nsx1/b10-config.db.in
index 660183b..5f93f3b 100644
--- a/tests/system/glue/nsx1/b10-config.db.in
+++ b/tests/system/glue/nsx1/b10-config.db.in
@@ -3,6 +3,26 @@
    "listen_on": [{"address": "10.53.0.1", "port": 53210}],
    "database_file": "@abs_builddir@/zone.sqlite3"
  },
+ "data_sources": {
+    "classes": {
+        "IN": [{
+            "type": "sqlite3",
+            "params": {
+                "database_file": "@abs_builddir@/zone.sqlite3"
+            }
+        }]
+    }
+ },
+ "Logging": {
+     "loggers": [
+        {
+            "name": "*",
+            "severity": "DEBUG",
+            "output_options": [],
+            "debuglevel": 99
+        }
+     ]
+ },
  "Boss": {
    "components": {
      "b10-auth": {"kind": "needed", "special": "auth" },
diff --git a/tests/system/glue/nsx1/root.db b/tests/system/glue/nsx1/root.db
index e43f2d2..271a4d8 100644
--- a/tests/system/glue/nsx1/root.db
+++ b/tests/system/glue/nsx1/root.db
@@ -37,8 +37,6 @@ example.			172800	IN	NS	NS.example.
 example.			172800	IN	NS	NS1.example.COM.
 NS.example.			172800	IN	A	192.0.2.1
 NS.example.			172800	IN	A	192.0.2.2
-; this "glue" is below a zone cut for com.  BIND 9 still uses it for
-; the delegation to example.  BIND 10 (with sqlite3 data source) doesn't.
 NS1.example.COM.		172800	IN	A	192.0.2.3
 
 ;
diff --git a/tests/system/glue/tests.sh b/tests/system/glue/tests.sh
index 50b2330..dafb1ad 100755
--- a/tests/system/glue/tests.sh
+++ b/tests/system/glue/tests.sh
@@ -38,10 +38,12 @@ $DIG +norec @10.53.0.1 -p 53210 foo.bar.example. A >dig.out.$n || status=1
 $PERL $DIGCOMP example.good dig.out.$n || status=1
 n=`expr $n + 1`
 
-echo "I:testing that we find glue A RRs we are authoritative for ($n)"
-$DIG +norec @10.53.0.1 -p 53210 foo.bar.example.org. a >dig.out.$n || status=1
-$PERL $DIGCOMP auth.good dig.out.$n || status=1
-n=`expr $n + 1`
+# Disabling this test, as it checks for looking up glue in a different zone
+# finder than the answer is from. This is not supported now.
+#echo "I:testing that we find glue A RRs we are authoritative for ($n)"
+#$DIG +norec @10.53.0.1 -p 53210 foo.bar.example.org. a >dig.out.$n || status=1
+#$PERL $DIGCOMP auth.good dig.out.$n || status=1
+#n=`expr $n + 1`
 
 # We cannot do this test for BIND 10 because b10-auth doesn't act as a
 # recursive (caching) server (by design)
diff --git a/tests/system/ixfr/b10-config.db.in b/tests/system/ixfr/b10-config.db.in
index 156c959..b3b27a4 100644
--- a/tests/system/ixfr/b10-config.db.in
+++ b/tests/system/ixfr/b10-config.db.in
@@ -14,6 +14,24 @@
         }],
         "database_file": "@abs_builddir@/zone.sqlite3"
     },
+    "data_sources": {
+        "classes": {
+            "IN": [{
+                "type": "sqlite3",
+                "params": {
+                    "database_file": "@abs_builddir@/zone.sqlite3"
+                }
+            }]
+        }
+    },
+    "Logging": {
+        "loggers": [{
+            "name": "*",
+            "severity": "DEBUG",
+            "output_options": [],
+            "debuglevel": 99
+        }]
+    },
     "Zonemgr": {
         "secondary_zones": [{
             "name": "example.",



More information about the bind10-changes mailing list