BIND 10 master, updated. 6c11d9c51b88e2a6d238eac951d1d0317978f636 [master] Resolve conflict in changelog

BIND 10 source code commits bind10-changes at lists.isc.org
Tue Feb 15 11:01:48 UTC 2011


The branch, master has been updated
       via  6c11d9c51b88e2a6d238eac951d1d0317978f636 (commit)
       via  cdd18357620129b8533e9619b30b37ecbc91ede0 (commit)
       via  8aa3b2246ae095bbe7f855fd11656ae3bdb98986 (commit)
       via  adba8b7c9e699cf557646e942012567f8e5156c9 (commit)
       via  0ae5d2d73aad78ee24e641870cec1ab06f65e3f6 (commit)
       via  a02e4f3441285f10958b72e2337aa1b6e290fb56 (commit)
       via  16bbee505681b46ef60febb8067765704afdeb24 (commit)
       via  1b4b8193675f0ebc9b63480900257fa21e5cfa72 (commit)
       via  214eb805737eed8035490dc8ada790bca5c14fb6 (commit)
       via  42e9021df5556117697f9228645a4ff3eee246ae (commit)
       via  26ab69e18bd0417086315c20192b8b93093bf6e3 (commit)
       via  c1dd1aeae9aa2cb06b372d2002fa15d57aa7c552 (commit)
       via  a8746fb17e10db78330cf69b2850515020f5cd56 (commit)
       via  42dbc3cabef1db3f4c9ce99bc0830ce34794a704 (commit)
       via  e7c61f1bb5cf375a1f005bb7d77080d2fcd8fb9e (commit)
       via  ac8359174eaeb1df18bddcb0a57807d49ff8ed53 (commit)
       via  c94995ad3292958582d1ad491fdfbaa76e43cad8 (commit)
       via  fca9cd2ad55dfdff80ed3106c4cb40bf4d508d26 (commit)
       via  42beef26ba126bab9740af0a809617fc3c1906c6 (commit)
       via  3f791c7c437212e55981f044ef722a759f58a184 (commit)
       via  e64c9d4107c1d012b68239ecf4d828467f7eb6f7 (commit)
       via  ba8595ee4dbcc87deb5aca78359dd7a42e4a6f45 (commit)
       via  0162b6441a567a0a687a726f651e23bb754bfd71 (commit)
       via  74266da0141650d6ca337a66f266ba675ad2d357 (commit)
       via  bd58459c94e2074aecb39b02fa47a2b79e48cfb6 (commit)
       via  238f276c9b5887fcf72e86011e610466ce163f5b (commit)
       via  87c347e04505f141d624eb7be497181a37e346d0 (commit)
       via  3a899ef4c5c11d4bdfd9f50ac4aaa1b276060a65 (commit)
       via  a99da0d489fbecc59b6d75a85e71e92ec7d173e3 (commit)
       via  a0e0f22323abff0332ac4dff60300874a3e2f1a0 (commit)
       via  4205ee154f209d4493e2b7176b53c79d5dbaf193 (commit)
       via  6e5884cfb1610b47339be5f2578e8e77840d3095 (commit)
       via  4e8c15eae9ffb0d159f5d9f138455aa0213163fe (commit)
       via  83d5d9a0bc2599bd9a643c2c6294f382638486b6 (commit)
       via  e75ba8ce2f5b2f9814741d0ea633f3542b458a74 (commit)
       via  f62f4f06cf94b4d979e5b036a41c06b4f53e5759 (commit)
       via  39158d307dd4b4a74f89bb755d22d1edd3a04d80 (commit)
       via  777f07c955102aaa875ed2567d788b4103f849e1 (commit)
       via  2aff13f019888ae254733f2c16d9a8b995a48318 (commit)
       via  0050a51bfb904132db32a2d4729064d8a35a5332 (commit)
       via  77f677784ed005ff2cf6e5387d837897e3e3bdc4 (commit)
       via  886b10843e5e8fe2fd7b04684a590affe1b812ab (commit)
       via  07e20270989ec37e95feb3a01fefeb5b80465bef (commit)
       via  a7bf808a220742d18fb1868241f1665f745ebdbc (commit)
       via  8eafc24514f6d6cc1a8b71bef7358cb9bdff5a8c (commit)
       via  38e8504574d599e1e6d139ebcfe5f905de678e2d (commit)
       via  61e391f3bb0af427263c2374d613af3fd10a5fe4 (commit)
       via  6c3a274305a7823a4060769ab21d55c5975615d6 (commit)
       via  203152faad9ccda93c9f799ef48c47d22da1d3bf (commit)
       via  b6b9f884f331a4f8726a3cd6a0f3eed7870b7cf8 (commit)
       via  5efcee702cfe268615733f30988abca319089531 (commit)
       via  5a7d082452848daa9dcb0b023f0829d457d8bcc0 (commit)
      from  541478374f183c2742a7f07e6558836a4dd09570 (commit)

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

- Log -----------------------------------------------------------------
commit 6c11d9c51b88e2a6d238eac951d1d0317978f636
Merge: cdd18357620129b8533e9619b30b37ecbc91ede0 541478374f183c2742a7f07e6558836a4dd09570
Author: Jelte Jansen <jelte at isc.org>
Date:   Tue Feb 15 11:59:56 2011 +0100

    [master] Resolve conflict in changelog
    
    Conflicts:
    	ChangeLog

commit cdd18357620129b8533e9619b30b37ecbc91ede0
Author: Jelte Jansen <jelte at isc.org>
Date:   Tue Feb 15 11:58:28 2011 +0100

    [master] update Changelog with correct git commit

commit 8aa3b2246ae095bbe7f855fd11656ae3bdb98986
Merge: 756e56a8c683906b1b50bba5675c996fb1295820 adba8b7c9e699cf557646e942012567f8e5156c9
Author: Jelte Jansen <jelte at isc.org>
Date:   Tue Feb 15 11:57:35 2011 +0100

    [master] Merge branch 'trac449'
    
    Conflicts:
    	doc/Doxyfile
    	src/lib/Makefile.am

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

Summary of changes:
 ChangeLog                                          |    5 +
 configure.ac                                       |    2 +
 doc/Doxyfile                                       |    2 +-
 src/lib/Makefile.am                                |    2 +-
 src/lib/{nsas => cache}/Makefile.am                |   27 +-
 src/lib/cache/TODO                                 |   12 +
 .../exceptions.cc => cache/cache_entry_key.cc}     |   36 ++-
 src/lib/cache/cache_entry_key.h                    |   56 ++++
 src/lib/cache/local_zone_data.cc                   |   58 ++++
 src/lib/cache/local_zone_data.h                    |   66 ++++
 src/lib/cache/message_cache.cc                     |   95 ++++++
 src/lib/cache/message_cache.h                      |   95 ++++++
 src/lib/cache/message_entry.cc                     |  249 +++++++++++++++
 src/lib/cache/message_entry.h                      |  183 +++++++++++
 src/lib/cache/resolver_cache.cc                    |  247 +++++++++++++++
 src/lib/cache/resolver_cache.h                     |  331 ++++++++++++++++++++
 src/lib/cache/rrset_cache.cc                       |  105 ++++++
 src/lib/cache/rrset_cache.h                        |  108 +++++++
 .../root_logger_name.cc => cache/rrset_copy.cc}    |   24 ++-
 .../root_logger_name.cc => cache/rrset_copy.h}     |   30 ++-
 src/lib/cache/rrset_entry.cc                       |   66 ++++
 src/lib/cache/rrset_entry.h                        |  137 ++++++++
 src/lib/{nsas => cache}/tests/Makefile.am          |   29 +-
 src/lib/cache/tests/cache_test_util.h              |   58 ++++
 src/lib/cache/tests/local_zone_data_unittest.cc    |   65 ++++
 src/lib/cache/tests/message_cache_unittest.cc      |   98 ++++++
 src/lib/cache/tests/message_entry_unittest.cc      |  236 ++++++++++++++
 src/lib/cache/tests/resolver_cache_unittest.cc     |  138 ++++++++
 src/lib/cache/tests/rrset_cache_unittest.cc        |   84 +++++
 src/lib/cache/tests/rrset_entry_unittest.cc        |  106 +++++++
 src/lib/{dns => cache}/tests/run_unittests.cc      |    3 +
 .../tests/testdata/message_fromWire1               |    0 
 .../tests/testdata/message_fromWire2}              |   10 +-
 src/lib/cache/tests/testdata/message_fromWire3     |   76 +++++
 src/lib/cache/tests/testdata/message_fromWire4     |   80 +++++
 src/lib/cache/tests/testdata/message_fromWire5     |   36 +++
 src/lib/cache/tests/testdata/message_fromWire6     |   40 +++
 src/lib/dns/rrset.h                                |   10 +-
 38 files changed, 2937 insertions(+), 68 deletions(-)
 copy src/lib/{nsas => cache}/Makefile.am (50%)
 create mode 100644 src/lib/cache/TODO
 copy src/lib/{dns/exceptions.cc => cache/cache_entry_key.cc} (57%)
 create mode 100644 src/lib/cache/cache_entry_key.h
 create mode 100644 src/lib/cache/local_zone_data.cc
 create mode 100644 src/lib/cache/local_zone_data.h
 create mode 100644 src/lib/cache/message_cache.cc
 create mode 100644 src/lib/cache/message_cache.h
 create mode 100644 src/lib/cache/message_entry.cc
 create mode 100644 src/lib/cache/message_entry.h
 create mode 100644 src/lib/cache/resolver_cache.cc
 create mode 100644 src/lib/cache/resolver_cache.h
 create mode 100644 src/lib/cache/rrset_cache.cc
 create mode 100644 src/lib/cache/rrset_cache.h
 copy src/lib/{log/root_logger_name.cc => cache/rrset_copy.cc} (63%)
 copy src/lib/{log/root_logger_name.cc => cache/rrset_copy.h} (59%)
 create mode 100644 src/lib/cache/rrset_entry.cc
 create mode 100644 src/lib/cache/rrset_entry.h
 copy src/lib/{nsas => cache}/tests/Makefile.am (60%)
 create mode 100644 src/lib/cache/tests/cache_test_util.h
 create mode 100644 src/lib/cache/tests/local_zone_data_unittest.cc
 create mode 100644 src/lib/cache/tests/message_cache_unittest.cc
 create mode 100644 src/lib/cache/tests/message_entry_unittest.cc
 create mode 100644 src/lib/cache/tests/resolver_cache_unittest.cc
 create mode 100644 src/lib/cache/tests/rrset_cache_unittest.cc
 create mode 100644 src/lib/cache/tests/rrset_entry_unittest.cc
 copy src/lib/{dns => cache}/tests/run_unittests.cc (92%)
 copy src/lib/{dns => cache}/tests/testdata/message_fromWire1 (100%)
 copy src/lib/{dns/tests/testdata/message_fromWire1 => cache/tests/testdata/message_fromWire2} (64%)
 create mode 100644 src/lib/cache/tests/testdata/message_fromWire3
 create mode 100644 src/lib/cache/tests/testdata/message_fromWire4
 create mode 100644 src/lib/cache/tests/testdata/message_fromWire5
 create mode 100644 src/lib/cache/tests/testdata/message_fromWire6

-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 6345608..9cf9b3b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+  169.  [func]      zhang likun, jelte
+	Added a basic implementation for a resolver cache (though not
+	used yet).
+	(Trac #449, git 8aa3b2246ae095bbe7f855fd11656ae3bdb98986)
+
   168.  [bug]       vorner
 	Boss no longer has the -f argument, which was undocumented and stayed as
 	a relict of previous versions, currently causing only strange behaviour.
diff --git a/configure.ac b/configure.ac
index fef2cbe..139166b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -712,6 +712,8 @@ AC_CONFIG_FILES([Makefile
                  src/lib/testutils/testdata/Makefile
                  src/lib/nsas/Makefile
                  src/lib/nsas/tests/Makefile
+                 src/lib/cache/Makefile
+                 src/lib/cache/tests/Makefile
                ])
 AC_OUTPUT([doc/version.ent
            src/bin/cfgmgr/b10-cfgmgr.py
diff --git a/doc/Doxyfile b/doc/Doxyfile
index 6ab2001..34ec3d8 100644
--- a/doc/Doxyfile
+++ b/doc/Doxyfile
@@ -568,7 +568,7 @@ WARN_LOGFILE           =
 # directories like "/usr/src/myproject". Separate the files or directories
 # with spaces.
 
-INPUT                  = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils
+INPUT                  = ../src/lib/cc ../src/lib/config ../src/lib/dns ../src/lib/exceptions ../src/lib/datasrc ../src/bin/auth ../src/bin/resolver ../src/lib/bench ../src/lib/log ../src/lib/asiolink/ ../src/lib/nsas ../src/lib/testutils ../src/lib/cache
 
 # This tag can be used to specify the character encoding of the source files
 # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index b7b80bf..8ab93ba 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -1,2 +1,2 @@
 SUBDIRS = exceptions dns cc config datasrc python xfr bench log \
-          resolve asiolink testutils nsas
+          resolve asiolink testutils nsas cache
diff --git a/src/lib/cache/Makefile.am b/src/lib/cache/Makefile.am
new file mode 100644
index 0000000..264aca6
--- /dev/null
+++ b/src/lib/cache/Makefile.am
@@ -0,0 +1,33 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/nsas -I$(top_builddir)/src/lib/nsas
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cache -I$(top_builddir)/src/lib/cache
+AM_CPPFLAGS += $(SQLITE_CFLAGS)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+if USE_CLANGPP
+# clang++ complains about unused function parameters in some boost header
+# files.
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
+
+lib_LTLIBRARIES = libcache.la
+libcache_la_SOURCES  = resolver_cache.h resolver_cache.cc
+libcache_la_SOURCES  += message_cache.h message_cache.cc
+libcache_la_SOURCES  += message_entry.h message_entry.cc
+libcache_la_SOURCES  += rrset_cache.h rrset_cache.cc
+libcache_la_SOURCES  += rrset_entry.h rrset_entry.cc
+libcache_la_SOURCES  += cache_entry_key.h cache_entry_key.cc
+libcache_la_SOURCES  += rrset_copy.h rrset_copy.cc
+libcache_la_SOURCES  += local_zone_data.h local_zone_data.cc
+
+CLEANFILES = *.gcno *.gcda
diff --git a/src/lib/cache/TODO b/src/lib/cache/TODO
new file mode 100644
index 0000000..0743ee4
--- /dev/null
+++ b/src/lib/cache/TODO
@@ -0,0 +1,12 @@
+* Revisit the algorithm used by getRRsetTrustLevel() in message_entry.cc.
+* Implement dump/load/resize interfaces of rrset/message/recursor cache.
+* Once LRU hash table is implemented, it should be used by message/rrset cache.
+* Once the hash/lrulist related files in /lib/nsas is moved to seperated
+  folder, the code of recursor cache has to be updated.
+* Set proper AD flags once DNSSEC is supported by the cache.
+* When the message or rrset entry has expired, it should be removed
+  from the cache, or just moved to the head of LRU list, so that it
+  can removed first.
+* Make resolver cache be smart to refetch the messages that are about
+  to expire.
+
diff --git a/src/lib/cache/cache_entry_key.cc b/src/lib/cache/cache_entry_key.cc
new file mode 100644
index 0000000..35917a0
--- /dev/null
+++ b/src/lib/cache/cache_entry_key.cc
@@ -0,0 +1,44 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <sstream>
+#include "cache_entry_key.h"
+
+using namespace std;
+
+namespace isc {
+namespace cache {
+const std::string
+genCacheEntryName(const isc::dns::Name& name, const isc::dns::RRType& type) {
+    std::string keystr = name.toText();
+    ostringstream stream;
+    stream << type.getCode();
+    keystr += stream.str();
+    return (keystr);
+}
+
+const std::string
+genCacheEntryName(const std::string& namestr, const uint16_t type) {
+    std::string keystr = namestr;
+    ostringstream stream;
+    stream << type;
+    keystr += stream.str();
+    return (keystr);
+}
+
+} // namespace cache
+} // namespace isc
+
diff --git a/src/lib/cache/cache_entry_key.h b/src/lib/cache/cache_entry_key.h
new file mode 100644
index 0000000..002f958
--- /dev/null
+++ b/src/lib/cache/cache_entry_key.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __CACHE_ENTRY_KEY_H
+#define __CACHE_ENTRY_KEY_H
+
+#include <string>
+#include <dns/name.h>
+#include <dns/rrtype.h>
+
+namespace isc {
+namespace cache {
+
+/// \brief Entry Name Generation Functions
+///
+/// Generate the name for message/rrset entries.
+///
+/// Concatenates the string representation of the Name and the
+/// string representation of the type number.
+///
+/// Note: the returned name is a text string, not wire format.
+/// eg. if name is 'example.com.', type is 'A', the return
+/// value is 'example.com.1'
+///
+/// \param name The Name to create a text entry for
+/// \param type The RRType to create a text entry for
+/// \return return the entry name.
+const std::string
+genCacheEntryName(const isc::dns::Name& name, const isc::dns::RRType& type);
+
+///
+/// \overload
+///
+/// \param namestr A string representation of a DNS Name
+/// \param type The value of a DNS RRType
+const std::string
+genCacheEntryName(const std::string& namestr, const uint16_t type);
+
+} // namespace cache
+} // namespace isc
+
+#endif // __CACHE_ENTRY_KEY_H
+
diff --git a/src/lib/cache/local_zone_data.cc b/src/lib/cache/local_zone_data.cc
new file mode 100644
index 0000000..2dcc113
--- /dev/null
+++ b/src/lib/cache/local_zone_data.cc
@@ -0,0 +1,58 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/rrset.h>
+#include "local_zone_data.h"
+#include "cache_entry_key.h"
+#include "rrset_copy.h"
+
+using namespace std;
+using namespace isc::dns;
+
+namespace isc {
+namespace cache {
+
+typedef pair<std::string, RRsetPtr> RRsetMapPair;
+typedef map<std::string, RRsetPtr>::iterator RRsetMapIterator;
+
+isc::dns::RRsetPtr
+LocalZoneData::lookup(const isc::dns::Name& name,
+                      const isc::dns::RRType& type)
+{
+    string key = genCacheEntryName(name, type);
+    RRsetMapIterator iter = rrsets_map_.find(key);
+    if (iter == rrsets_map_.end()) {
+        return (RRsetPtr());
+    } else {
+        return (iter->second);
+    }
+}
+
+void
+LocalZoneData::update(const isc::dns::RRset& rrset) {
+    //TODO Do we really need to recreate the rrset again?
+    string key = genCacheEntryName(rrset.getName(), rrset.getType());
+    RRset* rrset_copy = new RRset(rrset.getName(), rrset.getClass(),
+                                  rrset.getType(), rrset.getTTL());
+
+    rrsetCopy(rrset, *rrset_copy);
+    RRsetPtr rrset_ptr(rrset_copy);
+    rrsets_map_[key] = rrset_ptr;
+}
+
+} // namespace cache
+} // namespace isc
+
diff --git a/src/lib/cache/local_zone_data.h b/src/lib/cache/local_zone_data.h
new file mode 100644
index 0000000..bcf5a94
--- /dev/null
+++ b/src/lib/cache/local_zone_data.h
@@ -0,0 +1,66 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef _LOCAL_ZONE_DATA
+#define _LOCAL_ZONE_DATA
+
+#include <map>
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include <dns/rrset.h>
+
+namespace isc {
+namespace cache {
+
+/// \brief Local Zone Data
+/// The object of LocalZoneData represents the data of one
+/// local zone. It provides the interface for lookup the rrsets
+/// in the zone.
+class LocalZoneData {
+public:
+    LocalZoneData(uint16_t rrset_class) : class_(rrset_class)
+    {}
+
+    /// \brief Look up one rrset.
+    ///
+    /// \param qname The query name to look up
+    /// \param qtype The query type to look up
+    /// \return return the shared_ptr of rrset if it is
+    /// found in the local zone, or else, return NULL.
+    isc::dns::RRsetPtr lookup(const isc::dns::Name& qname,
+                              const isc::dns::RRType& qtype);
+
+    /// \brief Update the rrset in the local zone.
+    ///
+    /// If the rrset doesn't exist, it will be added.
+    /// Otherwise, the existed one will be overwritten.
+    ///
+    /// \param rrset The rrset to update
+    void update(const isc::dns::RRset& rrset);
+
+private:
+    std::map<std::string, isc::dns::RRsetPtr> rrsets_map_; // RRsets of the zone
+    uint16_t class_; // The class of the zone
+};
+
+typedef boost::shared_ptr<LocalZoneData> LocalZoneDataPtr;
+typedef boost::shared_ptr<const LocalZoneData> ConstLocalZoneDataPtr;
+
+} // namespace cache
+} // namespace isc
+
+#endif // _LOCAL_ZONE_DATA
+
diff --git a/src/lib/cache/message_cache.cc b/src/lib/cache/message_cache.cc
new file mode 100644
index 0000000..9706fc4
--- /dev/null
+++ b/src/lib/cache/message_cache.cc
@@ -0,0 +1,95 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <nsas/nsas_entry_compare.h>
+#include <nsas/hash_table.h>
+#include <nsas/hash_deleter.h>
+#include "message_cache.h"
+#include "cache_entry_key.h"
+
+using namespace isc::nsas;
+using namespace isc::dns;
+using namespace std;
+
+namespace isc {
+namespace cache {
+
+MessageCache::MessageCache(boost::shared_ptr<RRsetCache> rrset_cache,
+    uint32_t cache_size, uint16_t message_class):
+    message_class_(message_class),
+    rrset_cache_(rrset_cache),
+    message_table_(new NsasEntryCompare<MessageEntry>, cache_size),
+    message_lru_((3 * cache_size),
+                  new HashDeleter<MessageEntry>(message_table_))
+{
+}
+
+bool
+MessageCache::lookup(const isc::dns::Name& qname,
+                     const isc::dns::RRType& qtype,
+                     isc::dns::Message& response)
+{
+    std::string entry_name = genCacheEntryName(qname, qtype);
+    HashKey entry_key = HashKey(entry_name, RRClass(message_class_));
+    MessageEntryPtr msg_entry = message_table_.get(entry_key);
+    if(msg_entry) {
+        message_lru_.touch(msg_entry);
+        return (msg_entry->genMessage(time(NULL), response));
+    }
+
+    return (false);
+}
+
+bool
+MessageCache::update(const Message& msg) {
+    QuestionIterator iter = msg.beginQuestion();
+    std::string entry_name = genCacheEntryName((*iter)->getName(), (*iter)->getType());
+    HashKey entry_key = HashKey(entry_name, RRClass(message_class_));
+
+    // The simplest way to update is removing the old message entry directly.
+    // We have find the existed message entry, since we need to delete it
+    // from lru list too.
+    // TODO, but there should be a better way, since we here have to remove and
+    // add the message entry, maybe there is one way to touch it once.
+    MessageEntryPtr old_msg_entry = message_table_.get(entry_key);
+    if (old_msg_entry) {
+        message_lru_.remove(old_msg_entry);
+    }
+
+    MessageEntryPtr msg_entry(new MessageEntry(msg, rrset_cache_));
+    message_lru_.add(msg_entry);
+    return (message_table_.add(msg_entry, entry_key, true));
+}
+
+void
+MessageCache::dump(const std::string&) {
+    //TODO
+}
+
+void
+MessageCache::load(const std::string&) {
+    //TODO
+}
+
+bool
+MessageCache::resize(uint32_t) {
+    //TODO
+    return (true);
+}
+
+} // namespace cache
+} // namespace isc
+
diff --git a/src/lib/cache/message_cache.h b/src/lib/cache/message_cache.h
new file mode 100644
index 0000000..0131b30
--- /dev/null
+++ b/src/lib/cache/message_cache.h
@@ -0,0 +1,95 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __MESSAGE_CACHE_H
+#define __MESSAGE_CACHE_H
+
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include <dns/message.h>
+#include "message_entry.h"
+#include <nsas/hash_table.h>
+#include <nsas/lru_list.h>
+
+namespace isc {
+namespace cache {
+
+class RRsetCache;
+
+/// \brief Message Cache
+/// The object of MessageCache represents the cache for class-specific
+/// messages.
+///
+class MessageCache {
+// Noncopyable
+private:
+    MessageCache(const MessageCache& source);
+    MessageCache& operator=(const MessageCache& source);
+public:
+    /// \param cache_size The size of message cache.
+    MessageCache(boost::shared_ptr<RRsetCache> rrset_cache_,
+                 uint32_t cache_size, uint16_t message_class);
+
+    /// \brief Look up message in cache.
+    /// \param message generated response message if the message entry
+    ///        can be found.
+    ///
+    /// \return return true if the message can be found in cache, or else,
+    /// return false.
+    //TODO Maybe some user just want to get the message_entry.
+    bool lookup(const isc::dns::Name& qname,
+                const isc::dns::RRType& qtype,
+                isc::dns::Message& message);
+
+    /// \brief Update the message in the cache with the new one.
+    /// If the message doesn't exist in the cache, it will be added
+    /// directly.
+    bool update(const isc::dns::Message& msg);
+
+    /// \brief Dump the message cache to specified file.
+    /// \todo It should can be dumped to one configured database.
+    void dump(const std::string& file_name);
+
+    /// \brief Load the cache from one file.
+    /// \todo It should can be loaded from one configured database.
+    void load(const std::string& file_name);
+
+    /// \brief Resize the size of message cache in runtime.
+    bool resize(uint32_t size);
+
+protected:
+    /// \brief Get the hash key for the message entry in the cache.
+    /// \param name query name of the message.
+    /// \param type query type of the message.
+    /// \return return the hash key.
+    HashKey getEntryHashKey(const isc::dns::Name& name,
+                            const isc::dns::RRType& type) const;
+
+    // Make these variants be protected for easy unittest.
+protected:
+    uint16_t message_class_; // The class of the message cache.
+    boost::shared_ptr<RRsetCache> rrset_cache_;
+    isc::nsas::HashTable<MessageEntry> message_table_;
+    isc::nsas::LruList<MessageEntry> message_lru_;
+};
+
+typedef boost::shared_ptr<MessageCache> MessageCachePtr;
+
+} // namespace cache
+} // namespace isc
+
+#endif // __MESSAGE_CACHE_H
+
diff --git a/src/lib/cache/message_entry.cc b/src/lib/cache/message_entry.cc
new file mode 100644
index 0000000..26c8bee
--- /dev/null
+++ b/src/lib/cache/message_entry.cc
@@ -0,0 +1,249 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <limits>
+#include <dns/message.h>
+#include <nsas/nsas_entry.h>
+#include "message_entry.h"
+#include "rrset_cache.h"
+
+using namespace isc::dns;
+using namespace std;
+
+namespace isc {
+namespace cache {
+
+static uint32_t MAX_UINT32 = numeric_limits<uint32_t>::max();
+
+MessageEntry::MessageEntry(const isc::dns::Message& msg,
+                           boost::shared_ptr<RRsetCache> rrset_cache):
+    rrset_cache_(rrset_cache),
+    headerflag_aa_(false),
+    headerflag_tc_(false)
+{
+    initMessageEntry(msg);
+    entry_name_ = genCacheEntryName(query_name_, query_type_);
+    hash_key_ptr_ = new HashKey(entry_name_, RRClass(query_class_));
+}
+
+bool
+MessageEntry::getRRsetEntries(vector<RRsetEntryPtr>& rrset_entry_vec,
+                              const time_t time_now)
+{
+    uint16_t entry_count = answer_count_ + authority_count_ + additional_count_;
+    rrset_entry_vec.reserve(rrset_entry_vec.size() + entry_count);
+    for (int index = 0; index < entry_count; ++index) {
+        RRsetEntryPtr rrset_entry = rrset_cache_->lookup(rrsets_[index].name_,
+                                                        rrsets_[index].type_);
+        if (time_now < rrset_entry->getExpireTime()) {
+            rrset_entry_vec.push_back(rrset_entry);
+        } else {
+            return (false);
+        }
+    }
+
+    return (true);
+}
+
+void
+MessageEntry::addRRset(isc::dns::Message& message,
+                       const vector<RRsetEntryPtr>& rrset_entry_vec,
+                       const isc::dns::Message::Section& section,
+                       bool dnssec_need)
+{
+    uint16_t start_index = 0;
+    uint16_t end_index = answer_count_;
+    assert(section != Message::SECTION_QUESTION);
+
+    if (section == Message::SECTION_AUTHORITY) {
+        start_index = answer_count_;
+        end_index = answer_count_ + authority_count_;
+    } else if (section == Message::SECTION_ADDITIONAL) {
+        start_index = answer_count_ + authority_count_;
+        end_index = start_index + additional_count_;
+    }
+
+    for(uint16_t index = start_index; index < end_index; ++index) {
+        message.addRRset(section, rrset_entry_vec[index]->getRRset(), dnssec_need);
+    }
+}
+
+bool
+MessageEntry::genMessage(const time_t& time_now,
+                         isc::dns::Message& msg)
+{
+    if (time_now >= expire_time_) {
+        // The message entry has expired.
+        return (false);
+    } else {
+        // Before do any generation, we should check if some rrset
+        // has expired, if it is, return false.
+        vector<RRsetEntryPtr> rrset_entry_vec;
+        if (false == getRRsetEntries(rrset_entry_vec, time_now)) {
+            return (false);
+        }
+
+        // Begin message generation. We don't need to add question
+        // section, since it has been included in the message.
+        // Set cached header flags.
+        msg.setHeaderFlag(Message::HEADERFLAG_AA, headerflag_aa_);
+        msg.setHeaderFlag(Message::HEADERFLAG_TC, headerflag_tc_);
+
+        bool dnssec_need = msg.getEDNS().get();
+        addRRset(msg, rrset_entry_vec, Message::SECTION_ANSWER, dnssec_need);
+        addRRset(msg, rrset_entry_vec, Message::SECTION_AUTHORITY, dnssec_need);
+        addRRset(msg, rrset_entry_vec, Message::SECTION_ADDITIONAL, dnssec_need);
+
+        return (true);
+    }
+}
+
+RRsetTrustLevel
+MessageEntry::getRRsetTrustLevel(const Message& message,
+    const isc::dns::RRsetPtr& rrset,
+    const isc::dns::Message::Section& section)
+{
+    bool aa = message.getHeaderFlag(Message::HEADERFLAG_AA);
+    switch(section) {
+        case Message::SECTION_ANSWER: {
+            if (aa) {
+                RRsetIterator rrset_iter = message.beginSection(section);
+
+                // Make sure we are inspecting the right RRset
+                while((*rrset_iter)->getName() != rrset->getName() &&
+                      (*rrset_iter)->getType() != rrset->getType() &&
+                      rrset_iter != message.endSection(section)) {
+                    ++rrset_iter;
+                }
+                assert(rrset_iter != message.endSection(section));
+                
+                // According RFC2181 section 5.4.1, only the record
+                // describing that ailas is necessarily authoritative.
+                // If there is one or more CNAME records in answer section.
+                // CNAME records is assumed as the first rrset.
+                if ((*rrset_iter)->getType() == RRType::CNAME()) {
+                    // TODO: real equals for RRsets?
+                    if ((*rrset_iter).get() == rrset.get()) {
+                        return (RRSET_TRUST_ANSWER_AA);
+                    } else {
+                        return (RRSET_TRUST_ANSWER_NONAA);
+                    }
+                }
+
+                // Here, if the first rrset is DNAME, then assume the
+                // second rrset is synchronized CNAME record, except
+                // these two records, any other records in answer section
+                // should be treated as non-authoritative.
+                // TODO, this part logic should be revisited later,
+                // since it's not mentioned by RFC2181.
+                if ((*rrset_iter)->getType() == RRType::DNAME()) {
+                    // TODO: real equals for RRsets?
+                    if ((*rrset_iter).get() == rrset.get() ||
+                        ((++rrset_iter) != message.endSection(section) &&
+                                     (*rrset_iter).get() == rrset.get())) {
+                        return (RRSET_TRUST_ANSWER_AA);
+                    } else {
+                        return (RRSET_TRUST_ANSWER_NONAA);
+                    }
+                }
+
+                return (RRSET_TRUST_ANSWER_AA);
+
+            } else {
+                return (RRSET_TRUST_ANSWER_NONAA);
+            }
+            break;
+        }
+
+        case Message::SECTION_AUTHORITY: {
+            if (aa) {
+                return (RRSET_TRUST_AUTHORITY_AA);
+            } else {
+                return (RRSET_TRUST_AUTHORITY_NONAA);
+            }
+            break;
+        }
+
+        case Message::SECTION_ADDITIONAL: {
+            if (aa) {
+                return (RRSET_TRUST_ADDITIONAL_AA);
+            } else {
+                return (RRSET_TRUST_ADDITIONAL_NONAA);
+            }
+            break;
+        }
+
+        default:
+            return (RRSET_TRUST_DEFAULT);
+    }
+}
+
+void
+MessageEntry::parseSection(const isc::dns::Message& msg,
+                         const Message::Section& section,
+                         uint32_t& smaller_ttl,
+                         uint16_t& rrset_count)
+{
+    RRsetIterator iter;
+    int count = 0;
+    for (iter = msg.beginSection(section);
+         iter != msg.endSection(section);
+         ++iter) {
+        // Add the rrset entry to rrset_cache or update the existed
+        // rrset entry if the new one is more authoritative.
+        //TODO set proper rrset trust level.
+        RRsetPtr rrset_ptr = *iter;
+        RRsetTrustLevel level = getRRsetTrustLevel(msg, rrset_ptr, section);
+        RRsetEntryPtr rrset_entry = rrset_cache_->update(*rrset_ptr, level);
+        rrsets_.push_back(RRsetRef(rrset_ptr->getName(), rrset_ptr->getType()));
+
+        uint32_t rrset_ttl = rrset_entry->getTTL();
+        if (smaller_ttl > rrset_ttl) {
+            smaller_ttl = rrset_ttl;
+        }
+
+        count++;
+    }
+
+    rrset_count = count;
+}
+
+void
+MessageEntry::initMessageEntry(const isc::dns::Message& msg) {
+    //TODO better way to cache the header flags?
+    headerflag_aa_ = msg.getHeaderFlag(Message::HEADERFLAG_AA);
+    headerflag_tc_ = msg.getHeaderFlag(Message::HEADERFLAG_TC);
+
+    // We only cache the first question in question section.
+    // TODO, do we need to support muptiple questions?
+    query_count_ = 1;
+    QuestionIterator iter = msg.beginQuestion();
+    query_name_ = (*iter)->getName().toText();
+    query_type_ = (*iter)->getType().getCode();
+    query_class_ = (*iter)->getClass().getCode();
+
+    uint32_t min_ttl = MAX_UINT32;
+    parseSection(msg, Message::SECTION_ANSWER, min_ttl, answer_count_);
+    parseSection(msg, Message::SECTION_AUTHORITY, min_ttl, authority_count_);
+    parseSection(msg, Message::SECTION_ADDITIONAL, min_ttl, additional_count_);
+
+    expire_time_ = time(NULL) + min_ttl;
+}
+
+} // namespace cache
+} // namespace isc
+
+
diff --git a/src/lib/cache/message_entry.h b/src/lib/cache/message_entry.h
new file mode 100644
index 0000000..0ed00f0
--- /dev/null
+++ b/src/lib/cache/message_entry.h
@@ -0,0 +1,183 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __MESSAGE_ENTRY_H
+#define __MESSAGE_ENTRY_H
+
+#include <vector>
+#include <dns/message.h>
+#include <dns/rrset.h>
+#include <nsas/nsas_entry.h>
+#include "rrset_entry.h"
+
+
+using namespace isc::nsas;
+
+namespace isc {
+namespace cache {
+
+class RRsetEntry;
+class RRsetCache;
+
+/// \brief Information to refer an RRset.
+///
+/// There is no class information here, since the rrsets are cached in
+/// the class-specific rrset cache.
+struct RRsetRef{
+    /// \brief Constructor
+    ///
+    /// \param name The Name for the RRset
+    /// \param type the RRType for the RRrset
+    RRsetRef(const isc::dns::Name& name, const isc::dns::RRType& type):
+            name_(name), type_(type)
+    {}
+
+    isc::dns::Name name_; // Name of rrset.
+    isc::dns::RRType type_; // Type of rrset.
+};
+
+/// \brief Message Entry
+///
+/// The object of MessageEntry represents one response message
+/// answered to the resolver client.
+class MessageEntry : public NsasEntry<MessageEntry> {
+// Noncopyable
+private:
+    MessageEntry(const MessageEntry& source);
+    MessageEntry& operator=(const MessageEntry& source);
+public:
+
+    /// \brief Initialize the message entry object with one dns
+    ///        message.
+    /// \param message The message used to initialize MessageEntry.
+    /// \param rrset_cache the pointer of RRsetCache. When one message
+    ///        entry is created, rrset cache needs to be updated,
+    ///        since some new rrset entries may be inserted into
+    ///        rrset cache, or the existed rrset entries need
+    ///        to be updated.
+    MessageEntry(const isc::dns::Message& message,
+                 boost::shared_ptr<RRsetCache> rrset_cache);
+
+    /// \brief generate one dns message according
+    ///        the rrsets information of the message.
+    ///
+    /// \param time_now set the ttl of each rrset in the message
+    ///        as "expire_time - time_now" (expire_time is the
+    ///        expiration time of the rrset).
+    /// \param response generated dns message.
+    /// \return return true if the response message can be generated
+    ///         from the cached information, or else, return false.
+    bool genMessage(const time_t& time_now, isc::dns::Message& response);
+
+    /// \brief Get the hash key of the message entry.
+    ///
+    /// \return return hash key
+    virtual HashKey hashKey() const {
+        return (*hash_key_ptr_);
+    }
+
+protected:
+    /// \brief Initialize the message entry with dns message.
+    ///
+    /// \param message The Message to initialize the entry with
+    void initMessageEntry(const isc::dns::Message& message);
+
+    /// \brief These two functions should be static functions
+    ///        placed in cc file. Put them here just for easy unit
+    ///        tests.
+    //@{
+    /// \brief Parse the rrsets in specified section.
+    ///
+    /// \param msg The message to parse the RRsets from
+    /// \param section The Section to parse the RRsets from
+    /// \param smaller_ttl Get the smallest ttl of rrsets in
+    ///        specified section, if it's smaller than the given value.
+    /// \param rrset_count the rrset count of the section.
+    ///        (TODO for Message, getRRsetCount() should be one
+    ///        interface provided by Message.)
+    void parseSection(const isc::dns::Message& msg,
+                      const isc::dns::Message::Section& section,
+                      uint32_t& smaller_ttl,
+                      uint16_t& rrset_count);
+
+    /// \brief Get RRset Trustworthiness
+    ///        The algorithm refers to RFC2181 section 5.4.1
+    ///        Only the rrset can be updated by the rrsets
+    ///        with higher trust level.
+    ///
+    /// \param message Message that the rrset belongs to
+    /// \param rrset specified rrset which needs to get its
+    ///        trust worthiness
+    /// \param section Section of the rrset
+    /// \return return rrset trust level.
+    RRsetTrustLevel getRRsetTrustLevel(const isc::dns::Message& message,
+        const isc::dns::RRsetPtr& rrset,
+        const isc::dns::Message::Section& section);
+
+    /// \brief Add rrset to one section of message.
+    ///
+    /// \param message The message to add rrsets to.
+    /// \param rrset_entry_vec vector for rrset entries in
+    ///        different sections.
+    /// \param section The section to add to
+    /// \param dnssec_need need dnssec records or not.
+    void addRRset(isc::dns::Message& message,
+                  const std::vector<RRsetEntryPtr>& rrset_entry_vec,
+                  const isc::dns::Message::Section& section,
+                  bool dnssec_need);
+
+    /// \brief Get the all the rrset entries for the message entry.
+    ///
+    /// \param rrset_entry_vec vector to add unexpired rrset entries to
+    /// \param time_now the time of now. Used to compare with rrset
+    ///        entry's expire time.
+    /// \return return false if any rrset entry has expired, true
+    ///         otherwise.
+    bool getRRsetEntries(std::vector<RRsetEntryPtr>& rrset_entry_vec,
+                         const time_t time_now);
+    //@}
+protected:
+    /// \note Make the variable be protected for easy test.
+    time_t expire_time_;  // Expiration time of the message.
+
+private:
+    std::string entry_name_; // The name for this entry(name + type)
+    HashKey* hash_key_ptr_;  // the key for messag entry in hash table.
+
+    std::vector<RRsetRef> rrsets_;
+    boost::shared_ptr<RRsetCache> rrset_cache_;
+
+    std::string query_name_; // query name of the message.
+    uint16_t query_class_; // query class of the message.
+    uint16_t query_type_; // query type of message.
+
+    uint16_t query_count_; // query count in query section.
+    uint16_t answer_count_; // rrset count in answer section.
+    uint16_t authority_count_; // rrset count in authority section.
+    uint16_t additional_count_; // rrset count in addition section.
+
+    //TODO, there should be a better way to cache these header flags
+    bool headerflag_aa_; // Whether AA bit is set.
+    bool headerflag_tc_; // Whether TC bit is set.
+};
+
+typedef boost::shared_ptr<MessageEntry> MessageEntryPtr;
+
+} // namespace cache
+} // namespace isc
+
+#endif // __MESSAGE_ENTRY_H
+
diff --git a/src/lib/cache/resolver_cache.cc b/src/lib/cache/resolver_cache.cc
new file mode 100644
index 0000000..41a8487
--- /dev/null
+++ b/src/lib/cache/resolver_cache.cc
@@ -0,0 +1,247 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include "resolver_cache.h"
+#include "dns/message.h"
+#include "rrset_cache.h"
+#include <string>
+#include <algorithm>
+
+using namespace isc::dns;
+using namespace std;
+
+namespace isc {
+namespace cache {
+
+ResolverClassCache::ResolverClassCache(const RRClass& cache_class) :
+    cache_class_(cache_class)
+{
+    local_zone_data_ = LocalZoneDataPtr(new LocalZoneData(cache_class_.getCode()));
+    rrsets_cache_ = RRsetCachePtr(new RRsetCache(RRSET_CACHE_DEFAULT_SIZE,
+                                                 cache_class_.getCode()));
+    messages_cache_ = MessageCachePtr(new MessageCache(rrsets_cache_,
+                                      MESSAGE_CACHE_DEFAULT_SIZE,
+                                      cache_class_.getCode()));
+}
+
+ResolverClassCache::ResolverClassCache(CacheSizeInfo cache_info) :
+    cache_class_(cache_info.cclass)
+{
+    uint16_t klass = cache_class_.getCode();
+    // TODO We should find one way to load local zone data.
+    local_zone_data_ = LocalZoneDataPtr(new LocalZoneData(klass));
+    rrsets_cache_ = RRsetCachePtr(new
+                        RRsetCache(cache_info.rrset_cache_size, klass));
+    messages_cache_ = MessageCachePtr(new MessageCache(rrsets_cache_,
+                                      cache_info.message_cache_size,
+                                      klass));
+}
+
+const RRClass&
+ResolverClassCache::getClass() const {
+    return cache_class_;
+}
+
+bool
+ResolverClassCache::lookup(const isc::dns::Name& qname,
+                      const isc::dns::RRType& qtype,
+                      isc::dns::Message& response) const
+{
+    // message response should has question section already.
+    if (response.beginQuestion() == response.endQuestion()) {
+        isc_throw(MessageNoQuestionSection, "Message has no question section");
+    }
+
+    // First, query in local zone, if the rrset(qname, qtype, qclass) can be
+    // found in local zone, generated reply message with only the rrset in
+    // answer section.
+    RRsetPtr rrset_ptr = local_zone_data_->lookup(qname, qtype);
+    if (rrset_ptr) {
+        response.addRRset(Message::SECTION_ANSWER, rrset_ptr);
+        return (true);
+    }
+
+    // Search in class-specific message cache.
+    return (messages_cache_->lookup(qname, qtype, response));
+}
+
+isc::dns::RRsetPtr
+ResolverClassCache::lookup(const isc::dns::Name& qname,
+               const isc::dns::RRType& qtype) const
+{
+    // Algorithm:
+    // 1. Search in local zone data first,
+    // 2. Then do search in rrsets_cache_.
+    RRsetPtr rrset_ptr = local_zone_data_->lookup(qname, qtype);
+    if (rrset_ptr) {
+        return (rrset_ptr);
+    } else {
+        RRsetEntryPtr rrset_entry = rrsets_cache_->lookup(qname, qtype);
+        if (rrset_entry) {
+            return (rrset_entry->getRRset());
+        } else {
+            return (RRsetPtr());
+        }
+    }
+}
+
+bool
+ResolverClassCache::update(const isc::dns::Message& msg) {
+    return (messages_cache_->update(msg));
+}
+
+bool
+ResolverClassCache::updateRRsetCache(const isc::dns::ConstRRsetPtr rrset_ptr,
+                                RRsetCachePtr rrset_cache_ptr)
+{
+    RRsetTrustLevel level;
+    if (rrset_ptr->getType() == RRType::A() || 
+        rrset_ptr->getType() == RRType::AAAA()) {
+        level = RRSET_TRUST_PRIM_GLUE;
+    } else {
+        level = RRSET_TRUST_PRIM_ZONE_NONGLUE;
+    }
+
+    rrset_cache_ptr->update((*rrset_ptr.get()), level);
+    return (true);
+}
+
+bool
+ResolverClassCache::update(const isc::dns::ConstRRsetPtr rrset_ptr) {
+    // First update local zone, then update rrset cache.
+    local_zone_data_->update((*rrset_ptr.get()));
+    updateRRsetCache(rrset_ptr, rrsets_cache_);
+    return (true);
+}
+
+
+ResolverCache::ResolverCache()
+{
+    class_caches_.push_back(new ResolverClassCache(RRClass::IN()));
+}
+
+ResolverCache::ResolverCache(std::vector<CacheSizeInfo> caches_info)
+{
+    for (int i = 0; i < caches_info.size(); ++i) {
+        class_caches_.push_back(new ResolverClassCache(caches_info[i]));
+    }
+}
+
+ResolverCache::~ResolverCache()
+{
+    for (int i = 0; i < class_caches_.size(); ++i) {
+        delete class_caches_[i];
+    }
+}
+
+bool
+ResolverCache::lookup(const isc::dns::Name& qname,
+                      const isc::dns::RRType& qtype,
+                      const isc::dns::RRClass& qclass,
+                      isc::dns::Message& response) const
+{
+    ResolverClassCache* cc = getClassCache(qclass);
+    if (cc) {
+        return (cc->lookup(qname, qtype, response));
+    } else {
+        return (false);
+    }
+}
+
+isc::dns::RRsetPtr
+ResolverCache::lookup(const isc::dns::Name& qname,
+               const isc::dns::RRType& qtype,
+               const isc::dns::RRClass& qclass) const
+{
+    ResolverClassCache* cc = getClassCache(qclass);
+    if (cc) {
+        return (cc->lookup(qname, qtype));
+    } else {
+        return (RRsetPtr());
+    }
+}
+
+isc::dns::RRsetPtr
+ResolverCache::lookupClosestRRset(const isc::dns::Name& qname,
+                                  const isc::dns::RRType& qtype,
+                                  const isc::dns::RRClass& qclass) const
+{
+    ResolverClassCache* cc = getClassCache(qclass);
+    if (cc) {
+        unsigned int count = qname.getLabelCount();
+        unsigned int level = 0;
+        while(level < count) {
+            Name close_name = qname.split(level);
+            RRsetPtr rrset_ptr = cc->lookup(close_name, qtype);
+            if (rrset_ptr) {
+                return (rrset_ptr);
+            } else {
+                ++level;
+            }
+        }
+    }
+
+    return (RRsetPtr());
+}
+
+bool
+ResolverCache::update(const isc::dns::Message& msg) {
+    
+    QuestionIterator iter = msg.beginQuestion();
+    ResolverClassCache* cc = getClassCache((*iter)->getClass());
+    if (cc) {
+        return (cc->update(msg));
+    } else {
+        return (false);
+    }
+}
+
+bool
+ResolverCache::update(const isc::dns::ConstRRsetPtr rrset_ptr) {
+    ResolverClassCache* cc = getClassCache(rrset_ptr->getClass());
+    if (cc) {
+        return (cc->update(rrset_ptr));
+    } else {
+        return (false);
+    }
+}
+
+void
+ResolverCache::dump(const std::string&) {
+    //TODO
+}
+
+void
+ResolverCache::load(const std::string&) {
+    //TODO
+}
+
+ResolverClassCache*
+ResolverCache::getClassCache(const isc::dns::RRClass& cache_class) const {
+    for (int i = 0; i < class_caches_.size(); ++i) {
+        if (class_caches_[i]->getClass() == cache_class) {
+            return class_caches_[i];
+        }
+    }
+    return NULL;
+}
+
+
+
+
+} // namespace cache
+} // namespace isc
+
diff --git a/src/lib/cache/resolver_cache.h b/src/lib/cache/resolver_cache.h
new file mode 100644
index 0000000..7a0fdab
--- /dev/null
+++ b/src/lib/cache/resolver_cache.h
@@ -0,0 +1,331 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __RESOLVER_CACHE_H
+#define __RESOLVER_CACHE_H
+
+#include <map>
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include <dns/rrclass.h>
+#include <dns/message.h>
+#include <exceptions/exceptions.h>
+#include "message_cache.h"
+#include "rrset_cache.h"
+#include "local_zone_data.h"
+
+namespace isc {
+namespace cache {
+class RRsetCache;
+
+//TODO a better proper default cache size
+#define MESSAGE_CACHE_DEFAULT_SIZE 10000
+#define RRSET_CACHE_DEFAULT_SIZE   20000
+
+/// \brief Cache Size Information.
+///
+/// Used to initialize the size of class-specific rrset/message cache.
+struct CacheSizeInfo
+{
+public:
+    /// \brief Constructor
+    ///
+    /// \param cls The RRClass code
+    /// \param msg_cache_size The size for the message cache
+    /// \param rst_cache_size The size for the RRset cache
+    CacheSizeInfo(const isc::dns::RRClass& cls, 
+                  uint32_t msg_cache_size,
+                  uint32_t rst_cache_size):
+                    cclass(cls),
+                    message_cache_size(msg_cache_size),
+                    rrset_cache_size(rst_cache_size)
+    {}
+
+    isc::dns::RRClass cclass; // class of the cache.
+    uint32_t message_cache_size; // the size for message cache.
+    uint32_t rrset_cache_size; // The size for rrset cache.
+};
+
+/// \brief  Message has no question section.
+///
+/// Thrown if the given message has no question section when looking up
+/// the message in cache.
+class MessageNoQuestionSection : public isc::Exception {
+public:
+    MessageNoQuestionSection(const char*file, size_t line, const char*what) :
+        isc::Exception(file, line, what)
+    {}
+};
+
+/// \brief Class-specific Resolver Cache.
+///
+/// The object of ResolverCache represents the cache of the resolver. It may hold
+/// a list of message/rrset cache which are in different class.
+///
+/// \note Public interaction with the cache should be through ResolverCache,
+/// not directly with this one. (TODO: make this private/hidden/local to the .cc?)
+class ResolverClassCache {
+public:
+    /// \brief Default Constructor.
+    ///
+    /// Only support for class "IN", and message cache size is
+    /// MESSAGE_CACHE_DEFAULT_SIZE, rrset cache size is
+    /// RRSET_CACHE_DEFAULT_SIZE
+    ResolverClassCache(const isc::dns::RRClass& cache_class);
+
+    /// \brief Construct Function.
+    /// \param caches_size cache size information for each
+    ///        messages/rrsets of different classes.
+    ResolverClassCache(CacheSizeInfo cache_info);
+
+    /// \name Lookup Interfaces
+    //@{
+    /// \brief Look up message in cache.
+    ///
+    /// \param qname The query name to look up
+    /// \param qtype The query type to look up
+    /// \param response the query message (must be in RENDER mode)
+    ///        which has question section already (exception
+    ///        MessageNoQeustionSection will be thrown if it has
+    ///        no question section). If the message can be found
+    ///        in cache, rrsets for the message will be added to
+    ///        different sections(answer, authority, additional).
+    /// \return return true if the message can be found, or else,
+    ///         return false.
+    bool lookup(const isc::dns::Name& qname,
+                const isc::dns::RRType& qtype,
+                isc::dns::Message& response) const;
+
+    /// \brief Look up rrset in cache.
+    ///
+    /// \param qname The query name to look up
+    /// \param qtype The query type to look up
+    ///
+    /// \return return the shared_ptr of rrset if it can be found,
+    ///         or else, return NULL. When looking up, local zone
+    ///         data will be searched first, if not found, then
+    ///         search in rrset cache.
+    ///
+    /// \overload
+    ///
+    isc::dns::RRsetPtr lookup(const isc::dns::Name& qname,
+                              const isc::dns::RRType& qtype) const;
+
+    /// \brief Update the message in the cache with the new one.
+    ///
+    /// \param msg The message to update
+    ///
+    /// \return return true if the message is updated successfully,
+    ///         or else, return false.
+    ///
+    /// \note the function doesn't do any message validation check,
+    ///       the user should make sure the message is valid, and of
+    ///       the right class
+    bool update(const isc::dns::Message& msg);
+
+    /// \brief Update the rrset in the cache with the new one.
+    ///
+    /// local zone data and rrset cache will be updated together.
+    /// If the rrset doesn't exist in both of them, then the rrset
+    /// will be added into both of them.
+    ///
+    /// \param rrset_ptr The RRset to update
+    ///
+    /// \return return false, if the class of the parameter rrset is
+    ///        allowed to be cached.
+    ///
+    /// \overload
+    ///
+    /// \note The class of the RRset must have been checked. It is not
+    /// here.
+    bool update(const isc::dns::ConstRRsetPtr rrset_ptr);
+
+    /// \brief Get the RRClass this cache is for
+    ///
+    /// \return The RRClass of this cache
+    const isc::dns::RRClass& getClass() const;
+    
+private:
+    /// \brief Update rrset cache.
+    ///
+    /// \param rrset_ptr The rrset to update with
+    /// \param rrset_cache_ptr the rrset cache to update
+    ///
+    /// \return return true if the rrset is updated in the rrset cache,
+    ///         or else return false if failed.
+    /// \param rrset_cache_ptr The rrset cache need to be updated.
+    bool updateRRsetCache(const isc::dns::ConstRRsetPtr rrset_ptr,
+                          RRsetCachePtr rrset_cache_ptr);
+
+    /// \brief Class this cache is for.
+    const isc::dns::RRClass cache_class_;
+
+    /// \brief map of message caches for configured classes(each message
+    /// cache is class-specific)
+    MessageCachePtr messages_cache_;
+
+    /// \name rrset caches
+    //@{
+    /// \brief Local Zone data cache
+    /// Cache for rrsets in local zones, rrsets
+    /// in it never expire.
+    LocalZoneDataPtr local_zone_data_;
+
+    /// \brief cache the rrsets parsed from the received message.
+    RRsetCachePtr rrsets_cache_;
+    //@}
+};
+
+class ResolverCache {
+public:
+    /// \brief Default Constructor.
+    ///
+    /// Right now, only support for class "IN", and message cache size is
+    /// MESSAGE_CACHE_DEFAULT_SIZE, rrset cache size is
+    /// RRSET_CACHE_DEFAULT_SIZE
+    ResolverCache();
+
+    /// \brief Construct Function.
+    /// \param caches_size cache size information for each
+    ///        messages/rrsets of different classes.
+    ResolverCache(std::vector<CacheSizeInfo> caches_size);
+
+    /// \brief Destructor
+    ~ResolverCache();
+
+    /// \name Lookup Interfaces
+    //@{
+    /// \brief Look up message in cache.
+    ///
+    /// \param qname The query name to look up
+    /// \param qtype The query type to look up
+    /// \param qclass The query class to look up
+    /// \param response the query message (must be in RENDER mode)
+    ///        which has question section already (exception
+    ///        MessageNoQeustionSection will be thrown if it has
+    ///        no question section). If the message can be found
+    ///        in cache, rrsets for the message will be added to
+    ///        different sections(answer, authority, additional).
+    /// \return return true if the message can be found, or else,
+    ///         return false.
+    bool lookup(const isc::dns::Name& qname,
+                const isc::dns::RRType& qtype,
+                const isc::dns::RRClass& qclass,
+                isc::dns::Message& response) const;
+
+    /// \brief Look up rrset in cache.
+    ///
+    /// \param qname The query name to look up
+    /// \param qtype The query type to look up
+    /// \param qclass The query class to look up
+    ///
+    /// \return return the shared_ptr of rrset if it can be found,
+    ///         or else, return NULL. When looking up, local zone
+    ///         data will be searched first, if not found, then
+    ///         search in rrset cache.
+    ///
+    /// \overload
+    ///
+    isc::dns::RRsetPtr lookup(const isc::dns::Name& qname,
+                              const isc::dns::RRType& qtype,
+                              const isc::dns::RRClass& qclass) const;
+
+    /// \brief Look up closest rrset in cache.
+    ///
+    /// \param qname The query name to look up
+    /// \param qtype The query type to look up
+    /// \param qclass The query class to look up
+    ///
+    /// \return return the shared_ptr of rrset if it can be found in
+    ///         cache, or else return NULL.
+    ///
+    /// Currently the implementation is: search exact rrset
+    /// label by lable, If the rrset can't be found, remove the last
+    /// label, then search again. The efficiency may be very low when
+    /// the name of rrset is very long but it's closest rrset's name
+    /// is very short.
+    /// If a good perfermance is needed when looking up the closest rrset,
+    /// rrset cache structure(HashTable) should be redesigned. By using
+    /// HashTable, it can only garantee the performance for looking
+    /// up exact rrset.
+    /// So here there is another question, which rrset looking up interface
+    /// is used frequently? Exact or closest looking up.
+    isc::dns::RRsetPtr lookupClosestRRset(const isc::dns::Name& qname,
+                              const isc::dns::RRType& qtype,
+                              const isc::dns::RRClass& qclass) const;
+    //@}
+
+    /// \brief Update the message in the cache with the new one.
+    ///
+    /// \param msg The message to update
+    ///
+    /// \return return true if the message is updated successfully,
+    ///         or else, return false.
+    ///
+    /// \note the function doesn't do any message validation check,
+    ///       the user should make sure the message is valid.
+    bool update(const isc::dns::Message& msg);
+
+    /// \brief Update the rrset in the cache with the new one.
+    ///
+    /// local zone data and rrset cache will be updated together.
+    /// If the rrset doesn't exist in both of them, then the rrset
+    /// will be added into both of them.
+    ///
+    /// \param rrset_ptr The RRset to update
+    ///
+    /// \return return false, if the class of the parameter rrset is
+    ///        allowed to be cached.
+    ///
+    /// \overload
+    ///
+    bool update(const isc::dns::ConstRRsetPtr rrset_ptr);
+
+    /// \name Cache Serialization
+    //@{
+    /// \brief Dump the cache content to one file.
+    ///
+    /// \param file_name file to write to
+    ///
+    /// \todo It should can be dumped to one configured database.
+    void dump(const std::string& file_name);
+
+    /// \brief Load the cache from one file.
+    ///
+    /// \param file to load from
+    ///
+    /// \todo It should can be loaded from one configured database.
+    void load(const std::string& file_name);
+    //@}
+
+private:
+    /// \brief Returns the class-specific subcache
+    ///
+    /// \param cache_class the class to get the subcache for
+    /// \return The subcache, or NULL if there is no cache for this class
+    ResolverClassCache* getClassCache(const isc::dns::RRClass& cache_class) const;
+
+    /// The class-specific caches.
+    /// TODO: I think we can optimize for IN, and always have that
+    /// one directly available, use the vector for the rest?
+    std::vector<ResolverClassCache*> class_caches_;
+};
+
+} // namespace cache
+} // namespace isc
+
+#endif // __RESOLVER_CACHE_H
+
diff --git a/src/lib/cache/rrset_cache.cc b/src/lib/cache/rrset_cache.cc
new file mode 100644
index 0000000..d374164
--- /dev/null
+++ b/src/lib/cache/rrset_cache.cc
@@ -0,0 +1,105 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <string>
+#include "rrset_cache.h"
+#include <nsas/nsas_entry_compare.h>
+#include <nsas/hash_table.h>
+#include <nsas/hash_deleter.h>
+
+using namespace isc::nsas;
+using namespace isc::dns;
+using namespace std;
+
+namespace isc {
+namespace cache {
+
+RRsetCache::RRsetCache(uint32_t cache_size,
+                       uint16_t rrset_class):
+    class_(rrset_class),
+    rrset_table_(new NsasEntryCompare<RRsetEntry>, cache_size),
+    rrset_lru_((3 * cache_size),
+                  new HashDeleter<RRsetEntry>(rrset_table_))
+{
+}
+
+RRsetEntryPtr
+RRsetCache::lookup(const isc::dns::Name& qname,
+                   const isc::dns::RRType& qtype)
+{
+    const string entry_name = genCacheEntryName(qname, qtype);
+    RRsetEntryPtr entry_ptr = rrset_table_.get(HashKey(entry_name, RRClass(class_)));
+
+    //If the rrset entry has expired, return NULL.
+    if(entry_ptr && (time(NULL) > entry_ptr->getExpireTime())) {
+        return (RRsetEntryPtr());
+    }
+    return (entry_ptr);
+}
+
+RRsetEntryPtr
+RRsetCache::update(const isc::dns::RRset& rrset, const RRsetTrustLevel& level) {
+    // TODO: If the RRset is an NS, we should update the NSAS as well
+    
+    // lookup first
+    RRsetEntryPtr entry_ptr = lookup(rrset.getName(), rrset.getType());
+    if(!entry_ptr) {
+        // rrset entry doesn't exist, create one rrset entry for the rrset
+        // and add it directly.
+        entry_ptr.reset(new RRsetEntry(rrset, level));
+        // Replace the expired rrset entry if it exists.
+        rrset_table_.add(entry_ptr, entry_ptr->hashKey(), true);
+        //TODO , lru list touch.
+        return (entry_ptr);
+    } else {
+        // there is one rrset entry in the cache, need to check whether
+        // the new rrset is more authoritative.
+        if (entry_ptr->getTrustLevel() > level) {
+            // existed rrset entry is more authoritative, do nothing,
+            // just return it.
+            //TODO, lru list touch
+            return (entry_ptr);
+        } else {
+            HashKey key = entry_ptr->hashKey();
+            rrset_table_.remove(key);
+            entry_ptr.reset(new RRsetEntry(rrset, level));
+            //TODO, lru list touch.
+            // Replace the expired rrset entry if it exists.
+            rrset_table_.add(entry_ptr, key, true);
+            return (entry_ptr);
+        }
+    }
+}
+
+void
+RRsetCache::dump(const std::string&) {
+    //TODO
+}
+
+void
+RRsetCache::load(const std::string&) {
+    //TODO
+}
+
+bool
+RRsetCache::resize(uint32_t) {
+    //TODO
+    return (true);
+}
+
+} // namespace cache
+} // namespace isc
+
diff --git a/src/lib/cache/rrset_cache.h b/src/lib/cache/rrset_cache.h
new file mode 100644
index 0000000..d082b3c
--- /dev/null
+++ b/src/lib/cache/rrset_cache.h
@@ -0,0 +1,108 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __RRSET_CACHE_H
+#define __RRSET_CACHE_H
+
+#include <rrset_entry.h>
+#include <nsas/hash_table.h>
+#include <nsas/lru_list.h>
+
+using namespace isc::nsas;
+
+namespace isc {
+namespace cache {
+
+class RRsetEntry;
+
+/// \brief RRset Cache
+/// The object of RRsetCache represented the cache for class-specific
+/// RRsets.
+class RRsetCache{
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are intentionally
+    /// defined as private to make it uncopyable
+    //@{
+private:
+    RRsetCache(const RRsetCache&);
+    RRsetCache& operator=(const RRsetCache&);
+public:
+    /// \brief Constructor
+    ///
+    /// \param cache_size the size of rrset cache.
+    /// \param rrset_class the class of rrset cache.
+    RRsetCache(uint32_t cache_size, uint16_t rrset_class);
+    ~RRsetCache() {}
+    //@}
+
+    /// \brief Look up rrset in cache.
+    ///
+    /// \param qname The query name to look up
+    /// \param qtype The query type 
+    /// \return return the shared_ptr of rrset entry if it can be
+    /// found in the cache, or else, return NULL.
+    RRsetEntryPtr lookup(const isc::dns::Name& qname,
+                         const isc::dns::RRType& qtype);
+
+    /// \brief Update RRset Cache
+    /// Update the rrset entry in the cache with the new one.
+    /// If the rrset has expired or doesn't exist in the cache,
+    /// it will be added directly. It may be ingored if the new
+    /// rrset is not more authoritative than the old rrset in cache.
+    ///
+    /// \param rrset The new rrset used to update cache.
+    /// \param level trustworthiness of the rrset.
+    /// \return return the rrset entry in the cache, it may be the
+    /// new added rrset entry or existed one if it is not replaced.
+    RRsetEntryPtr update(const isc::dns::RRset& rrset,
+                         const RRsetTrustLevel& level);
+
+    /// \brief Dump the rrset cache to specified file.
+    ///
+    /// \param file_name The file to write to
+    ///
+    /// \todo It should can be dumped to one configured database.
+    void dump(const std::string& file_name);
+
+    /// \brief Load the cache from one file.
+    ///
+    /// \param file_name The file to read from
+    ///
+    /// \todo It should can be loaded from one configured database.
+    void load(const std::string& file_name);
+
+    /// \brief Resize the size of rrset cache in runtime.
+    ///
+    /// \param The size to resize to
+    /// \return true
+    bool resize(uint32_t size);
+
+private:
+    uint16_t class_; // The class of the rrset cache.
+    isc::nsas::HashTable<RRsetEntry> rrset_table_;
+    isc::nsas::LruList<RRsetEntry> rrset_lru_;
+};
+
+typedef boost::shared_ptr<RRsetCache> RRsetCachePtr;
+typedef boost::shared_ptr<const RRsetCache> ConstRRsetCachePtr;
+
+} // namespace cache
+} // namespace isc
+
+#endif // __RRSET_CACHE_H
+
diff --git a/src/lib/cache/rrset_copy.cc b/src/lib/cache/rrset_copy.cc
new file mode 100644
index 0000000..85ba153
--- /dev/null
+++ b/src/lib/cache/rrset_copy.cc
@@ -0,0 +1,40 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include "rrset_copy.h"
+
+using namespace isc::dns;
+
+namespace isc {
+namespace cache {
+
+void
+rrsetCopy(const isc::dns::RRset& src, isc::dns::RRset& dst) {
+    RdataIteratorPtr rdata_itor = src.getRdataIterator();
+    rdata_itor->first();
+    while(!rdata_itor->isLast()){
+        dst.addRdata(rdata_itor->getCurrent());
+        rdata_itor->next();
+    }
+
+    RRsetPtr rrsig = src.getRRsig();
+    if (rrsig != NULL){
+        dst.addRRsig(rrsig);
+    }
+}
+
+} // namespace cache
+} // namespace isc
diff --git a/src/lib/cache/rrset_copy.h b/src/lib/cache/rrset_copy.h
new file mode 100644
index 0000000..f6bee55
--- /dev/null
+++ b/src/lib/cache/rrset_copy.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __RRSET_COPY_
+#define __RRSET_COPY_
+
+#include <dns/rrset.h>
+
+namespace isc {
+namespace cache {
+
+/// \brief RRset Copy Function
+///
+/// Adds all Rdatas and the RRsig in the source RRset to the target
+/// RRset
+///
+/// \param src RRset to copy from
+/// \param dst RRset to copy to
+///
+/// \note RRset class doesn't provide the interface for
+///       doing RRset copy. But in cache's code, sometime
+///       we have to do the copy.
+
+void
+rrsetCopy(const isc::dns::RRset& src, isc::dns::RRset& dst);
+
+} // namespace cache
+} // namespace isc
+
+#endif // __RRSET_COPY_
+
diff --git a/src/lib/cache/rrset_entry.cc b/src/lib/cache/rrset_entry.cc
new file mode 100644
index 0000000..7c8b2bf
--- /dev/null
+++ b/src/lib/cache/rrset_entry.cc
@@ -0,0 +1,66 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <dns/message.h>
+#include <nsas/nsas_entry.h>
+#include <nsas/fetchable.h>
+#include "rrset_entry.h"
+#include "rrset_copy.h"
+
+using namespace isc::dns;
+
+namespace isc {
+namespace cache {
+
+RRsetEntry::RRsetEntry(const isc::dns::RRset& rrset, const RRsetTrustLevel& level):
+    entry_name_(genCacheEntryName(rrset.getName(), rrset.getType())),
+    expire_time_(time(NULL) + rrset.getTTL().getValue()),
+    trust_level_(level),
+    rrset_(new RRset(rrset.getName(), rrset.getClass(), rrset.getType(), rrset.getTTL())),
+    hash_key_(HashKey(entry_name_, rrset_->getClass()))
+{
+    rrsetCopy(rrset, *(rrset_.get()));
+}
+
+isc::dns::RRsetPtr
+RRsetEntry::getRRset() {
+    updateTTL();
+    return (rrset_);
+}
+
+time_t
+RRsetEntry::getExpireTime() const {
+    return (expire_time_);
+}
+
+void
+RRsetEntry::updateTTL(){
+    uint32_t oldTTL = rrset_->getTTL().getValue();
+    if(oldTTL == 0) {
+        return;
+    }
+
+    uint32_t now = time(NULL);
+    uint32_t newTTL = now < expire_time_ ? (expire_time_ - now) : 0;
+
+    RRTTL ttl(newTTL);
+    rrset_->setTTL(ttl);
+}
+
+} // namespace cache
+} // namespace isc
+
+
diff --git a/src/lib/cache/rrset_entry.h b/src/lib/cache/rrset_entry.h
new file mode 100644
index 0000000..f0149a4
--- /dev/null
+++ b/src/lib/cache/rrset_entry.h
@@ -0,0 +1,137 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __RRSET_ENTRY_H
+#define __RRSET_ENTRY_H
+
+#include <dns/rrset.h>
+#include <dns/message.h>
+#include <dns/rrttl.h>
+#include <nsas/nsas_entry.h>
+#include <nsas/fetchable.h>
+#include "cache_entry_key.h"
+
+using namespace isc::nsas;
+
+namespace isc {
+namespace cache {
+
+/// \enum RRset Trustworthiness
+/// For detail of RRset trustworthiness, please refer to
+/// RFC2181 section5.4.1.
+/// Bigger value is more trustworthy.
+enum RRsetTrustLevel {
+    /// Default trust for RRset.
+    RRSET_TRUST_DEFAULT = 0,
+    /// Additional information from non-authoritative answer.
+    RRSET_TRUST_ADDITIONAL_NONAA,
+    /// Data from the authority section of a non-authoritative answer
+    RRSET_TRUST_AUTHORITY_NONAA,
+    /// Additional information from an authoritative answer.
+    RRSET_TRUST_ADDITIONAL_AA,
+    /// Non-authoritative data from the answer section of authoritative
+    /// answers
+    RRSET_TRUST_NONAUTH_ANSWER_AA,
+    /// Data from the answer section of a non-authoritative answer.
+    RRSET_TRUST_ANSWER_NONAA,
+    /// Glue from a primary zone, or glue from a zone transfer.
+    RRSET_TRUST_PRIM_GLUE,
+    /// Data from the authority section of an authoritative answer.
+    RRSET_TRUST_AUTHORITY_AA,
+    /// Authoritative data included in the answer section of
+    /// an authoritative reply.
+    RRSET_TRUST_ANSWER_AA,
+    /// Data from a primary zone file, other than glue data.
+    RRSET_TRUST_PRIM_ZONE_NONGLUE
+};
+
+/// \brief RRset Entry
+/// The object of RRsetEntry represents one cached RRset.
+/// Each RRset entry may be refered using shared_ptr by several message
+/// entries.
+class RRsetEntry : public NsasEntry<RRsetEntry>
+{
+    ///
+    /// \name Constructors and Destructor
+    ///
+    /// Note: The copy constructor and the assignment operator are intentionally
+    /// defined as private to make it uncopyable
+    //@{
+private:
+    RRsetEntry(const RRsetEntry&);
+    RRsetEntry& operator=(const RRsetEntry&);
+public:
+    /// \brief Constructor
+    /// \param rrset The RRset used to initialize the RRset entry.
+    /// \param level trustworthiness of the RRset.
+    RRsetEntry(const isc::dns::RRset& rrset, const RRsetTrustLevel& level);
+
+    /// The destructor.
+    ~RRsetEntry() {}
+    //@}
+
+    /// \brief Return a pointer to a generated RRset
+    ///
+    /// \return Pointer to the generated RRset
+    isc::dns::RRsetPtr getRRset();
+
+    /// \brief Get the expiration time of the RRset.
+    ///
+    /// \return The expiration time of the RRset
+    ///
+    /// \todo RRsig expiration processing
+    time_t getExpireTime() const;
+
+    /// \brief Get the ttl of the RRset.
+    ///
+    /// \return The TTL of the RRset
+    uint32_t getTTL() {
+        updateTTL();
+        return (rrset_->getTTL().getValue());
+    }
+
+    /// \brief Get the hash key
+    ///
+    /// \return return hash key
+    HashKey hashKey() const {
+        return (hash_key_);
+    }
+
+    /// \brief get RRset trustworthiness
+    ///
+    /// \return return the trust level
+    RRsetTrustLevel getTrustLevel() const {
+        return (trust_level_);
+    }
+private:
+    /// \brief Update TTL according to expiration time
+    void updateTTL();
+
+private:
+    std::string entry_name_; // The entry name for this rrset entry.
+    time_t expire_time_;     // Expiration time of rrset.
+    RRsetTrustLevel trust_level_; // RRset trustworthiness.
+    boost::shared_ptr<isc::dns::RRset> rrset_;
+    HashKey hash_key_;       // RRsetEntry hash key
+};
+
+typedef boost::shared_ptr<RRsetEntry> RRsetEntryPtr;
+
+} // namespace cache
+} // namespace isc
+
+#endif // __RRSET_ENTRY_H
+
diff --git a/src/lib/cache/tests/Makefile.am b/src/lib/cache/tests/Makefile.am
new file mode 100644
index 0000000..9bc3e3a
--- /dev/null
+++ b/src/lib/cache/tests/Makefile.am
@@ -0,0 +1,57 @@
+SUBDIRS = .
+
+AM_CPPFLAGS  = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES) $(MULTITHREADING_FLAG)
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/dns -I$(top_builddir)/src/lib/dns
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/cache -I$(top_builddir)/src/lib/cache
+AM_CPPFLAGS += -DTEST_DATA_SRCDIR=\"$(srcdir)/testdata\"
+AM_CPPFLAGS += -DTEST_DATA_BUILDDIR=\"$(abs_top_builddir)/src/lib/cache/tests/testdata\"
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+
+AM_LDFLAGS = $(PTHREAD_LDFLAGS)
+if USE_STATIC_LINK
+AM_LDFLAGS += -static
+endif
+
+# Some versions of GCC warn about some versions of Boost regarding
+# missing initializer for members in its posix_time.
+# https://svn.boost.org/trac/boost/ticket/3477
+# But older GCC compilers don't have the flag.
+AM_CXXFLAGS += $(WARNING_NO_MISSING_FIELD_INITIALIZERS_CFLAG)
+
+if USE_CLANGPP
+# see ../Makefile.am
+AM_CXXFLAGS += -Wno-unused-parameter
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES  = run_unittests.cc
+run_unittests_SOURCES  += $(top_srcdir)/src/lib/dns/tests/unittest_util.cc
+run_unittests_SOURCES  += rrset_entry_unittest.cc
+run_unittests_SOURCES  += rrset_cache_unittest.cc
+run_unittests_SOURCES  += message_cache_unittest.cc
+run_unittests_SOURCES  += message_entry_unittest.cc
+run_unittests_SOURCES  += local_zone_data_unittest.cc
+run_unittests_SOURCES  += resolver_cache_unittest.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDADD = $(GTEST_LDADD)
+
+# NOTE: we may have to clean up this hack later (see the note in configure.ac)
+if NEED_LIBBOOST_THREAD
+run_unittests_LDADD += -lboost_thread
+endif
+
+run_unittests_LDADD += $(top_builddir)/src/lib/cache/libcache.la
+run_unittests_LDADD += $(top_builddir)/src/lib/nsas/libnsas.la
+run_unittests_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+run_unittests_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/src/lib/cache/tests/cache_test_util.h b/src/lib/cache/tests/cache_test_util.h
new file mode 100644
index 0000000..ed9988b
--- /dev/null
+++ b/src/lib/cache/tests/cache_test_util.h
@@ -0,0 +1,58 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+#include <vector>
+#include <dns/tests/unittest_util.h>
+#include <dns/buffer.h>
+#include <dns/message.h>
+
+using namespace isc;
+using namespace isc::dns;
+
+namespace {
+
+/// \brief Reads a Message from a data file
+///
+/// \param message Message to put the read data in
+/// \param datafile The file to read from
+void
+messageFromFile(Message& message, const char* datafile) {
+    std::vector<unsigned char> data;
+    UnitTestUtil::readWireData(datafile, data);
+
+    InputBuffer buffer(&data[0], data.size());
+    message.fromWire(buffer);
+}
+
+/// \brief Counts the number of rrsets in the given section
+///
+/// \param msg The message to count in
+/// \param section The section to count
+///
+/// \return The number of RRsets in the given section
+int
+sectionRRsetCount(Message& msg, Message::Section section) {
+    int count = 0;
+    for (RRsetIterator rrset_iter = msg.beginSection(section);
+         rrset_iter != msg.endSection(section); 
+         ++rrset_iter) {
+        ++count;
+    }
+
+    return count;
+}
+
+}   // namespace
+
diff --git a/src/lib/cache/tests/local_zone_data_unittest.cc b/src/lib/cache/tests/local_zone_data_unittest.cc
new file mode 100644
index 0000000..01e035b
--- /dev/null
+++ b/src/lib/cache/tests/local_zone_data_unittest.cc
@@ -0,0 +1,65 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+#include <config.h>
+#include <string>
+#include <gtest/gtest.h>
+#include <cache/local_zone_data.h>
+#include <dns/rrset.h>
+#include <dns/rrttl.h>
+#include "cache_test_util.h"
+
+using namespace isc::cache;
+using namespace isc::dns;
+using namespace std;
+
+namespace {
+
+class LocalZoneDataTest: public testing::Test {
+protected:
+    LocalZoneDataTest(): local_zone_data(1) 
+    {
+    }
+
+    LocalZoneData local_zone_data;
+};
+
+TEST_F(LocalZoneDataTest, updateAndLookup) {
+    Message msg(Message::PARSE);
+    messageFromFile(msg, "message_fromWire3");
+    RRsetIterator rrset_iter = msg.beginSection(Message::SECTION_AUTHORITY);
+    Name name = (*rrset_iter)->getName();
+    RRType type = (*rrset_iter)->getType();
+
+    EXPECT_FALSE(local_zone_data.lookup(name, type));
+    local_zone_data.update((*(*rrset_iter).get()));
+    EXPECT_TRUE(local_zone_data.lookup(name, type));
+
+    // Test whether the old one is replaced
+    uint32_t ttl = (*rrset_iter)->getTTL().getValue();
+    // Make sure it is not zero
+    ASSERT_NE(ttl / 2, ttl);
+    
+    RRsetPtr rrset_ptr = local_zone_data.lookup(name, type);
+    EXPECT_EQ(ttl, rrset_ptr->getTTL().getValue());
+
+    (*rrset_iter)->setTTL(RRTTL(ttl/2));
+
+    local_zone_data.update((*(*rrset_iter).get()));
+    rrset_ptr = local_zone_data.lookup(name, type);
+    EXPECT_EQ(ttl/2, rrset_ptr->getTTL().getValue());
+}
+
+}
diff --git a/src/lib/cache/tests/message_cache_unittest.cc b/src/lib/cache/tests/message_cache_unittest.cc
new file mode 100644
index 0000000..ed6ebc4
--- /dev/null
+++ b/src/lib/cache/tests/message_cache_unittest.cc
@@ -0,0 +1,98 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+#include <config.h>
+#include <string>
+#include <gtest/gtest.h>
+#include <dns/tests/unittest_util.h>
+#include <dns/buffer.h>
+#include "../message_cache.h"
+#include "../rrset_cache.h"
+#include "../resolver_cache.h"
+#include "cache_test_util.h"
+
+using namespace isc::cache;
+using namespace isc;
+using namespace isc::dns;
+using namespace std;
+
+namespace {
+
+/// \brief Derived from base class to make it easy to test
+/// its internals.
+class DerivedMessageCache: public MessageCache {
+public:
+    DerivedMessageCache(boost::shared_ptr<RRsetCache> rrset_cache_,
+                        uint32_t cache_size, uint16_t message_class):
+        MessageCache(rrset_cache_, cache_size, message_class)
+    {}
+
+    uint16_t messages_count() {
+        return message_lru_.size();
+    }
+};
+
+class MessageCacheTest: public testing::Test {
+public:
+    MessageCacheTest(): message_parse(Message::PARSE),
+                        message_render(Message::RENDER)
+    {
+        uint16_t class_ = RRClass::IN().getCode();
+        rrset_cache_.reset(new RRsetCache(RRSET_CACHE_DEFAULT_SIZE, class_));
+        message_cache_.reset(new DerivedMessageCache(rrset_cache_, 
+                                          MESSAGE_CACHE_DEFAULT_SIZE, class_ ));
+    }
+
+protected:
+    boost::shared_ptr<DerivedMessageCache> message_cache_;
+    RRsetCachePtr rrset_cache_;
+    Message message_parse;
+    Message message_render;
+};
+
+TEST_F(MessageCacheTest, testLookup) {
+    messageFromFile(message_parse, "message_fromWire1");
+    EXPECT_TRUE(message_cache_->update(message_parse));
+    Name qname("test.example.com.");
+    EXPECT_TRUE(message_cache_->lookup(qname, RRType::A(), message_render));
+    EXPECT_EQ(message_cache_->messages_count(), 1);
+
+    Message message_net(Message::PARSE);
+    messageFromFile(message_net, "message_fromWire2");
+    EXPECT_TRUE(message_cache_->update(message_net));
+    EXPECT_EQ(message_cache_->messages_count(), 2);
+
+    Name qname1("test.example.net.");
+    EXPECT_TRUE(message_cache_->lookup(qname1, RRType::A(), message_render));
+}
+
+TEST_F(MessageCacheTest, testUpdate) {
+    messageFromFile(message_parse, "message_fromWire4");
+    EXPECT_TRUE(message_cache_->update(message_parse));
+
+    Name qname("example.com.");
+    EXPECT_TRUE(message_cache_->lookup(qname, RRType::SOA(), message_render));
+    EXPECT_FALSE(message_render.getHeaderFlag(Message::HEADERFLAG_AA));
+
+    Message new_msg(Message::PARSE);
+    messageFromFile(new_msg, "message_fromWire3");
+    EXPECT_TRUE(message_cache_->update(new_msg));
+    Message new_msg_render(Message::RENDER);
+    EXPECT_TRUE(message_cache_->lookup(qname, RRType::SOA(), new_msg_render));
+    EXPECT_TRUE(new_msg_render.getHeaderFlag(Message::HEADERFLAG_AA));
+}
+
+}   // namespace
+
diff --git a/src/lib/cache/tests/message_entry_unittest.cc b/src/lib/cache/tests/message_entry_unittest.cc
new file mode 100644
index 0000000..48a02b9
--- /dev/null
+++ b/src/lib/cache/tests/message_entry_unittest.cc
@@ -0,0 +1,236 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+#include <config.h>
+#include <string>
+#include <gtest/gtest.h>
+#include <dns/tests/unittest_util.h>
+#include <dns/message.h>
+#include <dns/buffer.h>
+#include "../message_entry.h"
+#include "../rrset_cache.h"
+#include "../resolver_cache.h"
+#include "cache_test_util.h"
+
+using namespace isc::cache;
+using namespace isc;
+using namespace isc::dns;
+using namespace std;
+
+static uint32_t MAX_UINT32 = numeric_limits<uint32_t>::max();    
+
+namespace {
+
+/// \brief Derived from base class to make it easy to test
+/// its internals.
+class DerivedMessageEntry: public MessageEntry {
+public:
+    DerivedMessageEntry(const isc::dns::Message& message,
+                        boost::shared_ptr<RRsetCache> rrset_cache_):
+             MessageEntry(message, rrset_cache_)
+    {}
+
+    /// \brief Wrap the protected function so that it can be tested.   
+    void parseSectionForTest(const Message& msg,
+                           const Message::Section& section,
+                           uint32_t& smaller_ttl, 
+                           uint16_t& rrset_count)
+    {
+        parseSection(msg, section, smaller_ttl, rrset_count);
+    }
+
+    RRsetTrustLevel getRRsetTrustLevelForTest(const Message& message,
+                                              const RRsetPtr rrset,
+                                              const Message::Section& section) 
+    {
+        return getRRsetTrustLevel(message, rrset, section);
+    }
+
+    bool getRRsetEntriesForTest(vector<RRsetEntryPtr> vec, time_t now) {
+        return getRRsetEntries(vec, now);
+    }
+
+    time_t getExpireTime() {
+        return expire_time_;
+    }
+
+};
+
+class MessageEntryTest: public testing::Test {
+public:
+    MessageEntryTest(): class_(1),
+                        message_parse(Message::PARSE),
+                        message_render(Message::RENDER)
+    {
+        
+        rrset_cache_.reset(new RRsetCache(RRSET_CACHE_DEFAULT_SIZE, class_));
+    }
+
+protected:
+    uint16_t class_;
+    RRsetCachePtr rrset_cache_;
+    Message message_parse;
+    Message message_render;
+};
+
+TEST_F(MessageEntryTest, testParseRRset) {
+    messageFromFile(message_parse, "message_fromWire3");
+    DerivedMessageEntry message_entry(message_parse, rrset_cache_);
+    uint32_t ttl = MAX_UINT32;
+    uint16_t rrset_count = 0;
+    message_entry.parseSectionForTest(message_parse, Message::SECTION_ANSWER, ttl, rrset_count);
+    EXPECT_EQ(ttl, 21600);
+    EXPECT_EQ(rrset_count, 1);
+
+    ttl = MAX_UINT32;
+    message_entry.parseSectionForTest(message_parse, Message::SECTION_AUTHORITY, ttl, rrset_count);
+    EXPECT_EQ(ttl, 21600);
+    EXPECT_EQ(rrset_count, 1);
+
+    ttl = MAX_UINT32;
+    message_entry.parseSectionForTest(message_parse, Message::SECTION_ADDITIONAL, ttl, rrset_count);
+    EXPECT_EQ(ttl, 10800);
+    EXPECT_EQ(rrset_count, 5);
+}
+
+TEST_F(MessageEntryTest, testGetRRsetTrustLevel_AA) {
+    messageFromFile(message_parse, "message_fromWire3");
+    DerivedMessageEntry message_entry(message_parse, rrset_cache_);
+    
+
+    RRsetIterator rrset_iter = message_parse.beginSection(Message::SECTION_ANSWER);
+    RRsetTrustLevel level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                                    *rrset_iter,
+                                                                    Message::SECTION_ANSWER);
+    EXPECT_EQ(level, RRSET_TRUST_ANSWER_AA);
+
+    rrset_iter = message_parse.beginSection(Message::SECTION_AUTHORITY);
+    level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                    *rrset_iter,
+                                                    Message::SECTION_AUTHORITY);
+    EXPECT_EQ(level, RRSET_TRUST_AUTHORITY_AA);
+
+    rrset_iter = message_parse.beginSection(Message::SECTION_ADDITIONAL);
+    level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                    *rrset_iter,
+                                                    Message::SECTION_ADDITIONAL);
+    EXPECT_EQ(level, RRSET_TRUST_ADDITIONAL_AA);
+}
+
+TEST_F(MessageEntryTest, testGetRRsetTrustLevel_NONAA) {
+    messageFromFile(message_parse, "message_fromWire4");
+    DerivedMessageEntry message_entry(message_parse, rrset_cache_);
+    RRsetIterator rrset_iter = message_parse.beginSection(Message::SECTION_ANSWER);
+    RRsetTrustLevel level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                                    *rrset_iter,
+                                                                    Message::SECTION_ANSWER);
+    EXPECT_EQ(level, RRSET_TRUST_ANSWER_NONAA);
+
+    rrset_iter = message_parse.beginSection(Message::SECTION_AUTHORITY);
+    level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                    *rrset_iter,
+                                                    Message::SECTION_AUTHORITY);
+    EXPECT_EQ(level, RRSET_TRUST_AUTHORITY_NONAA);
+
+    rrset_iter = message_parse.beginSection(Message::SECTION_ADDITIONAL);
+    level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                    *rrset_iter,
+                                                    Message::SECTION_ADDITIONAL);
+    EXPECT_EQ(level, RRSET_TRUST_ADDITIONAL_NONAA);
+}
+
+TEST_F(MessageEntryTest, testGetRRsetTrustLevel_CNAME) {
+    messageFromFile(message_parse, "message_fromWire5");
+    DerivedMessageEntry message_entry(message_parse, rrset_cache_);
+    RRsetIterator rrset_iter = message_parse.beginSection(Message::SECTION_ANSWER);
+    RRsetTrustLevel level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                                    *rrset_iter,
+                                                                    Message::SECTION_ANSWER);
+    EXPECT_EQ(level, RRSET_TRUST_ANSWER_AA);
+
+    ++rrset_iter; // Get the rrset after the first cname rrset.
+    level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                    *rrset_iter,
+                                                    Message::SECTION_ANSWER);
+    EXPECT_EQ(level, RRSET_TRUST_ANSWER_AA);
+}
+
+TEST_F(MessageEntryTest, testGetRRsetTrustLevel_DNAME) {
+    messageFromFile(message_parse, "message_fromWire6");
+    DerivedMessageEntry message_entry(message_parse, rrset_cache_);
+    RRsetIterator rrset_iter = message_parse.beginSection(Message::SECTION_ANSWER);
+    RRsetTrustLevel level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                                    *rrset_iter,
+                                                                    Message::SECTION_ANSWER);
+    EXPECT_EQ(level, RRSET_TRUST_ANSWER_AA);
+
+    ++rrset_iter; // Get the rrset after the first dname rrset.
+    level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                    *rrset_iter,
+                                                    Message::SECTION_ANSWER);
+    EXPECT_EQ(level, RRSET_TRUST_ANSWER_AA);
+
+    ++rrset_iter; // Get the second cname rrset
+    level = message_entry.getRRsetTrustLevelForTest(message_parse,
+                                                    *rrset_iter,
+                                                    Message::SECTION_ANSWER);
+    EXPECT_EQ(level, RRSET_TRUST_ANSWER_AA);
+}
+
+// We only test the expire_time of the message entry.
+// The test for genMessage() will make sure whether InitMessageEntry()
+// is right
+TEST_F(MessageEntryTest, testInitMessageEntry) {
+    messageFromFile(message_parse, "message_fromWire3");
+    DerivedMessageEntry message_entry(message_parse, rrset_cache_);
+    time_t expire_time = message_entry.getExpireTime();
+    // 1 second should be enough to do the compare
+    EXPECT_TRUE((time(NULL) + 10801) > expire_time);
+}
+
+TEST_F(MessageEntryTest, testGetRRsetEntries) {
+    messageFromFile(message_parse, "message_fromWire3");
+    DerivedMessageEntry message_entry(message_parse, rrset_cache_);
+    vector<RRsetEntryPtr> vec;
+    
+    // the time is bigger than the smallest expire time of 
+    // the rrset in message.
+    time_t expire_time = time(NULL) + 10802;
+    EXPECT_FALSE(message_entry.getRRsetEntriesForTest(vec, expire_time));
+}
+
+TEST_F(MessageEntryTest, testGenMessage) {
+    messageFromFile(message_parse, "message_fromWire3");
+    DerivedMessageEntry message_entry(message_parse, rrset_cache_);
+    time_t expire_time = message_entry.getExpireTime();
+    
+    Message msg(Message::RENDER);
+    EXPECT_FALSE(message_entry.genMessage(expire_time + 2, msg));
+    message_entry.genMessage(time(NULL), msg);
+    // Check whether the generated message is same with cached one.
+    
+    EXPECT_TRUE(msg.getHeaderFlag(Message::HEADERFLAG_AA));
+    EXPECT_FALSE(msg.getHeaderFlag(Message::HEADERFLAG_TC));
+    EXPECT_EQ(1, sectionRRsetCount(msg, Message::SECTION_ANSWER)); 
+    EXPECT_EQ(1, sectionRRsetCount(msg, Message::SECTION_AUTHORITY)); 
+    EXPECT_EQ(5, sectionRRsetCount(msg, Message::SECTION_ADDITIONAL)); 
+
+    // Check the rrset in answer section.
+    EXPECT_EQ(1, msg.getRRCount(Message::SECTION_ANSWER));
+    EXPECT_EQ(5, msg.getRRCount(Message::SECTION_AUTHORITY));
+    EXPECT_EQ(7, msg.getRRCount(Message::SECTION_ADDITIONAL));
+}
+
+}   // namespace
diff --git a/src/lib/cache/tests/resolver_cache_unittest.cc b/src/lib/cache/tests/resolver_cache_unittest.cc
new file mode 100644
index 0000000..6621df0
--- /dev/null
+++ b/src/lib/cache/tests/resolver_cache_unittest.cc
@@ -0,0 +1,138 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+#include <config.h>
+#include <string>
+#include <gtest/gtest.h>
+#include <dns/rrset.h>
+#include "resolver_cache.h"
+#include "cache_test_util.h"
+
+using namespace isc::cache;
+using namespace isc::dns;
+using namespace std;
+
+namespace {
+
+class ResolverCacheTest: public testing::Test {
+public:
+    ResolverCacheTest() {
+        vector<CacheSizeInfo> vec;
+        CacheSizeInfo class_in(RRClass::IN(), 100, 200);
+        CacheSizeInfo class_ch(RRClass::CH(), 100, 200);
+        vec.push_back(class_in);
+        vec.push_back(class_ch);
+        cache = new ResolverCache(vec);
+    }
+
+    ~ResolverCacheTest() {
+        delete cache;
+    }
+
+    ResolverCache* cache;
+};
+
+TEST_F(ResolverCacheTest, testUpdateMessage) {
+    Message msg(Message::PARSE);
+    messageFromFile(msg, "message_fromWire3");
+    cache->update(msg);
+
+    Name qname("example.com.");
+
+    msg.makeResponse();
+    EXPECT_TRUE(cache->lookup(qname, RRType::SOA(), RRClass::IN(), msg));
+    EXPECT_TRUE(msg.getHeaderFlag(Message::HEADERFLAG_AA));
+
+    // Test whether the old message can be updated
+    Message new_msg(Message::PARSE);
+    messageFromFile(new_msg, "message_fromWire4");
+    cache->update(new_msg);
+
+    new_msg.makeResponse();
+    EXPECT_TRUE(cache->lookup(qname, RRType::SOA(), RRClass::IN(), new_msg));
+    EXPECT_FALSE(new_msg.getHeaderFlag(Message::HEADERFLAG_AA));
+}
+#if 0
+TEST_F(ResolverCacheTest, testUpdateRRset) {
+    Message msg(Message::PARSE);
+    messageFromFile(msg, "message_fromWire3");
+    cache->update(msg);
+
+    Name qname("example.com.");
+
+    msg.makeResponse();
+    EXPECT_TRUE(cache->lookup(qname, RRType::SOA(), RRClass::IN(), msg));
+
+    Message except_msg(Message::RENDER);
+    EXPECT_THROW(cache->lookup(qname, RRType::SOA(), RRClass::IN(), except_msg), 
+                 MessageNoQuestionSection);
+
+    // Get one rrset in the message, then use it to 
+    // update rrset cache-> Test whether the local zone
+    // data is updated.
+    RRsetIterator iter = msg.beginSection(Message::SECTION_AUTHORITY);
+    RRsetPtr rrset_ptr = *iter;
+    cache->update(rrset_ptr);
+
+    Message new_msg(Message::RENDER);
+    Question question(qname, klass, RRType::NS());
+    new_msg.addQuestion(question);
+    EXPECT_TRUE(cache->lookup(qname, RRType::NS(), RRClass::IN(), new_msg));
+    EXPECT_EQ(0, sectionRRsetCount(new_msg, Message::SECTION_AUTHORITY));
+    EXPECT_EQ(0, sectionRRsetCount(new_msg, Message::SECTION_ADDITIONAL));
+}
+
+TEST_F(ResolverCacheTest, testLookupUnsupportedClass) {
+    Message msg(Message::PARSE);
+    messageFromFile(msg, "message_fromWire3");
+    cache->update(msg);
+
+    Name qname("example.com.");
+
+    msg.makeResponse();
+    EXPECT_FALSE(cache->lookup(qname, RRType::SOA(), RRClass::CH(), msg));
+    EXPECT_FALSE(cache->lookup(qname, RRType::SOA(), RRClass::CH()));
+}
+
+TEST_F(ResolverCacheTest, testLookupClosestRRset) {
+    Message msg(Message::PARSE);
+    messageFromFile(msg, "message_fromWire3");
+    cache->update(msg);
+
+    Name qname("www.test.example.com.");
+
+    RRsetPtr rrset_ptr = cache->lookupClosestRRset(qname, RRType::NS(),
+                                                  RRClass::IN());
+    EXPECT_TRUE(rrset_ptr);
+    EXPECT_EQ(rrset_ptr->getName(), Name("example.com."));
+
+    rrset_ptr = cache->lookupClosestRRset(Name("example.com."),
+                                         RRType::NS(), RRClass::IN());
+    EXPECT_TRUE(rrset_ptr);
+    EXPECT_EQ(rrset_ptr->getName(), Name("example.com."));
+
+    rrset_ptr = cache->lookupClosestRRset(Name("com."),
+                                         RRType::NS(), RRClass::IN());
+    EXPECT_FALSE(rrset_ptr);
+}
+
+TEST_F(ResolverCacheTest, testHasClass) {
+    EXPECT_TRUE(cache->getClassCache(RRClass::IN()));
+    EXPECT_TRUE(cache->getClassCache(RRClass::CH()));
+    EXPECT_FALSE(cache->getClassCache(RRClass::ANY()));
+}
+#endif
+
+}
diff --git a/src/lib/cache/tests/rrset_cache_unittest.cc b/src/lib/cache/tests/rrset_cache_unittest.cc
new file mode 100644
index 0000000..1263406
--- /dev/null
+++ b/src/lib/cache/tests/rrset_cache_unittest.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+#include <config.h>
+#include <string>
+#include <gtest/gtest.h>
+#include <cache/resolver_cache.h>
+#include <cache/cache_entry_key.h>
+#include <cache/rrset_entry.h>
+#include <cache/rrset_cache.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+#include <dns/rrset.h>
+
+using namespace isc::cache;
+using namespace isc::dns;
+using namespace std;
+
+namespace {
+
+class RRsetCacheTest : public testing::Test {
+protected:
+    RRsetCacheTest():
+        cache(RRSET_CACHE_DEFAULT_SIZE, RRClass::IN().getCode()),
+        name("example.com"),
+        rrset1(name, RRClass::IN(), RRType::A(), RRTTL(20)),
+        rrset2(name, RRClass::IN(), RRType::A(), RRTTL(10)),
+        rrset_entry1(rrset1, RRSET_TRUST_ADDITIONAL_AA),
+        rrset_entry2(rrset2, RRSET_TRUST_PRIM_ZONE_NONGLUE)
+    {
+    }
+
+    RRsetCache cache;
+    Name name;
+    RRset rrset1;
+    RRset rrset2;
+    RRsetEntry rrset_entry1;
+    RRsetEntry rrset_entry2;
+};
+
+TEST_F(RRsetCacheTest, lookup) {
+    const RRType& type = RRType::A();
+    EXPECT_TRUE(cache.lookup(name, type) == NULL);
+
+    cache.update(rrset1, rrset_entry1.getTrustLevel());
+    RRsetEntryPtr rrset_entry_ptr = cache.lookup(name, type);
+    EXPECT_EQ(rrset_entry_ptr->getTrustLevel(), rrset_entry1.getTrustLevel());
+    EXPECT_EQ(rrset_entry_ptr->getRRset()->getName(), rrset_entry1.getRRset()->getName());
+    EXPECT_EQ(rrset_entry_ptr->getRRset()->getType(), rrset_entry1.getRRset()->getType());
+    EXPECT_EQ(rrset_entry_ptr->getRRset()->getClass(), rrset_entry1.getRRset()->getClass());
+}
+
+TEST_F(RRsetCacheTest, update) {
+    const RRType& type = RRType::A();
+
+    cache.update(rrset1, rrset_entry1.getTrustLevel());
+    RRsetEntryPtr rrset_entry_ptr = cache.lookup(name, type);
+    EXPECT_EQ(rrset_entry_ptr->getTrustLevel(), rrset_entry1.getTrustLevel());
+
+    cache.update(rrset2, rrset_entry2.getTrustLevel());
+    rrset_entry_ptr = cache.lookup(name, type);
+    // The trust level should be updated
+    EXPECT_EQ(rrset_entry_ptr->getTrustLevel(), rrset_entry2.getTrustLevel());
+
+    cache.update(rrset1, rrset_entry1.getTrustLevel());
+    // The trust level should not be updated
+    EXPECT_EQ(rrset_entry_ptr->getTrustLevel(), rrset_entry2.getTrustLevel());
+}
+
+}
diff --git a/src/lib/cache/tests/rrset_entry_unittest.cc b/src/lib/cache/tests/rrset_entry_unittest.cc
new file mode 100644
index 0000000..ce6238f
--- /dev/null
+++ b/src/lib/cache/tests/rrset_entry_unittest.cc
@@ -0,0 +1,106 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+#include <config.h>
+#include <string>
+#include <gtest/gtest.h>
+#include <cache/cache_entry_key.h>
+#include <cache/rrset_entry.h>
+#include <dns/name.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <dns/rrttl.h>
+#include <dns/rrset.h>
+
+using namespace isc::cache;
+using namespace isc::dns;
+using namespace std;
+
+namespace {
+class GenCacheKeyTest: public testing::Test {
+};
+
+TEST_F(GenCacheKeyTest, genCacheEntryKey1) {
+    string name = "example.com.";
+    uint16_t type = 12;
+    string name_type = "example.com.12";
+
+    EXPECT_EQ(name_type, genCacheEntryName(name, type));
+}
+
+TEST_F(GenCacheKeyTest, genCacheEntryKey2) {
+    Name name("example.com");
+    RRType type(1234);
+    string keystr = "example.com.1234";
+    EXPECT_EQ(keystr, genCacheEntryName(name, type));
+}
+
+class DerivedRRsetEntry: public RRsetEntry {
+public:
+
+    void updateTTLForTest() {
+        
+    }
+};
+
+#define TEST_TTL 100
+class RRsetEntryTest : public ::testing::Test {
+protected:
+    RRsetEntryTest():
+        name("test.example.com"),
+        rrset(name, RRClass::IN(), RRType::A(), RRTTL(TEST_TTL)),
+        trust_level(RRSET_TRUST_ADDITIONAL_AA),
+        rrset_entry(rrset, trust_level)
+    {
+    }
+    Name name;
+    RRset rrset;
+    RRsetTrustLevel trust_level;
+    RRsetEntry rrset_entry;
+};
+
+TEST_F(RRsetEntryTest, constructor) {
+    EXPECT_EQ(trust_level, rrset_entry.getTrustLevel());
+    EXPECT_EQ(rrset.getName(), rrset_entry.getRRset()->getName());
+    EXPECT_EQ(rrset.getClass(), rrset_entry.getRRset()->getClass());
+    EXPECT_EQ(rrset.getType(), rrset_entry.getRRset()->getType());
+    EXPECT_EQ(rrset.getRdataCount(), rrset_entry.getRRset()->getRdataCount());
+}
+
+TEST_F(RRsetEntryTest, updateTTL) {
+    uint32_t ttl = rrset_entry.getTTL();
+    sleep(1);
+    // The TTL should be decreased
+    EXPECT_TRUE(rrset_entry.getTTL() < ttl);
+}
+
+TEST_F(RRsetEntryTest, TTLExpire) {
+    RRset exp_rrset(name, RRClass::IN(), RRType::A(), RRTTL(1));
+    RRsetEntry rrset_entry(exp_rrset, RRSET_TRUST_ANSWER_AA);
+    sleep(1);
+    uint32_t ttl = rrset_entry.getTTL();
+    EXPECT_LT(ttl, 1);
+    sleep(1);
+    ttl = rrset_entry.getTTL();
+    EXPECT_LT(ttl, 1);
+}
+
+TEST_F(RRsetEntryTest, getExpireTime){
+    uint32_t exp_time = time(NULL) + TEST_TTL;
+    EXPECT_EQ(exp_time, rrset_entry.getExpireTime());
+}
+
+}   // namespace
+
diff --git a/src/lib/cache/tests/run_unittests.cc b/src/lib/cache/tests/run_unittests.cc
new file mode 100644
index 0000000..b34b3dd
--- /dev/null
+++ b/src/lib/cache/tests/run_unittests.cc
@@ -0,0 +1,29 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id: run_unittests.cc 3020 2010-09-26 03:47:26Z jinmei $
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+#include <dns/tests/unittest_util.h>
+
+int
+main(int argc, char* argv[]) {
+    ::testing::InitGoogleTest(&argc, argv);
+    isc::UnitTestUtil::addDataPath(TEST_DATA_SRCDIR);
+    isc::UnitTestUtil::addDataPath(TEST_DATA_BUILDDIR);
+
+    return (RUN_ALL_TESTS());
+}
diff --git a/src/lib/cache/tests/testdata/message_fromWire1 b/src/lib/cache/tests/testdata/message_fromWire1
new file mode 100644
index 0000000..5b76e3f
--- /dev/null
+++ b/src/lib/cache/tests/testdata/message_fromWire1
@@ -0,0 +1,22 @@
+#
+# A simple DNS response message
+# ID = 0x1035
+# QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
+# QDCOUNT=1, ANCOUNT=2, other COUNTS=0
+# Question: test.example.com. IN A
+# Answer:
+#  test.example.com. 3600 IN A 192.0.2.1
+#  test.example.com. 7200 IN A 192.0.2.2
+#
+1035 8500
+0001 0002 0000 0000
+#(4) t  e  s  t (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+0001 0001
+# same name, fully compressed
+c0 0c
+# TTL=3600, A, IN, RDLENGTH=4, RDATA
+0001 0001 00000e10 0004 c0 00 02 01
+# mostly same, with the slight difference in RDATA and TTL
+c0 0c
+0001 0001 00001c20 0004 c0 00 02 02
diff --git a/src/lib/cache/tests/testdata/message_fromWire2 b/src/lib/cache/tests/testdata/message_fromWire2
new file mode 100644
index 0000000..c8fddbd
--- /dev/null
+++ b/src/lib/cache/tests/testdata/message_fromWire2
@@ -0,0 +1,22 @@
+#
+# A simple DNS response message
+# ID = 0x1035
+# QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
+# QDCOUNT=1, ANCOUNT=2, other COUNTS=0
+# Question: test.example.net. IN A
+# Answer:
+#  test.example.net. 3600 IN A 192.0.2.1
+#  test.example.net. 7200 IN A 192.0.2.2
+#
+1035 8500
+0001 0002 0000 0000
+#(4) t  e  s  t (7) e  x  a  m  p  l  e (3) n  e  t  .
+ 04 74 65 73 74 07 65 78 61 6d 70 6c 65 03 6e 65 74 00
+0001 0001
+# same name, fully compressed
+c0 0c
+# TTL=3600, A, IN, RDLENGTH=4, RDATA
+0001 0001 00000e10 0004 c0 00 02 01
+# mostly same, with the slight difference in RDATA and TTL
+c0 0c
+0001 0001 00001c20 0004 c0 00 02 02
diff --git a/src/lib/cache/tests/testdata/message_fromWire3 b/src/lib/cache/tests/testdata/message_fromWire3
new file mode 100644
index 0000000..f7b3a4a
--- /dev/null
+++ b/src/lib/cache/tests/testdata/message_fromWire3
@@ -0,0 +1,76 @@
+#
+# A simple DNS response message
+# ID = 0x0513
+# QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
+# QDCOUNT=1, ANCOUNT=1, AUTHORITY COUNT=5, ADDITIONAL COUNT=7
+# Question: example.com. IN SOA
+# ANSWER:
+#   ;; QUESTION SECTION:
+#   ;example.com.                   IN      SOA
+
+#   ;; ANSWER SECTION:
+#   example.com.            21600   IN      SOA     a.dns.example.com. root.example.com. 2009070811 7200 3600 2419200 21600
+
+#   ;; AUTHORITY SECTION:
+#   example.com.            21600   IN      NS      b.dns.example.com.
+#   example.com.            21600   IN      NS      c.dns.example.com.
+#   example.com.            21600   IN      NS      a.dns.example.com.
+#   example.com.            21600   IN      NS      e.dns.example.com.
+#   example.com.            21600   IN      NS      d.dns.example.com.
+
+#    ;; ADDITIONAL SECTION:
+#    a.dns.example.com.      21600   IN      A       1.1.1.1
+#    a.dns.example.com.      21600   IN      A       2.2.2.2
+#    b.dns.example.com.      21600   IN      A       3.3.3.3
+#    c.dns.example.com.      10800   IN      A       4.4.4.4
+#    d.dns.example.com.      43200   IN      A       5.5.5.5
+#    e.dns.example.com.      21600   IN      A       7.7.7.7
+#    e.dns.example.com.      21600   IN      A       6.6.6.6
+
+0513 8500
+0001 0001 0005 0007
+#(7) e x  a  m  p  l  e (3) c  o  m  .
+ 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+0006 0001
+# same name, fully compressed
+c0 0c
+# SOA IN  TTL=6h   RDLENGTH=35 rdata
+0006 0001 00005460 0023 01 61 03 64 6e 73 c0 0c 04 72 6f 6f 74 c0 0c 77 bf fc db 00 00 1c 20 00 00 0e 10 00 24 ea 00 00 00 54 60
+#Authority section begin
+c0 0c
+# NS IN   TTL=6h   RDLENGTH=4  b.dns.example.com.
+0002 0001 00005460 0004 01 62 c0 2b
+# NS IN   TTL=6h  c.dns.example.com.
+c0 0c
+0002 0001 00005460 00 04 01 63 c0 2b
+# NS IN a.dns.example.com.
+c0 0c
+0002 0001 00005460 00 02 c0 29
+# NS IN e.dns.example.com.
+c0 0c
+0002 0001 00005460 0004 01 65 c0 2b
+# NS IN d.dns.example.com.
+c0 0c
+0002 0001 00005460 0004 01 64 c0 2b
+# additional section begin
+# a.dns.example.com. A
+c0 29
+0001 0001 00005460 0004 01 01 01 01
+# a.dns.example.com. A
+c0 29
+0001 0001 00005460 0004 02 02 02 02
+#b.dns.example.com.  A
+c0 58
+0001 0001 00002A30 0004 03 03 03 03
+#c.dns.example.com.  A
+c0 68
+0001 0001 00005460 0004 04 04 04 04
+# d.dns.example.com. A
+c0 96
+0001 0001 0000A8C0 0004 05 05 05 05
+# e.dns.example.com. A
+c0 86
+0001 0001 00005460 0004 07 07 07 07
+# e.dns.example.com. A
+c0 86
+0001 0001 00005460 0004 06 06 06 06
diff --git a/src/lib/cache/tests/testdata/message_fromWire4 b/src/lib/cache/tests/testdata/message_fromWire4
new file mode 100644
index 0000000..251abd5
--- /dev/null
+++ b/src/lib/cache/tests/testdata/message_fromWire4
@@ -0,0 +1,80 @@
+# Note: This message is same with message_fromWire3, except
+#       AA bit is not set. There should be a better way to
+#       avoid the duplicated file by clear the AA bit flags
+#       after reading the message from message_fromWire4.
+# 
+# A simple DNS response message
+# ID = 0x0513
+# QR=1 (response), Opcode=0, RD=1 (other fields are 0)
+# QDCOUNT=1, ANCOUNT=1, AUTHORITY COUNT=5, ADDITIONAL COUNT=7
+# Question: example.com. IN SOA
+# ANSWER:
+#   ;; QUESTION SECTION:
+#   ;example.com.                   IN      SOA
+
+#   ;; ANSWER SECTION:
+#   example.com.            21600   IN      SOA     a.dns.example.com. root.example.com. 2009070811 7200 3600 2419200 21600
+
+#   ;; AUTHORITY SECTION:
+#   example.com.            21600   IN      NS      b.dns.example.com.
+#   example.com.            21600   IN      NS      c.dns.example.com.
+#   example.com.            21600   IN      NS      a.dns.example.com.
+#   example.com.            21600   IN      NS      e.dns.example.com.
+#   example.com.            21600   IN      NS      d.dns.example.com.
+
+#    ;; ADDITIONAL SECTION:
+#    a.dns.example.com.      21600   IN      A       1.1.1.1
+#    a.dns.example.com.      21600   IN      A       2.2.2.2
+#    b.dns.example.com.      21600   IN      A       3.3.3.3
+#    c.dns.example.com.      10800   IN      A       4.4.4.4
+#    d.dns.example.com.      43200   IN      A       5.5.5.5
+#    e.dns.example.com.      21600   IN      A       7.7.7.7
+#    e.dns.example.com.      21600   IN      A       6.6.6.6
+
+0513 8100
+0001 0001 0005 0007
+#(7) e x  a  m  p  l  e (3) c  o  m  .
+ 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+0006 0001
+# same name, fully compressed
+c0 0c
+# SOA IN  TTL=6h   RDLENGTH=35 rdata
+0006 0001 00005460 0023 01 61 03 64 6e 73 c0 0c 04 72 6f 6f 74 c0 0c 77 bf fc db 00 00 1c 20 00 00 0e 10 00 24 ea 00 00 00 54 60
+#Authority section begin
+c0 0c
+# NS IN   TTL=6h   RDLENGTH=4  b.dns.example.com.
+0002 0001 00005460 0004 01 62 c0 2b
+# NS IN   TTL=6h  c.dns.example.com.
+c0 0c
+0002 0001 00005460 00 04 01 63 c0 2b
+# NS IN a.dns.example.com.
+c0 0c
+0002 0001 00005460 00 02 c0 29
+# NS IN e.dns.example.com.
+c0 0c
+0002 0001 00005460 0004 01 65 c0 2b
+# NS IN d.dns.example.com.
+c0 0c
+0002 0001 00005460 0004 01 64 c0 2b
+# additional section begin
+# a.dns.example.com. A
+c0 29
+0001 0001 00005460 0004 01 01 01 01
+# a.dns.example.com. A
+c0 29
+0001 0001 00005460 0004 02 02 02 02
+#b.dns.example.com.  A
+c0 58
+0001 0001 00002A30 0004 03 03 03 03
+#c.dns.example.com.  A
+c0 68
+0001 0001 00005460 0004 04 04 04 04
+# d.dns.example.com. A
+c0 96
+0001 0001 0000A8C0 0004 05 05 05 05
+# e.dns.example.com. A
+c0 86
+0001 0001 00005460 0004 07 07 07 07
+# e.dns.example.com. A
+c0 86
+0001 0001 00005460 0004 06 06 06 06
diff --git a/src/lib/cache/tests/testdata/message_fromWire5 b/src/lib/cache/tests/testdata/message_fromWire5
new file mode 100644
index 0000000..965f250
--- /dev/null
+++ b/src/lib/cache/tests/testdata/message_fromWire5
@@ -0,0 +1,36 @@
+#
+# A simple DNS response message
+# ID = 0x07b2
+# QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
+# QDCOUNT=1, ANCOUNT=2, other COUNTS=0
+# Question: a.example.net. IN A
+# Answer:
+#    ANSWER SECTION:
+#    a.example.com.          21600   IN      CNAME   cname.example.com.
+#    cname.example.com.      21600   IN      A       1.1.1.1
+#
+#    AUTHORITY SECTION:
+#    example.com.            21600   IN      NS      a.dns.example.com.
+#
+#    ADDITIONAL SECTION:
+#    a.dns.example.com.      21600   IN      A       1.1.1.1
+#
+07b2 8500
+0001 0002 0001 0001
+#(1) a (7)  e  x  a  m  p  l  e  (3) c o  m  .
+ 01 61 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+# A  IN
+0001 0001
+#
+c0 0c
+#CNAME IN  TTL     RDATA_LEN
+0005 0001 00005460 0008 05 63 6e 61 6d 65 c0 0e
+#
+c0 2b
+0001 0001 00005460 0004 01 01 01 01
+#
+c0 0e
+0002 0001 00005460 0008 01 61 03 64 6e 73 c0 0e
+#
+c0 4f
+0001 0001 00005460 0004 01 01 01 01
diff --git a/src/lib/cache/tests/testdata/message_fromWire6 b/src/lib/cache/tests/testdata/message_fromWire6
new file mode 100644
index 0000000..23684ba
--- /dev/null
+++ b/src/lib/cache/tests/testdata/message_fromWire6
@@ -0,0 +1,40 @@
+#
+# A simple DNS response message
+# ID = 0x005e
+# QR=1 (response), Opcode=0, AA=1, RD=1 (other fields are 0)
+# QDCOUNT=1, ANCOUNT=2, other COUNTS=0
+# Question: a.d.example.net. IN A
+# Answer:
+#    ;; ANSWER SECTION:
+#    d.example.com.          21600   IN      DNAME   dname.example.com.
+#    a.d.example.com.        21600   IN      CNAME   a.dname.example.com.
+#    a.dname.example.com.    21600   IN      A       1.1.1.1
+#
+#    ;; AUTHORITY SECTION:
+#    example.com.            21600   IN      NS      a.dns.example.com.
+#
+#    ;; ADDITIONAL SECTION:
+#    a.dns.example.com.      21600   IN      A       1.1.1.1
+#
+#
+005e 8500
+0001 0003 0001 0001
+#(1)a (1) b (7) e  x  a  m  p  l  e (3) c  o  m  .
+ 01 61 01 64 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+# A  IN
+0001 0001
+#
+c0 0e
+0027 0001 00005460 0013 05 64 6e 61 6d 65 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00
+# 
+c0 0c
+0005 0001 00005460 0004 01 61 c0 2d
+#
+c0 4c
+0001 0001 00005460 0004 01 01 01 01
+#
+c0 33
+0002 0001 00005460 0008 01 61 03 64 6e 73 c0 33
+#
+c0 6c
+0001 0001 00005460 0004 01 01 01 01
diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h
index 4fc6cdc..acb4224 100644
--- a/src/lib/dns/rrset.h
+++ b/src/lib/dns/rrset.h
@@ -229,8 +229,8 @@ public:
 
     /// \brief Updates the owner name of the \c RRset.
     ///
-    /// \param name A reference to a \c RRTTL class object to be copied as the
-    /// new TTL.
+    /// \param name A reference to a \c Name class object to be copied as the
+    /// new name.
     virtual void setName(const Name& name) = 0;
 
     /// \brief Updates the TTL of the \c RRset.
@@ -588,8 +588,8 @@ public:
     /// internal copy of the \c name involves resource allocation and it
     /// fails.
     ///
-    /// \param name A reference to a \c RRTTL class object to be copied as the
-    /// new TTL.
+    /// \param name A reference to a \c Name class object to be copied as the
+    /// new name.
     virtual void setName(const Name& name);
 
     /// \brief Updates the TTL of the \c RRset.
@@ -720,7 +720,7 @@ public:
     void removeRRsig() { rrsig_ = RRsetPtr(); }
 
     /// \brief Return a pointer to this RRset's RRSIG RRset
-    RRsetPtr getRRsig() { return (rrsig_); }
+    RRsetPtr getRRsig() const { return (rrsig_); }
 private:
     RRsetPtr rrsig_;
 };




More information about the bind10-changes mailing list