BIND 10 master, updated. 385f6f102749b237bdab4854d7a30f38203a46cf [master] Merge branch 'master' of ssh://git.bind10.isc.org/var/bind10/git/bind10

BIND 10 source code commits bind10-changes at lists.isc.org
Thu Jan 24 21:59:14 UTC 2013


The branch, master has been updated
       via  385f6f102749b237bdab4854d7a30f38203a46cf (commit)
       via  ee17e979fcde48b59d91c74ac368244169065f3b (commit)
       via  5106746a3bcc359ba14fb569d6921b9cdf5b244a (commit)
       via  a333e6c631fd02410295adfac58d8681c635f782 (commit)
       via  3c7af17b0022c2404e22618bb46682991c7e6a3c (commit)
       via  bc66f6d0df259657efc39b87f33e68dd08062202 (commit)
       via  e99a3dd0a0c6e698a5b3108af017c76fa6d115ec (commit)
       via  6317823834dced610691841ee7c082249fa1f8fe (commit)
       via  c99567a4b1d2f5cfe345239c74b981efc8a4d585 (commit)
       via  1da05510732e259e76ef280d7b879fd237b746f3 (commit)
       via  ba3695664abb8b686c8fee6d25bd356b68cd5c7c (commit)
       via  07414de00e7bbbafcb73166eb969ce1fd38105ee (commit)
      from  4921791213303bf926778b79873a30fdb334d033 (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 385f6f102749b237bdab4854d7a30f38203a46cf
Merge: ee17e97 4921791
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Jan 24 13:42:14 2013 -0800

    [master] Merge branch 'master' of ssh://git.bind10.isc.org/var/bind10/git/bind10

commit ee17e979fcde48b59d91c74ac368244169065f3b
Merge: cabbe83 5106746
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Thu Jan 24 13:27:36 2013 -0800

    [master] Merge branch 'trac2309'

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

Summary of changes:
 src/bin/auth/query.cc                              |   13 +-
 src/bin/auth/tests/query_unittest.cc               |   82 ++-
 src/lib/datasrc/Makefile.am                        |    6 +-
 src/lib/datasrc/client.h                           |    3 +-
 src/lib/datasrc/database.cc                        |    2 +-
 src/lib/datasrc/memory/memory_client.h             |    2 +-
 src/lib/datasrc/memory/zone_data_loader.h          |    2 +-
 src/lib/datasrc/memory/zone_finder.cc              |    2 +-
 src/lib/datasrc/memory/zone_finder.h               |    2 +-
 src/lib/datasrc/memory_datasrc.cc                  |    3 +-
 src/lib/datasrc/rrset_collection_base.cc           |    1 +
 src/lib/datasrc/tests/client_list_unittest.cc      |    2 +-
 src/lib/datasrc/tests/database_unittest.cc         |  265 +++++++-
 src/lib/datasrc/tests/faked_nsec3.h                |    2 +-
 src/lib/datasrc/tests/memory_datasrc_unittest.cc   |    2 +-
 .../datasrc/tests/zone_finder_context_unittest.cc  |    2 +-
 src/lib/datasrc/zone.h                             |  715 +-------------------
 src/lib/datasrc/zone_finder.cc                     |   95 ++-
 src/lib/datasrc/{zone.h => zone_finder.h}          |  423 ++----------
 src/lib/datasrc/zone_finder_context.cc             |    2 +-
 src/lib/datasrc/{iterator.h => zone_iterator.h}    |    0
 src/lib/datasrc/zone_loader.cc                     |    2 +-
 src/lib/datasrc/zonetable.h                        |    2 +-
 src/lib/python/isc/datasrc/client_python.cc        |    2 +-
 src/lib/python/isc/datasrc/finder_python.cc        |    2 +-
 src/lib/python/isc/datasrc/iterator_python.cc      |    2 +-
 26 files changed, 472 insertions(+), 1164 deletions(-)
 copy src/lib/datasrc/{zone.h => zone_finder.h} (66%)
 rename src/lib/datasrc/{iterator.h => zone_iterator.h} (100%)

-----------------------------------------------------------------------
diff --git a/src/bin/auth/query.cc b/src/bin/auth/query.cc
index 5b71565..a2a4117 100644
--- a/src/bin/auth/query.cc
+++ b/src/bin/auth/query.cc
@@ -101,8 +101,11 @@ Query::ResponseCreator::create(Message& response,
 
 void
 Query::addSOA(ZoneFinder& finder) {
-    ZoneFinderContextPtr soa_ctx = finder.find(finder.getOrigin(),
-                                               RRType::SOA(), dnssec_opt_);
+    // This method is always called in finding SOA for a negative response,
+    // so we specify the use of min(RRTTL, SOA MINTTL) as specified in
+    // Section 3 of RFC2308.
+    ZoneFinderContextPtr soa_ctx = finder.findAtOrigin(RRType::SOA(), true,
+                                                       dnssec_opt_);
     if (soa_ctx->code != ZoneFinder::SUCCESS) {
         isc_throw(NoSOA, "There's no SOA record in zone " <<
             finder.getOrigin().toText());
@@ -318,11 +321,9 @@ void
 Query::addAuthAdditional(ZoneFinder& finder,
                          vector<ConstRRsetPtr>& additionals)
 {
-    const Name& origin = finder.getOrigin();
-
     // Fill in authority and addtional sections.
-    ConstZoneFinderContextPtr ns_context = finder.find(origin, RRType::NS(),
-                                                       dnssec_opt_);
+    ConstZoneFinderContextPtr ns_context =
+        finder.findAtOrigin(RRType::NS(), false, dnssec_opt_);
 
     // zone origin name should have NS records
     if (ns_context->code != ZoneFinder::SUCCESS) {
diff --git a/src/bin/auth/tests/query_unittest.cc b/src/bin/auth/tests/query_unittest.cc
index a22d2d7..9822768 100644
--- a/src/bin/auth/tests/query_unittest.cc
+++ b/src/bin/auth/tests/query_unittest.cc
@@ -90,6 +90,10 @@ private:
 #include <auth/tests/example_base_inc.cc>
 #include <auth/tests/example_nsec3_inc.cc>
 
+// This SOA is used in negative responses; its RRTTL is set to SOA's MINTTL
+const char* const soa_minttl_txt =
+    "example.com. 0 IN SOA . . 1 0 0 0 0\n";
+
 // This is used only in one pathological test case.
 const char* const zone_ds_txt =
     "example.com. 3600 IN DS 57855 5 1 "
@@ -1207,7 +1211,7 @@ TEST_P(QueryTest, nodomainANY) {
     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());
+                  NULL, soa_minttl_txt, NULL, mock_finder->getOrigin());
 }
 
 // This tests that when we need to look up Zone's apex NS records for
@@ -1345,7 +1349,7 @@ TEST_P(QueryTest, nxdomain) {
                                   Name("nxdomain.example.com"), qtype,
                                   response));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 1, 0,
-                  NULL, soa_txt, NULL, mock_finder->getOrigin());
+                  NULL, soa_minttl_txt, NULL, mock_finder->getOrigin());
 }
 
 TEST_P(QueryTest, nxdomainWithNSEC) {
@@ -1356,8 +1360,8 @@ TEST_P(QueryTest, nxdomainWithNSEC) {
                                   Name("nxdomain.example.com"), qtype,
                                   response, true));
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
-                  NULL, (string(soa_txt) +
-                         string("example.com. 3600 IN RRSIG ") +
+                  NULL, (string(soa_minttl_txt) +
+                         string("example.com. 0 IN RRSIG ") +
                          getCommonRRSIGText("SOA") + "\n" +
                          string(nsec_nxdomain_txt) + "\n" +
                          string("noglue.example.com. 3600 IN RRSIG ") +
@@ -1382,8 +1386,8 @@ TEST_P(QueryTest, nxdomainWithNSEC2) {
     query.process(*list_, Name("(.no.example.com"), qtype, response,
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
-                  NULL, (string(soa_txt) +
-                         string("example.com. 3600 IN RRSIG ") +
+                  NULL, (string(soa_minttl_txt) +
+                         string("example.com. 0 IN RRSIG ") +
                          getCommonRRSIGText("SOA") + "\n" +
                          string(nsec_mx_txt) + "\n" +
                          string("mx.example.com. 3600 IN RRSIG ") +
@@ -1407,8 +1411,8 @@ TEST_P(QueryTest, nxdomainWithNSECDuplicate) {
     query.process(*list_, Name("nx.no.example.com"), qtype, response,
                   true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 4, 0,
-                  NULL, (string(soa_txt) +
-                         string("example.com. 3600 IN RRSIG ") +
+                  NULL, (string(soa_minttl_txt) +
+                         string("example.com. 0 IN RRSIG ") +
                          getCommonRRSIGText("SOA") + "\n" +
                          string(nsec_no_txt) + "\n" +
                          string(").no.example.com. 3600 IN RRSIG ") +
@@ -1474,8 +1478,8 @@ TEST_F(QueryTestForMockOnly, nxdomainBadNSEC5) {
     query.process(*list_, Name("nxdomain.example.com"), qtype,
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 6, 0,
-                  NULL, (string(soa_txt) +
-                         string("example.com. 3600 IN RRSIG ") +
+                  NULL, (string(soa_minttl_txt) +
+                         string("example.com. 0 IN RRSIG ") +
                          getCommonRRSIGText("SOA") + "\n" +
                          string(nsec_nxdomain_txt) + "\n" +
                          string("noglue.example.com. 3600 IN RRSIG ") +
@@ -1503,7 +1507,7 @@ TEST_P(QueryTest, nxrrset) {
                                   RRType::TXT(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
-                  NULL, soa_txt, NULL, mock_finder->getOrigin());
+                  NULL, soa_minttl_txt, NULL, mock_finder->getOrigin());
 }
 
 TEST_P(QueryTest, nxrrsetWithNSEC) {
@@ -1513,7 +1517,8 @@ TEST_P(QueryTest, nxrrsetWithNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_www_txt) + "\n" +
                    string("www.example.com. 3600 IN RRSIG ") +
@@ -1534,7 +1539,8 @@ TEST_P(QueryTest, emptyNameWithNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_mx_txt) + "\n" +
                    string("mx.example.com. 3600 IN RRSIG ") +
@@ -1550,7 +1556,8 @@ TEST_P(QueryTest, nxrrsetWithoutNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n").c_str(),
                   NULL, mock_finder->getOrigin());
 }
@@ -1706,7 +1713,8 @@ TEST_P(QueryTest, wildcardNxrrsetWithDuplicateNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_wild_txt) +
                    string("*.wild.example.com. 3600 IN RRSIG ") +
@@ -1729,7 +1737,8 @@ TEST_P(QueryTest, wildcardNxrrsetWithNSEC) {
                   RRType::TXT(), response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_wild_txt_nxrrset) +
                    string("*.uwild.example.com. 3600 IN RRSIG ") +
@@ -1753,7 +1762,8 @@ TEST_P(QueryTest, wildcardNxrrsetWithNSEC3) {
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 8, 0, NULL,
                   // SOA + its RRSIG
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    // NSEC3 for the closest encloser + its RRSIG
                    string(nsec3_uwild_txt) +
@@ -1816,7 +1826,8 @@ TEST_P(QueryTest, wildcardEmptyWithNSEC) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 6, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_empty_prev_txt) +
                    string("t.example.com. 3600 IN RRSIG ") +
@@ -2043,7 +2054,7 @@ TEST_P(QueryTest, DNAME_NX_RRSET) {
                     RRType::TXT(), response));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 1, 0,
-        NULL, soa_txt, NULL, mock_finder->getOrigin());
+        NULL, soa_minttl_txt, NULL, mock_finder->getOrigin());
 }
 
 /*
@@ -2307,8 +2318,8 @@ TEST_P(QueryTest, dsAboveDelegationNoData) {
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) +
-                   string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(unsigned_delegation_nsec_txt) +
                    "unsigned-delegation.example.com. 3600 IN RRSIG " +
@@ -2324,7 +2335,8 @@ TEST_P(QueryTest, dsBelowDelegation) {
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec_apex_txt) + "\n" +
                    string("example.com. 3600 IN RRSIG ") +
@@ -2342,7 +2354,8 @@ TEST_P(QueryTest, dsBelowDelegationWithDS) {
                                   RRType::DS(), response, true));
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 2, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA")).c_str(), NULL,
                   mock_finder->getOrigin());
 }
@@ -2382,9 +2395,10 @@ TEST_F(QueryTestForMockOnly, dsAtGrandParentAndChild) {
     memory_client.addZone(ZoneFinderPtr(
                               new AlternateZoneFinder(childname)));
     query.process(*list_, childname, RRType::DS(), response, true);
+    // Note that RR TTL of SOA and its RRSIG are set to SOA MINTTL, 0
     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 " +
+                  (childname.toText() + " 0 IN SOA . . 0 0 0 0 0\n" +
+                   childname.toText() + " 0 IN RRSIG " +
                    getCommonRRSIGText("SOA") + "\n" +
                    childname.toText() + " 3600 IN NSEC " +
                    childname.toText() + " SOA NSEC RRSIG\n" +
@@ -2404,9 +2418,10 @@ TEST_F(QueryTestForMockOnly, dsAtRoot) {
                               new AlternateZoneFinder(Name::ROOT_NAME())));
     query.process(*list_, Name::ROOT_NAME(), RRType::DS(), response,
                   true);
+    // Note that RR TTL of SOA and its RRSIG are set to SOA MINTTL, 0
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(". 3600 IN SOA . . 0 0 0 0 0\n") +
-                   ". 3600 IN RRSIG " + getCommonRRSIGText("SOA") + "\n" +
+                  (string(". 0 IN SOA . . 0 0 0 0 0\n") +
+                   ". 0 IN RRSIG " + getCommonRRSIGText("SOA") + "\n" +
                    ". 3600 IN NSEC " + ". SOA NSEC RRSIG\n" +
                    ". 3600 IN RRSIG " +
                    getCommonRRSIGText("NSEC")).c_str(), NULL);
@@ -2443,7 +2458,8 @@ TEST_P(QueryTest, nxrrsetWithNSEC3) {
                   response, true);
 
     responseCheck(response, Rcode::NOERROR(), AA_FLAG, 0, 4, 0, NULL,
-                  (string(soa_txt) + string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec3_www_txt) + "\n" +
                    nsec3_hash_.calculate(Name("www.example.com.")) +
@@ -2478,7 +2494,8 @@ TEST_P(QueryTest, nxrrsetWithNSEC3_ds_exact) {
     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 ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(unsigned_delegation_nsec3_txt) + "\n" +
                    nsec3_hash_.calculate(
@@ -2500,7 +2517,8 @@ TEST_P(QueryTest, nxrrsetWithNSEC3_ds_no_exact) {
     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 ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    string(nsec3_apex_txt) + "\n" +
                    nsec3_hash_.calculate(Name("example.com.")) +
@@ -2528,8 +2546,8 @@ TEST_P(QueryTest, nxdomainWithNSEC3Proof) {
                   response, true);
     responseCheck(response, Rcode::NXDOMAIN(), AA_FLAG, 0, 8, 0, NULL,
                   // SOA + its RRSIG
-                  (string(soa_txt) +
-                   string("example.com. 3600 IN RRSIG ") +
+                  (string(soa_minttl_txt) +
+                   string("example.com. 0 IN RRSIG ") +
                    getCommonRRSIGText("SOA") + "\n" +
                    // NSEC3 for the closest encloser + its RRSIG
                    string(nsec3_apex_txt) + "\n" +
diff --git a/src/lib/datasrc/Makefile.am b/src/lib/datasrc/Makefile.am
index dc1007a..1a5776f 100644
--- a/src/lib/datasrc/Makefile.am
+++ b/src/lib/datasrc/Makefile.am
@@ -28,10 +28,12 @@ libb10_datasrc_la_SOURCES += rbnode_rrset.h
 libb10_datasrc_la_SOURCES += rbtree.h
 libb10_datasrc_la_SOURCES += exceptions.h
 libb10_datasrc_la_SOURCES += zonetable.h zonetable.cc
-libb10_datasrc_la_SOURCES += zone.h zone_finder.cc zone_finder_context.cc
+libb10_datasrc_la_SOURCES += zone.h zone_finder.h zone_finder.cc
+libb10_datasrc_la_SOURCES += zone_finder_context.cc
+libb10_datasrc_la_SOURCES += zone_iterator.h
 libb10_datasrc_la_SOURCES += result.h
 libb10_datasrc_la_SOURCES += logger.h logger.cc
-libb10_datasrc_la_SOURCES += client.h client.cc iterator.h
+libb10_datasrc_la_SOURCES += client.h client.cc
 libb10_datasrc_la_SOURCES += database.h database.cc
 libb10_datasrc_la_SOURCES += factory.h factory.cc
 libb10_datasrc_la_SOURCES += client_list.h client_list.cc
diff --git a/src/lib/datasrc/client.h b/src/lib/datasrc/client.h
index 607af05..9c5d262 100644
--- a/src/lib/datasrc/client.h
+++ b/src/lib/datasrc/client.h
@@ -21,6 +21,7 @@
 #include <boost/shared_ptr.hpp>
 
 #include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 
 /// \file
 /// Datasource clients
@@ -66,7 +67,7 @@
 namespace isc {
 namespace datasrc {
 
-// The iterator.h is not included on purpose, most application won't need it
+// zone_iterator.h is not included on purpose, most application won't need it
 class ZoneIterator;
 typedef boost::shared_ptr<ZoneIterator> ZoneIteratorPtr;
 
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index 0b010a4..0ca9226 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -18,7 +18,7 @@
 
 #include <datasrc/database.h>
 #include <datasrc/data_source.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/rrset_collection_base.h>
 
 #include <exceptions/exceptions.h>
diff --git a/src/lib/datasrc/iterator.h b/src/lib/datasrc/iterator.h
deleted file mode 100644
index e1c6929..0000000
--- a/src/lib/datasrc/iterator.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (C) 2011  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_ZONE_ITERATOR_H
-#define DATASRC_ZONE_ITERATOR_H 1
-
-#include <dns/rrset.h>
-
-#include <boost/noncopyable.hpp>
-
-#include <datasrc/zone.h>
-
-namespace isc {
-namespace datasrc {
-
-/**
- * \brief Read-only iterator to a zone.
- *
- * You can get an instance of (descendand of) ZoneIterator from
- * DataSourceClient::getIterator() method. The actual concrete implementation
- * will be different depending on the actual data source used. This is the
- * abstract interface.
- *
- * There's no way to start iterating from the beginning again or return.
- */
-class ZoneIterator : public boost::noncopyable {
-public:
-    /**
-     * \brief Destructor
-     *
-     * Virtual destructor. It is empty, but ensures the right destructor from
-     * descendant is called.
-     */
-    virtual ~ ZoneIterator() { }
-
-    /**
-     * \brief Get next RRset from the zone.
-     *
-     * This returns the next RRset in the zone as a shared pointer. The
-     * shared pointer is used to allow both accessing in-memory data and
-     * automatic memory management.
-     *
-     * Any special order is not guaranteed.
-     *
-     * While this can potentially throw anything (including standard allocation
-     * errors), it should be rare.
-     *
-     * \return Pointer to the next RRset or NULL pointer when the iteration
-     *     gets to the end of the zone.
-     */
-    virtual isc::dns::ConstRRsetPtr getNextRRset() = 0;
-
-    /**
-     * \brief Return the SOA record of the zone in the iterator context.
-     *
-     * This method returns the zone's SOA record (if any, and a valid zone
-     * should have it) in the form of an RRset object.  This SOA is identical
-     * to that (again, if any) contained in the sequence of RRsets returned
-     * by the iterator.  In that sense this method is redundant, but is
-     * provided as a convenient utility for the application of the
-     * iterator; the application may need to know the SOA serial or the
-     * SOA RR itself for the purpose of protocol handling or skipping the
-     * expensive iteration processing.
-     *
-     * If the zone doesn't have an SOA (which is broken, but some data source
-     * may allow that situation), this method returns NULL.  Also, in the
-     * normal and valid case, the SOA should have exactly one RDATA, but
-     * this API does not guarantee it as some data source may accept such an
-     * abnormal condition.  It's up to the caller whether to check the number
-     * of RDATA and how to react to the unexpected case.
-     *
-     * Each concrete derived method must ensure that the SOA returned by this
-     * method is identical to the zone's SOA returned via the iteration.
-     * For example, even if another thread or process updates the SOA while
-     * the iterator is working, the result of this method must not be
-     * affected by the update.  For database based data sources, this can
-     * be done by making the entire iterator operation as a single database
-     * transaction, but the actual implementation can differ.
-     *
-     * \exception None
-     *
-     * \return A shared pointer to an SOA RRset that would be returned
-     * from the iteration.  It will be NULL if the zone doesn't have an SOA.
-     */
-    virtual isc::dns::ConstRRsetPtr getSOA() const = 0;
-};
-
-}
-}
-#endif  // DATASRC_ZONE_ITERATOR_H
-
-// Local Variables:
-// mode: c++
-// End:
diff --git a/src/lib/datasrc/memory/memory_client.h b/src/lib/datasrc/memory/memory_client.h
index 169421f..10e8a81 100644
--- a/src/lib/datasrc/memory/memory_client.h
+++ b/src/lib/datasrc/memory/memory_client.h
@@ -17,7 +17,7 @@
 
 #include <util/memory_segment.h>
 
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/client.h>
 #include <datasrc/memory/zone_table.h>
 #include <datasrc/memory/zone_data.h>
diff --git a/src/lib/datasrc/memory/zone_data_loader.h b/src/lib/datasrc/memory/zone_data_loader.h
index db7ac3b..32ed58b 100644
--- a/src/lib/datasrc/memory/zone_data_loader.h
+++ b/src/lib/datasrc/memory/zone_data_loader.h
@@ -17,7 +17,7 @@
 
 #include <datasrc/exceptions.h>
 #include <datasrc/memory/zone_data.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <dns/name.h>
 #include <dns/rrclass.h>
 #include <util/memory_segment.h>
diff --git a/src/lib/datasrc/memory/zone_finder.cc b/src/lib/datasrc/memory/zone_finder.cc
index 7f57d8e..bc21869 100644
--- a/src/lib/datasrc/memory/zone_finder.cc
+++ b/src/lib/datasrc/memory/zone_finder.cc
@@ -17,7 +17,7 @@
 #include <datasrc/memory/treenode_rrset.h>
 #include <datasrc/memory/rdata_serialization.h>
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 #include <datasrc/data_source.h>
 #include <dns/labelsequence.h>
 #include <dns/name.h>
diff --git a/src/lib/datasrc/memory/zone_finder.h b/src/lib/datasrc/memory/zone_finder.h
index c95b5bc..254f5d2 100644
--- a/src/lib/datasrc/memory/zone_finder.h
+++ b/src/lib/datasrc/memory/zone_finder.h
@@ -18,7 +18,7 @@
 #include <datasrc/memory/zone_data.h>
 #include <datasrc/memory/treenode_rrset.h>
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 #include <dns/name.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 686dd94..45d7920 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -26,9 +26,10 @@
 #include <datasrc/rbtree.h>
 #include <datasrc/rbnode_rrset.h>
 #include <datasrc/logger.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/data_source.h>
 #include <datasrc/factory.h>
+#include <datasrc/zone_finder.h>
 
 #include <boost/function.hpp>
 #include <boost/shared_ptr.hpp>
diff --git a/src/lib/datasrc/rrset_collection_base.cc b/src/lib/datasrc/rrset_collection_base.cc
index b19f62e..9da4075 100644
--- a/src/lib/datasrc/rrset_collection_base.cc
+++ b/src/lib/datasrc/rrset_collection_base.cc
@@ -14,6 +14,7 @@
 
 #include <datasrc/rrset_collection_base.h>
 #include <datasrc/zone_loader.h>
+#include <datasrc/zone_finder.h>
 #include <exceptions/exceptions.h>
 
 using namespace isc;
diff --git a/src/lib/datasrc/tests/client_list_unittest.cc b/src/lib/datasrc/tests/client_list_unittest.cc
index 29a0daa..0838fb6 100644
--- a/src/lib/datasrc/tests/client_list_unittest.cc
+++ b/src/lib/datasrc/tests/client_list_unittest.cc
@@ -14,7 +14,7 @@
 
 #include <datasrc/client_list.h>
 #include <datasrc/client.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/data_source.h>
 #include <datasrc/memory/memory_client.h>
 #include <datasrc/memory/zone_table_segment.h>
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index 9f5ade4..c293540 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -25,8 +25,9 @@
 
 #include <datasrc/database.h>
 #include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 #include <datasrc/data_source.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/sqlite3_accessor.h>
 
 #include <testutils/dnsmessage_test.h>
@@ -1728,58 +1729,107 @@ TYPED_TEST(DatabaseClientTest, updateAfterDeleteIterator) {
 }
 
 void
-doFindTest(ZoneFinder& finder,
-           const isc::dns::Name& name,
-           const isc::dns::RRType& type,
-           const isc::dns::RRType& expected_type,
-           const isc::dns::RRTTL expected_ttl,
-           ZoneFinder::Result expected_result,
-           const std::vector<std::string>& expected_rdatas,
-           const std::vector<std::string>& expected_sig_rdatas,
-           ZoneFinder::FindResultFlags expected_flags =
-           ZoneFinder::RESULT_DEFAULT,
-           const isc::dns::Name& expected_name = isc::dns::Name::ROOT_NAME(),
-           const ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT)
+findTestCommon(ZoneFinder& finder, const isc::dns::Name& name,
+               const isc::dns::RRType& type,
+               ConstZoneFinderContextPtr actual_result,
+               const isc::dns::RRType& expected_type,
+               const isc::dns::RRTTL expected_ttl,
+               ZoneFinder::Result expected_result,
+               const std::vector<string>& expected_rdatas,
+               const std::vector<string>& expected_sig_rdatas,
+               ZoneFinder::FindResultFlags expected_flags,
+               const isc::dns::Name& expected_name,
+               const ZoneFinder::FindOptions options)
 {
-    SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
-    ConstZoneFinderContextPtr result = finder.find(name, type, options);
-    ASSERT_EQ(expected_result, result->code) << name << " " << type;
+    ASSERT_EQ(expected_result, actual_result->code) << name << " " << type;
     EXPECT_EQ((expected_flags & ZoneFinder::RESULT_WILDCARD) != 0,
-              result->isWildcard());
+              actual_result->isWildcard());
     EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC_SIGNED) != 0,
-              result->isNSECSigned());
+              actual_result->isNSECSigned());
     EXPECT_EQ((expected_flags & ZoneFinder::RESULT_NSEC3_SIGNED) != 0,
-              result->isNSEC3Signed());
-    if (!expected_rdatas.empty() && result->rrset) {
-        checkRRset(result->rrset, expected_name != Name(".") ? expected_name :
+              actual_result->isNSEC3Signed());
+    if (!expected_rdatas.empty() && actual_result->rrset) {
+        checkRRset(actual_result->rrset,
+                   expected_name != Name::ROOT_NAME() ? expected_name :
                    name, finder.getClass(), expected_type, expected_ttl,
                    expected_rdatas);
         if ((options & ZoneFinder::FIND_DNSSEC) == ZoneFinder::FIND_DNSSEC) {
-            if (!expected_sig_rdatas.empty() && result->rrset->getRRsig()) {
-                checkRRset(result->rrset->getRRsig(),
-                           expected_name != Name(".") ? expected_name : name,
+            if (!expected_sig_rdatas.empty() &&
+                actual_result->rrset->getRRsig()) {
+                checkRRset(actual_result->rrset->getRRsig(),
+                           expected_name != Name::ROOT_NAME() ?
+                           expected_name : name,
                            finder.getClass(),
                            isc::dns::RRType::RRSIG(), expected_ttl,
                            expected_sig_rdatas);
             } else if (expected_sig_rdatas.empty()) {
-                EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset->getRRsig()) <<
-                    "Unexpected RRSIG: " << result->rrset->getRRsig()->toText();
+                EXPECT_EQ(isc::dns::RRsetPtr(),
+                          actual_result->rrset->getRRsig()) <<
+                    "Unexpected RRSIG: " <<
+                    actual_result->rrset->getRRsig()->toText();
             } else {
                 ADD_FAILURE() << "Missing RRSIG";
             }
-        } else if (result->rrset->getRRsig()) {
-            EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset->getRRsig()) <<
-                "Unexpected RRSIG: " << result->rrset->getRRsig()->toText();
+        } else if (actual_result->rrset->getRRsig()) {
+            EXPECT_EQ(isc::dns::RRsetPtr(), actual_result->rrset->getRRsig())
+                << "Unexpected RRSIG: "
+                << actual_result->rrset->getRRsig()->toText();
         }
     } else if (expected_rdatas.empty()) {
-        EXPECT_EQ(isc::dns::RRsetPtr(), result->rrset) <<
-            "Unexpected RRset: " << result->rrset->toText();
+        EXPECT_EQ(isc::dns::RRsetPtr(), actual_result->rrset) <<
+            "Unexpected RRset: " << actual_result->rrset->toText();
     } else {
         ADD_FAILURE() << "Missing result";
     }
 }
 
 void
+doFindTest(ZoneFinder& finder,
+           const isc::dns::Name& name,
+           const isc::dns::RRType& type,
+           const isc::dns::RRType& expected_type,
+           const isc::dns::RRTTL expected_ttl,
+           ZoneFinder::Result expected_result,
+           const std::vector<std::string>& expected_rdatas,
+           const std::vector<std::string>& expected_sig_rdatas,
+           ZoneFinder::FindResultFlags expected_flags =
+           ZoneFinder::RESULT_DEFAULT,
+           const isc::dns::Name& expected_name = isc::dns::Name::ROOT_NAME(),
+           const ZoneFinder::FindOptions options = ZoneFinder::FIND_DEFAULT)
+{
+    SCOPED_TRACE("doFindTest " + name.toText() + " " + type.toText());
+    ConstZoneFinderContextPtr result = finder.find(name, type, options);
+    findTestCommon(finder, name, type, result, expected_type, expected_ttl,
+                   expected_result, expected_rdatas, expected_sig_rdatas,
+                   expected_flags, expected_name, options);
+}
+
+void
+doFindAtOriginTest(ZoneFinder& finder,
+                   const isc::dns::Name& origin,
+                   const isc::dns::RRType& type,
+                   const isc::dns::RRType& expected_type,
+                   const isc::dns::RRTTL expected_ttl,
+                   ZoneFinder::Result expected_result,
+                   const std::vector<std::string>& expected_rdatas,
+                   const std::vector<std::string>& expected_sig_rdatas,
+                   bool use_minttl = false,
+                   ZoneFinder::FindResultFlags expected_flags =
+                   ZoneFinder::RESULT_DEFAULT,
+                   const isc::dns::Name& expected_name =
+                   isc::dns::Name::ROOT_NAME(),
+                   const ZoneFinder::FindOptions options =
+                   ZoneFinder::FIND_DEFAULT)
+{
+    SCOPED_TRACE("doFindOriginTest " + origin.toText() + " " + type.toText());
+    ConstZoneFinderContextPtr result =
+        finder.findAtOrigin(type, use_minttl, options);
+    findTestCommon(finder, origin, type, result, expected_type, expected_ttl,
+                   expected_result, expected_rdatas, expected_sig_rdatas,
+                   expected_flags, expected_name, options);
+}
+
+void
 doFindAllTestResult(ZoneFinder& finder, const isc::dns::Name& name,
                     ZoneFinder::Result expected_result,
                     const isc::dns::RRType expected_type,
@@ -2116,6 +2166,159 @@ TYPED_TEST(DatabaseClientTest, find) {
                this->expected_rdatas_, this->expected_sig_rdatas_);
 }
 
+TYPED_TEST(DatabaseClientTest, findAtOrigin) {
+    ZoneFinderPtr finder(this->getFinder());
+
+    // Specified type of RR exists, no DNSSEC
+    this->expected_rdatas_.clear();
+    this->expected_rdatas_.push_back("ns.example.com.");
+    doFindAtOriginTest(*finder, this->zname_, RRType::NS(), RRType::NS(),
+                       this->rrttl_, ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_);
+
+    // Specified type of RR exists, with DNSSEC
+    this->expected_sig_rdatas_.push_back("NS 5 3 3600 20000101000000 "
+                                         "20000201000000 12345 example.org. "
+                                         "FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, this->zname_, RRType::NS(), RRType::NS(),
+                       this->rrttl_, ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       false, ZoneFinder::RESULT_DEFAULT, this->zname_,
+                       ZoneFinder::FIND_DNSSEC);
+
+    // Specified type of RR doesn't exist, no DNSSEC
+    this->expected_rdatas_.clear();
+    this->expected_sig_rdatas_.clear();
+    doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), this->qtype_,
+                       this->rrttl_, ZoneFinder::NXRRSET,
+                       this->expected_rdatas_, this->expected_sig_rdatas_);
+
+    // Specified type of RR doesn't exist, with DNSSEC
+    this->expected_rdatas_.clear();
+    this->expected_sig_rdatas_.clear();
+    this->expected_rdatas_.push_back(
+        "acnamesig1.example.org. A NS RRSIG NSEC");
+    this->expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+                                         "20000201000000 12345 example.org. "
+                                         "FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), RRType::NSEC(),
+                       this->rrttl_, ZoneFinder::NXRRSET,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       false, ZoneFinder::RESULT_NSEC_SIGNED,
+                       this->zname_, ZoneFinder::FIND_DNSSEC);
+
+    // Specified type of RR doesn't exist, with DNSSEC, enabling NSEC3
+    this->current_accessor_->enableNSEC3();
+    this->expected_rdatas_.clear();
+    this->expected_sig_rdatas_.clear();
+    doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), RRType::TXT(),
+                       this->rrttl_, ZoneFinder::NXRRSET,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       false, ZoneFinder::RESULT_NSEC3_SIGNED,
+                       this->zname_, ZoneFinder::FIND_DNSSEC);
+}
+
+TYPED_TEST(DatabaseClientTest, findAtOriginWithMinTTL) {
+    // First, replace the SOA of the test zone so that its RR TTL is larger
+    // than MINTTL (the original data are used in many places, so replacing
+    // them just for this doesn't make sense).
+    RRsetPtr old_soa(new RRset(this->zname_, this->qclass_, RRType::SOA(),
+                               this->rrttl_));
+    old_soa->addRdata(rdata::createRdata(RRType::SOA(), this->qclass_,
+                                         "ns1.example.org. admin.example.org. "
+                                         "1234 3600 1800 2419200 7200"));
+
+    const string new_soa_rdata = "ns1.example.org. admin.example.org. "
+        "1234 3600 1800 2419200 1200";
+    RRsetPtr new_soa(new RRset(this->zname_, this->qclass_, RRType::SOA(),
+                               this->rrttl_));
+    new_soa->addRdata(rdata::createRdata(RRType::SOA(), this->qclass_,
+                                         new_soa_rdata));
+
+    this->updater_ = this->client_->getUpdater(this->zname_, false);
+    this->updater_->deleteRRset(*old_soa);
+    this->updater_->addRRset(*new_soa);
+    this->updater_->commit();
+
+    ZoneFinderPtr finder = this->getFinder();
+
+    // Specify the use of min TTL, then the resulting TTL should be derived
+    // from the SOA MINTTL (which is smaller).
+    this->expected_rdatas_.push_back(new_soa_rdata);
+    doFindAtOriginTest(*finder, this->zname_, RRType::SOA(), RRType::SOA(),
+                       RRTTL(1200), ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true);
+
+    // If DNSSEC is requested, TTL of the RRSIG should also be the min.
+    this->expected_sig_rdatas_.push_back(
+        "SOA 5 3 3600 20000101000000 "
+        "20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, this->zname_, RRType::SOA(), RRType::SOA(),
+                       RRTTL(1200), ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true, ZoneFinder::RESULT_DEFAULT, this->zname_,
+                       ZoneFinder::FIND_DNSSEC);
+
+    // Not really intended usage, but specify the use of min TTL for non SOA.
+    // It should still work as specified.
+    this->expected_rdatas_.clear();
+    this->expected_sig_rdatas_.clear();
+    this->expected_rdatas_.push_back("ns.example.com.");
+    doFindAtOriginTest(*finder, this->zname_, RRType::NS(), RRType::NS(),
+                       RRTTL(1200), ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true);
+
+    // If we don't request the use of min TTL, the original TTL will be used.
+    this->expected_rdatas_.clear();
+    this->expected_rdatas_.push_back(new_soa_rdata);
+    doFindAtOriginTest(*finder, this->zname_, RRType::SOA(), RRType::SOA(),
+                       this->rrttl_, ZoneFinder::SUCCESS,
+                       this->expected_rdatas_, this->expected_sig_rdatas_);
+
+    // If no RRset is returned, use_minttl doesn't matter (it shouldn't cause
+    // disruption)
+    this->expected_rdatas_.clear();
+    doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), this->qtype_,
+                       this->rrttl_, ZoneFinder::NXRRSET,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true);
+
+    // If it results in NXRRSET with NSEC, and if we specify the use of min
+    // TTL, the NSEC and RRSIG should have the min TTL (again, though, this
+    // use case is not really the intended one)
+    this->expected_rdatas_.push_back(
+        "acnamesig1.example.org. A NS RRSIG NSEC");
+    this->expected_sig_rdatas_.push_back("NSEC 5 3 3600 20000101000000 "
+                                         "20000201000000 12345 example.org. "
+                                         "FAKEFAKEFAKE");
+    doFindAtOriginTest(*finder, this->zname_, RRType::TXT(), RRType::NSEC(),
+                       RRTTL(1200), ZoneFinder::NXRRSET,
+                       this->expected_rdatas_, this->expected_sig_rdatas_,
+                       true, ZoneFinder::RESULT_NSEC_SIGNED,
+                       this->zname_, ZoneFinder::FIND_DNSSEC);
+}
+
+TYPED_TEST(DatabaseClientTest, findAtOriginWithMinTTLBroken) {
+    // Similar to the previous case, but we intentionally remove the SOA
+    // (assuming the underlying data source doesn't complain about it).
+    // This will cause exception in subsequent findAtOrigin() with use_minttl
+    // being true.
+    RRsetPtr old_soa(new RRset(this->zname_, this->qclass_, RRType::SOA(),
+                               this->rrttl_));
+    old_soa->addRdata(rdata::createRdata(RRType::SOA(), this->qclass_,
+                                         "ns1.example.org. admin.example.org. "
+                                         "1234 3600 1800 2419200 7200"));
+    this->updater_ = this->client_->getUpdater(this->zname_, false);
+    this->updater_->deleteRRset(*old_soa);
+    this->updater_->commit();
+
+    EXPECT_THROW(this->getFinder()->findAtOrigin(RRType::NS(), true,
+                                                 ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+}
+
 TYPED_TEST(DatabaseClientTest, findOutOfZone) {
     // If the query name is out-of-zone it should result in an exception
     boost::shared_ptr<DatabaseClient::Finder> finder(this->getFinder());
diff --git a/src/lib/datasrc/tests/faked_nsec3.h b/src/lib/datasrc/tests/faked_nsec3.h
index 26a7b8d..13dd5fb 100644
--- a/src/lib/datasrc/tests/faked_nsec3.h
+++ b/src/lib/datasrc/tests/faked_nsec3.h
@@ -15,7 +15,7 @@
 #ifndef FAKED_NSEC3_H
 #define FAKED_NSEC3_H
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 
 #include <dns/nsec3hash.h>
 
diff --git a/src/lib/datasrc/tests/memory_datasrc_unittest.cc b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
index 85be310..81eb3ca 100644
--- a/src/lib/datasrc/tests/memory_datasrc_unittest.cc
+++ b/src/lib/datasrc/tests/memory_datasrc_unittest.cc
@@ -28,7 +28,7 @@
 #include <datasrc/client.h>
 #include <datasrc/memory_datasrc.h>
 #include <datasrc/data_source.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 
 #include "test_client.h"
 
diff --git a/src/lib/datasrc/tests/zone_finder_context_unittest.cc b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
index 85b167e..a5c8a8f 100644
--- a/src/lib/datasrc/tests/zone_finder_context_unittest.cc
+++ b/src/lib/datasrc/tests/zone_finder_context_unittest.cc
@@ -18,7 +18,7 @@
 #include <dns/name.h>
 #include <dns/rrclass.h>
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 #include <datasrc/memory/memory_client.h>
 #include <datasrc/memory/zone_table_segment.h>
 #include <datasrc/database.h>
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index 01d6a83..a75f4a0 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -24,726 +24,15 @@
 #include <datasrc/rrset_collection_base.h>
 
 #include <utility>
-#include <vector>
 
 namespace isc {
 namespace datasrc {
 
-/// \brief Out of zone exception
-///
-/// This is thrown when a method is called for a name or RRset which
-/// is not in or below the zone.
-class OutOfZone : public ZoneException {
-public:
-    OutOfZone(const char* file, size_t line, const char* what) :
-        ZoneException(file, line, what) {}
-};
-
-/// \brief The base class to search a zone for RRsets
-///
-/// The \c ZoneFinder class is an abstract base class for representing
-/// an object that performs DNS lookups in a specific zone accessible via
-/// a data source.  In general, different types of data sources (in-memory,
-/// database-based, etc) define their own derived classes of \c ZoneFinder,
-/// implementing ways to retrieve the required data through the common
-/// interfaces declared in the base class.  Each concrete \c ZoneFinder
-/// object is therefore (conceptually) associated with a specific zone
-/// of one specific data source instance.
-///
-/// The origin name and the RR class of the associated zone are available
-/// via the \c getOrigin() and \c getClass() methods, respectively.
-///
-/// The most important method of this class is \c find(), which performs
-/// the lookup for a given domain and type.  See the description of the
-/// method for details.
-///
-/// \note It's not clear whether we should request that a zone finder form a
-/// "transaction", that is, whether to ensure the finder is not susceptible
-/// to changes made by someone else than the creator of the finder.  If we
-/// don't request that, for example, two different lookup results for the
-/// same name and type can be different if other threads or programs make
-/// updates to the zone between the lookups.  We should revisit this point
-/// as we gain more experiences.
-class ZoneFinder {
-public:
-    /// Result codes of the \c find() method.
-    ///
-    /// Note: the codes are tentative.  We may need more, or we may find
-    /// some of them unnecessary as we implement more details.
-    ///
-    /// See the description of \c find() for further details of how
-    /// these results should be interpreted.
-    enum Result {
-        SUCCESS,                ///< An exact match is found.
-        DELEGATION,             ///< The search encounters a zone cut.
-        NXDOMAIN, ///< There is no domain name that matches the search name
-        NXRRSET,  ///< There is a matching name but no RRset of the search type
-        CNAME,    ///< The search encounters and returns a CNAME RR
-        DNAME    ///< The search encounters and returns a DNAME RR
-    };
-
-    /// Special attribute flags on the result of the \c find() method
-    ///
-    /// The flag values defined here are intended to signal to the caller
-    /// that it may need special handling on the result.  This is particularly
-    /// of concern when DNSSEC is requested.  For example, for negative
-    /// responses the caller would want to know whether the zone is signed
-    /// with NSEC or NSEC3 so that it can subsequently provide necessary
-    /// proof of the result.
-    ///
-    /// The caller is generally expected to get access to the information
-    /// via read-only getter methods of \c FindContext so that it won't rely
-    /// on specific details of the representation of the flags.  So these
-    /// definitions are basically only meaningful for data source
-    /// implementations.
-    enum FindResultFlags {
-        RESULT_DEFAULT = 0,       ///< The default flags
-        RESULT_WILDCARD = 1,      ///< find() resulted in a wildcard match
-        RESULT_NSEC_SIGNED = 2,   ///< The zone is signed with NSEC RRs
-        RESULT_NSEC3_SIGNED = 4   ///< The zone is signed with NSEC3 RRs
-    };
-
-    /// Find options.
-    ///
-    /// The option values are used as a parameter for \c find().
-    /// These are values of a bitmask type.  Bitwise operations can be
-    /// performed on these values to express compound options.
-    enum FindOptions {
-        FIND_DEFAULT = 0,       ///< The default options
-        FIND_GLUE_OK = 1,       ///< Allow search under a zone cut
-        FIND_DNSSEC = 2,        ///< Require DNSSEC data in the answer
-                                ///< (RRSIG, NSEC, etc.). The implementation
-                                ///< is allowed to include it even if it is
-                                ///< not set.
-        NO_WILDCARD = 4         ///< Do not try wildcard matching.
-    };
-
-protected:
-    /// \brief A convenient tuple representing a set of find() results.
-    ///
-    /// This helper structure is specifically expected to be used as an input
-    /// for the construct of the \c Context class object used by derived
-    /// ZoneFinder implementations.  This is therefore defined as protected.
-    struct ResultContext {
-        ResultContext(Result code_param,
-                      isc::dns::ConstRRsetPtr rrset_param,
-                      FindResultFlags flags_param = RESULT_DEFAULT) :
-            code(code_param), rrset(rrset_param), flags(flags_param)
-        {}
-        const Result code;
-        const isc::dns::ConstRRsetPtr rrset;
-        const FindResultFlags flags;
-    };
-
-public:
-    /// \brief A helper function to strip RRSIGs when FIND_DNSSEC is not
-    /// requested.
-    static isc::dns::ConstRRsetPtr
-    stripRRsigs(isc::dns::ConstRRsetPtr rp, const FindOptions options);
-
-    /// \brief Context of the result of a find() call.
-    ///
-    /// This class encapsulates results and (possibly) associated context
-    /// of a call to the \c find() method.   The public member variables of
-    /// this class represent the result of the call.  They are a
-    /// straightforward tuple of the result code and a pointer (and
-    /// optionally special flags) to the found RRset.
-    ///
-    /// These member variables will be initialized on construction and never
-    /// change, so for convenience we allow the applications to refer to some
-    /// of the members directly.  For some others we provide read-only accessor
-    /// methods to hide specific representation.
-    ///
-    /// Another role of this class is to provide the interface to some common
-    /// processing logic that may be necessary using the result of \c find().
-    /// Specifically, it's expected to be used in the context of DNS query
-    /// handling, where the caller would need to look into the data source
-    /// again based on the \c find() result.  For example, it would need to
-    /// get A and/or AAAA records for some of the answer or authority RRs.
-    ///
-    /// This class defines (a set of) method(s) that can be commonly used
-    /// for such purposes for any type of data source (as long as it conforms
-    /// to the public \c find() interface).  In some cases, a specific data
-    /// source implementation may want to (and can) optimize the processing
-    /// exploiting its internal data structure and the knowledge of the context
-    /// of the precedent \c find() call.  Such a data source implementation
-    /// can define a derived class of the base Context and override the
-    /// specific virtual method.
-    ///
-    /// This base class defines these common protected methods along with
-    /// some helper pure virtual methods that would be necessary for the
-    /// common methods.  If a derived class wants to use the common version
-    /// of the protected method, it needs to provide expected result through
-    /// their implementation of the pure virtual methods.
-    ///
-    /// This class object is generally expected to be associated with the
-    /// ZoneFinder that originally performed the \c find() call, and expects
-    /// the finder is valid throughout the lifetime of this object.  It's
-    /// caller's responsibility to ensure that assumption.
-    class Context {
-    public:
-        /// \brief The constructor.
-        ///
-        /// \param options The find options specified for the find() call.
-        /// \param result The result of the find() call.
-        Context(FindOptions options, const ResultContext& result) :
-            code(result.code), rrset(result.rrset),
-            flags_(result.flags), options_(options)
-        {}
-
-        /// \brief The destructor.
-        virtual ~Context() {}
-
-        const Result code;
-        const isc::dns::ConstRRsetPtr rrset;
-
-        /// Return true iff find() results in a wildcard match.
-        bool isWildcard() const { return ((flags_ & RESULT_WILDCARD) != 0); }
-
-        /// Return true when the underlying zone is signed with NSEC.
-        ///
-        /// The \c find() implementation allows this to return false if
-        /// \c FIND_DNSSEC isn't specified regardless of whether the zone
-        /// is signed or which of NSEC/NSEC3 is used.
-        ///
-        /// When this is returned, the implementation of find() must ensure
-        /// that \c rrset be a valid NSEC RRset as described in \c find()
-        /// documentation.
-        bool isNSECSigned() const {
-            return ((flags_ & RESULT_NSEC_SIGNED) != 0);
-        }
-
-        /// Return true when the underlying zone is signed with NSEC3.
-        ///
-        /// The \c find() implementation allows this to return false if
-        /// \c FIND_DNSSEC isn't specified regardless of whether the zone
-        /// is signed or which of NSEC/NSEC3 is used.
-        bool isNSEC3Signed() const {
-            return ((flags_ & RESULT_NSEC3_SIGNED) != 0);
-        }
-
-        /// \brief Find and return additional RRsets corresponding to the
-        ///        result of \c find().
-        ///
-        /// If this context is based on a normal find() call that resulted
-        /// in SUCCESS or DELEGATION, it examines the returned RRset (in many
-        /// cases NS, sometimes MX or others), searches the data source for
-        /// specified type of additional RRs for each RDATA of the RRset
-        /// (e.g., A or AAAA for the name server addresses), and stores the
-        /// result in the given vector.  The vector may not be empty; this
-        /// method appends any found RRsets to it, without touching existing
-        /// elements.
-        ///
-        /// If this context is based on a findAll() call that resulted in
-        /// SUCCESS, it performs the same process for each RRset returned in
-        /// the \c findAll() call.
-        ///
-        /// The caller specifies desired RR types of the additional RRsets
-        /// in \c requested_types.  Normally it consists of A and/or AAAA
-        /// types, but other types can be specified.
-        ///
-        /// This method is meaningful only when the precedent find()/findAll()
-        /// call resulted in SUCCESS or DELEGATION.  Otherwise this method
-        /// does nothing.
-        ///
-        /// \note The additional RRsets returned via method are limited to
-        /// ones contained in the zone which the corresponding find/findAll
-        /// call searched (possibly including glues under a zone cut where
-        /// they are applicable).  If the caller needs to get out-of-zone
-        /// additional RRsets, it needs to explicitly finds them by
-        /// identifying the corresponding zone and calls \c find() for it.
-        ///
-        /// \param requested_types A vector of RR types for desired additional
-        ///  RRsets.
-        /// \param result A vector to which any found additional RRsets are
-        /// to be inserted.
-        void getAdditional(
-            const std::vector<isc::dns::RRType>& requested_types,
-            std::vector<isc::dns::ConstRRsetPtr>& result)
-        {
-            // Perform common checks, and delegate the process to the default
-            // or specialized implementation.
-            if (code != SUCCESS && code != DELEGATION) {
-                return;
-            }
-
-            getAdditionalImpl(requested_types, result);
-        }
-
-    protected:
-        /// \brief Return the \c ZoneFinder that created this \c Context.
-        ///
-        /// A derived class implementation can return NULL if it defines
-        /// other protected methods that require a non NULL result from
-        /// this method.  Otherwise it must return a valid, non NULL pointer
-        /// to the \c ZoneFinder object.
-        ///
-        /// When returning non NULL, the ownership of the pointed object
-        /// was not transferred to the caller; it cannot be assumed to be
-        /// valid after the originating \c Context object is destroyed.
-        /// Also, the caller must not try to delete the returned object.
-        virtual ZoneFinder* getFinder() = 0;
-
-        /// \brief Return a vector of RRsets corresponding to findAll() result.
-        ///
-        /// This method returns a set of RRsets that correspond to the
-        /// returned RRsets to a prior \c findAll() call.
-        ///
-        /// A derived class implementation can return NULL if it defines
-        /// other protected methods that require a non NULL result from
-        /// this method.  Otherwise it must return a valid, non NULL pointer
-        /// to a vector that correspond to the expected set of RRsets.
-        ///
-        /// When returning non NULL, the ownership of the pointed object
-        /// was not transferred to the caller; it cannot be assumed to be
-        /// valid after the originating \c Context object is destroyed.
-        /// Also, the caller must not try to delete the returned object.
-        virtual const std::vector<isc::dns::ConstRRsetPtr>*
-        getAllRRsets() const = 0;
-
-        /// \brief Actual implementation of getAdditional().
-        ///
-        /// This base class defines a default implementation that can be
-        /// used for any type of data sources.  A data source implementation
-        /// can override it.
-        ///
-        /// The default version of this implementation requires both
-        /// \c getFinder() and \c getAllRRsets() return valid results.
-        virtual void getAdditionalImpl(
-            const std::vector<isc::dns::RRType>& requested_types,
-            std::vector<isc::dns::ConstRRsetPtr>& result);
-
-    private:
-        const FindResultFlags flags_;
-    protected:
-        const FindOptions options_;
-    };
-
-    /// \brief Generic ZoneFinder context that works for all implementations.
-    ///
-    /// This is a concrete derived class of \c ZoneFinder::Context that
-    /// only use the generic (default) versions of the protected methods
-    /// and therefore work for any data source implementation.
-    ///
-    /// A data source implementation can use this class to create a
-    /// \c Context object as a return value of \c find() or \c findAll()
-    /// method if it doesn't have to optimize specific protected methods.
-    class GenericContext : public Context {
-    public:
-        /// \brief The constructor for the normal find call.
-        ///
-        /// This constructor is expected to be called from the \c find()
-        /// method when it constructs the return value.
-        ///
-        /// \param finder The ZoneFinder on which find() is called.
-        /// \param options See the \c Context class.
-        /// \param result See the \c Context class.
-        GenericContext(ZoneFinder& finder, FindOptions options,
-                       const ResultContext& result) :
-            Context(options, result), finder_(finder)
-        {}
-
-        /// \brief The constructor for the normal findAll call.
-        ///
-        /// This constructor is expected to be called from the \c findAll()
-        /// method when it constructs the return value.
-        ///
-        /// It copies the vector that is to be returned to the caller of
-        /// \c findAll() for possible subsequent use.  Note that it cannot
-        /// simply hold a reference to the vector because the caller may
-        /// alter it after the \c findAll() call.
-        ///
-        /// \param finder The ZoneFinder on which findAll() is called.
-        /// \param options See the \c Context class.
-        /// \param result See the \c Context class.
-        /// \param all_set Reference to the vector given by the caller of
-        ///       \c findAll(), storing the RRsets to be returned.
-        GenericContext(ZoneFinder& finder, FindOptions options,
-                       const ResultContext& result,
-                       const std::vector<isc::dns::ConstRRsetPtr>& all_set) :
-            Context(options, result), finder_(finder), all_set_(all_set)
-        {}
-
-    protected:
-        virtual ZoneFinder* getFinder() { return (&finder_); }
-        virtual const std::vector<isc::dns::ConstRRsetPtr>*
-        getAllRRsets() const {
-            return (&all_set_);
-        }
-
-    private:
-        ZoneFinder& finder_;
-        std::vector<isc::dns::ConstRRsetPtr> all_set_;
-    };
-
-    ///
-    /// \name Constructors and Destructor.
-    ///
-    //@{
-protected:
-    /// The default constructor.
-    ///
-    /// This is intentionally defined as \c protected as this base class should
-    /// never be instantiated (except as part of a derived class).
-    ZoneFinder() {}
-public:
-    /// The destructor.
-    virtual ~ZoneFinder() {}
-    //@}
-
-    ///
-    /// \name Getter Methods
-    ///
-    /// These methods should never throw an exception.
-    //@{
-    /// Return the origin name of the zone.
-    virtual isc::dns::Name getOrigin() const = 0;
-
-    /// Return the RR class of the zone.
-    virtual isc::dns::RRClass getClass() const = 0;
-    //@}
-
-    ///
-    /// \name Search Methods
-    ///
-    //@{
-    /// Search the zone for a given pair of domain name and RR type.
-    ///
-    /// Each derived version of this method searches the underlying backend
-    /// for the data that best matches the given name and type.
-    /// This method is expected to be "intelligent", and identifies the
-    /// best possible answer for the search key.  Specifically,
-    ///
-    /// - If the search name belongs under a zone cut, it returns the code
-    ///   of \c DELEGATION and the NS RRset at the zone cut.
-    /// - If there is no matching name, it returns the code of \c NXDOMAIN.
-    /// - If there is a matching name but no RRset of the search type, it
-    ///   returns the code of \c NXRRSET.  This case includes the search name
-    ///   matches an empty node of the zone.
-    /// - If there is a CNAME RR of the searched name but there is no
-    ///   RR of the searched type of the name (so this type is different from
-    ///   CNAME), it returns the code of \c CNAME and that CNAME RR.
-    ///   Note that if the searched RR type is CNAME, it is considered
-    ///   a successful match, and the code of \c SUCCESS will be returned.
-    /// - If the search name matches a delegation point of DNAME, it returns
-    ///   the code of \c DNAME and that DNAME RR.
-    ///
-    /// No RRset will be returned in the \c NXDOMAIN and \c NXRRSET cases
-    /// (\c rrset member of \c FindContext will be NULL), unless DNSSEC data
-    /// are required.  See below for the cases with DNSSEC.
-    ///
-    /// The returned \c FindContext object can also provide supplemental
-    /// information about the search result via its methods returning a
-    /// boolean value.  Such information may be useful for the caller if
-    /// the caller wants to collect additional DNSSEC proofs based on the
-    /// search result.
-    ///
-    /// The \c options parameter specifies customized behavior of the search.
-    /// Their semantics is as follows (they are or bit-field):
-    ///
-    /// - \c FIND_GLUE_OK Allow search under a zone cut.  By default the search
-    ///   will stop once it encounters a zone cut.  If this option is specified
-    ///   it remembers information about the highest zone cut and continues
-    ///   the search until it finds an exact match for the given name or it
-    ///   detects there is no exact match.  If an exact match is found,
-    ///   RRsets for that name are searched just like the normal case;
-    ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
-    ///   with the information of the highest zone cut will be returned.
-    ///   Note: the term "glue" in the DNS protocol standard may sometimes
-    ///   cause confusion: some people use this term strictly for an address
-    ///   record (type AAAA or A) for the name used in the RDATA of an NS RR;
-    ///   some others seem to give it broader flexibility.  Nevertheless,
-    ///   in this API the "GLUE OK" simply means the search by find() can
-    ///   continue beyond a zone cut; the derived class implementation does
-    ///   not have to, and should not, check whether the type is an address
-    ///   record or whether the query name is pointed by some NS RR.
-    ///   It's up to the caller with which definition of "glue" the search
-    ///   result with this option should be used.
-    /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
-    ///   returned with the answer. It is allowed for the data source to
-    ///   include them even when not requested.
-    /// - \c NO_WILDCARD Do not try wildcard matching.  This option is of no
-    ///   use for normal lookups; it's intended to be used to get a DNSSEC
-    ///   proof of the non existence of any matching wildcard or non existence
-    ///   of an exact match when a wildcard match is found.
-    ///
-    /// In general, \c name is expected to be included in the zone, that is,
-    /// it should be equal to or a subdomain of the zone origin.  Otherwise
-    /// this method will return \c NXDOMAIN with an empty RRset.  But such a
-    /// case should rather be considered a caller's bug.
-    ///
-    /// \note For this reason it's probably better to throw an exception
-    /// than returning \c NXDOMAIN.  This point should be revisited in a near
-    /// future version.  In any case applications shouldn't call this method
-    /// for an out-of-zone name.
-    ///
-    /// <b>DNSSEC considerations:</b>
-    /// The result when DNSSEC data are required can be very complicated,
-    /// especially if it involves negative result or wildcard match.
-    /// Specifically, if an application calls this method for DNS query
-    /// processing with DNSSEC data, and if the search result code is
-    /// either \c NXDOMAIN or \c NXRRRSET, and/or \c isWildcard() returns
-    /// true, then the application will need to find additional NSEC or
-    /// NSEC3 records for supplemental proofs.  This method helps the
-    /// application for such post search processing.
-    ///
-    /// First, it tells the application whether the zone is signed with
-    /// NSEC or NSEC3 via the \c isNSEC(3)Signed() method.  Any sanely signed
-    /// zone should be signed with either (and only one) of these two types
-    /// of RRs; however, the application should expect that the zone could
-    /// be broken and these methods could both return false.  But this method
-    /// should ensure that not both of these methods return true.
-    ///
-    /// In case it's signed with NSEC3, there is no further information
-    /// returned from this method.
-    ///
-    /// In case it's signed with NSEC, this method will possibly return
-    /// a related NSEC RRset in the \c rrset member of \c FindContext.
-    /// What kind of NSEC is returned depends on the result code
-    /// (\c NXDOMAIN or \c NXRRSET) and on whether it's a wildcard match:
-    ///
-    /// - In case of NXDOMAIN, the returned NSEC covers the queried domain
-    ///   that proves that the query name does not exist in the zone.  Note
-    ///   that this does not necessarily prove it doesn't even match a
-    ///   wildcard (even if the result of NXDOMAIN can only happen when
-    ///   there's no matching wildcard either).  It is caller's
-    ///   responsibility to provide a proof that there is no matching
-    ///   wildcard if that proof is necessary.
-    /// - In case of NXRRSET, we need to consider the following cases
-    ///   referring to Section 3.1.3 of RFC4035:
-    ///
-    /// -# (Normal) no data: there is a matching non-wildcard name with a
-    ///    different RR type.  This is the "No Data" case of the RFC.
-    /// -# (Normal) empty non terminal: there is no matching (exact or
-    ///    wildcard) name, but there is a subdomain with an RR of the query
-    ///    name.  This is one case of "Name Error" of the RFC.
-    /// -# Wildcard empty non terminal: similar to 2a, but the empty name
-    ///    is a wildcard, and matches the query name by wildcard expansion.
-    ///    This is a special case of "Name Error" of the RFC.
-    /// -# Wildcard no data: there is no exact match name, but there is a
-    ///    wildcard name that matches the query name with a different type
-    ///    of RR.  This is the "Wildcard No Data" case of the RFC.
-    ///
-    /// In case 1, \c find() returns NSEC of the matching name.
-    ///
-    /// In case 2, \c find() will return NSEC for the interval where the
-    /// empty nonterminal lives. The end of the interval is the subdomain
-    /// causing existence of the empty nonterminal (if there's
-    /// sub.x.example.com, and no record in x.example.com, then
-    /// x.example.com exists implicitly - is the empty nonterminal and
-    /// sub.x.example.com is the subdomain causing it).  Note that this NSEC
-    /// proves not only the existence of empty non terminal name but also
-    /// the non existence of possibly matching wildcard name, because
-    /// there can be no better wildcard match than the exact matching empty
-    /// name.
-    ///
-    /// In case 3, \c find() will return NSEC for the interval where the
-    /// wildcard empty nonterminal lives.   Cases 2 and 3 are especially
-    /// complicated and confusing.  See the examples below.
-    ///
-    /// In case 4, \c find() will return NSEC of the matching wildcard name.
-    ///
-    /// Examples: if zone "example.com" has the following record:
-    /// \code
-    /// a.example.com. NSEC a.b.example.com.
-    /// \endcode
-    /// a call to \c find() for "b.example.com." with the FIND_DNSSEC option
-    /// will result in NXRRSET, and this NSEC will be returned.
-    /// Likewise, if zone "example.org" has the following record,
-    /// \code
-    /// a.example.org. NSEC x.*.b.example.org.
-    /// \endcode
-    /// a call to \c find() for "y.b.example.org" with FIND_DNSSEC will
-    /// result in NXRRSET and this NSEC; \c isWildcard() on the returned
-    /// \c FindContext object will return true.
-    ///
-    /// \exception std::bad_alloc Memory allocation such as for constructing
-    ///  the resulting RRset fails
-    /// \throw OutOfZone The Name \c name is outside of the origin of the
-    /// zone of this ZoneFinder.
-    /// \exception DataSourceError Derived class specific exception, e.g.
-    /// when encountering a bad zone configuration or database connection
-    /// failure.  Although these are considered rare, exceptional events,
-    /// it can happen under relatively usual conditions (unlike memory
-    /// allocation failure).  So, in general, the application is expected
-    /// to catch this exception, either specifically or as a result of
-    /// catching a base exception class, and handle it gracefully.
-    ///
-    /// \param name The domain name to be searched for.
-    /// \param type The RR type to be searched for.
-    /// \param options The search options.
-    /// \return A \c FindContext object enclosing the search result
-    ///         (see above).
-    virtual boost::shared_ptr<Context> find(const isc::dns::Name& name,
-                                            const isc::dns::RRType& type,
-                                            const FindOptions options
-                                            = FIND_DEFAULT) = 0;
-
-    ///
-    /// \brief Finds all RRsets in the given name.
-    ///
-    /// This function works almost exactly in the same way as the find one. The
-    /// only difference is, when the lookup is successful (eg. the code is
-    /// SUCCESS), all the RRsets residing in the named node are
-    /// copied into the \c target parameter and the rrset member of the result
-    /// is NULL. All the other (unsuccessful) cases are handled the same,
-    /// including returning delegations, NSEC/NSEC3 availability and NSEC
-    /// proofs, wildcard information etc. The options parameter works the
-    /// same way and it should conform to the same exception restrictions.
-    ///
-    /// \param name \see find, parameter name
-    /// \param target the successfull result is returned through this
-    /// \param options \see find, parameter options
-    /// \return \see find and it's result
-    virtual boost::shared_ptr<Context> findAll(
-        const isc::dns::Name& name,
-        std::vector<isc::dns::ConstRRsetPtr> &target,
-        const FindOptions options = FIND_DEFAULT) = 0;
-
-    /// A helper structure to represent the search result of \c findNSEC3().
-    ///
-    /// The idea is similar to that of \c FindContext, but \c findNSEC3() has
-    /// special interface and semantics, we use a different structure to
-    /// represent the result.
-    struct FindNSEC3Result {
-        FindNSEC3Result(bool param_matched, uint8_t param_closest_labels,
-                        isc::dns::ConstRRsetPtr param_closest_proof,
-                        isc::dns::ConstRRsetPtr param_next_proof) :
-            matched(param_matched), closest_labels(param_closest_labels),
-            closest_proof(param_closest_proof),
-            next_proof(param_next_proof)
-        {}
-
-        /// true iff closest_proof is a matching NSEC3
-        const bool matched;
-
-        /// The number of labels of the identified closest encloser.
-        const uint8_t closest_labels;
-
-        /// Either the NSEC3 for the closest provable encloser of the given
-        /// name or NSEC3 that covers the name
-        const isc::dns::ConstRRsetPtr closest_proof;
-
-        /// When non NULL, NSEC3 for the next closer name.
-        const isc::dns::ConstRRsetPtr next_proof;
-    };
-
-    /// Search the zone for the NSEC3 RR(s) that prove existence or non
-    /// existence of a give name.
-    ///
-    /// It searches the NSEC3 namespace of the zone (how that namespace is
-    /// implemented can vary in specific data source implementation) for NSEC3
-    /// RRs that match or cover the NSEC3 hash value for the given name.
-    ///
-    /// If \c recursive is false, it will first look for the NSEC3 that has
-    /// a matching hash.  If it doesn't exist, it identifies the covering NSEC3
-    /// for the hash.  In either case the search stops at that point and the
-    /// found NSEC3 RR(set) will be returned in the closest_proof member of
-    /// \c FindNSEC3Result.  \c matched is true or false depending on
-    /// the found NSEC3 is a matched one or covering one.  \c next_proof
-    /// is always NULL.  closest_labels must be equal to the number of
-    /// labels of \c name (and therefore meaningless).
-    ///
-    /// If \c recursive is true, it will continue the search toward the zone
-    /// apex (origin name) until it finds a provable encloser, that is,
-    /// an ancestor of \c name that has a matching NSEC3.  This is the closest
-    /// provable encloser of \c name as defined in RFC5155.  In this case,
-    /// if the found encloser is not equal to \c name, the search should
-    /// have seen a covering NSEC3 for the immediate child of the found
-    /// encloser.  That child name is the next closer name as defined in
-    /// RFC5155.  In this case, this method returns the NSEC3 for the
-    /// closest encloser in \c closest_proof, and the NSEC3 for the next
-    /// closer name in \c next_proof of \c FindNSEC3Result.  This set of
-    /// NSEC3 RRs provide the closest encloser proof as defined in RFC5155.
-    /// closest_labels will be set to the number of labels of the identified
-    /// closest encloser.  This will be useful when the caller needs to
-    /// construct the closest encloser name from the original \c name.
-    /// If, on the other hand, the found closest name is equal to \c name,
-    /// this method simply returns it in \c closest_proof.  \c next_proof
-    /// is set to NULL.  In all cases \c matched is set to true.
-    /// closest_labels will be set to the number of labels of \c name.
-    ///
-    /// When looking for NSEC3, this method retrieves NSEC3 parameters from
-    /// the corresponding zone to calculate hash values.  Actual implementation
-    /// of how to do this will differ in different data sources.  If the
-    /// NSEC3 parameters are not available \c DataSourceError exception
-    /// will be thrown.
-    ///
-    /// \note This implicitly means this method assumes the zone does not
-    /// have more than one set of parameters.  This assumption should be
-    /// reasonable in actual deployment and will help simplify the interface
-    /// and implementation.  But if there's a real need for supporting
-    /// multiple sets of parameters in a single zone, we will have to
-    /// extend this method so that, e.g., the caller can specify the parameter
-    /// set.
-    ///
-    /// In general, this method expects the zone is properly signed with NSEC3
-    /// RRs.  Specifically, it assumes at least the apex node has a matching
-    /// NSEC3 RR (so the search in the recursive mode must always succeed);
-    /// it also assumes that it can retrieve NSEC parameters (iterations,
-    /// algorithm, and salt) from the zone as noted above.  If these
-    /// assumptions aren't met, \c DataSourceError exception will be thrown.
-    ///
-    /// \exception OutOfZone name is not a subdomain of the zone origin
-    /// \exception DataSourceError Low-level or internal datasource errors
-    /// happened, or the zone isn't properly signed with NSEC3
-    /// (NSEC3 parameters cannot be found, no NSEC3s are available, etc).
-    /// \exception std::bad_alloc The underlying implementation involves
-    /// memory allocation and it fails
-    ///
-    /// \param name The name for which NSEC3 RRs are to be found.  It must
-    /// be a subdomain of the zone.
-    /// \param recursive Whether or not search should continue until it finds
-    /// a provable encloser (see above).
-    ///
-    /// \return The search result and whether or not the closest_proof is
-    /// a matching NSEC3, in the form of \c FindNSEC3Result object.
-    virtual FindNSEC3Result
-    findNSEC3(const isc::dns::Name& name, bool recursive) = 0;
-    //@}
-};
-
-/// \brief Operator to combine FindOptions
-///
-/// We would need to manually static-cast the options if we put or
-/// between them, which is undesired with bit-flag options. Therefore
-/// we hide the cast here, which is the simplest solution and it still
-/// provides reasonable level of type safety.
-inline ZoneFinder::FindOptions operator |(ZoneFinder::FindOptions a,
-                                          ZoneFinder::FindOptions b)
-{
-    return (static_cast<ZoneFinder::FindOptions>(static_cast<unsigned>(a) |
-                                                 static_cast<unsigned>(b)));
-}
-
-/// \brief Operator to combine FindResultFlags
-///
-/// Similar to the same operator for \c FindOptions.  Refer to the description
-/// of that function.
-inline ZoneFinder::FindResultFlags operator |(
-    ZoneFinder::FindResultFlags a,
-    ZoneFinder::FindResultFlags b)
-{
-    return (static_cast<ZoneFinder::FindResultFlags>(
-                static_cast<unsigned>(a) | static_cast<unsigned>(b)));
-}
-
-/// \brief A pointer-like type pointing to a \c ZoneFinder object.
-typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
-
-/// \brief A pointer-like type pointing to an immutable \c ZoneFinder object.
-typedef boost::shared_ptr<const ZoneFinder> ConstZoneFinderPtr;
-
-/// \brief A pointer-like type pointing to a \c ZoneFinder::Context object.
-typedef boost::shared_ptr<ZoneFinder::Context> ZoneFinderContextPtr;
-
-/// \brief A pointer-like type pointing to an immutable
-/// \c ZoneFinder::Context object.
-typedef boost::shared_ptr<ZoneFinder::Context> ConstZoneFinderContextPtr;
-
 /// \brief A forward declaration
 class RRsetCollectionBase;
 
+class ZoneFinder;
+
 /// The base class to make updates to a single zone.
 ///
 /// On construction, each derived class object will start a "transaction"
diff --git a/src/lib/datasrc/zone_finder.cc b/src/lib/datasrc/zone_finder.cc
index 562b43f..b4240c0 100644
--- a/src/lib/datasrc/zone_finder.cc
+++ b/src/lib/datasrc/zone_finder.cc
@@ -12,13 +12,14 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <datasrc/zone_finder.h>
+#include <datasrc/data_source.h>
+
 #include <dns/rdata.h>
 #include <dns/rrset.h>
 #include <dns/rrtype.h>
 #include <dns/rdataclass.h>
 
-#include <datasrc/zone.h>
-
 using namespace std;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
@@ -26,6 +27,96 @@ using namespace isc::dns::rdata;
 namespace isc {
 namespace datasrc {
 
+namespace {
+// Identify zone's SOA and return its MINTTL in the form of RRTTL.
+RRTTL
+getMinTTL(ZoneFinder& finder, ConstRRsetPtr rrset) {
+    ConstRRsetPtr soa_rrset;
+    if (rrset->getType() == RRType::SOA()) {
+        // Shortcut: if we are looking at SOA itself (which should be the
+        // case in the expected scenario), we can simply use its RDATA.
+        soa_rrset = rrset;
+    } else {
+        soa_rrset =
+            finder.findAtOrigin(RRType::SOA(), false,
+                                ZoneFinder::FIND_DEFAULT)->rrset;
+    }
+
+    // In a valid zone there is one and only one SOA RR at the origin.
+    // Otherwise either zone data or the data source implementation is broken.
+    if (!soa_rrset || soa_rrset->getRdataCount() != 1) {
+        isc_throw(DataSourceError, "Zone " << rrset->getName().toText(true)
+                  << "/" << rrset->getClass().toText() << " is broken: "
+                  << (!soa_rrset ? "no SOA" : "empty SOA"));
+    }
+
+    return (RRTTL(dynamic_cast<const generic::SOA&>(
+                      soa_rrset->getRdataIterator()->getCurrent()).
+                  getMinimum()));
+}
+
+// Make a fresh copy of given RRset, just replacing RRTTL with the given one.
+RRsetPtr
+copyRRset(const AbstractRRset& rrset, const RRTTL& ttl) {
+    RRsetPtr rrset_copy(new RRset(rrset.getName(), rrset.getClass(),
+                                  rrset.getType(), ttl));
+    for (RdataIteratorPtr rit = rrset.getRdataIterator();
+         !rit->isLast();
+         rit->next()) {
+        rrset_copy->addRdata(rit->getCurrent());
+    }
+
+    ConstRRsetPtr rrsig = rrset.getRRsig();
+    if (rrsig) {
+        RRsetPtr rrsig_copy(new RRset(rrset.getName(), rrset.getClass(),
+                                      RRType::RRSIG(), ttl));
+        for (RdataIteratorPtr rit = rrsig->getRdataIterator();
+             !rit->isLast();
+             rit->next()) {
+            rrsig_copy->addRdata(rit->getCurrent());
+        }
+        rrset_copy->addRRsig(rrsig_copy);
+    }
+
+    return (rrset_copy);
+}
+}
+
+ZoneFinderContextPtr
+ZoneFinder::findAtOrigin(const dns::RRType& type, bool use_minttl,
+                         FindOptions options)
+{
+    ZoneFinderContextPtr context = find(getOrigin(), type, options);
+
+    // If we are requested to use the min TTL and the RRset's RR TTL is larger
+    // than that, we need to make a copy of the RRset, replacing the TTL,
+    // and return a newly created context copying other parameters.
+    if (use_minttl && context->rrset) {
+        const AbstractRRset& rrset = *context->rrset;
+        const RRTTL min_ttl = getMinTTL(*this, context->rrset);
+        if (min_ttl < rrset.getTTL()) {
+            FindResultFlags flags_copy = RESULT_DEFAULT;
+            if (context->isWildcard()) {
+                flags_copy = flags_copy | RESULT_WILDCARD;
+            }
+            if (context->isNSECSigned()) {
+                flags_copy = flags_copy | RESULT_NSEC_SIGNED;
+            } else if (context->isNSEC3Signed()) {
+                flags_copy = flags_copy | RESULT_NSEC3_SIGNED;
+            }
+
+            return (ZoneFinderContextPtr(
+                        new GenericContext(*this, options,
+                                           ResultContext(context->code,
+                                                         copyRRset(rrset,
+                                                                   min_ttl),
+                                                         flags_copy))));
+        }
+    }
+
+    return (context);
+}
+
 isc::dns::ConstRRsetPtr
 ZoneFinder::stripRRsigs(isc::dns::ConstRRsetPtr rp,
                         const FindOptions options) {
diff --git a/src/lib/datasrc/zone_finder.h b/src/lib/datasrc/zone_finder.h
new file mode 100644
index 0000000..6e1cee0
--- /dev/null
+++ b/src/lib/datasrc/zone_finder.h
@@ -0,0 +1,809 @@
+// Copyright (C) 2010  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_ZONE_FINDER_H
+#define DATASRC_ZONE_FINDER_H 1
+
+#include <dns/name.h>
+#include <dns/rrset.h>
+#include <dns/rrtype.h>
+
+#include <datasrc/exceptions.h>
+#include <datasrc/result.h>
+#include <datasrc/rrset_collection_base.h>
+
+#include <utility>
+#include <vector>
+
+namespace isc {
+namespace datasrc {
+
+/// \brief Out of zone exception
+///
+/// This is thrown when a method is called for a name or RRset which
+/// is not in or below the zone.
+class OutOfZone : public ZoneException {
+public:
+    OutOfZone(const char* file, size_t line, const char* what) :
+        ZoneException(file, line, what) {}
+};
+
+/// \brief The base class to search a zone for RRsets
+///
+/// The \c ZoneFinder class is an abstract base class for representing
+/// an object that performs DNS lookups in a specific zone accessible via
+/// a data source.  In general, different types of data sources (in-memory,
+/// database-based, etc) define their own derived classes of \c ZoneFinder,
+/// implementing ways to retrieve the required data through the common
+/// interfaces declared in the base class.  Each concrete \c ZoneFinder
+/// object is therefore (conceptually) associated with a specific zone
+/// of one specific data source instance.
+///
+/// The origin name and the RR class of the associated zone are available
+/// via the \c getOrigin() and \c getClass() methods, respectively.
+///
+/// The most important method of this class is \c find(), which performs
+/// the lookup for a given domain and type.  See the description of the
+/// method for details.
+///
+/// \note It's not clear whether we should request that a zone finder form a
+/// "transaction", that is, whether to ensure the finder is not susceptible
+/// to changes made by someone else than the creator of the finder.  If we
+/// don't request that, for example, two different lookup results for the
+/// same name and type can be different if other threads or programs make
+/// updates to the zone between the lookups.  We should revisit this point
+/// as we gain more experiences.
+class ZoneFinder {
+public:
+    /// Result codes of the \c find() method.
+    ///
+    /// Note: the codes are tentative.  We may need more, or we may find
+    /// some of them unnecessary as we implement more details.
+    ///
+    /// See the description of \c find() for further details of how
+    /// these results should be interpreted.
+    enum Result {
+        SUCCESS,                ///< An exact match is found.
+        DELEGATION,             ///< The search encounters a zone cut.
+        NXDOMAIN, ///< There is no domain name that matches the search name
+        NXRRSET,  ///< There is a matching name but no RRset of the search type
+        CNAME,    ///< The search encounters and returns a CNAME RR
+        DNAME    ///< The search encounters and returns a DNAME RR
+    };
+
+    /// Special attribute flags on the result of the \c find() method
+    ///
+    /// The flag values defined here are intended to signal to the caller
+    /// that it may need special handling on the result.  This is particularly
+    /// of concern when DNSSEC is requested.  For example, for negative
+    /// responses the caller would want to know whether the zone is signed
+    /// with NSEC or NSEC3 so that it can subsequently provide necessary
+    /// proof of the result.
+    ///
+    /// The caller is generally expected to get access to the information
+    /// via read-only getter methods of \c FindContext so that it won't rely
+    /// on specific details of the representation of the flags.  So these
+    /// definitions are basically only meaningful for data source
+    /// implementations.
+    enum FindResultFlags {
+        RESULT_DEFAULT = 0,       ///< The default flags
+        RESULT_WILDCARD = 1,      ///< find() resulted in a wildcard match
+        RESULT_NSEC_SIGNED = 2,   ///< The zone is signed with NSEC RRs
+        RESULT_NSEC3_SIGNED = 4   ///< The zone is signed with NSEC3 RRs
+    };
+
+    /// Find options.
+    ///
+    /// The option values are used as a parameter for \c find().
+    /// These are values of a bitmask type.  Bitwise operations can be
+    /// performed on these values to express compound options.
+    enum FindOptions {
+        FIND_DEFAULT = 0,       ///< The default options
+        FIND_GLUE_OK = 1,       ///< Allow search under a zone cut
+        FIND_DNSSEC = 2,        ///< Require DNSSEC data in the answer
+                                ///< (RRSIG, NSEC, etc.). The implementation
+                                ///< is allowed to include it even if it is
+                                ///< not set.
+        NO_WILDCARD = 4         ///< Do not try wildcard matching.
+    };
+
+protected:
+    /// \brief A convenient tuple representing a set of find() results.
+    ///
+    /// This helper structure is specifically expected to be used as an input
+    /// for the construct of the \c Context class object used by derived
+    /// ZoneFinder implementations.  This is therefore defined as protected.
+    struct ResultContext {
+        ResultContext(Result code_param,
+                      isc::dns::ConstRRsetPtr rrset_param,
+                      FindResultFlags flags_param = RESULT_DEFAULT) :
+            code(code_param), rrset(rrset_param), flags(flags_param)
+        {}
+        const Result code;
+        const isc::dns::ConstRRsetPtr rrset;
+        const FindResultFlags flags;
+    };
+
+public:
+    /// \brief A helper function to strip RRSIGs when FIND_DNSSEC is not
+    /// requested.
+    static isc::dns::ConstRRsetPtr
+    stripRRsigs(isc::dns::ConstRRsetPtr rp, const FindOptions options);
+
+    /// \brief Context of the result of a find() call.
+    ///
+    /// This class encapsulates results and (possibly) associated context
+    /// of a call to the \c find() method.   The public member variables of
+    /// this class represent the result of the call.  They are a
+    /// straightforward tuple of the result code and a pointer (and
+    /// optionally special flags) to the found RRset.
+    ///
+    /// These member variables will be initialized on construction and never
+    /// change, so for convenience we allow the applications to refer to some
+    /// of the members directly.  For some others we provide read-only accessor
+    /// methods to hide specific representation.
+    ///
+    /// Another role of this class is to provide the interface to some common
+    /// processing logic that may be necessary using the result of \c find().
+    /// Specifically, it's expected to be used in the context of DNS query
+    /// handling, where the caller would need to look into the data source
+    /// again based on the \c find() result.  For example, it would need to
+    /// get A and/or AAAA records for some of the answer or authority RRs.
+    ///
+    /// This class defines (a set of) method(s) that can be commonly used
+    /// for such purposes for any type of data source (as long as it conforms
+    /// to the public \c find() interface).  In some cases, a specific data
+    /// source implementation may want to (and can) optimize the processing
+    /// exploiting its internal data structure and the knowledge of the context
+    /// of the precedent \c find() call.  Such a data source implementation
+    /// can define a derived class of the base Context and override the
+    /// specific virtual method.
+    ///
+    /// This base class defines these common protected methods along with
+    /// some helper pure virtual methods that would be necessary for the
+    /// common methods.  If a derived class wants to use the common version
+    /// of the protected method, it needs to provide expected result through
+    /// their implementation of the pure virtual methods.
+    ///
+    /// This class object is generally expected to be associated with the
+    /// ZoneFinder that originally performed the \c find() call, and expects
+    /// the finder is valid throughout the lifetime of this object.  It's
+    /// caller's responsibility to ensure that assumption.
+    class Context {
+    public:
+        /// \brief The constructor.
+        ///
+        /// \param options The find options specified for the find() call.
+        /// \param result The result of the find() call.
+        Context(FindOptions options, const ResultContext& result) :
+            code(result.code), rrset(result.rrset),
+            flags_(result.flags), options_(options)
+        {}
+
+        /// \brief The destructor.
+        virtual ~Context() {}
+
+        const Result code;
+        const isc::dns::ConstRRsetPtr rrset;
+
+        /// Return true iff find() results in a wildcard match.
+        bool isWildcard() const { return ((flags_ & RESULT_WILDCARD) != 0); }
+
+        /// Return true when the underlying zone is signed with NSEC.
+        ///
+        /// The \c find() implementation allows this to return false if
+        /// \c FIND_DNSSEC isn't specified regardless of whether the zone
+        /// is signed or which of NSEC/NSEC3 is used.
+        ///
+        /// When this is returned, the implementation of find() must ensure
+        /// that \c rrset be a valid NSEC RRset as described in \c find()
+        /// documentation.
+        bool isNSECSigned() const {
+            return ((flags_ & RESULT_NSEC_SIGNED) != 0);
+        }
+
+        /// Return true when the underlying zone is signed with NSEC3.
+        ///
+        /// The \c find() implementation allows this to return false if
+        /// \c FIND_DNSSEC isn't specified regardless of whether the zone
+        /// is signed or which of NSEC/NSEC3 is used.
+        bool isNSEC3Signed() const {
+            return ((flags_ & RESULT_NSEC3_SIGNED) != 0);
+        }
+
+        /// \brief Find and return additional RRsets corresponding to the
+        ///        result of \c find().
+        ///
+        /// If this context is based on a normal find() call that resulted
+        /// in SUCCESS or DELEGATION, it examines the returned RRset (in many
+        /// cases NS, sometimes MX or others), searches the data source for
+        /// specified type of additional RRs for each RDATA of the RRset
+        /// (e.g., A or AAAA for the name server addresses), and stores the
+        /// result in the given vector.  The vector may not be empty; this
+        /// method appends any found RRsets to it, without touching existing
+        /// elements.
+        ///
+        /// If this context is based on a findAll() call that resulted in
+        /// SUCCESS, it performs the same process for each RRset returned in
+        /// the \c findAll() call.
+        ///
+        /// The caller specifies desired RR types of the additional RRsets
+        /// in \c requested_types.  Normally it consists of A and/or AAAA
+        /// types, but other types can be specified.
+        ///
+        /// This method is meaningful only when the precedent find()/findAll()
+        /// call resulted in SUCCESS or DELEGATION.  Otherwise this method
+        /// does nothing.
+        ///
+        /// \note The additional RRsets returned via method are limited to
+        /// ones contained in the zone which the corresponding find/findAll
+        /// call searched (possibly including glues under a zone cut where
+        /// they are applicable).  If the caller needs to get out-of-zone
+        /// additional RRsets, it needs to explicitly finds them by
+        /// identifying the corresponding zone and calls \c find() for it.
+        ///
+        /// \param requested_types A vector of RR types for desired additional
+        ///  RRsets.
+        /// \param result A vector to which any found additional RRsets are
+        /// to be inserted.
+        void getAdditional(
+            const std::vector<isc::dns::RRType>& requested_types,
+            std::vector<isc::dns::ConstRRsetPtr>& result)
+        {
+            // Perform common checks, and delegate the process to the default
+            // or specialized implementation.
+            if (code != SUCCESS && code != DELEGATION) {
+                return;
+            }
+
+            getAdditionalImpl(requested_types, result);
+        }
+
+    protected:
+        /// \brief Return the \c ZoneFinder that created this \c Context.
+        ///
+        /// A derived class implementation can return NULL if it defines
+        /// other protected methods that require a non NULL result from
+        /// this method.  Otherwise it must return a valid, non NULL pointer
+        /// to the \c ZoneFinder object.
+        ///
+        /// When returning non NULL, the ownership of the pointed object
+        /// was not transferred to the caller; it cannot be assumed to be
+        /// valid after the originating \c Context object is destroyed.
+        /// Also, the caller must not try to delete the returned object.
+        virtual ZoneFinder* getFinder() = 0;
+
+        /// \brief Return a vector of RRsets corresponding to findAll() result.
+        ///
+        /// This method returns a set of RRsets that correspond to the
+        /// returned RRsets to a prior \c findAll() call.
+        ///
+        /// A derived class implementation can return NULL if it defines
+        /// other protected methods that require a non NULL result from
+        /// this method.  Otherwise it must return a valid, non NULL pointer
+        /// to a vector that correspond to the expected set of RRsets.
+        ///
+        /// When returning non NULL, the ownership of the pointed object
+        /// was not transferred to the caller; it cannot be assumed to be
+        /// valid after the originating \c Context object is destroyed.
+        /// Also, the caller must not try to delete the returned object.
+        virtual const std::vector<isc::dns::ConstRRsetPtr>*
+        getAllRRsets() const = 0;
+
+        /// \brief Actual implementation of getAdditional().
+        ///
+        /// This base class defines a default implementation that can be
+        /// used for any type of data sources.  A data source implementation
+        /// can override it.
+        ///
+        /// The default version of this implementation requires both
+        /// \c getFinder() and \c getAllRRsets() return valid results.
+        virtual void getAdditionalImpl(
+            const std::vector<isc::dns::RRType>& requested_types,
+            std::vector<isc::dns::ConstRRsetPtr>& result);
+
+    private:
+        const FindResultFlags flags_;
+    protected:
+        const FindOptions options_;
+    };
+
+    /// \brief Generic ZoneFinder context that works for all implementations.
+    ///
+    /// This is a concrete derived class of \c ZoneFinder::Context that
+    /// only use the generic (default) versions of the protected methods
+    /// and therefore work for any data source implementation.
+    ///
+    /// A data source implementation can use this class to create a
+    /// \c Context object as a return value of \c find() or \c findAll()
+    /// method if it doesn't have to optimize specific protected methods.
+    class GenericContext : public Context {
+    public:
+        /// \brief The constructor for the normal find call.
+        ///
+        /// This constructor is expected to be called from the \c find()
+        /// method when it constructs the return value.
+        ///
+        /// \param finder The ZoneFinder on which find() is called.
+        /// \param options See the \c Context class.
+        /// \param result See the \c Context class.
+        GenericContext(ZoneFinder& finder, FindOptions options,
+                       const ResultContext& result) :
+            Context(options, result), finder_(finder)
+        {}
+
+        /// \brief The constructor for the normal findAll call.
+        ///
+        /// This constructor is expected to be called from the \c findAll()
+        /// method when it constructs the return value.
+        ///
+        /// It copies the vector that is to be returned to the caller of
+        /// \c findAll() for possible subsequent use.  Note that it cannot
+        /// simply hold a reference to the vector because the caller may
+        /// alter it after the \c findAll() call.
+        ///
+        /// \param finder The ZoneFinder on which findAll() is called.
+        /// \param options See the \c Context class.
+        /// \param result See the \c Context class.
+        /// \param all_set Reference to the vector given by the caller of
+        ///       \c findAll(), storing the RRsets to be returned.
+        GenericContext(ZoneFinder& finder, FindOptions options,
+                       const ResultContext& result,
+                       const std::vector<isc::dns::ConstRRsetPtr>& all_set) :
+            Context(options, result), finder_(finder), all_set_(all_set)
+        {}
+
+    protected:
+        virtual ZoneFinder* getFinder() { return (&finder_); }
+        virtual const std::vector<isc::dns::ConstRRsetPtr>*
+        getAllRRsets() const {
+            return (&all_set_);
+        }
+
+    private:
+        ZoneFinder& finder_;
+        std::vector<isc::dns::ConstRRsetPtr> all_set_;
+    };
+
+    ///
+    /// \name Constructors and Destructor.
+    ///
+    //@{
+protected:
+    /// The default constructor.
+    ///
+    /// This is intentionally defined as \c protected as this base class should
+    /// never be instantiated (except as part of a derived class).
+    ZoneFinder() {}
+public:
+    /// The destructor.
+    virtual ~ZoneFinder() {}
+    //@}
+
+    ///
+    /// \name Getter Methods
+    ///
+    /// These methods should never throw an exception.
+    //@{
+    /// Return the origin name of the zone.
+    virtual isc::dns::Name getOrigin() const = 0;
+
+    /// Return the RR class of the zone.
+    virtual isc::dns::RRClass getClass() const = 0;
+    //@}
+
+    ///
+    /// \name Search Methods
+    ///
+    //@{
+    /// \brief Search the zone for a given pair of domain name and RR type.
+    ///
+    /// Each derived version of this method searches the underlying backend
+    /// for the data that best matches the given name and type.
+    /// This method is expected to be "intelligent", and identifies the
+    /// best possible answer for the search key.  Specifically,
+    ///
+    /// - If the search name belongs under a zone cut, it returns the code
+    ///   of \c DELEGATION and the NS RRset at the zone cut.
+    /// - If there is no matching name, it returns the code of \c NXDOMAIN.
+    /// - If there is a matching name but no RRset of the search type, it
+    ///   returns the code of \c NXRRSET.  This case includes the search name
+    ///   matches an empty node of the zone.
+    /// - If there is a CNAME RR of the searched name but there is no
+    ///   RR of the searched type of the name (so this type is different from
+    ///   CNAME), it returns the code of \c CNAME and that CNAME RR.
+    ///   Note that if the searched RR type is CNAME, it is considered
+    ///   a successful match, and the code of \c SUCCESS will be returned.
+    /// - If the search name matches a delegation point of DNAME, it returns
+    ///   the code of \c DNAME and that DNAME RR.
+    ///
+    /// No RRset will be returned in the \c NXDOMAIN and \c NXRRSET cases
+    /// (\c rrset member of \c FindContext will be NULL), unless DNSSEC data
+    /// are required.  See below for the cases with DNSSEC.
+    ///
+    /// The returned \c FindContext object can also provide supplemental
+    /// information about the search result via its methods returning a
+    /// boolean value.  Such information may be useful for the caller if
+    /// the caller wants to collect additional DNSSEC proofs based on the
+    /// search result.
+    ///
+    /// The \c options parameter specifies customized behavior of the search.
+    /// Their semantics is as follows (they are or bit-field):
+    ///
+    /// - \c FIND_GLUE_OK Allow search under a zone cut.  By default the search
+    ///   will stop once it encounters a zone cut.  If this option is specified
+    ///   it remembers information about the highest zone cut and continues
+    ///   the search until it finds an exact match for the given name or it
+    ///   detects there is no exact match.  If an exact match is found,
+    ///   RRsets for that name are searched just like the normal case;
+    ///   otherwise, if the search has encountered a zone cut, \c DELEGATION
+    ///   with the information of the highest zone cut will be returned.
+    ///   Note: the term "glue" in the DNS protocol standard may sometimes
+    ///   cause confusion: some people use this term strictly for an address
+    ///   record (type AAAA or A) for the name used in the RDATA of an NS RR;
+    ///   some others seem to give it broader flexibility.  Nevertheless,
+    ///   in this API the "GLUE OK" simply means the search by find() can
+    ///   continue beyond a zone cut; the derived class implementation does
+    ///   not have to, and should not, check whether the type is an address
+    ///   record or whether the query name is pointed by some NS RR.
+    ///   It's up to the caller with which definition of "glue" the search
+    ///   result with this option should be used.
+    /// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
+    ///   returned with the answer. It is allowed for the data source to
+    ///   include them even when not requested.
+    /// - \c NO_WILDCARD Do not try wildcard matching.  This option is of no
+    ///   use for normal lookups; it's intended to be used to get a DNSSEC
+    ///   proof of the non existence of any matching wildcard or non existence
+    ///   of an exact match when a wildcard match is found.
+    ///
+    /// In general, \c name is expected to be included in the zone, that is,
+    /// it should be equal to or a subdomain of the zone origin.  Otherwise
+    /// this method will return \c NXDOMAIN with an empty RRset.  But such a
+    /// case should rather be considered a caller's bug.
+    ///
+    /// \note For this reason it's probably better to throw an exception
+    /// than returning \c NXDOMAIN.  This point should be revisited in a near
+    /// future version.  In any case applications shouldn't call this method
+    /// for an out-of-zone name.
+    ///
+    /// <b>DNSSEC considerations:</b>
+    /// The result when DNSSEC data are required can be very complicated,
+    /// especially if it involves negative result or wildcard match.
+    /// Specifically, if an application calls this method for DNS query
+    /// processing with DNSSEC data, and if the search result code is
+    /// either \c NXDOMAIN or \c NXRRRSET, and/or \c isWildcard() returns
+    /// true, then the application will need to find additional NSEC or
+    /// NSEC3 records for supplemental proofs.  This method helps the
+    /// application for such post search processing.
+    ///
+    /// First, it tells the application whether the zone is signed with
+    /// NSEC or NSEC3 via the \c isNSEC(3)Signed() method.  Any sanely signed
+    /// zone should be signed with either (and only one) of these two types
+    /// of RRs; however, the application should expect that the zone could
+    /// be broken and these methods could both return false.  But this method
+    /// should ensure that not both of these methods return true.
+    ///
+    /// In case it's signed with NSEC3, there is no further information
+    /// returned from this method.
+    ///
+    /// In case it's signed with NSEC, this method will possibly return
+    /// a related NSEC RRset in the \c rrset member of \c FindContext.
+    /// What kind of NSEC is returned depends on the result code
+    /// (\c NXDOMAIN or \c NXRRSET) and on whether it's a wildcard match:
+    ///
+    /// - In case of NXDOMAIN, the returned NSEC covers the queried domain
+    ///   that proves that the query name does not exist in the zone.  Note
+    ///   that this does not necessarily prove it doesn't even match a
+    ///   wildcard (even if the result of NXDOMAIN can only happen when
+    ///   there's no matching wildcard either).  It is caller's
+    ///   responsibility to provide a proof that there is no matching
+    ///   wildcard if that proof is necessary.
+    /// - In case of NXRRSET, we need to consider the following cases
+    ///   referring to Section 3.1.3 of RFC4035:
+    ///
+    /// -# (Normal) no data: there is a matching non-wildcard name with a
+    ///    different RR type.  This is the "No Data" case of the RFC.
+    /// -# (Normal) empty non terminal: there is no matching (exact or
+    ///    wildcard) name, but there is a subdomain with an RR of the query
+    ///    name.  This is one case of "Name Error" of the RFC.
+    /// -# Wildcard empty non terminal: similar to 2a, but the empty name
+    ///    is a wildcard, and matches the query name by wildcard expansion.
+    ///    This is a special case of "Name Error" of the RFC.
+    /// -# Wildcard no data: there is no exact match name, but there is a
+    ///    wildcard name that matches the query name with a different type
+    ///    of RR.  This is the "Wildcard No Data" case of the RFC.
+    ///
+    /// In case 1, \c find() returns NSEC of the matching name.
+    ///
+    /// In case 2, \c find() will return NSEC for the interval where the
+    /// empty nonterminal lives. The end of the interval is the subdomain
+    /// causing existence of the empty nonterminal (if there's
+    /// sub.x.example.com, and no record in x.example.com, then
+    /// x.example.com exists implicitly - is the empty nonterminal and
+    /// sub.x.example.com is the subdomain causing it).  Note that this NSEC
+    /// proves not only the existence of empty non terminal name but also
+    /// the non existence of possibly matching wildcard name, because
+    /// there can be no better wildcard match than the exact matching empty
+    /// name.
+    ///
+    /// In case 3, \c find() will return NSEC for the interval where the
+    /// wildcard empty nonterminal lives.   Cases 2 and 3 are especially
+    /// complicated and confusing.  See the examples below.
+    ///
+    /// In case 4, \c find() will return NSEC of the matching wildcard name.
+    ///
+    /// Examples: if zone "example.com" has the following record:
+    /// \code
+    /// a.example.com. NSEC a.b.example.com.
+    /// \endcode
+    /// a call to \c find() for "b.example.com." with the FIND_DNSSEC option
+    /// will result in NXRRSET, and this NSEC will be returned.
+    /// Likewise, if zone "example.org" has the following record,
+    /// \code
+    /// a.example.org. NSEC x.*.b.example.org.
+    /// \endcode
+    /// a call to \c find() for "y.b.example.org" with FIND_DNSSEC will
+    /// result in NXRRSET and this NSEC; \c isWildcard() on the returned
+    /// \c FindContext object will return true.
+    ///
+    /// \exception std::bad_alloc Memory allocation such as for constructing
+    ///  the resulting RRset fails
+    /// \throw OutOfZone The Name \c name is outside of the origin of the
+    /// zone of this ZoneFinder.
+    /// \exception DataSourceError Derived class specific exception, e.g.
+    /// when encountering a bad zone configuration or database connection
+    /// failure.  Although these are considered rare, exceptional events,
+    /// it can happen under relatively usual conditions (unlike memory
+    /// allocation failure).  So, in general, the application is expected
+    /// to catch this exception, either specifically or as a result of
+    /// catching a base exception class, and handle it gracefully.
+    ///
+    /// \param name The domain name to be searched for.
+    /// \param type The RR type to be searched for.
+    /// \param options The search options.
+    /// \return A \c FindContext object enclosing the search result
+    ///         (see above).
+    virtual boost::shared_ptr<Context> find(const isc::dns::Name& name,
+                                            const isc::dns::RRType& type,
+                                            const FindOptions options
+                                            = FIND_DEFAULT) = 0;
+
+    /// \brief Search for an RRset of given RR type at the zone origin.
+    ///
+    /// In terms of API this method is equivalent to a call to \c find() where
+    /// the \c name parameter is the zone origin (return value of
+    /// \c getOrigin()) and is redundant.  This method is provided as an
+    /// optimization point for some kind of finder implementations that can
+    /// exploit the fact that the query name is the zone origin and for
+    /// applications that want to possibly benefit from such implementations.
+    ///
+    /// If \c use_minttl is set to \c true and the returned context would
+    /// contain a non NULL RRset, its RR TTL is (possibly) adjusted so that
+    /// it's set to the minimum of its own TTL and the minimum TTL field value
+    /// of the zone's SOA record.  If the RRset contains an RRSIG, its TTL
+    /// is also adjusted in the same way.
+    ///
+    /// The origin of a zone is special in some points: for any valid zone
+    /// there should always be an SOA and at least one NS RR there, which
+    /// also means the origin name is never empty.  Also, the SOA record can
+    /// be used in a DNS response for negative answers, in which case the
+    /// RR TTL must be set to minimum of its own RRTTL and the value of the
+    /// minimum TTL field.  Although these operations can be performed
+    /// through other public interfaces, they can be sometimes suboptimal
+    /// in performance or could be more efficient in a specialized
+    /// implementation.  For example, a specific implementation of
+    /// \c getOrigin() could involve a dynamic creation of a \c Name object,
+    /// which is less efficient; on the other hand, the underlying finder
+    /// implementation may have an efficient way to access RRs of the origin
+    /// in implementation specific way; and, while reconstructing an RRset
+    /// with replacing the TTL is relatively expensive, this can be done
+    /// much faster if the need for it is known beforehand.
+    ///
+    /// If the underlying finder implementation wants to optimize these cases,
+    /// it can do so by specializing the method.  It has the default
+    /// implementation for any other implementations, which should work for
+    /// any finder implementation as long as it conforms to other public
+    /// interfaces.
+    ///
+    /// So, an implementation of a finder does not have to care about this
+    /// method unless it sees the need for optimizing the behavior.
+    /// Also, applications normally do not have to use this interface;
+    /// using the generic \c find() method (with some post call processing)
+    /// can do everything this method can provide.  The default implementation
+    /// may even be slower than such straightforward usage due to the
+    /// internal overhead.  This method should be used if and only if the
+    /// application needs to achieve the possible best performance with an
+    /// optimized finder implementation.
+    ///
+    /// \param type The RR type to be searched for.
+    /// \param use_minttl Whether to adjust the TTL (see the description).
+    /// \param options The search options.  Same for \c find().
+    ///
+    /// \return A \c FindContext object enclosing the search result.
+    ///         See \c find().
+    virtual boost::shared_ptr<Context> findAtOrigin(
+        const isc::dns::RRType& type, bool use_minttl,
+        FindOptions options);
+
+public:
+    ///
+    /// \brief Finds all RRsets in the given name.
+    ///
+    /// This function works almost exactly in the same way as the find one. The
+    /// only difference is, when the lookup is successful (eg. the code is
+    /// SUCCESS), all the RRsets residing in the named node are
+    /// copied into the \c target parameter and the rrset member of the result
+    /// is NULL. All the other (unsuccessful) cases are handled the same,
+    /// including returning delegations, NSEC/NSEC3 availability and NSEC
+    /// proofs, wildcard information etc. The options parameter works the
+    /// same way and it should conform to the same exception restrictions.
+    ///
+    /// \param name \see find, parameter name
+    /// \param target the successfull result is returned through this
+    /// \param options \see find, parameter options
+    /// \return \see find and it's result
+    virtual boost::shared_ptr<Context> findAll(
+        const isc::dns::Name& name,
+        std::vector<isc::dns::ConstRRsetPtr> &target,
+        const FindOptions options = FIND_DEFAULT) = 0;
+
+    /// A helper structure to represent the search result of \c findNSEC3().
+    ///
+    /// The idea is similar to that of \c FindContext, but \c findNSEC3() has
+    /// special interface and semantics, we use a different structure to
+    /// represent the result.
+    struct FindNSEC3Result {
+        FindNSEC3Result(bool param_matched, uint8_t param_closest_labels,
+                        isc::dns::ConstRRsetPtr param_closest_proof,
+                        isc::dns::ConstRRsetPtr param_next_proof) :
+            matched(param_matched), closest_labels(param_closest_labels),
+            closest_proof(param_closest_proof),
+            next_proof(param_next_proof)
+        {}
+
+        /// true iff closest_proof is a matching NSEC3
+        const bool matched;
+
+        /// The number of labels of the identified closest encloser.
+        const uint8_t closest_labels;
+
+        /// Either the NSEC3 for the closest provable encloser of the given
+        /// name or NSEC3 that covers the name
+        const isc::dns::ConstRRsetPtr closest_proof;
+
+        /// When non NULL, NSEC3 for the next closer name.
+        const isc::dns::ConstRRsetPtr next_proof;
+    };
+
+    /// Search the zone for the NSEC3 RR(s) that prove existence or non
+    /// existence of a give name.
+    ///
+    /// It searches the NSEC3 namespace of the zone (how that namespace is
+    /// implemented can vary in specific data source implementation) for NSEC3
+    /// RRs that match or cover the NSEC3 hash value for the given name.
+    ///
+    /// If \c recursive is false, it will first look for the NSEC3 that has
+    /// a matching hash.  If it doesn't exist, it identifies the covering NSEC3
+    /// for the hash.  In either case the search stops at that point and the
+    /// found NSEC3 RR(set) will be returned in the closest_proof member of
+    /// \c FindNSEC3Result.  \c matched is true or false depending on
+    /// the found NSEC3 is a matched one or covering one.  \c next_proof
+    /// is always NULL.  closest_labels must be equal to the number of
+    /// labels of \c name (and therefore meaningless).
+    ///
+    /// If \c recursive is true, it will continue the search toward the zone
+    /// apex (origin name) until it finds a provable encloser, that is,
+    /// an ancestor of \c name that has a matching NSEC3.  This is the closest
+    /// provable encloser of \c name as defined in RFC5155.  In this case,
+    /// if the found encloser is not equal to \c name, the search should
+    /// have seen a covering NSEC3 for the immediate child of the found
+    /// encloser.  That child name is the next closer name as defined in
+    /// RFC5155.  In this case, this method returns the NSEC3 for the
+    /// closest encloser in \c closest_proof, and the NSEC3 for the next
+    /// closer name in \c next_proof of \c FindNSEC3Result.  This set of
+    /// NSEC3 RRs provide the closest encloser proof as defined in RFC5155.
+    /// closest_labels will be set to the number of labels of the identified
+    /// closest encloser.  This will be useful when the caller needs to
+    /// construct the closest encloser name from the original \c name.
+    /// If, on the other hand, the found closest name is equal to \c name,
+    /// this method simply returns it in \c closest_proof.  \c next_proof
+    /// is set to NULL.  In all cases \c matched is set to true.
+    /// closest_labels will be set to the number of labels of \c name.
+    ///
+    /// When looking for NSEC3, this method retrieves NSEC3 parameters from
+    /// the corresponding zone to calculate hash values.  Actual implementation
+    /// of how to do this will differ in different data sources.  If the
+    /// NSEC3 parameters are not available \c DataSourceError exception
+    /// will be thrown.
+    ///
+    /// \note This implicitly means this method assumes the zone does not
+    /// have more than one set of parameters.  This assumption should be
+    /// reasonable in actual deployment and will help simplify the interface
+    /// and implementation.  But if there's a real need for supporting
+    /// multiple sets of parameters in a single zone, we will have to
+    /// extend this method so that, e.g., the caller can specify the parameter
+    /// set.
+    ///
+    /// In general, this method expects the zone is properly signed with NSEC3
+    /// RRs.  Specifically, it assumes at least the apex node has a matching
+    /// NSEC3 RR (so the search in the recursive mode must always succeed);
+    /// it also assumes that it can retrieve NSEC parameters (iterations,
+    /// algorithm, and salt) from the zone as noted above.  If these
+    /// assumptions aren't met, \c DataSourceError exception will be thrown.
+    ///
+    /// \exception OutOfZone name is not a subdomain of the zone origin
+    /// \exception DataSourceError Low-level or internal datasource errors
+    /// happened, or the zone isn't properly signed with NSEC3
+    /// (NSEC3 parameters cannot be found, no NSEC3s are available, etc).
+    /// \exception std::bad_alloc The underlying implementation involves
+    /// memory allocation and it fails
+    ///
+    /// \param name The name for which NSEC3 RRs are to be found.  It must
+    /// be a subdomain of the zone.
+    /// \param recursive Whether or not search should continue until it finds
+    /// a provable encloser (see above).
+    ///
+    /// \return The search result and whether or not the closest_proof is
+    /// a matching NSEC3, in the form of \c FindNSEC3Result object.
+    virtual FindNSEC3Result
+    findNSEC3(const isc::dns::Name& name, bool recursive) = 0;
+    //@}
+};
+
+/// \brief Operator to combine FindOptions
+///
+/// We would need to manually static-cast the options if we put or
+/// between them, which is undesired with bit-flag options. Therefore
+/// we hide the cast here, which is the simplest solution and it still
+/// provides reasonable level of type safety.
+inline ZoneFinder::FindOptions operator |(ZoneFinder::FindOptions a,
+                                          ZoneFinder::FindOptions b)
+{
+    return (static_cast<ZoneFinder::FindOptions>(static_cast<unsigned>(a) |
+                                                 static_cast<unsigned>(b)));
+}
+
+/// \brief Operator to combine FindResultFlags
+///
+/// Similar to the same operator for \c FindOptions.  Refer to the description
+/// of that function.
+inline ZoneFinder::FindResultFlags operator |(
+    ZoneFinder::FindResultFlags a,
+    ZoneFinder::FindResultFlags b)
+{
+    return (static_cast<ZoneFinder::FindResultFlags>(
+                static_cast<unsigned>(a) | static_cast<unsigned>(b)));
+}
+
+/// \brief A pointer-like type pointing to a \c ZoneFinder object.
+typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
+
+/// \brief A pointer-like type pointing to an immutable \c ZoneFinder object.
+typedef boost::shared_ptr<const ZoneFinder> ConstZoneFinderPtr;
+
+/// \brief A pointer-like type pointing to a \c ZoneFinder::Context object.
+typedef boost::shared_ptr<ZoneFinder::Context> ZoneFinderContextPtr;
+
+/// \brief A pointer-like type pointing to an immutable
+/// \c ZoneFinder::Context object.
+typedef boost::shared_ptr<ZoneFinder::Context> ConstZoneFinderContextPtr;
+
+} // end of datasrc
+} // end of isc
+
+#endif  // DATASRC_ZONE_FINDER_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/zone_finder_context.cc b/src/lib/datasrc/zone_finder_context.cc
index 482eb65..8d7edf0 100644
--- a/src/lib/datasrc/zone_finder_context.cc
+++ b/src/lib/datasrc/zone_finder_context.cc
@@ -19,7 +19,7 @@
 #include <dns/rrtype.h>
 #include <dns/rdataclass.h>
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 
 #include <boost/foreach.hpp>
 
diff --git a/src/lib/datasrc/zone_iterator.h b/src/lib/datasrc/zone_iterator.h
new file mode 100644
index 0000000..e1c6929
--- /dev/null
+++ b/src/lib/datasrc/zone_iterator.h
@@ -0,0 +1,105 @@
+// Copyright (C) 2011  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_ZONE_ITERATOR_H
+#define DATASRC_ZONE_ITERATOR_H 1
+
+#include <dns/rrset.h>
+
+#include <boost/noncopyable.hpp>
+
+#include <datasrc/zone.h>
+
+namespace isc {
+namespace datasrc {
+
+/**
+ * \brief Read-only iterator to a zone.
+ *
+ * You can get an instance of (descendand of) ZoneIterator from
+ * DataSourceClient::getIterator() method. The actual concrete implementation
+ * will be different depending on the actual data source used. This is the
+ * abstract interface.
+ *
+ * There's no way to start iterating from the beginning again or return.
+ */
+class ZoneIterator : public boost::noncopyable {
+public:
+    /**
+     * \brief Destructor
+     *
+     * Virtual destructor. It is empty, but ensures the right destructor from
+     * descendant is called.
+     */
+    virtual ~ ZoneIterator() { }
+
+    /**
+     * \brief Get next RRset from the zone.
+     *
+     * This returns the next RRset in the zone as a shared pointer. The
+     * shared pointer is used to allow both accessing in-memory data and
+     * automatic memory management.
+     *
+     * Any special order is not guaranteed.
+     *
+     * While this can potentially throw anything (including standard allocation
+     * errors), it should be rare.
+     *
+     * \return Pointer to the next RRset or NULL pointer when the iteration
+     *     gets to the end of the zone.
+     */
+    virtual isc::dns::ConstRRsetPtr getNextRRset() = 0;
+
+    /**
+     * \brief Return the SOA record of the zone in the iterator context.
+     *
+     * This method returns the zone's SOA record (if any, and a valid zone
+     * should have it) in the form of an RRset object.  This SOA is identical
+     * to that (again, if any) contained in the sequence of RRsets returned
+     * by the iterator.  In that sense this method is redundant, but is
+     * provided as a convenient utility for the application of the
+     * iterator; the application may need to know the SOA serial or the
+     * SOA RR itself for the purpose of protocol handling or skipping the
+     * expensive iteration processing.
+     *
+     * If the zone doesn't have an SOA (which is broken, but some data source
+     * may allow that situation), this method returns NULL.  Also, in the
+     * normal and valid case, the SOA should have exactly one RDATA, but
+     * this API does not guarantee it as some data source may accept such an
+     * abnormal condition.  It's up to the caller whether to check the number
+     * of RDATA and how to react to the unexpected case.
+     *
+     * Each concrete derived method must ensure that the SOA returned by this
+     * method is identical to the zone's SOA returned via the iteration.
+     * For example, even if another thread or process updates the SOA while
+     * the iterator is working, the result of this method must not be
+     * affected by the update.  For database based data sources, this can
+     * be done by making the entire iterator operation as a single database
+     * transaction, but the actual implementation can differ.
+     *
+     * \exception None
+     *
+     * \return A shared pointer to an SOA RRset that would be returned
+     * from the iteration.  It will be NULL if the zone doesn't have an SOA.
+     */
+    virtual isc::dns::ConstRRsetPtr getSOA() const = 0;
+};
+
+}
+}
+#endif  // DATASRC_ZONE_ITERATOR_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/datasrc/zone_loader.cc b/src/lib/datasrc/zone_loader.cc
index 9e9dd4a..2c57b4f 100644
--- a/src/lib/datasrc/zone_loader.cc
+++ b/src/lib/datasrc/zone_loader.cc
@@ -17,7 +17,7 @@
 
 #include <datasrc/client.h>
 #include <datasrc/data_source.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/zone.h>
 #include <datasrc/logger.h>
 #include <datasrc/rrset_collection_base.h>
diff --git a/src/lib/datasrc/zonetable.h b/src/lib/datasrc/zonetable.h
index 911391c..ef8a33b 100644
--- a/src/lib/datasrc/zonetable.h
+++ b/src/lib/datasrc/zonetable.h
@@ -19,7 +19,7 @@
 
 #include <dns/rrset.h>
 
-#include <datasrc/zone.h>
+#include <datasrc/zone_finder.h>
 
 #include <boost/shared_ptr.hpp>
 
diff --git a/src/lib/python/isc/datasrc/client_python.cc b/src/lib/python/isc/datasrc/client_python.cc
index 9e4bd42..a30ae38 100644
--- a/src/lib/python/isc/datasrc/client_python.cc
+++ b/src/lib/python/isc/datasrc/client_python.cc
@@ -27,7 +27,7 @@
 #include <datasrc/database.h>
 #include <datasrc/data_source.h>
 #include <datasrc/sqlite3_accessor.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/client_list.h>
 
 #include <dns/python/name_python.h>
diff --git a/src/lib/python/isc/datasrc/finder_python.cc b/src/lib/python/isc/datasrc/finder_python.cc
index 1b0e3d1..05c44c9 100644
--- a/src/lib/python/isc/datasrc/finder_python.cc
+++ b/src/lib/python/isc/datasrc/finder_python.cc
@@ -26,7 +26,7 @@
 #include <datasrc/database.h>
 #include <datasrc/data_source.h>
 #include <datasrc/sqlite3_accessor.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 #include <datasrc/zone.h>
 
 #include <dns/python/name_python.h>
diff --git a/src/lib/python/isc/datasrc/iterator_python.cc b/src/lib/python/isc/datasrc/iterator_python.cc
index 9e6900c..9757a3b 100644
--- a/src/lib/python/isc/datasrc/iterator_python.cc
+++ b/src/lib/python/isc/datasrc/iterator_python.cc
@@ -25,7 +25,7 @@
 #include <datasrc/client.h>
 #include <datasrc/database.h>
 #include <datasrc/sqlite3_accessor.h>
-#include <datasrc/iterator.h>
+#include <datasrc/zone_iterator.h>
 
 #include <dns/python/name_python.h>
 #include <dns/python/rrset_python.h>



More information about the bind10-changes mailing list