BIND 10 trac930, updated. f20be125d667bceea0d940fc5fabf87b2eef86cd [trac930] revise the entry of ChangeLog for trac928, trac929 and trac930

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Aug 15 04:15:54 UTC 2011


The branch, trac930 has been updated
  discards  732ee5d1ac0091aec99862b7b43ee62d9c84df45 (commit)
  discards  5a605b8e01e18c6ac3c309634d952c7058c2c414 (commit)
  discards  b14b3742acdea7c8ad26321c49dcae6d547c0c6a (commit)
  discards  db91d50b51e831b8388bbfd7233537a29d86dab2 (commit)
  discards  df5cfbd3af5c3da48699367e00854b7831de16f1 (commit)
  discards  9587813bd3757b16845c0c0902e101424e5eb8bd (commit)
  discards  b9597508947bd57ef7fab55628cf97c6c5afcce8 (commit)
  discards  0ebf17477af88cdd11029caeb485ceb105471457 (commit)
  discards  cdbacefd925f5b0e3ffd51b1ad8f07d35089e673 (commit)
  discards  31b4eb7e1e8e348ba0a31354ca788e44538164c9 (commit)
  discards  2afe6b613b4965eb0ff3f8deb6e250bd77fa9324 (commit)
  discards  75163a8bf9838ed4109d5ba766f17fbc736f1ac2 (commit)
  discards  1af449cb9ce4df5d429b6f700b08bfa38ce06236 (commit)
  discards  aa11de71155b006c19e299c185afce675c452749 (commit)
  discards  ca409a7d71b91fb33d42a5d1a0cf5ab1ea2bb491 (commit)
  discards  312653dfd3d6d26a07b80895f7292b4d1c318d19 (commit)
  discards  f77f32a6085905778586bd43b1cc78fc7b3ffa1d (commit)
  discards  926497e73b0ad8f2508fc9bfa3868f04fd7b05e8 (commit)
  discards  b7c9f192457178cfff64072ed8f0bea01d416c83 (commit)
  discards  2aa136505584811bce8260ee2ee17c9c20703cb9 (commit)
  discards  63bff4c4a6dc5b32fa53c82db128e04024b65a0f (commit)
  discards  09468a691a66c7d9d3b6d7a055415370741f102b (commit)
  discards  2067eda9635f92312e5d8d7251cff2b354329a4c (commit)
  discards  9398673539d34182bd154cdd18cb211b6ba96fde (commit)
  discards  3b04ea8924dc6ae5f4993060e32f67c2d3e0d959 (commit)
  discards  acfd5206272b4a6c062a72e6dc6176e518557ba5 (commit)
  discards  f6e79b1390bd1c530a654c150caadf885293b02c (commit)
  discards  07f9fea30ce4f11d57c04f619da42441b93e9706 (commit)
  discards  a2a36de8522a4c47df9b98847e9a9273224e1c4e (commit)
  discards  d37222088c0cefe8a5fb314717569741bae76b93 (commit)
  discards  f44f640bb841376070e92bd2106b339a057fc2a6 (commit)
  discards  e585e49e1ae6a56cbfbfd97bbbbd7b889c71d066 (commit)
  discards  dbcb38f1431cfc470a397cf63b2a3d8d4d1c4165 (commit)
  discards  b86acab9caa3ceebd12cf96e64d00bfcda10324b (commit)
  discards  ce38c4520c011e6c81bb4882eea1167a85d501e3 (commit)
  discards  96874e7eeb545e9f63e27edf7a604185cc28c306 (commit)
  discards  cce58c235847c36a614edd4b1bfe74f8fa166dda (commit)
  discards  f83b10d2b5347113aa3b9b6f535b70085b2259d4 (commit)
  discards  ed0a306cd7adfa30e570c0bc17c69dccf01157a1 (commit)
  discards  7c989a9efe8b25cb608dc92e33eb803bd682736b (commit)
  discards  e98030dfd393fe9fa73bde31172a24fdfe492084 (commit)
  discards  6dc5afaadd699a8d7aeba332a06d6da796c4c695 (commit)
  discards  1ee0777744051fea91a49d0d1cce827c7f162002 (commit)
  discards  827c461a9717bef527c678caedae7de6e61cf772 (commit)
  discards  430b763b2a3cc3d902fa91fb4406ae400c0a4f4d (commit)
  discards  dcf0ccfad06022738086cd8390b7cd5f6eb1fc45 (commit)
  discards  88c497de1d7191df88594a7143adaa179a52d8ee (commit)
  discards  c257aa7ebefbf0fd8149cba943b9a45928272322 (commit)
  discards  49a65fe7a00e41b408fa768e0d6991e7d8815cf0 (commit)
  discards  6045a682cf028cd06b9915502354310a46c8fcde (commit)
  discards  711df35ae8a4a46f8b051aec49cf5df8845eb8a0 (commit)
  discards  fc4895c406740f5a19a76861b5620c93dbf72a38 (commit)
  discards  0ee7f1aa1560c6564a5fb3a5047490b8d94c8fe0 (commit)
  discards  fbd4c644015d80866951e51a5623f47b6c39fb0c (commit)
  discards  84f900a5bb31a4786aac2a5b9a107ad93f4e2ace (commit)
  discards  e13baa92edabf6a2a069d99a306efd79b21a29d4 (commit)
  discards  7f9ef1c58d82ece7e9650d7b713dff766b688f3d (commit)
       via  f20be125d667bceea0d940fc5fabf87b2eef86cd (commit)
       via  fcc707041d663b98c1992cdd1402cc183155d3c0 (commit)
       via  da5d5926cb26ca8dbdae119c03687cd3415f6638 (commit)
       via  0314c7bb66b85775dea73c95463eed88e9e286c3 (commit)
       via  b8cecbbd905c10d28bcb905def7160d9e406dac4 (commit)
       via  7a31e95e63013a298b449573cc5336bcd64a0419 (commit)
       via  e18a678b62d03729f065c40650d7183e2f260b22 (commit)
       via  1d1a87939a010bd16ed23cd817261e9a655bf98f (commit)
       via  c6948a6df9aeedd3753bc4c5e3a553088cd98f63 (commit)
       via  db0371fc9e5c7a85ab524ab7bc0b8169b9ba0486 (commit)
       via  e906efc3747f052128eef50bed0107a0d53546c8 (commit)
       via  d86a9dceaddf5a2cee44170e6e677f492df5e0ea (commit)
       via  4c2732cbf0bb7384ed61ab3604855f143a0c6c5d (commit)
       via  aaffb9c83c0fe59d9c7d590c5bea559ed8876269 (commit)
       via  e8a22472e58bfc7df4a661d665152fe4d70454a6 (commit)
       via  2c22d334a05ec1e77299a6c55252f1d1c33082af (commit)
       via  8a24b9066537caf373d0cfc11dca855eb6c3e4d9 (commit)
       via  7275c59de54593d3baca81345226dda2d3a19c30 (commit)
       via  bcf37a11b08922d69d02fa2ea1b280b2fa2c21e0 (commit)
       via  a142fa6302e1e0ea2ad1c9faf59d6a70a53a6489 (commit)
       via  ae8748f77a0261623216b1a11f9d979f555fe892 (commit)
       via  d0d5a67123b8009e89e84515eee4f93b37ec8497 (commit)
       via  a9a976d2a5871f1501018d697d3afd299ceec5da (commit)
       via  df9a8f921f0d20bd70c519218335357297bffa7d (commit)
       via  e95625332a20fb50afe43da2db0cab507efe8ebe (commit)
       via  28cad73dff9dae43a38ad7dafbee406c690fb77c (commit)
       via  4de3a5bdf367d87247cb9138f8929ab4798f014e (commit)
       via  aa108cc824539a1d32a4aa2f46f9e58171074a9e (commit)
       via  691328d91b4c4d15ace467ca47a3c987a9fb52b9 (commit)
       via  c06463cf96ea7401325a208af8ba457e661d1cec (commit)
       via  c074f6e0b72c3facf6b325b17dea1ca13a2788cc (commit)
       via  daa1d6dd07292142d3dec5928583b0ab1da89adf (commit)
       via  e7b4337aeaa760947e8e7906e64077ad7aaadc66 (commit)
       via  0b235902f38d611606d44661506f32baf266fdda (commit)
       via  c19a295eb4125b4d2a391de65972271002412258 (commit)
       via  9261da8717a433cf20218af08d3642fbeffb7d4b (commit)
       via  d4078d52343247b07c47370b497927a3a47a4f9a (commit)
       via  1aa728ddf691657611680385c920e3a7bd5fee12 (commit)
       via  1768e822df82943f075ebed023b72d225b3b0216 (commit)
       via  326885a3f98c49a848a67dc48db693b8bcc7b508 (commit)
       via  3e0a0e157bc2a1ca7ad9efb566755ec61eedd180 (commit)
       via  93a7f7d1495795b731242e270b6dc76b1ad6b0dc (commit)
       via  87e410c0061df72fe69fb47c7456ae54c609b219 (commit)
       via  1ddc6158f7544c95742757654863379fff847771 (commit)
       via  0f787178301c7cbf59fc7c516ebe920a33e22429 (commit)
       via  9b6993b6f6507fab1bc8956f727cca60c8c9243a (commit)
       via  7bda7762ab9243404bbd0964908b3365cd052969 (commit)
       via  7cf7ec751e4f776dbb60cd290cea4fb217173cdb (commit)
       via  d5ded106a85afaf695e59941bd382bca4811fe46 (commit)
       via  c4ef641d07c7ddfd6b86d6b5ae944ab9a30d6990 (commit)
       via  e443a325b31edefe9cd4da71e10497db6544468c (commit)
       via  cddcafd790288f5e666198effa142132b6fc43fa (commit)
       via  ab5085e81007711f9d18ed77f3d78f51cf37545c (commit)
       via  5e621bce015d2847104303fba574989fdf0399e0 (commit)
       via  7d5c3d56743fb696405f509663b3e1558fa72e25 (commit)
       via  990247bfd2248be5ae4293928101eec87e1997e9 (commit)
       via  e9e36557849ba6b650e503841596bd31034c1936 (commit)
       via  2e60562cfda15fad37550ce5996e942084131d1c (commit)
       via  2f49e3eb0ddf31d601184b516b7f44ab4ea6eece (commit)
       via  17a87c6bb9d16e992fadd47b11b3eb26af54ac69 (commit)
       via  2cc500af0929c1f268aeb6f8480bc428af70f4c4 (commit)
       via  c46b0bc28c22f2ae4b46c592f450e745774846d4 (commit)
       via  7740b9810bc093a9083e8c3404afc627c8b78242 (commit)
       via  779e145d8f15ad9975f6ca689e6a595ea0a3de4b (commit)
       via  959dc163810ac286e01d0163624f5bbad5b82c55 (commit)
       via  1d74428fb7a817790c397338db92d102e2113e1c (commit)
       via  d5e24e94bbd581098e460fc3a0b437478340c876 (commit)
       via  4cd96de7e7d4ac12c38b45efe7b3ee0ed331d3b9 (commit)
       via  914fe9bc05003defeff70acb84a52e86fb9ced4c (commit)
       via  c6ca831b3f171da96fad75c21dffbd2bed71e297 (commit)
       via  8ce8e05a403440e7f2323e9d43dca08be1cf8a94 (commit)
       via  414b25d4bfa89e0609cd3c8c3a6e610681f4c929 (commit)
       via  f57e8133a7af31a59578ac2cd50dd20418cb8fbc (commit)
       via  85a14b1daffb3a20e9e510b73d25c71ba95cc350 (commit)
       via  774a56a8beeef3a73258910b12cace20443a1bcb (commit)
       via  d719b47c4131e2120305cee60395c0a88f5aca25 (commit)
       via  ac15a86eb62832cc22533bc33b802ea297666ad5 (commit)
       via  0af72968bfd192fa418551ae75def455adcfbb4b (commit)
       via  b19a36e30d0d3829c68f2e0300ea1487da242af8 (commit)
       via  12b3473393fb7a471fc7d928476b0ba66da145e9 (commit)
       via  cfd1d9e142fa2fd8b21f74de0e4a0109e0a04439 (commit)
       via  5951ef6faaffcff62d9a9963260a932666e3decb (commit)
       via  f82dc7b09f470f79ed2bf099216fa64c76528d3b (commit)
       via  f6a1807c25d85a0ca762bfa276ebac4a3430e7c7 (commit)
       via  9351dbcc88ccdd6aa83d72f432f19a76c031124b (commit)
       via  46b961d69aff3a2e4d1cb7f3d0910bfcc66d1e19 (commit)
       via  c9d7e29600f7a80094bcda2c3bd87d8f07d813e9 (commit)
       via  2b6bcb84a17fc98ea0ea87df65e6a77829857ecd (commit)
       via  cc6d6b14603924a4ef2d86dfaf758447cca6a7ff (commit)
       via  69642fb8f55cb4741f977d3fbaacd5d12d742625 (commit)
       via  86257c05755c8adbb19ce684546b718dd48a5ef8 (commit)
       via  5f13949918d125f851bd2ba8ab092c301835d3ac (commit)
       via  7e1e150e056d0dcf5a58b2a8036f47c2e5dac820 (commit)
       via  15428e5a9c1bb01f5e7a04979c17ec5f1de9d1db (commit)
       via  ac9fd0a240cbfa8c448cb01bb69ac92313eb7e56 (commit)
       via  ce0544bd0852415891cb31e0c1b7d0ba0b3d19f3 (commit)
       via  dba1e2c7884b5bc68f945fd5d2dd500f9a258c6b (commit)
       via  bc281e8b48c92102d3c64318e07598c8e96e493c (commit)
       via  82667b0cdd6592053f5b2f4cfa1cbd0ec92db0b2 (commit)
       via  71b0ae9ddbcbf4093900ff879e2e1c82be89867f (commit)
       via  1b96c2563342098e05ac4b240c66e60222249cf4 (commit)
       via  ff14da4f9b706a47f152491eae60586b75430c6e (commit)
       via  d23cde8c4285cf55b007b300123c41fa852d38d9 (commit)
       via  16e52275c4c9e355cf4e448a5b17136f24324d7a (commit)
       via  61029d971895738ba353841d99f4ca07ecf792b7 (commit)
       via  1c8043e5b50bd47d7734397a08d5015e3672b9ad (commit)
       via  9819295a58b8b40ca6d95c84f1f1de08fb0eb707 (commit)
       via  dc3b856b460ff380feb68cdff551f334e6db5a27 (commit)
       via  87a4f24037965ae88435ebe3f887750c500cbfde (commit)
       via  aa9497f4d2346e7a18cd07b9bf31dfb5832031bc (commit)
       via  7b0201a4f98ee1b1288ae3b074cd1007707b6b21 (commit)
       via  ba7bc1e14fcf1a223a9a42ede2e9cd7d290c8b61 (commit)
       via  c6ef5865b3fd8e5d5fb8c891467b3722fde4d685 (commit)
       via  e05a3418c9d6b3f70cdb387d1f30d8ba59733f02 (commit)

This update added new revisions after undoing existing revisions.  That is
to say, the old revision is not a strict subset of the new revision.  This
situation occurs when you --force push a change and generate a repository
containing something like this:

 * -- * -- B -- O -- O -- O (732ee5d1ac0091aec99862b7b43ee62d9c84df45)
            \
             N -- N -- N (f20be125d667bceea0d940fc5fabf87b2eef86cd)

When this happens we assume that you've already had alert emails for all
of the O revisions, and so we here report only the revisions in the N
branch from the common base, B.

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 f20be125d667bceea0d940fc5fabf87b2eef86cd
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Tue Aug 9 15:57:22 2011 +0900

    [trac930] revise the entry of ChangeLog for trac928, trac929 and trac930

commit fcc707041d663b98c1992cdd1402cc183155d3c0
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Aug 5 16:24:03 2011 +0900

    [trac930]
      - revise header comments in each test script
      - replace some hard-coded time strings with the constants defined in the
        setUp function
      - merged several checks about B10_FROM_SOURCE into the TestOSEnv class

commit da5d5926cb26ca8dbdae119c03687cd3415f6638
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Aug 5 14:48:27 2011 +0900

    [trac930]
      - change address for test to 127.0.0.1 due to platform 127.0.0.2 can't be
        assigned
      - remove unnecessary thread.Event.wait()
      - add thread.Event.clear() after thread.Event.wait()

commit 0314c7bb66b85775dea73c95463eed88e9e286c3
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Aug 3 11:41:05 2011 +0900

    [trac930] refactor unittests
     - remove time.sleep from various unittests and add in the "run" method in
       ThreadingServerManager
     - adjust the sleep time (TIMEOUT_SEC)
     - join some small unittests
       (test_start_with_err, test_command_status, test_command_shutdown)

commit b8cecbbd905c10d28bcb905def7160d9e406dac4
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Tue Aug 2 22:00:11 2011 +0900

    [trac930] add comments about abstracts of the test scripts in their headers

commit 7a31e95e63013a298b449573cc5336bcd64a0419
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Tue Aug 2 21:44:07 2011 +0900

    [trac930] modify stats.py
     - add more documentations into update_modules, get_statistics_data and
       update_statistics_data methods
     - modify two methods: "update_modules" and "get_statistics_data" methods raise
       StatsError instead of just returning None, when communication between stats
       module and config manager is failed or when it can't find specified
       statistics data.
     - also modify the unittest depending on the changes of these behaviors.

commit e18a678b62d03729f065c40650d7183e2f260b22
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Tue Aug 2 20:17:28 2011 +0900

    [trac930] modify b10-stats_test.py
     - set the constant variables in the setUp method in the TestUtilties class,
       and compare values returned from the functions with these constants in
       testing methods.
    
    [trac930] remove the tearDown method which has no test case in the TestCallback
              class

commit 1d1a87939a010bd16ed23cd817261e9a655bf98f
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Tue Aug 2 19:57:58 2011 +0900

    [trac930] remove tailing whitespaces.

commit c6948a6df9aeedd3753bc4c5e3a553088cd98f63
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Mon Aug 1 18:38:35 2011 +0900

    [trac930] raise StatsError including errors in the stats spec file

commit db0371fc9e5c7a85ab524ab7bc0b8169b9ba0486
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Mon Aug 1 18:21:23 2011 +0900

    [trac930] rename the function name
     - rename the name of 'parse_spec' to 'get_spec_defaults' in the result of
       consideration of what it is doing
     - modify the description of the function as docstring
     - fix unitttests for the stats module depending on the function name

commit e906efc3747f052128eef50bed0107a0d53546c8
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 29 22:11:38 2011 +0900

    [trac930] remove a unnecessary x bit from stats_httpd.py.in

commit d86a9dceaddf5a2cee44170e6e677f492df5e0ea
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Thu Jul 28 22:07:15 2011 +0900

    [trac930] modify logging
    add loggings and new messages for logging
    remove unused messages from the message file
    add test logging names into unittest scripts

commit 4c2732cbf0bb7384ed61ab3604855f143a0c6c5d
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Jul 27 20:45:18 2011 +0900

    [trac930] modify the update_modues function
    There is no part of statistics category in the spec file of a module which has
    no statistics data.

commit aaffb9c83c0fe59d9c7d590c5bea559ed8876269
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Jul 27 16:49:21 2011 +0900

    [trac930]
     - correct error messages in bindctl
       it prints together with arguments.
     - modify the command_show function
       it reports statistics data of the module even if name is not specified.
     - add/modify unittests depending on the changes of error messages

commit e8a22472e58bfc7df4a661d665152fe4d70454a6
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Jul 27 16:42:54 2011 +0900

    [trac930] remove unnecessary a white space

commit 2c22d334a05ec1e77299a6c55252f1d1c33082af
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Jul 27 10:18:07 2011 +0900

    [trac930] add a test pattern which the set command with a non-existent item
    name is sent

commit 8a24b9066537caf373d0cfc11dca855eb6c3e4d9
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Jul 27 10:14:57 2011 +0900

    [trac930] modify parse_spec function
    returns empty dict if list-type is not specified in the argument

commit 7275c59de54593d3baca81345226dda2d3a19c30
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 21:40:07 2011 +0900

    [trac930] fix conflicts with trac1021

commit bcf37a11b08922d69d02fa2ea1b280b2fa2c21e0
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:50:41 2011 +0900

    [trac930] add changes because query counter names described in the specfile are changed.

commit a142fa6302e1e0ea2ad1c9faf59d6a70a53a6489
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:45:19 2011 +0900

    [trac930] add the logging when the validation of statistics data fails

commit ae8748f77a0261623216b1a11f9d979f555fe892
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:43:26 2011 +0900

    [trac930] Add unittests to test sumitStatistics with the validation of statistics data and add mock ModuleSpec class

commit d0d5a67123b8009e89e84515eee4f93b37ec8497
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:41:34 2011 +0900

    [trac930] Add prototypes of validator_typea and registerStatisticsValidator
     - validator_type -- a type of statistics validation function
     - registerStatisticsValidator -- the function to register the validation function

commit a9a976d2a5871f1501018d697d3afd299ceec5da
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:37:22 2011 +0900

    [trac930]
    - Add implementation to validate statistics data
      -- When validation is success, it sends data to statistics module. But when it fails, it doesn't send and logs the message.
    
    - Add the function to register the validation function into the class

commit df9a8f921f0d20bd70c519218335357297bffa7d
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:32:22 2011 +0900

    [trac930] add the helper functions which are used around the registration of the function to validate the statistics data.

commit e95625332a20fb50afe43da2db0cab507efe8ebe
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 22 18:28:40 2011 +0900

    [trac930] add new messages into the message file of Auth and Boss
    when validation of statistics data to send to statistics module is failed.

commit 28cad73dff9dae43a38ad7dafbee406c690fb77c
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Jul 20 10:00:29 2011 +0900

    [trac930] add statistics validation for bob

commit 4de3a5bdf367d87247cb9138f8929ab4798f014e
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Wed Jul 13 20:25:54 2011 +0900

    [trac930]
     - increase seconds in sleep time which is before HTTP client connects to the server
     - delete 'test_log_message' because of the deletion of original function

commit aa108cc824539a1d32a4aa2f46f9e58171074a9e
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 21:22:34 2011 +0900

    [trac930] remove unneeded empty TODO comments

commit 691328d91b4c4d15ace467ca47a3c987a9fb52b9
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 21:09:41 2011 +0900

    [trac930] add new entry for #928-#930

commit c06463cf96ea7401325a208af8ba457e661d1cec
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 20:08:22 2011 +0900

    [trac930] refurbish the unittests for new stats module, new stats httpd module
    and new mockups and utilities in test_utils.py

commit c074f6e0b72c3facf6b325b17dea1ca13a2788cc
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 19:56:24 2011 +0900

    [trac930] modify Stats
     - remove unneeded subject and listener classes
    
     - add StatsError for handling errors in Stats
    
     - add some new methods (update_modules, update_statistics_data and
       get_statistics_data)
    
     - modify implementations of existent commands(show and set) according changes
       stats.spec
    
     - remove reset and remove command because stats module couldn't manage other
       modules' statistics data schema
    
     - add implementation of strict validation of each statistics data
       (If the validation is failed, it puts out the error.)
    
     - stats module shows its PID when status command invoked
    
     - add new command showschema invokable via bindctl
    
     - set command requires arguments of owner module name and statistics item name
    
     - show and showschema commands accepts arguments of owner module name and
       statistics item name
    
     - exits at exit code 1 if got runtime errors
    
     - has boot time in _BASETIME

commit daa1d6dd07292142d3dec5928583b0ab1da89adf
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 19:40:15 2011 +0900

    [trac930]
     - remove "stats-schema.spec" setting and getting statistics data schema via
       this spec file
    
     - add "version" item in DEFAULT_CONFIG
    
     - get the address family by socket.getaddrinfo function with specified
       server_address in advance, and create HttpServer object once, in stead of
       creating double HttpServer objects for IPv6 and IPv4 in the prior code
       (It is aimed for avoiding to fail to close the once opened sockets.)
    
     - open HTTP port in start method
    
     - avoid calling config_handler recursively in the except statement
    
     - create XML, XSD, XSL documents after getting statistics data and schema from
       remote stats module via CC session
    
     - definitely close once opened template file object

commit e7b4337aeaa760947e8e7906e64077ad7aaadc66
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:33:59 2011 +0900

    [trac930] update spec file of stats module
    - update description of status command, shutdown command and show command
    - change argument of show command (Owner module name of statistics data can be
    specified)
    - change argument of set command (Owner module name of statistics data is
    always required)
    - add showschema command which shows statistics data schema of each module
    specified)
    - disabled reset command and remove command

commit 0b235902f38d611606d44661506f32baf266fdda
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:21:49 2011 +0900

    [trac930] update argument name and argument format of set command in auth module and boss module
    and also update related unittests of their modules

commit c19a295eb4125b4d2a391de65972271002412258
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:18:38 2011 +0900

    [trac930] remove description about removing statistics data by stats module
    update example format in bindctl when show command of stats module is invoked

commit 9261da8717a433cf20218af08d3642fbeffb7d4b
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:13:17 2011 +0900

    [trac930] add a column "Owner" in the table tag

commit d4078d52343247b07c47370b497927a3a47a4f9a
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:12:09 2011 +0900

    [trac930] remove descriptions about "stats-schema.spec" and add description about new
    features because stats module can be requested to show statistics data schema.

commit 1aa728ddf691657611680385c920e3a7bd5fee12
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 16:00:30 2011 +0900

    [trac930] add utilities and mock-up modules for unittests of
    statistics modules and change some environ variables (PYTHONPATH,
    CONFIG_TESTDATA_PATH) in Makefile
    
    test_utilies.py internally calls msgq, cfgmgr and some mock modules
    with threads for as real situation as possible.

commit 1768e822df82943f075ebed023b72d225b3b0216
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 15:57:41 2011 +0900

    [trac930] remove unneeded mockups, fake modules and dummy data

commit 326885a3f98c49a848a67dc48db693b8bcc7b508
Author: Naoki Kambe <kambe at jprs.co.jp>
Date:   Fri Jul 8 15:55:55 2011 +0900

    [trac930] remove unneeded specfile "stats-schema.spec"

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

Summary of changes:
 ChangeLog                                          |    4 +
 README                                             |    4 +-
 doc/guide/bind10-guide.xml                         |  760 ++++++++++++++++++--
 src/bin/auth/query.cc                              |    8 +-
 src/bin/auth/query.h                               |    8 +-
 src/bin/auth/tests/query_unittest.cc               |    4 +-
 src/bin/bind10/creatorapi.txt                      |  123 ++++
 src/lib/datasrc/database.cc                        |  235 ++++++-
 src/lib/datasrc/database.h                         |  135 ++++-
 src/lib/datasrc/datasrc_messages.mes               |   40 +
 src/lib/datasrc/memory_datasrc.cc                  |    2 +-
 src/lib/datasrc/memory_datasrc.h                   |    2 +-
 src/lib/datasrc/sqlite3_accessor.cc                |  120 +++-
 src/lib/datasrc/sqlite3_accessor.h                 |   55 ++
 src/lib/datasrc/tests/database_unittest.cc         |  592 +++++++++++++++-
 src/lib/datasrc/tests/sqlite3_accessor_unittest.cc |  148 ++++-
 src/lib/datasrc/zone.h                             |    2 +-
 src/lib/dns/rdata/generic/rrsig_46.cc              |    5 +
 src/lib/dns/rdata/generic/rrsig_46.h               |    3 +
 src/lib/dns/tests/rdata_rrsig_unittest.cc          |    2 +-
 src/lib/util/filename.h                            |    5 +
 src/lib/util/tests/filename_unittest.cc            |   15 +
 22 files changed, 2160 insertions(+), 112 deletions(-)
 create mode 100644 src/bin/bind10/creatorapi.txt

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index c102840..3e1efbe 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,10 @@ xxx.    [func]          naokikambe
 	schema by each module via both bindctl and HTTP/XML.
 	(Trac #928,#929,#930, git nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn)
 
+278.	[doc]		jelte
+	Add logging configuration documentation to the guide.
+	(Trac #1011, git TODO)
+
 277.	[func]		jerry
 	Implement the SRV rrtype according to RFC2782.
 	(Trac #1128, git 5fd94aa027828c50e63ae1073d9d6708e0a9c223)
diff --git a/README b/README
index a9e05f1..4b84a88 100644
--- a/README
+++ b/README
@@ -67,8 +67,8 @@ e.g.,
 Operating-System specific tips:
 
 - FreeBSD
-  You may need to install a python binding for sqlite3 by hand.  A
-  sample procedure is as follows:
+  You may need to install a python binding for sqlite3 by hand.
+  A sample procedure is as follows:
   - add the following to /etc/make.conf
     PYTHON_VERSION=3.1
   - build and install the python binding from ports, assuming the top
diff --git a/doc/guide/bind10-guide.xml b/doc/guide/bind10-guide.xml
index 6c3f332..297400c 100644
--- a/doc/guide/bind10-guide.xml
+++ b/doc/guide/bind10-guide.xml
@@ -146,7 +146,7 @@
 	The processes started by the <command>bind10</command>
 	command have names starting with "b10-", including:
       </para>
-      
+
       <para>
 
         <itemizedlist>
@@ -547,7 +547,7 @@ Debian and Ubuntu:
           <varlistentry>
             <term>--prefix</term>
             <listitem>
-              <simpara>Define the the installation location (the
+              <simpara>Define the installation location (the
                 default is <filename>/usr/local/</filename>).
               </simpara>
             </listitem> 
@@ -1486,61 +1486,679 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
   <chapter id="logging">
     <title>Logging</title>
 
-<!-- TODO: how to configure logging, logging destinations etc. -->
+    <section>
+      <title>Logging configuration</title>
 
-    <para>
-        Each message written by BIND 10 to the configured logging destinations
-        comprises a number of components that identify the origin of the
-        message and, if the message indicates a problem, information about the
-        problem that may be useful in fixing it.
-    </para>
+      <para>
 
-    <para>
-        Consider the message below logged to a file:
-        <screen>2011-06-15 13:48:22.034 ERROR [b10-resolver.asiolink]
-    ASIODNS_OPENSOCK error 111 opening TCP socket to 127.0.0.1(53)</screen>
-    </para>
+	The logging system in BIND 10 is configured through the
+	Logging module. All BIND 10 modules will look at the
+	configuration in Logging to see what should be logged and
+	to where.
 
-    <para>
-      Note: the layout of messages written to the system logging
-      file (syslog) may be slightly different.  This message has
-      been split across two lines here for display reasons; in the
-      logging file, it will appear on one line.)
-    </para>
+<!-- TODO: what is context of Logging module for readers of this guide? -->
 
-    <para>
-      The log message comprises a number of components:
+      </para>
+
+      <section>
+        <title>Loggers</title>
+
+        <para>
+
+	  Within BIND 10, a message is logged through a component
+	  called a "logger". Different parts of BIND 10 log messages
+	  through different loggers, and each logger can be configured
+	  independently of one another.
+
+        </para>
+
+        <para>
+
+	  In the Logging module, you can specify the configuration
+	  for zero or more loggers; any that are not specified will
+	  take appropriate default values..
+
+        </para>
+
+        <para>
+
+	  The three most important elements of a logger configuration
+	  are the <option>name</option> (the component that is
+	  generating the messages), the <option>severity</option>
+	  (what to log), and the <option>output_options</option>
+	  (where to log).
+
+        </para>
+
+        <section>
+          <title>name (string)</title>
+
+          <para>
+	  Each logger in the system has a name, the name being that
+	  of the component using it to log messages. For instance,
+	  if you want to configure logging for the resolver module,
+	  you add an entry for a logger named <quote>Resolver</quote>. This
+	  configuration will then be used by the loggers in the
+	  Resolver module, and all the libraries used by it.
+              </para>
+
+<!-- TODO: later we will have a way to know names of all modules
+
+Right now you can only see what their names are if they are running
+(a simple 'help' without anything else in bindctl for instance).
+
+ -->
+
+        <para>
+
+	  If you want to specify logging for one specific library
+	  within the module, you set the name to
+	  <replaceable>module.library</replaceable>.  For example, the
+	  logger used by the nameserver address store component
+	  has the full name of <quote>Resolver.nsas</quote>. If
+	  there is no entry in Logging for a particular library,
+	  it will use the configuration given for the module.
+
+<!-- TODO: how to know these specific names?
+
+We will either have to document them or tell the administrator to
+specify module-wide logging and see what appears...
+
+-->
+
+        </para>
+
+        <para>
+
+<!-- TODO: severity has not been covered yet -->
+
+	  To illustrate this, suppose you want the cache library
+	  to log messages of severity DEBUG, and the rest of the
+	  resolver code to log messages of severity INFO. To achieve
+	  this you specify two loggers, one with the name
+	  <quote>Resolver</quote> and severity INFO, and one with
+	  the name <quote>Resolver.cache</quote> with severity
+	  DEBUG. As there are no entries for other libraries (e.g.
+	  the nsas), they will use the configuration for the module
+	  (<quote>Resolver</quote>), so giving the desired behavior.
+
+        </para>
+
+        <para>
+
+	  One special case is that of a module name of <quote>*</quote>
+	  (asterisks), which is interpreted as <emphasis>any</emphasis>
+	  module. You can set global logging options by using this,
+	  including setting the logging configuration for a library
+	  that is used by multiple modules (e.g. <quote>*.config</quote>
+	  specifies the configuration library code in whatever
+	  module is using it).
+
+        </para>
+
+        <para>
+
+	  If there are multiple logger specifications in the
+	  configuration that might match a particular logger, the
+	  specification with the more specific logger name takes
+	  precedence. For example, if there are entries for for
+	  both <quote>*</quote> and <quote>Resolver</quote>, the
+	  resolver module — and all libraries it uses —
+	  will log messages according to the configuration in the
+	  second entry (<quote>Resolver</quote>). All other modules
+	  will use the configuration of the first entry
+	  (<quote>*</quote>). If there was also a configuration
+	  entry for <quote>Resolver.cache</quote>, the cache library
+	  within the resolver would use that in preference to the
+	  entry for <quote>Resolver</quote>.
+
+        </para>
+
+        <para>
+
+	  One final note about the naming. When specifying the
+	  module name within a logger, use the name of the module
+	  as specified in <command>bindctl</command>, e.g.
+	  <quote>Resolver</quote> for the resolver module,
+	  <quote>Xfrout</quote> for the xfrout module, etc. When
+	  the message is logged, the message will include the name
+	  of the logger generating the message, but with the module
+	  name replaced by the name of the process implementing
+	  the module (so for example, a message generated by the
+	  <quote>Auth.cache</quote> logger will appear in the output
+	  with a logger name of <quote>b10-auth.cache</quote>).
+
+        </para>
+
+        </section>
+
+        <section>
+          <title>severity (string)</title>
+
+        <para>
+
+          This specifies the category of messages logged.
+	  Each message is logged with an associated severity which
+	  may be one of the following (in descending order of
+	  severity):
+        </para>
+
+        <itemizedlist>
+          <listitem>
+            <simpara> FATAL </simpara>
+          </listitem>
+
+          <listitem>
+            <simpara> ERROR </simpara>
+          </listitem>
+
+          <listitem>
+            <simpara> WARN </simpara>
+          </listitem>
+
+          <listitem>
+            <simpara> INFO </simpara>
+          </listitem>
+
+          <listitem>
+            <simpara> DEBUG </simpara>
+          </listitem>
+        </itemizedlist>
+
+        <para>
+
+	  When the severity of a logger is set to one of these
+	  values, it will only log messages of that severity, and
+	  the severities above it. The severity may also be set to
+	  NONE, in which case all messages from that logger are
+	  inhibited.
+
+<!-- TODO: worded wrong? If I set to INFO, why would it show DEBUG which is literally below in that list? -->
+
+        </para>
+
+        </section>
+
+        <section>
+          <title>output_options (list)</title>
+
+        <para>
+
+	  Each logger can have zero or more
+	  <option>output_options</option>. These specify where log
+	  messages are sent to. These are explained in detail below.
+
+        </para>
+
+        <para>
+
+          The other options for a logger are:
+
+        </para>
+
+        </section>
+
+        <section>
+          <title>debuglevel (integer)</title>
+
+        <para>
+
+	  When a logger's severity is set to DEBUG, this value
+	  specifies what debug messages should be printed. It ranges
+	  from 0 (least verbose) to 99 (most verbose).
+        </para>
+
+
+<!-- TODO: complete this sentence:
+
+	  The general classification of debug message types is
+
+TODO; there's a ticket to determine these levels, see #1074
+
+ -->
+
+        <para>
+
+          If severity for the logger is not DEBUG, this value is ignored.
+
+        </para>
+
+        </section>
+
+        <section>
+          <title>additive (true or false)</title>
+
+        <para>
+
+	  If this is true, the <option>output_options</option> from
+	  the parent will be used. For example, if there are two
+	  loggers configured; <quote>Resolver</quote> and
+	  <quote>Resolver.cache</quote>, and <option>additive</option>
+	  is true in the second, it will write the log messages
+	  not only to the destinations specified for
+	  <quote>Resolver.cache</quote>, but also to the destinations
+	  as specified in the <option>output_options</option> in
+	  the logger named <quote>Resolver</quote>.
+
+<!-- TODO: check this -->
+
+      </para>
+
+      </section>
+
+      </section>
+
+      <section>
+        <title>Output Options</title>
+
+        <para>
+
+	  The main settings for an output option are the
+	  <option>destination</option> and a value called
+	  <option>output</option>, the meaning of which depends on
+	  the destination that is set.
+
+        </para>
+
+        <section>
+          <title>destination (string)</title>
+
+          <para>
+
+            The destination is the type of output. It can be one of:
+
+          </para>
+
+          <itemizedlist>
+
+            <listitem>
+              <simpara> console </simpara>
+          </listitem>
+
+            <listitem>
+              <simpara> file </simpara>
+          </listitem>
+
+            <listitem>
+              <simpara> syslog </simpara>
+            </listitem>
+
+          </itemizedlist>
+
+        </section>
+
+        <section>
+          <title>output (string)</title>
+
+        <para>
+
+	  Depending on what is set as the output destination, this
+	  value is interpreted as follows:
+
+        </para>
 
         <variablelist>
-        <varlistentry>
-        <term>2011-06-15 13:48:22.034</term>
-        <listitem><para>
-            The date and time at which the message was generated.
-        </para></listitem>
-        </varlistentry>
-
-        <varlistentry>
-        <term>ERROR</term>
-        <listitem><para>
-            The severity of the message.
-        </para></listitem>
-        </varlistentry>
-
-        <varlistentry>
-        <term>[b10-resolver.asiolink]</term>
-        <listitem><para>
-	    The source of the message.  This comprises two components:
-	    the BIND 10 process generating the message (in this
-	    case, <command>b10-resolver</command>) and the module
-	    within the program from which the message originated
-	    (which in the example is the asynchronous I/O link
-	    module, asiolink).
-        </para></listitem>
-        </varlistentry>
-
-        <varlistentry>
-        <term>ASIODNS_OPENSOCK</term>
-        <listitem><para>
+
+          <varlistentry>
+            <term><option>destination</option> is <quote>console</quote></term>
+            <listitem>
+              <simpara>
+		 The value of output must be one of <quote>stdout</quote>
+		 (messages printed to standard output) or
+		 <quote>stderr</quote> (messages printed to standard
+		 error).
+              </simpara>
+            </listitem>
+          </varlistentry>
+
+          <varlistentry>
+            <term><option>destination</option> is <quote>file</quote></term>
+            <listitem>
+              <simpara>
+		The value of output is interpreted as a file name;
+		log messages will be appended to this file.
+              </simpara>
+            </listitem>
+          </varlistentry>
+
+          <varlistentry>
+            <term><option>destination</option> is <quote>syslog</quote></term>
+            <listitem>
+              <simpara>
+		The value of output is interpreted as the
+		<command>syslog</command> facility (e.g.
+		<emphasis>local0</emphasis>) that should be used
+		for log messages.
+              </simpara>
+            </listitem>
+          </varlistentry>
+
+        </variablelist>
+
+        <para>
+
+          The other options for <option>output_options</option> are:
+
+        </para>
+
+        <section>
+          <title>flush (true of false)</title>
+
+          <para>
+	    Flush buffers after each log message. Doing this will
+	    reduce performance but will ensure that if the program
+	    terminates abnormally, all messages up to the point of
+	    termination are output.
+          </para>
+
+        </section>
+
+        <section>
+          <title>maxsize (integer)</title>
+
+          <para>
+	    Only relevant when destination is file, this is maximum
+	    file size of output files in bytes. When the maximum
+	    size is reached, the file is renamed and a new file opened.
+	    (For example, a ".1" is appended to the name —
+	    if a ".1" file exists, it is renamed ".2",
+            etc.)
+          </para>
+
+          <para>
+            If this is 0, no maximum file size is used.
+          </para>
+
+        </section>
+
+        <section>
+          <title>maxver (integer)</title>
+
+          <para>
+	    Maximum number of old log files to keep around when
+	    rolling the output file. Only relevant when
+	    <option>destination</option> is <quote>file</quote>.
+          </para>
+
+        </section>
+
+      </section>
+
+      </section>
+
+      <section>
+        <title>Example session</title>
+
+        <para>
+
+	  In this example we want to set the global logging to
+	  write to the file <filename>/var/log/my_bind10.log</filename>,
+	  at severity WARN. We want the authoritative server to
+	  log at DEBUG with debuglevel 40, to a different file
+	  (<filename>/tmp/debug_messages</filename>).
+
+        </para>
+
+        <para>
+
+          Start <command>bindctl</command>.
+
+        </para>
+
+        <para>
+
+           <screen>["login success "]
+> <userinput>config show Logging</userinput>
+Logging/loggers	[]	list
+</screen>
+
+        </para>
+
+        <para>
+
+	  By default, no specific loggers are configured, in which
+	  case the severity defaults to INFO and the output is
+	  written to stderr.
+
+        </para>
+
+        <para>
+
+          Let's first add a default logger:
+
+        </para>
+
+<!-- TODO: adding the empty loggers makes no sense -->
+        <para>
+
+          <screen><userinput>> config add Logging/loggers</userinput>
+> <userinput>config show Logging</userinput>
+Logging/loggers/	list	(modified)
+</screen>
+
+        </para>
+
+        <para>
+
+	  The loggers value line changed to indicate that it is no
+	  longer an empty list:
+
+        </para>
+
+        <para>
+
+          <screen>> <userinput>config show Logging/loggers</userinput>
+Logging/loggers[0]/name	""	string	(default)
+Logging/loggers[0]/severity	"INFO"	string	(default)
+Logging/loggers[0]/debuglevel	0	integer	(default)
+Logging/loggers[0]/additive	false	boolean	(default)
+Logging/loggers[0]/output_options	[]	list	(default)
+</screen>
+
+        </para>
+
+        <para>
+
+	  The name is mandatory, so we must set it. We will also
+	  change the severity as well. Let's start with the global
+	  logger.
+
+        </para>
+
+        <para>
+
+          <screen>> <userinput>config set Logging/loggers[0]/name *</userinput>
+> <userinput>config set Logging/loggers[0]/severity WARN</userinput>
+> <userinput>config show Logging/loggers</userinput>
+Logging/loggers[0]/name	"*"	string	(modified)
+Logging/loggers[0]/severity	"WARN"	string	(modified)
+Logging/loggers[0]/debuglevel	0	integer	(default)
+Logging/loggers[0]/additive	false	boolean	(default)
+Logging/loggers[0]/output_options	[]	list	(default)
+</screen>
+
+        </para>
+
+        <para>
+
+	  Of course, we need to specify where we want the log
+	  messages to go, so we add an entry for an output option.
+
+        </para>
+
+        <para>
+
+          <screen>> <userinput> config add Logging/loggers[0]/output_options</userinput>
+> <userinput> config show Logging/loggers[0]/output_options</userinput>
+Logging/loggers[0]/output_options[0]/destination	"console"	string	(default)
+Logging/loggers[0]/output_options[0]/output	"stdout"	string	(default)
+Logging/loggers[0]/output_options[0]/flush	false	boolean	(default)
+Logging/loggers[0]/output_options[0]/maxsize	0	integer	(default)
+Logging/loggers[0]/output_options[0]/maxver	0	integer	(default)
+</screen>
+
+
+        </para>
+
+        <para>
+
+          These aren't the values we are looking for.
+
+        </para>
+
+        <para>
+
+          <screen>> <userinput> config set Logging/loggers[0]/output_options[0]/destination file</userinput>
+> <userinput> config set Logging/loggers[0]/output_options[0]/output /var/log/bind10.log</userinput>
+> <userinput> config set Logging/loggers[0]/output_options[0]/maxsize 30000</userinput>
+> <userinput> config set Logging/loggers[0]/output_options[0]/maxver 8</userinput>
+</screen>
+
+        </para>
+
+        <para>
+
+	  Which would make the entire configuration for this logger
+	  look like:
+
+        </para>
+
+        <para>
+
+          <screen>> <userinput> config show all Logging/loggers</userinput>
+Logging/loggers[0]/name	"*"	string	(modified)
+Logging/loggers[0]/severity	"WARN"	string	(modified)
+Logging/loggers[0]/debuglevel	0	integer	(default)
+Logging/loggers[0]/additive	false	boolean	(default)
+Logging/loggers[0]/output_options[0]/destination	"file"	string	(modified)
+Logging/loggers[0]/output_options[0]/output	"/var/log/bind10.log"	string	(modified)
+Logging/loggers[0]/output_options[0]/flush	false	boolean	(default)
+Logging/loggers[0]/output_options[0]/maxsize	30000	integer	(modified)
+Logging/loggers[0]/output_options[0]/maxver	8	integer	(modified)
+</screen>
+
+        </para>
+
+        <para>
+
+	  That looks OK, so let's commit it before we add the
+	  configuration for the authoritative server's logger.
+
+        </para>
+
+        <para>
+
+          <screen>> <userinput> config commit</userinput></screen>
+
+        </para>
+
+        <para>
+
+	  Now that we have set it, and checked each value along
+	  the way, adding a second entry is quite similar.
+
+        </para>
+
+        <para>
+
+          <screen>> <userinput> config add Logging/loggers</userinput>
+> <userinput> config set Logging/loggers[1]/name Auth</userinput>
+> <userinput> config set Logging/loggers[1]/severity DEBUG</userinput>
+> <userinput> config set Logging/loggers[1]/debuglevel 40</userinput>
+> <userinput> config add Logging/loggers[1]/output_options</userinput>
+> <userinput> config set Logging/loggers[1]/output_options[0]/destination file</userinput>
+> <userinput> config set Logging/loggers[1]/output_options[0]/output /tmp/auth_debug.log</userinput>
+> <userinput> config commit</userinput>
+</screen>
+
+        </para>
+
+        <para>
+
+	  And that's it. Once we have found whatever it was we
+	  needed the debug messages for, we can simply remove the
+	  second logger to let the authoritative server use the
+	  same settings as the rest.
+
+        </para>
+
+        <para>
+
+          <screen>> <userinput> config remove Logging/loggers[1]</userinput>
+> <userinput> config commit</userinput>
+</screen>
+
+        </para>
+
+        <para>
+
+	  And every module will now be using the values from the
+	  logger named <quote>*</quote>.
+
+        </para>
+
+      </section>
+
+    </section>
+
+    <section>
+      <title>Logging Message Format</title>
+
+      <para>
+	  Each message written by BIND 10 to the configured logging
+	  destinations comprises a number of components that identify
+	  the origin of the message and, if the message indicates
+	  a problem, information about the problem that may be
+	  useful in fixing it.
+      </para>
+
+      <para>
+          Consider the message below logged to a file:
+          <screen>2011-06-15 13:48:22.034 ERROR [b10-resolver.asiolink]
+    ASIODNS_OPENSOCK error 111 opening TCP socket to 127.0.0.1(53)</screen>
+      </para>
+
+      <para>
+        Note: the layout of messages written to the system logging
+        file (syslog) may be slightly different.  This message has
+        been split across two lines here for display reasons; in the
+        logging file, it will appear on one line.)
+      </para>
+
+      <para>
+        The log message comprises a number of components:
+
+          <variablelist>
+          <varlistentry>
+          <term>2011-06-15 13:48:22.034</term>
+<!-- TODO: timestamp repeated even if using syslog? -->
+          <listitem><para>
+              The date and time at which the message was generated.
+          </para></listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term>ERROR</term>
+          <listitem><para>
+              The severity of the message.
+          </para></listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term>[b10-resolver.asiolink]</term>
+          <listitem><para>
+            The source of the message.  This comprises two components:
+            the BIND 10 process generating the message (in this
+            case, <command>b10-resolver</command>) and the module
+            within the program from which the message originated
+            (which in the example is the asynchronous I/O link
+            module, asiolink).
+          </para></listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term>ASIODNS_OPENSOCK</term>
+          <listitem><para>
 	    The message identification.  Every message in BIND 10
 	    has a unique identification, which can be used as an
 	    index into the <ulink
@@ -1548,25 +2166,29 @@ then change those defaults with config set Resolver/forward_addresses[0]/address
 	    Manual</citetitle></ulink> (<ulink
 	    url="http://bind10.isc.org/docs/bind10-messages.html"
 	    />) from which more information can be obtained.
-        </para></listitem>
-        </varlistentry>
-
-        <varlistentry>
-        <term>error 111 opening TCP socket to 127.0.0.1(53)</term>
-        <listitem><para>
-            A brief description of the cause of the problem.  Within this text,
-            information relating to the condition that caused the message to
-            be logged will be included.  In this example, error number 111
-            (an operating system-specific error number) was encountered when
-            trying to open a TCP connection to port 53 on the local system
-            (address 127.0.0.1).  The next step would be to find out the reason
-            for the failure by consulting your system's documentation to
-            identify what error number 111 means.
-        </para></listitem>
-        </varlistentry>
-        </variablelist>
+          </para></listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term>error 111 opening TCP socket to 127.0.0.1(53)</term>
+          <listitem><para>
+	      A brief description of the cause of the problem.
+	      Within this text, information relating to the condition
+	      that caused the message to be logged will be included.
+	      In this example, error number 111 (an operating
+	      system-specific error number) was encountered when
+	      trying to open a TCP connection to port 53 on the
+	      local system (address 127.0.0.1).  The next step
+	      would be to find out the reason for the failure by
+	      consulting your system's documentation to identify
+	      what error number 111 means.
+          </para></listitem>
+          </varlistentry>
+          </variablelist>
+      </para>
+
+    </section>
 
-    </para>
   </chapter>
 
 <!-- TODO: how to help: run unit tests, join lists, review trac tickets -->
diff --git a/src/bin/auth/query.cc b/src/bin/auth/query.cc
index 05bcd89..3fe03c8 100644
--- a/src/bin/auth/query.cc
+++ b/src/bin/auth/query.cc
@@ -31,7 +31,7 @@ namespace isc {
 namespace auth {
 
 void
-Query::getAdditional(const ZoneFinder& zone, const RRset& rrset) const {
+Query::getAdditional(ZoneFinder& zone, const RRset& rrset) const {
     RdataIteratorPtr rdata_iterator(rrset.getRdataIterator());
     for (; !rdata_iterator->isLast(); rdata_iterator->next()) {
         const Rdata& rdata(rdata_iterator->getCurrent());
@@ -47,7 +47,7 @@ Query::getAdditional(const ZoneFinder& zone, const RRset& rrset) const {
 }
 
 void
-Query::findAddrs(const ZoneFinder& zone, const Name& qname,
+Query::findAddrs(ZoneFinder& zone, const Name& qname,
                  const ZoneFinder::FindOptions options) const
 {
     // Out of zone name
@@ -86,7 +86,7 @@ Query::findAddrs(const ZoneFinder& zone, const Name& qname,
 }
 
 void
-Query::putSOA(const ZoneFinder& zone) const {
+Query::putSOA(ZoneFinder& zone) const {
     ZoneFinder::FindResult soa_result(zone.find(zone.getOrigin(),
         RRType::SOA()));
     if (soa_result.code != ZoneFinder::SUCCESS) {
@@ -104,7 +104,7 @@ Query::putSOA(const ZoneFinder& zone) const {
 }
 
 void
-Query::getAuthAdditional(const ZoneFinder& zone) const {
+Query::getAuthAdditional(ZoneFinder& zone) const {
     // Fill in authority and addtional sections.
     ZoneFinder::FindResult ns_result = zone.find(zone.getOrigin(),
                                                  RRType::NS());
diff --git a/src/bin/auth/query.h b/src/bin/auth/query.h
index fa023fe..13523e8 100644
--- a/src/bin/auth/query.h
+++ b/src/bin/auth/query.h
@@ -69,7 +69,7 @@ private:
     /// Adds a SOA of the zone into the authority zone of response_.
     /// Can throw NoSOA.
     ///
-    void putSOA(const isc::datasrc::ZoneFinder& zone) const;
+    void putSOA(isc::datasrc::ZoneFinder& zone) const;
 
     /// \brief Look up additional data (i.e., address records for the names
     /// included in NS or MX records).
@@ -85,7 +85,7 @@ private:
     /// query is to be found.
     /// \param rrset The RRset (i.e., NS or MX rrset) which require additional
     /// processing.
-    void getAdditional(const isc::datasrc::ZoneFinder& zone,
+    void getAdditional(isc::datasrc::ZoneFinder& zone,
                        const isc::dns::RRset& rrset) const;
 
     /// \brief Find address records for a specified name.
@@ -104,7 +104,7 @@ private:
     /// be found.
     /// \param qname The name in rrset RDATA.
     /// \param options The search options.
-    void findAddrs(const isc::datasrc::ZoneFinder& zone,
+    void findAddrs(isc::datasrc::ZoneFinder& zone,
                    const isc::dns::Name& qname,
                    const isc::datasrc::ZoneFinder::FindOptions options
                    = isc::datasrc::ZoneFinder::FIND_DEFAULT) const;
@@ -127,7 +127,7 @@ private:
     ///
     /// \param zone The \c ZoneFinder through which the NS and additional data
     /// for the query are to be found.
-    void getAuthAdditional(const isc::datasrc::ZoneFinder& zone) const;
+    void getAuthAdditional(isc::datasrc::ZoneFinder& zone) const;
 
 public:
     /// Constructor from query parameters.
diff --git a/src/bin/auth/tests/query_unittest.cc b/src/bin/auth/tests/query_unittest.cc
index 9ef8c13..68f0a1d 100644
--- a/src/bin/auth/tests/query_unittest.cc
+++ b/src/bin/auth/tests/query_unittest.cc
@@ -127,7 +127,7 @@ public:
     virtual FindResult find(const isc::dns::Name& name,
                             const isc::dns::RRType& type,
                             RRsetList* target = NULL,
-                            const FindOptions options = FIND_DEFAULT) const;
+                            const FindOptions options = FIND_DEFAULT);
 
     // If false is passed, it makes the zone broken as if it didn't have the
     // SOA.
@@ -165,7 +165,7 @@ private:
 
 ZoneFinder::FindResult
 MockZoneFinder::find(const Name& name, const RRType& type,
-                     RRsetList* target, const FindOptions options) const
+                     RRsetList* target, const FindOptions options)
 {
     // Emulating a broken zone: mandatory apex RRs are missing if specifically
     // configured so (which are rare cases).
diff --git a/src/bin/bind10/creatorapi.txt b/src/bin/bind10/creatorapi.txt
new file mode 100644
index 0000000..c23d907
--- /dev/null
+++ b/src/bin/bind10/creatorapi.txt
@@ -0,0 +1,123 @@
+Socket creator API
+==================
+
+This API is between Boss and other modules to allow them requesting of sockets.
+For simplicity, we will use the socket creator for all (even non-privileged)
+ports for now, but we should have some function where we can abstract it later.
+
+Goals
+-----
+* Be able to request a socket of any combination IPv4/IPv6 UDP/TCP bound to given
+  port and address (sockets that are not bound to anything can be created
+  without privileges, therefore are not requested from the socket creator).
+* Allow to provide the same socket to multiple modules (eg. multiple running
+  auth servers).
+* Allow releasing the sockets (in case all modules using it give it up,
+  terminate or crash).
+* Allow restricting of the sharing (don't allow shared socket between auth
+  and recursive, as the packets would often get to the wrong application,
+  show error instead).
+* Get the socket to the application.
+
+Transport of sockets
+--------------------
+It seems we are stuck with current msgq for a while and there's a chance the
+new replacement will not be able to send sockets inbound. So, we need another
+channel.
+
+The boss will create a unix-domain socket and listen on it. When something
+requests a socket over the command channel and the socket is created, some kind
+of token is returned to the application (which will represent the future
+socket). The application then connects to the unix-domain socket, sends the
+token over the connection (so Boss will know which socket to send there, in case
+multiple applications ask for sockets simultaneously) and Boss sends the socket
+in return.
+
+In theory, we could send the requests directly over the unix-domain
+socket, but it has two disadvantages:
+* The msgq handles serializing/deserializing of structured
+  information (like the parameters to be used), we would have to do it
+  manually on the socket.
+* We could place some kind of security in front of msgq (in case file
+  permissions are not enough, for example if they are not honored on
+  socket files, as indicated in the first paragraph of:
+  http://lkml.indiana.edu/hypermail/linux/kernel/0505.2/0008.html).
+  The socket would have to be secured separately. With the tokens,
+  there's some level of security already - someone not having the
+  token can't request a priviledged socket.
+
+Caching of sockets
+------------------
+To allow sending the same socket to multiple application, the Boss process will
+hold a cache. Each socket that is created and sent is kept open in Boss and
+preserved there as well. A reference count is kept with each of them.
+
+When another application asks for the same socket, it is simply sent from the
+cache instead of creating it again by the creator.
+
+When application gives the socket willingly (by sending a message over the
+command channel), the reference count can be decreased without problems. But
+when the application terminates or crashes, we need to decrease it as well.
+There's a problem, since we don't know which command channel connection (eg.
+lname) belongs to which PID. Furthermore, the applications don't need to be
+started by boss.
+
+There are two possibilities:
+* Let the msgq send messages about disconnected clients (eg. group message to
+  some name). This one is better if we want to migrate to dbus, since dbus
+  already has this capability as well as sending the sockets inbound (at least it
+  seems so on unix) and we could get rid of the unix-domain socket completely.
+* Keep the unix-domain connections open forever. Boss can remember which socket
+  was sent to which connection and when the connection closes (because the
+  application crashed), it can drop all the references on the sockets. This
+  seems easier to implement.
+
+The commands
+------------
+* Command to release a socket. This one would have single parameter, the token
+  used to get the socket. After this, boss would decrease its reference count
+  and if it drops to zero, close its own copy of the socket. This should be used
+  when the module stops using the socket (and after closes it). The
+  library could remember the file-descriptor to token mapping (for
+  common applications that don't request the same socket multiple
+  times in parallel).
+* Command to request a socket. It would have parameters to specify which socket
+  (IP address, address family, port) and how to allow sharing. Sharing would be
+  one of:
+  - None
+  - Same kind of application (however, it is not entirely clear what
+    this means, in case it won't work out intuitively, we'll need to
+    define it somehow)
+  - Any kind of application
+  And a kind of application would be provided, to decide if the sharing is
+  possible (eg. if auth allows sharing with the same kind and something else
+  allows sharing with anything, the sharing is not possible, two auths can).
+
+  It would return either error (the socket can't be created or sharing is not
+  possible) or the token. Then there would be some time for the application to
+  pick up the requested socket.
+
+Examples
+--------
+We probably would have a library with blocking calls to request the
+sockets, so a code could look like:
+
+(socket_fd, token) = request_socket(address, port, 'UDP', SHARE_SAMENAME, 'test-application')
+sock = socket.fromfd(socket_fd)
+
+# Some sock.send and sock.recv stuff here
+
+sock.close()
+release_socket(socket_fd) # or release_socket(token)
+
+Known limitations
+-----------------
+Currently the socket creator doesn't support specifying any socket
+options. If it turns out there are any options that need to be set
+before bind(), we'll need to extend it (and extend the protocol as
+well). If we want to support them, we'll have to solve a possible
+conflict (what to do when two applications request the same socket and
+want to share it, but want different options).
+
+The current socket creator doesn't know raw sockets, but if they are
+needed, it should be easy to add.
diff --git a/src/lib/datasrc/database.cc b/src/lib/datasrc/database.cc
index 0e1418d..d2202cd 100644
--- a/src/lib/datasrc/database.cc
+++ b/src/lib/datasrc/database.cc
@@ -12,10 +12,20 @@
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
 
+#include <vector>
+
 #include <datasrc/database.h>
 
 #include <exceptions/exceptions.h>
 #include <dns/name.h>
+#include <dns/rrttl.h>
+#include <dns/rdata.h>
+#include <dns/rdataclass.h>
+
+#include <datasrc/data_source.h>
+#include <datasrc/logger.h>
+
+#include <boost/foreach.hpp>
 
 using isc::dns::Name;
 
@@ -61,14 +71,229 @@ DatabaseClient::Finder::Finder(boost::shared_ptr<DatabaseAccessor>
     zone_id_(zone_id)
 { }
 
+namespace {
+// Adds the given Rdata to the given RRset
+// If the rrset is an empty pointer, a new one is
+// created with the given name, class, type and ttl
+// The type is checked if the rrset exists, but the
+// name is not.
+//
+// Then adds the given rdata to the set
+//
+// Raises a DataSourceError if the type does not
+// match, or if the given rdata string does not
+// parse correctly for the given type and class
+//
+// The DatabaseAccessor is passed to print the
+// database name in the log message if the TTL is
+// modified
+void addOrCreate(isc::dns::RRsetPtr& rrset,
+                    const isc::dns::Name& name,
+                    const isc::dns::RRClass& cls,
+                    const isc::dns::RRType& type,
+                    const isc::dns::RRTTL& ttl,
+                    const std::string& rdata_str,
+                    const DatabaseAccessor& db
+                )
+{
+    if (!rrset) {
+        rrset.reset(new isc::dns::RRset(name, cls, type, ttl));
+    } else {
+        // This is a check to make sure find() is not messing things up
+        assert(type == rrset->getType());
+        if (ttl != rrset->getTTL()) {
+            if (ttl < rrset->getTTL()) {
+                rrset->setTTL(ttl);
+            }
+            logger.info(DATASRC_DATABASE_FIND_TTL_MISMATCH)
+                .arg(db.getDBName()).arg(name).arg(cls)
+                .arg(type).arg(rrset->getTTL());
+        }
+    }
+    try {
+        rrset->addRdata(isc::dns::rdata::createRdata(type, cls, rdata_str));
+    } catch (const isc::dns::rdata::InvalidRdataText& ivrt) {
+        // at this point, rrset may have been initialised for no reason,
+        // and won't be used. But the caller would drop the shared_ptr
+        // on such an error anyway, so we don't care.
+        isc_throw(DataSourceError,
+                    "bad rdata in database for " << name << " "
+                    << type << ": " << ivrt.what());
+    }
+}
+
+// This class keeps a short-lived store of RRSIG records encountered
+// during a call to find(). If the backend happens to return signatures
+// before the actual data, we might not know which signatures we will need
+// So if they may be relevant, we store the in this class.
+//
+// (If this class seems useful in other places, we might want to move
+// it to util. That would also provide an opportunity to add unit tests)
+class RRsigStore {
+public:
+    // Adds the given signature Rdata to the store
+    // The signature rdata MUST be of the RRSIG rdata type
+    // (the caller must make sure of this).
+    // NOTE: if we move this class to a public namespace,
+    // we should add a type_covered argument, so as not
+    // to have to do this cast here.
+    void addSig(isc::dns::rdata::RdataPtr sig_rdata) {
+        const isc::dns::RRType& type_covered =
+            static_cast<isc::dns::rdata::generic::RRSIG*>(
+                sig_rdata.get())->typeCovered();
+        sigs[type_covered].push_back(sig_rdata);
+    }
+
+    // If the store contains signatures for the type of the given
+    // rrset, they are appended to it.
+    void appendSignatures(isc::dns::RRsetPtr& rrset) const {
+        std::map<isc::dns::RRType,
+                 std::vector<isc::dns::rdata::RdataPtr> >::const_iterator
+            found = sigs.find(rrset->getType());
+        if (found != sigs.end()) {
+            BOOST_FOREACH(isc::dns::rdata::RdataPtr sig, found->second) {
+                rrset->addRRsig(sig);
+            }
+        }
+    }
+
+private:
+    std::map<isc::dns::RRType, std::vector<isc::dns::rdata::RdataPtr> > sigs;
+};
+}
+
+
 ZoneFinder::FindResult
-DatabaseClient::Finder::find(const isc::dns::Name&,
-                             const isc::dns::RRType&,
+DatabaseClient::Finder::find(const isc::dns::Name& name,
+                             const isc::dns::RRType& type,
                              isc::dns::RRsetList*,
-                             const FindOptions) const
+                             const FindOptions)
 {
-    // TODO Implement
-    return (FindResult(SUCCESS, isc::dns::ConstRRsetPtr()));
+    // This variable is used to determine the difference between
+    // NXDOMAIN and NXRRSET
+    bool records_found = false;
+    isc::dns::RRsetPtr result_rrset;
+    ZoneFinder::Result result_status = SUCCESS;
+    RRsigStore sig_store;
+    logger.debug(DBG_TRACE_DETAILED, DATASRC_DATABASE_FIND_RECORDS)
+        .arg(database_->getDBName()).arg(name).arg(type);
+
+    try {
+        database_->searchForRecords(zone_id_, name.toText());
+
+        std::string columns[DatabaseAccessor::COLUMN_COUNT];
+        while (database_->getNextRecord(columns,
+                                        DatabaseAccessor::COLUMN_COUNT)) {
+            if (!records_found) {
+                records_found = true;
+            }
+
+            try {
+                const isc::dns::RRType cur_type(columns[DatabaseAccessor::
+                                                        TYPE_COLUMN]);
+                const isc::dns::RRTTL cur_ttl(columns[DatabaseAccessor::
+                                                      TTL_COLUMN]);
+                // Ths sigtype column was an optimization for finding the
+                // relevant RRSIG RRs for a lookup. Currently this column is
+                // not used in this revised datasource implementation. We
+                // should either start using it again, or remove it from use
+                // completely (i.e. also remove it from the schema and the
+                // backend implementation).
+                // Note that because we don't use it now, we also won't notice
+                // it if the value is wrong (i.e. if the sigtype column
+                // contains an rrtype that is different from the actual value
+                // of the 'type covered' field in the RRSIG Rdata).
+                //cur_sigtype(columns[SIGTYPE_COLUMN]);
+
+                if (cur_type == type) {
+                    if (result_rrset &&
+                        result_rrset->getType() == isc::dns::RRType::CNAME()) {
+                        isc_throw(DataSourceError, "CNAME found but it is not "
+                                  "the only record for " + name.toText());
+                    }
+                    addOrCreate(result_rrset, name, getClass(), cur_type,
+                                cur_ttl, columns[DatabaseAccessor::
+                                                 RDATA_COLUMN],
+                                *database_);
+                } else if (cur_type == isc::dns::RRType::CNAME()) {
+                    // There should be no other data, so result_rrset should
+                    // be empty.
+                    if (result_rrset) {
+                        isc_throw(DataSourceError, "CNAME found but it is not "
+                                  "the only record for " + name.toText());
+                    }
+                    addOrCreate(result_rrset, name, getClass(), cur_type,
+                                cur_ttl, columns[DatabaseAccessor::
+                                                 RDATA_COLUMN],
+                                *database_);
+                    result_status = CNAME;
+                } else if (cur_type == isc::dns::RRType::RRSIG()) {
+                    // If we get signatures before we get the actual data, we
+                    // can't know which ones to keep and which to drop...
+                    // So we keep a separate store of any signature that may be
+                    // relevant and add them to the final RRset when we are
+                    // done.
+                    // A possible optimization here is to not store them for
+                    // types we are certain we don't need
+                    sig_store.addSig(isc::dns::rdata::createRdata(cur_type,
+                                    getClass(),
+                                    columns[DatabaseAccessor::
+                                            RDATA_COLUMN]));
+                }
+            } catch (const isc::dns::InvalidRRType& irt) {
+                isc_throw(DataSourceError, "Invalid RRType in database for " <<
+                        name << ": " << columns[DatabaseAccessor::
+                                                TYPE_COLUMN]);
+            } catch (const isc::dns::InvalidRRTTL& irttl) {
+                isc_throw(DataSourceError, "Invalid TTL in database for " <<
+                        name << ": " << columns[DatabaseAccessor::
+                                                TTL_COLUMN]);
+            } catch (const isc::dns::rdata::InvalidRdataText& ird) {
+                isc_throw(DataSourceError, "Invalid rdata in database for " <<
+                        name << ": " << columns[DatabaseAccessor::
+                                                RDATA_COLUMN]);
+            }
+        }
+    } catch (const DataSourceError& dse) {
+        logger.error(DATASRC_DATABASE_FIND_ERROR)
+            .arg(database_->getDBName()).arg(dse.what());
+        // call cleanup and rethrow
+        database_->resetSearch();
+        throw;
+    } catch (const isc::Exception& isce) {
+        logger.error(DATASRC_DATABASE_FIND_UNCAUGHT_ISC_ERROR)
+            .arg(database_->getDBName()).arg(isce.what());
+        // cleanup, change it to a DataSourceError and rethrow
+        database_->resetSearch();
+        isc_throw(DataSourceError, isce.what());
+    } catch (const std::exception& ex) {
+        logger.error(DATASRC_DATABASE_FIND_UNCAUGHT_ERROR)
+            .arg(database_->getDBName()).arg(ex.what());
+        database_->resetSearch();
+        throw;
+    }
+
+    if (!result_rrset) {
+        if (records_found) {
+            logger.debug(DBG_TRACE_DETAILED,
+                         DATASRC_DATABASE_FOUND_NXRRSET)
+                        .arg(database_->getDBName()).arg(name)
+                        .arg(getClass()).arg(type);
+            result_status = NXRRSET;
+        } else {
+            logger.debug(DBG_TRACE_DETAILED,
+                         DATASRC_DATABASE_FOUND_NXDOMAIN)
+                        .arg(database_->getDBName()).arg(name)
+                        .arg(getClass()).arg(type);
+            result_status = NXDOMAIN;
+        }
+    } else {
+        sig_store.appendSignatures(result_rrset);
+        logger.debug(DBG_TRACE_DETAILED,
+                     DATASRC_DATABASE_FOUND_RRSET)
+                    .arg(database_->getDBName()).arg(*result_rrset);
+    }
+    return (FindResult(result_status, result_rrset));
 }
 
 Name
diff --git a/src/lib/datasrc/database.h b/src/lib/datasrc/database.h
index 1f6bd22..5253e60 100644
--- a/src/lib/datasrc/database.h
+++ b/src/lib/datasrc/database.h
@@ -72,6 +72,96 @@ public:
      *     an opaque handle.
      */
     virtual std::pair<bool, int> getZone(const isc::dns::Name& name) const = 0;
+
+    /**
+     * \brief Starts a new search for records of the given name in the given zone
+     *
+     * The data searched by this call can be retrieved with subsequent calls to
+     * getNextRecord().
+     *
+     * \exception DataSourceError if there is a problem connecting to the
+     *                            backend database
+     *
+     * \param zone_id The zone to search in, as returned by getZone()
+     * \param name The name of the records to find
+     */
+    virtual void searchForRecords(int zone_id, const std::string& name) = 0;
+
+    /**
+     * \brief Retrieves the next record from the search started with searchForRecords()
+     *
+     * Returns a boolean specifying whether or not there was more data to read.
+     * In the case of a database error, a DatasourceError is thrown.
+     *
+     * The columns passed is an array of std::strings consisting of
+     * DatabaseConnection::COLUMN_COUNT elements, the elements of which
+     * are defined in DatabaseConnection::RecordColumns, in their basic
+     * string representation.
+     *
+     * If you are implementing a derived database connection class, you
+     * should have this method check the column_count value, and fill the
+     * array with strings conforming to their description in RecordColumn.
+     *
+     * \exception DatasourceError if there was an error reading from the database
+     *
+     * \param columns The elements of this array will be filled with the data
+     *                for one record as defined by RecordColumns
+     *                If there was no data, the array is untouched.
+     * \return true if there was a next record, false if there was not
+     */
+    virtual bool getNextRecord(std::string columns[], size_t column_count) = 0;
+
+    /**
+     * \brief Resets the current search initiated with searchForRecords()
+     *
+     * This method will be called when the called of searchForRecords() and
+     * getNextRecord() finds bad data, and aborts the current search.
+     * It should clean up whatever handlers searchForRecords() created, and
+     * any other state modified or needed by getNextRecord()
+     *
+     * Of course, the implementation of getNextRecord may also use it when
+     * it is done with a search. If it does, the implementation of this
+     * method should make sure it can handle being called multiple times.
+     *
+     * The implementation for this method should make sure it never throws.
+     */
+    virtual void resetSearch() = 0;
+
+    /**
+     * Definitions of the fields as they are required to be filled in
+     * by getNextRecord()
+     *
+     * When implementing getNextRecord(), the columns array should
+     * be filled with the values as described in this enumeration,
+     * in this order, i.e. TYPE_COLUMN should be the first element
+     * (index 0) of the array, TTL_COLUMN should be the second element
+     * (index 1), etc.
+     */
+    enum RecordColumns {
+        TYPE_COLUMN = 0,    ///< The RRType of the record (A/NS/TXT etc.)
+        TTL_COLUMN = 1,     ///< The TTL of the record (a
+        SIGTYPE_COLUMN = 2, ///< For RRSIG records, this contains the RRTYPE
+                            ///< the RRSIG covers. In the current implementation,
+                            ///< this field is ignored.
+        RDATA_COLUMN = 3    ///< Full text representation of the record's RDATA
+    };
+
+    /// The number of fields the columns array passed to getNextRecord should have
+    static const size_t COLUMN_COUNT = 4;
+
+    /**
+     * \brief Returns a string identifying this dabase backend
+     *
+     * The returned string is mainly intended to be used for
+     * debugging/logging purposes.
+     *
+     * Any implementation is free to choose the exact string content,
+     * but it is advisable to make it a name that is distinguishable
+     * from the others.
+     *
+     * \return the name of the database
+     */
+    virtual const std::string& getDBName() const = 0;
 };
 
 /**
@@ -134,11 +224,51 @@ public:
         // ZoneFinder's pure virtual methods.
         virtual isc::dns::Name getOrigin() const;
         virtual isc::dns::RRClass getClass() const;
+
+        /**
+         * \brief Find an RRset in the datasource
+         *
+         * Searches the datasource for an RRset of the given name and
+         * type. If there is a CNAME at the given name, the CNAME rrset
+         * is returned.
+         * (this implementation is not complete, and currently only
+         * does full matches, CNAMES, and the signatures for matches and
+         * CNAMEs)
+         * \note target was used in the original design to handle ANY
+         *       queries. This is not implemented yet, and may use
+         *       target again for that, but it might also use something
+         *       different. It is left in for compatibility at the moment.
+         * \note options are ignored at this moment
+         *
+         * \note Maybe counter intuitively, this method is not a const member
+         * function.  This is intentional; some of the underlying implementations
+         * are expected to use a database backend, and would internally contain
+         * some abstraction of "database connection".  In the most strict sense
+         * any (even read only) operation might change the internal state of
+         * such a connection, and in that sense the operation cannot be considered
+         * "const".  In order to avoid giving a false sense of safety to the
+         * caller, we indicate a call to this method may have a surprising
+         * side effect.  That said, this view may be too strict and it may
+         * make sense to say the internal database connection doesn't affect
+         * external behavior in terms of the interface of this method.  As
+         * we gain more experiences with various kinds of backends we may
+         * revisit the constness.
+         *
+         * \exception DataSourceError when there is a problem reading
+         *                            the data from the dabase backend.
+         *                            This can be a connection, code, or
+         *                            data (parse) error.
+         *
+         * \param name The name to find
+         * \param type The RRType to find
+         * \param target Unused at this moment
+         * \param options Unused at this moment
+         */
         virtual FindResult find(const isc::dns::Name& name,
                                 const isc::dns::RRType& type,
                                 isc::dns::RRsetList* target = NULL,
-                                const FindOptions options = FIND_DEFAULT)
-            const;
+                                const FindOptions options = FIND_DEFAULT);
+
         /**
          * \brief The zone ID
          *
@@ -176,6 +306,7 @@ public:
      *     should use it as a ZoneFinder only.
      */
     virtual FindResult findZone(const isc::dns::Name& name) const;
+
 private:
     /// \brief Our database.
     const boost::shared_ptr<DatabaseAccessor> database_;
diff --git a/src/lib/datasrc/datasrc_messages.mes b/src/lib/datasrc/datasrc_messages.mes
index 1a911c0..6af4fe6 100644
--- a/src/lib/datasrc/datasrc_messages.mes
+++ b/src/lib/datasrc/datasrc_messages.mes
@@ -63,6 +63,46 @@ The maximum allowed number of items of the hotspot cache is set to the given
 number. If there are too many, some of them will be dropped. The size of 0
 means no limit.
 
+% DATASRC_DATABASE_FIND_ERROR error retrieving data from datasource %1: %2
+This was an internal error while reading data from a datasource. This can either
+mean the specific data source implementation is not behaving correctly, or the
+data it provides is invalid. The current search is aborted.
+The error message contains specific information about the error.
+
+% DATASRC_DATABASE_FIND_RECORDS looking in datasource %1 for record %2/%3
+Debug information. The database data source is looking up records with the given
+name and type in the database.
+
+% DATASRC_DATABASE_FIND_TTL_MISMATCH TTL values differ in %1 for elements of %2/%3/%4, setting to %5
+The datasource backend provided resource records for the given RRset with
+different TTL values. The TTL of the RRSET is set to the lowest value, which
+is printed in the log message.
+
+% DATASRC_DATABASE_FIND_UNCAUGHT_ERROR uncaught general error retrieving data from datasource %1: %2
+There was an uncaught general exception while reading data from a datasource.
+This most likely points to a logic error in the code, and can be considered a
+bug. The current search is aborted. Specific information about the exception is
+printed in this error message.
+
+% DATASRC_DATABASE_FIND_UNCAUGHT_ISC_ERROR uncaught error retrieving data from datasource %1: %2
+There was an uncaught ISC exception while reading data from a datasource. This
+most likely points to a logic error in the code, and can be considered a bug.
+The current search is aborted. Specific information about the exception is
+printed in this error message.
+
+% DATASRC_DATABASE_FOUND_NXDOMAIN search in datasource %1 resulted in NXDOMAIN for %2/%3/%4
+The data returned by the database backend did not contain any data for the given
+domain name, class and type.
+
+% DATASRC_DATABASE_FOUND_NXRRSET search in datasource %1 resulted in NXRRSET for %2/%3/%4
+The data returned by the database backend contained data for the given domain
+name and class, but not for the given type.
+
+% DATASRC_DATABASE_FOUND_RRSET search in datasource %1 resulted in RRset %2
+The data returned by the database backend contained data for the given domain
+name, and it either matches the type or has a relevant type. The RRset that is
+returned is printed.
+
 % DATASRC_DO_QUERY handling query for '%1/%2'
 A debug message indicating that a query for the given name and RR type is being
 processed.
diff --git a/src/lib/datasrc/memory_datasrc.cc b/src/lib/datasrc/memory_datasrc.cc
index 26223da..d06cd9b 100644
--- a/src/lib/datasrc/memory_datasrc.cc
+++ b/src/lib/datasrc/memory_datasrc.cc
@@ -618,7 +618,7 @@ InMemoryZoneFinder::getClass() const {
 
 ZoneFinder::FindResult
 InMemoryZoneFinder::find(const Name& name, const RRType& type,
-                 RRsetList* target, const FindOptions options) const
+                 RRsetList* target, const FindOptions options)
 {
     return (impl_->find(name, type, target, options));
 }
diff --git a/src/lib/datasrc/memory_datasrc.h b/src/lib/datasrc/memory_datasrc.h
index 9707797..0234a91 100644
--- a/src/lib/datasrc/memory_datasrc.h
+++ b/src/lib/datasrc/memory_datasrc.h
@@ -73,7 +73,7 @@ public:
     virtual FindResult find(const isc::dns::Name& name,
                             const isc::dns::RRType& type,
                             isc::dns::RRsetList* target = NULL,
-                            const FindOptions options = FIND_DEFAULT) const;
+                            const FindOptions options = FIND_DEFAULT);
 
     /// \brief Inserts an rrset into the zone.
     ///
diff --git a/src/lib/datasrc/sqlite3_accessor.cc b/src/lib/datasrc/sqlite3_accessor.cc
index 352768d..817d530 100644
--- a/src/lib/datasrc/sqlite3_accessor.cc
+++ b/src/lib/datasrc/sqlite3_accessor.cc
@@ -17,6 +17,7 @@
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/logger.h>
 #include <datasrc/data_source.h>
+#include <util/filename.h>
 
 namespace isc {
 namespace datasrc {
@@ -24,19 +25,20 @@ namespace datasrc {
 struct SQLite3Parameters {
     SQLite3Parameters() :
         db_(NULL), version_(-1),
-        q_zone_(NULL) /*, q_record_(NULL), q_addrs_(NULL), q_referral_(NULL),
-        q_any_(NULL), q_count_(NULL), q_previous_(NULL), q_nsec3_(NULL),
+        q_zone_(NULL), q_any_(NULL)
+        /*q_record_(NULL), q_addrs_(NULL), q_referral_(NULL),
+        q_count_(NULL), q_previous_(NULL), q_nsec3_(NULL),
         q_prevnsec3_(NULL) */
     {}
     sqlite3* db_;
     int version_;
     sqlite3_stmt* q_zone_;
+    sqlite3_stmt* q_any_;
     /*
     TODO: Yet unneeded statements
     sqlite3_stmt* q_record_;
     sqlite3_stmt* q_addrs_;
     sqlite3_stmt* q_referral_;
-    sqlite3_stmt* q_any_;
     sqlite3_stmt* q_count_;
     sqlite3_stmt* q_previous_;
     sqlite3_stmt* q_nsec3_;
@@ -47,7 +49,9 @@ struct SQLite3Parameters {
 SQLite3Database::SQLite3Database(const std::string& filename,
                                      const isc::dns::RRClass& rrclass) :
     dbparameters_(new SQLite3Parameters),
-    class_(rrclass.toText())
+    class_(rrclass.toText()),
+    database_name_("sqlite3_" +
+                   isc::util::Filename(filename).nameAndExtension())
 {
     LOG_DEBUG(logger, DBG_TRACE_BASIC, DATASRC_SQLITE_NEWCONN);
 
@@ -69,6 +73,9 @@ public:
         if (params_.q_zone_ != NULL) {
             sqlite3_finalize(params_.q_zone_);
         }
+        if (params_.q_any_ != NULL) {
+            sqlite3_finalize(params_.q_any_);
+        }
         /*
         if (params_.q_record_ != NULL) {
             sqlite3_finalize(params_.q_record_);
@@ -79,9 +86,6 @@ public:
         if (params_.q_referral_ != NULL) {
             sqlite3_finalize(params_.q_referral_);
         }
-        if (params_.q_any_ != NULL) {
-            sqlite3_finalize(params_.q_any_);
-        }
         if (params_.q_count_ != NULL) {
             sqlite3_finalize(params_.q_count_);
         }
@@ -132,6 +136,9 @@ const char* const SCHEMA_LIST[] = {
 
 const char* const q_zone_str = "SELECT id FROM zones WHERE name=?1 AND rdclass = ?2";
 
+const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
+    "FROM records WHERE zone_id=?1 AND name=?2";
+
 /* TODO: Prune the statements, not everything will be needed maybe?
 const char* const q_record_str = "SELECT rdtype, ttl, sigtype, rdata "
     "FROM records WHERE zone_id=?1 AND name=?2 AND "
@@ -148,9 +155,6 @@ const char* const q_referral_str = "SELECT rdtype, ttl, sigtype, rdata FROM "
     "(rdtype='NS' OR sigtype='NS' OR rdtype='DS' OR sigtype='DS' OR "
     "rdtype='DNAME' OR sigtype='DNAME')";
 
-const char* const q_any_str = "SELECT rdtype, ttl, sigtype, rdata "
-    "FROM records WHERE zone_id=?1 AND name=?2";
-
 const char* const q_count_str = "SELECT COUNT(*) FROM records "
     "WHERE zone_id=?1 AND rname LIKE (?2 || '%');";
 
@@ -200,11 +204,11 @@ checkAndSetupSchema(Initializer* initializer) {
     }
 
     initializer->params_.q_zone_ = prepare(db, q_zone_str);
+    initializer->params_.q_any_ = prepare(db, q_any_str);
     /* TODO: Yet unneeded statements
     initializer->params_.q_record_ = prepare(db, q_record_str);
     initializer->params_.q_addrs_ = prepare(db, q_addrs_str);
     initializer->params_.q_referral_ = prepare(db, q_referral_str);
-    initializer->params_.q_any_ = prepare(db, q_any_str);
     initializer->params_.q_count_ = prepare(db, q_count_str);
     initializer->params_.q_previous_ = prepare(db, q_previous_str);
     initializer->params_.q_nsec3_ = prepare(db, q_nsec3_str);
@@ -252,6 +256,9 @@ SQLite3Database::close(void) {
     sqlite3_finalize(dbparameters_->q_zone_);
     dbparameters_->q_zone_ = NULL;
 
+    sqlite3_finalize(dbparameters_->q_any_);
+    dbparameters_->q_any_ = NULL;
+
     /* TODO: Once they are needed or not, uncomment or drop
     sqlite3_finalize(dbparameters->q_record_);
     dbparameters->q_record_ = NULL;
@@ -262,9 +269,6 @@ SQLite3Database::close(void) {
     sqlite3_finalize(dbparameters->q_referral_);
     dbparameters->q_referral_ = NULL;
 
-    sqlite3_finalize(dbparameters->q_any_);
-    dbparameters->q_any_ = NULL;
-
     sqlite3_finalize(dbparameters->q_count_);
     dbparameters->q_count_ = NULL;
 
@@ -290,7 +294,7 @@ SQLite3Database::getZone(const isc::dns::Name& name) const {
     // and prepare it (bind the parameters to it)
     sqlite3_reset(dbparameters_->q_zone_);
     rc = sqlite3_bind_text(dbparameters_->q_zone_, 1, name.toText().c_str(),
-                           -1, SQLITE_STATIC);
+                           -1, SQLITE_TRANSIENT);
     if (rc != SQLITE_OK) {
         isc_throw(SQLite3Error, "Could not bind " << name <<
                   " to SQL statement (zone)");
@@ -318,5 +322,91 @@ SQLite3Database::getZone(const isc::dns::Name& name) const {
     return (result);
 }
 
+void
+SQLite3Database::searchForRecords(int zone_id, const std::string& name) {
+    resetSearch();
+    if (sqlite3_bind_int(dbparameters_->q_any_, 1, zone_id) != SQLITE_OK) {
+        isc_throw(DataSourceError,
+                  "Error in sqlite3_bind_int() for zone_id " <<
+                  zone_id << ": " << sqlite3_errmsg(dbparameters_->db_));
+    }
+    // use transient since name is a ref and may disappear
+    if (sqlite3_bind_text(dbparameters_->q_any_, 2, name.c_str(), -1,
+                               SQLITE_TRANSIENT) != SQLITE_OK) {
+        isc_throw(DataSourceError,
+                  "Error in sqlite3_bind_text() for name " <<
+                  name << ": " << sqlite3_errmsg(dbparameters_->db_));
+    }
+}
+
+namespace {
+// This helper function converts from the unsigned char* type (used by
+// sqlite3) to char* (wanted by std::string). Technically these types
+// might not be directly convertable
+// In case sqlite3_column_text() returns NULL, we just make it an
+// empty string.
+// The sqlite3parameters value is only used to check the error code if
+// ucp == NULL
+const char*
+convertToPlainChar(const unsigned char* ucp,
+                   SQLite3Parameters* dbparameters) {
+    if (ucp == NULL) {
+        // The field can really be NULL, in which case we return an
+        // empty string, or sqlite may have run out of memory, in
+        // which case we raise an error
+        if (dbparameters != NULL &&
+            sqlite3_errcode(dbparameters->db_) == SQLITE_NOMEM) {
+            isc_throw(DataSourceError,
+                      "Sqlite3 backend encountered a memory allocation "
+                      "error in sqlite3_column_text()");
+        } else {
+            return ("");
+        }
+    }
+    const void* p = ucp;
+    return (static_cast<const char*>(p));
+}
+}
+
+bool
+SQLite3Database::getNextRecord(std::string columns[], size_t column_count) {
+    if (column_count != COLUMN_COUNT) {
+            isc_throw(DataSourceError,
+                    "Datasource backend caller did not pass a column array "
+                    "of size " << COLUMN_COUNT << " to getNextRecord()");
+    }
+
+    sqlite3_stmt* current_stmt = dbparameters_->q_any_;
+    const int rc = sqlite3_step(current_stmt);
+
+    if (rc == SQLITE_ROW) {
+        for (int column = 0; column < column_count; ++column) {
+            try {
+                columns[column] = convertToPlainChar(sqlite3_column_text(
+                                                     current_stmt, column),
+                                                     dbparameters_);
+            } catch (const std::bad_alloc&) {
+                isc_throw(DataSourceError,
+                        "bad_alloc in Sqlite3Connection::getNextRecord");
+            }
+        }
+        return (true);
+    } else if (rc == SQLITE_DONE) {
+        // reached the end of matching rows
+        resetSearch();
+        return (false);
+    }
+    isc_throw(DataSourceError, "Unexpected failure in sqlite3_step: " <<
+                               sqlite3_errmsg(dbparameters_->db_));
+    // Compilers might not realize isc_throw always throws
+    return (false);
+}
+
+void
+SQLite3Database::resetSearch() {
+    sqlite3_reset(dbparameters_->q_any_);
+    sqlite3_clear_bindings(dbparameters_->q_any_);
+}
+
 }
 }
diff --git a/src/lib/datasrc/sqlite3_accessor.h b/src/lib/datasrc/sqlite3_accessor.h
index 0d7ddee..4c2ec8b 100644
--- a/src/lib/datasrc/sqlite3_accessor.h
+++ b/src/lib/datasrc/sqlite3_accessor.h
@@ -88,6 +88,60 @@ public:
      *     element and the zone id in the second if it was.
      */
     virtual std::pair<bool, int> getZone(const isc::dns::Name& name) const;
+
+    /**
+     * \brief Start a new search for the given name in the given zone.
+     *
+     * This implements the searchForRecords from DatabaseConnection.
+     * This particular implementation does not raise DataSourceError.
+     *
+     * \exception DataSourceError when sqlite3_bind_int() or
+     *                            sqlite3_bind_text() fails
+     *
+     * \param zone_id The zone to seach in, as returned by getZone()
+     * \param name The name to find records for
+     */
+    virtual void searchForRecords(int zone_id, const std::string& name);
+
+    /**
+     * \brief Retrieve the next record from the search started with
+     *        searchForRecords
+     *
+     * This implements the getNextRecord from DatabaseConnection.
+     * See the documentation there for more information.
+     *
+     * If this method raises an exception, the contents of columns are undefined.
+     *
+     * \exception DataSourceError if there is an error returned by sqlite_step()
+     *                            When this exception is raised, the current
+     *                            search as initialized by searchForRecords() is
+     *                            NOT reset, and the caller is expected to take
+     *                            care of that.
+     * \param columns This vector will be cleared, and the fields of the record will
+     *                be appended here as strings (in the order rdtype, ttl, sigtype,
+     *                and rdata). If there was no data (i.e. if this call returns
+     *                false), the vector is untouched.
+     * \return true if there was a next record, false if there was not
+     */
+    virtual bool getNextRecord(std::string columns[], size_t column_count);
+
+    /**
+     * \brief Resets any state created by searchForRecords
+     *
+     * This implements the resetSearch from DatabaseConnection.
+     * See the documentation there for more information.
+     *
+     * This function never throws.
+     */
+    virtual void resetSearch();
+
+    /// The SQLite3 implementation of this method returns a string starting
+    /// with a fixed prefix of "sqlite3_" followed by the DB file name
+    /// removing any path name.  For example, for the DB file
+    /// /somewhere/in/the/system/bind10.sqlite3, this method will return
+    /// "sqlite3_bind10.sqlite3".
+    virtual const std::string& getDBName() const { return (database_name_); }
+
 private:
     /// \brief Private database data
     SQLite3Parameters* dbparameters_;
@@ -97,6 +151,7 @@ private:
     void open(const std::string& filename);
     /// \brief Closes the database
     void close();
+    const std::string database_name_;
 };
 
 }
diff --git a/src/lib/datasrc/tests/database_unittest.cc b/src/lib/datasrc/tests/database_unittest.cc
index 4144a5b..fcfcefe 100644
--- a/src/lib/datasrc/tests/database_unittest.cc
+++ b/src/lib/datasrc/tests/database_unittest.cc
@@ -15,9 +15,17 @@
 #include <gtest/gtest.h>
 
 #include <dns/name.h>
+#include <dns/rrttl.h>
+#include <dns/rrset.h>
 #include <exceptions/exceptions.h>
 
 #include <datasrc/database.h>
+#include <datasrc/zone.h>
+#include <datasrc/data_source.h>
+
+#include <testutils/dnsmessage_test.h>
+
+#include <map>
 
 using namespace isc::datasrc;
 using namespace std;
@@ -27,11 +35,17 @@ using isc::dns::Name;
 namespace {
 
 /*
- * A virtual database connection that pretends it contains single zone --
+ * A virtual database database that pretends it contains single zone --
  * example.org.
  */
 class MockAccessor : public DatabaseAccessor {
 public:
+    MockAccessor() : search_running_(false),
+                       database_name_("mock_database")
+    {
+        fillData();
+    }
+
     virtual std::pair<bool, int> getZone(const Name& name) const {
         if (name == Name("example.org")) {
             return (std::pair<bool, int>(true, 42));
@@ -39,6 +53,217 @@ public:
             return (std::pair<bool, int>(false, 0));
         }
     }
+
+    virtual void searchForRecords(int zone_id, const std::string& name) {
+        search_running_ = true;
+
+        // 'hardcoded' name to trigger exceptions (for testing
+        // the error handling of find() (the other on is below in
+        // if the name is "exceptiononsearch" it'll raise an exception here
+        if (name == "dsexception.in.search.") {
+            isc_throw(DataSourceError, "datasource exception on search");
+        } else if (name == "iscexception.in.search.") {
+            isc_throw(isc::Exception, "isc exception on search");
+        } else if (name == "basicexception.in.search.") {
+            throw std::exception();
+        }
+        searched_name_ = name;
+
+        // we're not aiming for efficiency in this test, simply
+        // copy the relevant vector from records
+        cur_record = 0;
+        if (zone_id == 42) {
+            if (records.count(name) > 0) {
+                cur_name = records.find(name)->second;
+            } else {
+                cur_name.clear();
+            }
+        } else {
+            cur_name.clear();
+        }
+    };
+
+    virtual bool getNextRecord(std::string columns[], size_t column_count) {
+        if (searched_name_ == "dsexception.in.getnext.") {
+            isc_throw(DataSourceError, "datasource exception on getnextrecord");
+        } else if (searched_name_ == "iscexception.in.getnext.") {
+            isc_throw(isc::Exception, "isc exception on getnextrecord");
+        } else if (searched_name_ == "basicexception.in.getnext.") {
+            throw std::exception();
+        }
+
+        if (column_count != DatabaseAccessor::COLUMN_COUNT) {
+            isc_throw(DataSourceError, "Wrong column count in getNextRecord");
+        }
+        if (cur_record < cur_name.size()) {
+            for (size_t i = 0; i < column_count; ++i) {
+                columns[i] = cur_name[cur_record][i];
+            }
+            cur_record++;
+            return (true);
+        } else {
+            resetSearch();
+            return (false);
+        }
+    };
+
+    virtual void resetSearch() {
+        search_running_ = false;
+    };
+
+    bool searchRunning() const {
+        return (search_running_);
+    }
+
+    virtual const std::string& getDBName() const {
+        return (database_name_);
+    }
+private:
+    std::map<std::string, std::vector< std::vector<std::string> > > records;
+    // used as internal index for getNextRecord()
+    size_t cur_record;
+    // used as temporary storage after searchForRecord() and during
+    // getNextRecord() calls, as well as during the building of the
+    // fake data
+    std::vector< std::vector<std::string> > cur_name;
+
+    // This boolean is used to make sure find() calls resetSearch
+    // when it encounters an error
+    bool search_running_;
+
+    // We store the name passed to searchForRecords, so we can
+    // hardcode some exceptions into getNextRecord
+    std::string searched_name_;
+
+    const std::string database_name_;
+
+    // Adds one record to the current name in the database
+    // The actual data will not be added to 'records' until
+    // addCurName() is called
+    void addRecord(const std::string& name,
+                   const std::string& type,
+                   const std::string& sigtype,
+                   const std::string& rdata) {
+        std::vector<std::string> columns;
+        columns.push_back(name);
+        columns.push_back(type);
+        columns.push_back(sigtype);
+        columns.push_back(rdata);
+        cur_name.push_back(columns);
+    }
+
+    // Adds all records we just built with calls to addRecords
+    // to the actual fake database. This will clear cur_name,
+    // so we can immediately start adding new records.
+    void addCurName(const std::string& name) {
+        ASSERT_EQ(0, records.count(name));
+        records[name] = cur_name;
+        cur_name.clear();
+    }
+
+    // Fills the database with zone data.
+    // This method constructs a number of resource records (with addRecord),
+    // which will all be added for one domain name to the fake database
+    // (with addCurName). So for instance the first set of calls create
+    // data for the name 'www.example.org', which will consist of one A RRset
+    // of one record, and one AAAA RRset of two records.
+    // The order in which they are added is the order in which getNextRecord()
+    // will return them (so we can test whether find() etc. support data that
+    // might not come in 'normal' order)
+    // It shall immediately fail if you try to add the same name twice.
+    void fillData() {
+        // some plain data
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("AAAA", "3600", "", "2001:db8::1");
+        addRecord("AAAA", "3600", "", "2001:db8::2");
+        addCurName("www.example.org.");
+
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("AAAA", "3600", "", "2001:db8::1");
+        addRecord("A", "3600", "", "192.0.2.2");
+        addCurName("www2.example.org.");
+
+        addRecord("CNAME", "3600", "", "www.example.org.");
+        addCurName("cname.example.org.");
+
+        // some DNSSEC-'signed' data
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
+        addRecord("AAAA", "3600", "", "2001:db8::1");
+        addRecord("AAAA", "3600", "", "2001:db8::2");
+        addRecord("RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addCurName("signed1.example.org.");
+        addRecord("CNAME", "3600", "", "www.example.org.");
+        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addCurName("signedcname1.example.org.");
+        // special case might fail; sig is for cname, which isn't there (should be ignored)
+        // (ignoring of 'normal' other type is done above by www.)
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addCurName("acnamesig1.example.org.");
+
+        // let's pretend we have a database that is not careful
+        // about the order in which it returns data
+        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addRecord("AAAA", "3600", "", "2001:db8::2");
+        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("RRSIG", "3600", "", "AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addRecord("AAAA", "3600", "", "2001:db8::1");
+        addCurName("signed2.example.org.");
+        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addRecord("CNAME", "3600", "", "www.example.org.");
+        addCurName("signedcname2.example.org.");
+
+        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addCurName("acnamesig2.example.org.");
+
+        addRecord("RRSIG", "3600", "", "CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addRecord("RRSIG", "3600", "", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addRecord("A", "3600", "", "192.0.2.1");
+        addCurName("acnamesig3.example.org.");
+
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("A", "360", "", "192.0.2.2");
+        addCurName("ttldiff1.example.org.");
+        addRecord("A", "360", "", "192.0.2.1");
+        addRecord("A", "3600", "", "192.0.2.2");
+        addCurName("ttldiff2.example.org.");
+
+        // also add some intentionally bad data
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("CNAME", "3600", "", "www.example.org.");
+        addCurName("badcname1.example.org.");
+
+        addRecord("CNAME", "3600", "", "www.example.org.");
+        addRecord("A", "3600", "", "192.0.2.1");
+        addCurName("badcname2.example.org.");
+
+        addRecord("CNAME", "3600", "", "www.example.org.");
+        addRecord("CNAME", "3600", "", "www.example2.org.");
+        addCurName("badcname3.example.org.");
+
+        addRecord("A", "3600", "", "bad");
+        addCurName("badrdata.example.org.");
+
+        addRecord("BAD_TYPE", "3600", "", "192.0.2.1");
+        addCurName("badtype.example.org.");
+
+        addRecord("A", "badttl", "", "192.0.2.1");
+        addCurName("badttl.example.org.");
+
+        addRecord("A", "badttl", "", "192.0.2.1");
+        addRecord("RRSIG", "3600", "", "A 5 3 3600 somebaddata 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addCurName("badsig.example.org.");
+
+        addRecord("A", "3600", "", "192.0.2.1");
+        addRecord("RRSIG", "3600", "TXT", "A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+        addCurName("badsigtype.example.org.");
+    }
 };
 
 class DatabaseClientTest : public ::testing::Test {
@@ -58,6 +283,8 @@ public:
     // Will be deleted by client_, just keep the current value for comparison.
     MockAccessor* current_database_;
     shared_ptr<DatabaseClient> client_;
+    const std::string database_name_;
+
     /**
      * Check the zone finder is a valid one and references the zone ID and
      * database available here.
@@ -92,8 +319,369 @@ TEST_F(DatabaseClientTest, superZone) {
 }
 
 TEST_F(DatabaseClientTest, noAccessorException) {
-    EXPECT_THROW(DatabaseClient(shared_ptr<DatabaseAccessor>()),
+    // We need a dummy variable here; some compiler would regard it a mere
+    // declaration instead of an instantiation and make the test fail.
+    EXPECT_THROW(DatabaseClient dummy((shared_ptr<DatabaseAccessor>())),
                  isc::InvalidParameter);
 }
 
+namespace {
+// checks if the given rrset matches the
+// given name, class, type and rdatas
+void
+checkRRset(isc::dns::ConstRRsetPtr rrset,
+           const isc::dns::Name& name,
+           const isc::dns::RRClass& rrclass,
+           const isc::dns::RRType& rrtype,
+           const isc::dns::RRTTL& rrttl,
+           const std::vector<std::string>& rdatas) {
+    isc::dns::RRsetPtr expected_rrset(
+        new isc::dns::RRset(name, rrclass, rrtype, rrttl));
+    for (unsigned int i = 0; i < rdatas.size(); ++i) {
+        expected_rrset->addRdata(
+            isc::dns::rdata::createRdata(rrtype, rrclass,
+                                         rdatas[i]));
+    }
+    isc::testutils::rrsetCheck(expected_rrset, rrset);
+}
+
+void
+doFindTest(shared_ptr<DatabaseClient::Finder> 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::FindResult result =
+        finder->find(name, type, NULL, ZoneFinder::FIND_DEFAULT);
+    ASSERT_EQ(expected_result, result.code) << name << " " << type;
+    if (expected_rdatas.size() > 0) {
+        checkRRset(result.rrset, name, finder->getClass(),
+                   expected_type, expected_ttl, expected_rdatas);
+
+        if (expected_sig_rdatas.size() > 0) {
+            checkRRset(result.rrset->getRRsig(), name,
+                       finder->getClass(), isc::dns::RRType::RRSIG(),
+                       expected_ttl, expected_sig_rdatas);
+        } else {
+            EXPECT_EQ(isc::dns::RRsetPtr(), result.rrset->getRRsig());
+        }
+    } else {
+        EXPECT_EQ(isc::dns::RRsetPtr(), result.rrset);
+    }
+}
+} // end anonymous namespace
+
+TEST_F(DatabaseClientTest, find) {
+    DataSourceClient::FindResult zone(client_->findZone(Name("example.org")));
+    ASSERT_EQ(result::SUCCESS, zone.code);
+    shared_ptr<DatabaseClient::Finder> finder(
+        dynamic_pointer_cast<DatabaseClient::Finder>(zone.zone_finder));
+    EXPECT_EQ(42, finder->zone_id());
+    EXPECT_FALSE(current_database_->searchRunning());
+    std::vector<std::string> expected_rdatas;
+    std::vector<std::string> expected_sig_rdatas;
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    doFindTest(finder, isc::dns::Name("www.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    expected_rdatas.push_back("192.0.2.2");
+    doFindTest(finder, isc::dns::Name("www2.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("2001:db8::1");
+    expected_rdatas.push_back("2001:db8::2");
+    doFindTest(finder, isc::dns::Name("www.example.org."),
+               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    doFindTest(finder, isc::dns::Name("www.example.org."),
+               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::NXRRSET,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("www.example.org.");
+    doFindTest(finder, isc::dns::Name("cname.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::CNAME,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("www.example.org.");
+    doFindTest(finder, isc::dns::Name("cname.example.org."),
+               isc::dns::RRType::CNAME(), isc::dns::RRType::CNAME(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    doFindTest(finder, isc::dns::Name("doesnotexist.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::NXDOMAIN,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("signed1.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("2001:db8::1");
+    expected_rdatas.push_back("2001:db8::2");
+    expected_sig_rdatas.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("signed1.example.org."),
+               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    doFindTest(finder, isc::dns::Name("signed1.example.org."),
+               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::NXRRSET,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("www.example.org.");
+    expected_sig_rdatas.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("signedcname1.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::CNAME,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12346 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("signed2.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("2001:db8::2");
+    expected_rdatas.push_back("2001:db8::1");
+    expected_sig_rdatas.push_back("AAAA 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("signed2.example.org."),
+               isc::dns::RRType::AAAA(), isc::dns::RRType::AAAA(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    doFindTest(finder, isc::dns::Name("signed2.example.org."),
+               isc::dns::RRType::TXT(), isc::dns::RRType::TXT(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::NXRRSET,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("www.example.org.");
+    expected_sig_rdatas.push_back("CNAME 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("signedcname2.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::CNAME(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::CNAME,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("acnamesig1.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("acnamesig2.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("acnamesig3.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    expected_rdatas.push_back("192.0.2.2");
+    doFindTest(finder, isc::dns::Name("ttldiff1.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(360),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    expected_rdatas.push_back("192.0.2.2");
+    doFindTest(finder, isc::dns::Name("ttldiff2.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(360),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+
+    EXPECT_THROW(finder->find(isc::dns::Name("badcname1.example.org."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("badcname2.example.org."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("badcname3.example.org."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("badrdata.example.org."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("badtype.example.org."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("badttl.example.org."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("badsig.example.org."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    // Trigger the hardcoded exceptions and see if find() has cleaned up
+    EXPECT_THROW(finder->find(isc::dns::Name("dsexception.in.search."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("iscexception.in.search."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("basicexception.in.search."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 std::exception);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    EXPECT_THROW(finder->find(isc::dns::Name("dsexception.in.getnext."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("iscexception.in.getnext."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 DataSourceError);
+    EXPECT_FALSE(current_database_->searchRunning());
+    EXPECT_THROW(finder->find(isc::dns::Name("basicexception.in.getnext."),
+                                              isc::dns::RRType::A(),
+                                              NULL, ZoneFinder::FIND_DEFAULT),
+                 std::exception);
+    EXPECT_FALSE(current_database_->searchRunning());
+
+    // This RRSIG has the wrong sigtype field, which should be
+    // an error if we decide to keep using that field
+    // Right now the field is ignored, so it does not error
+    expected_rdatas.clear();
+    expected_sig_rdatas.clear();
+    expected_rdatas.push_back("192.0.2.1");
+    expected_sig_rdatas.push_back("A 5 3 3600 20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE");
+    doFindTest(finder, isc::dns::Name("badsigtype.example.org."),
+               isc::dns::RRType::A(), isc::dns::RRType::A(),
+               isc::dns::RRTTL(3600),
+               ZoneFinder::SUCCESS,
+               expected_rdatas, expected_sig_rdatas);
+    EXPECT_FALSE(current_database_->searchRunning());
+}
+
 }
diff --git a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
index 409201d..097c821 100644
--- a/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
+++ b/src/lib/datasrc/tests/sqlite3_accessor_unittest.cc
@@ -11,13 +11,14 @@
 // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 // PERFORMANCE OF THIS SOFTWARE.
-
 #include <datasrc/sqlite3_accessor.h>
+
 #include <datasrc/data_source.h>
 
 #include <dns/rrclass.h>
 
 #include <gtest/gtest.h>
+#include <boost/scoped_ptr.hpp>
 
 using namespace isc::datasrc;
 using isc::data::ConstElementPtr;
@@ -29,7 +30,9 @@ namespace {
 // Some test data
 std::string SQLITE_DBFILE_EXAMPLE = TEST_DATA_DIR "/test.sqlite3";
 std::string SQLITE_DBFILE_EXAMPLE2 = TEST_DATA_DIR "/example2.com.sqlite3";
+std::string SQLITE_DBNAME_EXAMPLE2 = "sqlite3_example2.com.sqlite3";
 std::string SQLITE_DBFILE_EXAMPLE_ROOT = TEST_DATA_DIR "/test-root.sqlite3";
+std::string SQLITE_DBNAME_EXAMPLE_ROOT = "sqlite3_test-root.sqlite3";
 std::string SQLITE_DBFILE_BROKENDB = TEST_DATA_DIR "/brokendb.sqlite3";
 std::string SQLITE_DBFILE_MEMORY = ":memory:";
 
@@ -73,8 +76,8 @@ public:
     void initAccessor(const std::string& filename, const RRClass& rrclass) {
         db.reset(new SQLite3Database(filename, rrclass));
     }
-    // The tested db
-    std::auto_ptr<SQLite3Database> db;
+    // The tested dbection
+    boost::scoped_ptr<SQLite3Database> db;
 };
 
 // This zone exists in the data, so it should be found
@@ -100,4 +103,143 @@ TEST_F(SQLite3Access, noClass) {
     EXPECT_FALSE(db->getZone(Name("example.com")).first);
 }
 
+TEST(SQLite3Open, getDBNameExample2) {
+    SQLite3Database db(SQLITE_DBFILE_EXAMPLE2, RRClass::IN());
+    EXPECT_EQ(SQLITE_DBNAME_EXAMPLE2, db.getDBName());
 }
+
+TEST(SQLite3Open, getDBNameExampleROOT) {
+    SQLite3Database db(SQLITE_DBFILE_EXAMPLE_ROOT, RRClass::IN());
+    EXPECT_EQ(SQLITE_DBNAME_EXAMPLE_ROOT, db.getDBName());
+}
+
+// Simple function to cound the number of records for
+// any name
+void
+checkRecordRow(const std::string columns[],
+               const std::string& field0,
+               const std::string& field1,
+               const std::string& field2,
+               const std::string& field3)
+{
+    EXPECT_EQ(field0, columns[0]);
+    EXPECT_EQ(field1, columns[1]);
+    EXPECT_EQ(field2, columns[2]);
+    EXPECT_EQ(field3, columns[3]);
+}
+
+TEST_F(SQLite3Access, getRecords) {
+    const std::pair<bool, int> zone_info(db->getZone(Name("example.com")));
+    ASSERT_TRUE(zone_info.first);
+
+    const int zone_id = zone_info.second;
+    ASSERT_EQ(1, zone_id);
+
+    const size_t column_count = DatabaseAccessor::COLUMN_COUNT;
+    std::string columns[column_count];
+
+    // without search, getNext() should return false
+    EXPECT_FALSE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "", "", "", "");
+
+    db->searchForRecords(zone_id, "foo.bar.");
+    EXPECT_FALSE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "", "", "", "");
+
+    db->searchForRecords(zone_id, "");
+    EXPECT_FALSE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "", "", "", "");
+
+    // Should error on a bad number of columns
+    EXPECT_THROW(db->getNextRecord(columns, 3), DataSourceError);
+    EXPECT_THROW(db->getNextRecord(columns, 5), DataSourceError);
+
+    // now try some real searches
+    db->searchForRecords(zone_id, "foo.example.com.");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "CNAME", "3600", "",
+                   "cnametest.example.org.");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "RRSIG", "3600", "CNAME",
+                   "CNAME 5 3 3600 20100322084538 20100220084538 33495 "
+                   "example.com. FAKEFAKEFAKEFAKE");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "NSEC", "7200", "",
+                   "mail.example.com. CNAME RRSIG NSEC");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "RRSIG", "7200", "NSEC",
+                   "NSEC 5 3 7200 20100322084538 20100220084538 33495 "
+                   "example.com. FAKEFAKEFAKEFAKE");
+    EXPECT_FALSE(db->getNextRecord(columns, column_count));
+    // with no more records, the array should not have been modified
+    checkRecordRow(columns, "RRSIG", "7200", "NSEC",
+                   "NSEC 5 3 7200 20100322084538 20100220084538 33495 "
+                   "example.com. FAKEFAKEFAKEFAKE");
+
+    db->searchForRecords(zone_id, "example.com.");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "SOA", "3600", "",
+                   "master.example.com. admin.example.com. "
+                   "1234 3600 1800 2419200 7200");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "RRSIG", "3600", "SOA",
+                   "SOA 5 2 3600 20100322084538 20100220084538 "
+                   "33495 example.com. FAKEFAKEFAKEFAKE");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "NS", "1200", "", "dns01.example.com.");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "NS", "3600", "", "dns02.example.com.");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "NS", "1800", "", "dns03.example.com.");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "RRSIG", "3600", "NS",
+                   "NS 5 2 3600 20100322084538 20100220084538 "
+                   "33495 example.com. FAKEFAKEFAKEFAKE");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "MX", "3600", "", "10 mail.example.com.");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "MX", "3600", "",
+                   "20 mail.subzone.example.com.");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "RRSIG", "3600", "MX",
+                   "MX 5 2 3600 20100322084538 20100220084538 "
+                   "33495 example.com. FAKEFAKEFAKEFAKE");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "NSEC", "7200", "",
+                   "cname-ext.example.com. NS SOA MX RRSIG NSEC DNSKEY");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "RRSIG", "7200", "NSEC",
+                   "NSEC 5 2 7200 20100322084538 20100220084538 "
+                   "33495 example.com. FAKEFAKEFAKEFAKE");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "DNSKEY", "3600", "",
+                   "256 3 5 AwEAAcOUBllYc1hf7ND9uDy+Yz1BF3sI0m4q NGV7W"
+                   "cTD0WEiuV7IjXgHE36fCmS9QsUxSSOV o1I/FMxI2PJVqTYHkX"
+                   "FBS7AzLGsQYMU7UjBZ SotBJ6Imt5pXMu+lEDNy8TOUzG3xm7g"
+                   "0qcbW YF6qCEfvZoBtAqi5Rk7Mlrqs8agxYyMx");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "DNSKEY", "3600", "",
+                   "257 3 5 AwEAAe5WFbxdCPq2jZrZhlMj7oJdff3W7syJ tbvzg"
+                   "62tRx0gkoCDoBI9DPjlOQG0UAbj+xUV 4HQZJStJaZ+fHU5AwV"
+                   "NT+bBZdtV+NujSikhd THb4FYLg2b3Cx9NyJvAVukHp/91HnWu"
+                   "G4T36 CzAFrfPwsHIrBz9BsaIQ21VRkcmj7DswfI/i DGd8j6b"
+                   "qiODyNZYQ+ZrLmF0KIJ2yPN3iO6Zq 23TaOrVTjB7d1a/h31OD"
+                   "fiHAxFHrkY3t3D5J R9Nsl/7fdRmSznwtcSDgLXBoFEYmw6p86"
+                   "Acv RyoYNcL1SXjaKVLG5jyU3UR+LcGZT5t/0xGf oIK/aKwEN"
+                   "rsjcKZZj660b1M=");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "RRSIG", "3600", "DNSKEY",
+                   "DNSKEY 5 2 3600 20100322084538 20100220084538 "
+                   "4456 example.com. FAKEFAKEFAKEFAKE");
+    ASSERT_TRUE(db->getNextRecord(columns, column_count));
+    checkRecordRow(columns, "RRSIG", "3600", "DNSKEY",
+                   "DNSKEY 5 2 3600 20100322084538 20100220084538 "
+                   "33495 example.com. FAKEFAKEFAKEFAKE");
+    EXPECT_FALSE(db->getNextRecord(columns, column_count));
+    // getnextrecord returning false should mean array is not altered
+    checkRecordRow(columns, "RRSIG", "3600", "DNSKEY",
+                   "DNSKEY 5 2 3600 20100322084538 20100220084538 "
+                   "33495 example.com. FAKEFAKEFAKEFAKE");
+}
+
+} // end anonymous namespace
diff --git a/src/lib/datasrc/zone.h b/src/lib/datasrc/zone.h
index f67ed4b..0dacc5d 100644
--- a/src/lib/datasrc/zone.h
+++ b/src/lib/datasrc/zone.h
@@ -197,7 +197,7 @@ public:
                             const isc::dns::RRType& type,
                             isc::dns::RRsetList* target = NULL,
                             const FindOptions options
-                            = FIND_DEFAULT) const = 0;
+                            = FIND_DEFAULT) = 0;
     //@}
 };
 
diff --git a/src/lib/dns/rdata/generic/rrsig_46.cc b/src/lib/dns/rdata/generic/rrsig_46.cc
index 0c82406..fc8e340 100644
--- a/src/lib/dns/rdata/generic/rrsig_46.cc
+++ b/src/lib/dns/rdata/generic/rrsig_46.cc
@@ -243,5 +243,10 @@ RRSIG::compare(const Rdata& other) const {
     }
 }
 
+const RRType&
+RRSIG::typeCovered() {
+    return (impl_->covered_);
+}
+
 // END_RDATA_NAMESPACE
 // END_ISC_NAMESPACE
diff --git a/src/lib/dns/rdata/generic/rrsig_46.h b/src/lib/dns/rdata/generic/rrsig_46.h
index 19acc40..b8e6306 100644
--- a/src/lib/dns/rdata/generic/rrsig_46.h
+++ b/src/lib/dns/rdata/generic/rrsig_46.h
@@ -38,6 +38,9 @@ public:
     // END_COMMON_MEMBERS
     RRSIG& operator=(const RRSIG& source);
     ~RRSIG();
+
+    // specialized methods
+    const RRType& typeCovered();
 private:
     RRSIGImpl* impl_;
 };
diff --git a/src/lib/dns/tests/rdata_rrsig_unittest.cc b/src/lib/dns/tests/rdata_rrsig_unittest.cc
index 903021f..3324b99 100644
--- a/src/lib/dns/tests/rdata_rrsig_unittest.cc
+++ b/src/lib/dns/tests/rdata_rrsig_unittest.cc
@@ -47,7 +47,7 @@ TEST_F(Rdata_RRSIG_Test, fromText) {
                      "f49t+sXKPzbipN9g+s1ZPiIyofc=");
     generic::RRSIG rdata_rrsig(rrsig_txt);
     EXPECT_EQ(rrsig_txt, rdata_rrsig.toText());
-
+    EXPECT_EQ(isc::dns::RRType::A(), rdata_rrsig.typeCovered());
 }
 
 TEST_F(Rdata_RRSIG_Test, badText) {
diff --git a/src/lib/util/filename.h b/src/lib/util/filename.h
index c9874ce..f625938 100644
--- a/src/lib/util/filename.h
+++ b/src/lib/util/filename.h
@@ -103,6 +103,11 @@ public:
         return (extension_);
     }
 
+    /// \return Name + extension of Given File Name
+    std::string nameAndExtension() const {
+        return (name_ + extension_);
+    }
+
     /// \brief Expand Name with Default
     ///
     /// A default file specified is supplied and used to fill in any missing
diff --git a/src/lib/util/tests/filename_unittest.cc b/src/lib/util/tests/filename_unittest.cc
index be29ff1..07f3525 100644
--- a/src/lib/util/tests/filename_unittest.cc
+++ b/src/lib/util/tests/filename_unittest.cc
@@ -51,42 +51,49 @@ TEST_F(FilenameTest, Components) {
     EXPECT_EQ("/alpha/beta/", fname.directory());
     EXPECT_EQ("gamma", fname.name());
     EXPECT_EQ(".delta", fname.extension());
+    EXPECT_EQ("gamma.delta", fname.nameAndExtension());
 
     // Directory only
     fname.setName("/gamma/delta/");
     EXPECT_EQ("/gamma/delta/", fname.directory());
     EXPECT_EQ("", fname.name());
     EXPECT_EQ("", fname.extension());
+    EXPECT_EQ("", fname.nameAndExtension());
 
     // Filename only
     fname.setName("epsilon");
     EXPECT_EQ("", fname.directory());
     EXPECT_EQ("epsilon", fname.name());
     EXPECT_EQ("", fname.extension());
+    EXPECT_EQ("epsilon", fname.nameAndExtension());
 
     // Extension only
     fname.setName(".zeta");
     EXPECT_EQ("", fname.directory());
     EXPECT_EQ("", fname.name());
     EXPECT_EQ(".zeta", fname.extension());
+    EXPECT_EQ(".zeta", fname.nameAndExtension());
 
     // Missing directory
     fname.setName("eta.theta");
     EXPECT_EQ("", fname.directory());
     EXPECT_EQ("eta", fname.name());
     EXPECT_EQ(".theta", fname.extension());
+    EXPECT_EQ("eta.theta", fname.nameAndExtension());
 
     // Missing filename
     fname.setName("/iota/.kappa");
     EXPECT_EQ("/iota/", fname.directory());
     EXPECT_EQ("", fname.name());
     EXPECT_EQ(".kappa", fname.extension());
+    EXPECT_EQ(".kappa", fname.nameAndExtension());
 
     // Missing extension
     fname.setName("lambda/mu/nu");
     EXPECT_EQ("lambda/mu/", fname.directory());
     EXPECT_EQ("nu", fname.name());
     EXPECT_EQ("", fname.extension());
+    EXPECT_EQ("nu", fname.nameAndExtension());
 
     // Check that the decomposition can occur in the presence of leading and
     // trailing spaces
@@ -94,18 +101,21 @@ TEST_F(FilenameTest, Components) {
     EXPECT_EQ("lambda/mu/", fname.directory());
     EXPECT_EQ("nu", fname.name());
     EXPECT_EQ("", fname.extension());
+    EXPECT_EQ("nu", fname.nameAndExtension());
 
     // Empty string
     fname.setName("");
     EXPECT_EQ("", fname.directory());
     EXPECT_EQ("", fname.name());
     EXPECT_EQ("", fname.extension());
+    EXPECT_EQ("", fname.nameAndExtension());
 
     // ... and just spaces
     fname.setName("  ");
     EXPECT_EQ("", fname.directory());
     EXPECT_EQ("", fname.name());
     EXPECT_EQ("", fname.extension());
+    EXPECT_EQ("", fname.nameAndExtension());
 
     // Check corner cases - where separators are present, but strings are
     // absent.
@@ -113,16 +123,19 @@ TEST_F(FilenameTest, Components) {
     EXPECT_EQ("/", fname.directory());
     EXPECT_EQ("", fname.name());
     EXPECT_EQ("", fname.extension());
+    EXPECT_EQ("", fname.nameAndExtension());
 
     fname.setName(".");
     EXPECT_EQ("", fname.directory());
     EXPECT_EQ("", fname.name());
     EXPECT_EQ(".", fname.extension());
+    EXPECT_EQ(".", fname.nameAndExtension());
 
     fname.setName("/.");
     EXPECT_EQ("/", fname.directory());
     EXPECT_EQ("", fname.name());
     EXPECT_EQ(".", fname.extension());
+    EXPECT_EQ(".", fname.nameAndExtension());
 
     // Note that the space is a valid filename here; only leading and trailing
     // spaces should be trimmed.
@@ -130,11 +143,13 @@ TEST_F(FilenameTest, Components) {
     EXPECT_EQ("/", fname.directory());
     EXPECT_EQ(" ", fname.name());
     EXPECT_EQ(".", fname.extension());
+    EXPECT_EQ(" .", fname.nameAndExtension());
 
     fname.setName(" / . ");
     EXPECT_EQ("/", fname.directory());
     EXPECT_EQ(" ", fname.name());
     EXPECT_EQ(".", fname.extension());
+    EXPECT_EQ(" .", fname.nameAndExtension());
 }
 
 // Check that the expansion with a default works.




More information about the bind10-changes mailing list