Browse Source

[master] Merge branch 'trac449'

Conflicts:
	doc/Doxyfile
	src/lib/Makefile.am
Jelte Jansen 14 years ago
parent
commit
8aa3b2246a
38 changed files with 3130 additions and 7 deletions
  1. 5 0
      ChangeLog
  2. 2 0
      configure.ac
  3. 1 1
      doc/Doxyfile
  4. 1 1
      src/lib/Makefile.am
  5. 33 0
      src/lib/cache/Makefile.am
  6. 12 0
      src/lib/cache/TODO
  7. 44 0
      src/lib/cache/cache_entry_key.cc
  8. 56 0
      src/lib/cache/cache_entry_key.h
  9. 58 0
      src/lib/cache/local_zone_data.cc
  10. 66 0
      src/lib/cache/local_zone_data.h
  11. 95 0
      src/lib/cache/message_cache.cc
  12. 95 0
      src/lib/cache/message_cache.h
  13. 249 0
      src/lib/cache/message_entry.cc
  14. 183 0
      src/lib/cache/message_entry.h
  15. 247 0
      src/lib/cache/resolver_cache.cc
  16. 331 0
      src/lib/cache/resolver_cache.h
  17. 105 0
      src/lib/cache/rrset_cache.cc
  18. 108 0
      src/lib/cache/rrset_cache.h
  19. 40 0
      src/lib/cache/rrset_copy.cc
  20. 44 0
      src/lib/cache/rrset_copy.h
  21. 66 0
      src/lib/cache/rrset_entry.cc
  22. 137 0
      src/lib/cache/rrset_entry.h
  23. 57 0
      src/lib/cache/tests/Makefile.am
  24. 58 0
      src/lib/cache/tests/cache_test_util.h
  25. 65 0
      src/lib/cache/tests/local_zone_data_unittest.cc
  26. 98 0
      src/lib/cache/tests/message_cache_unittest.cc
  27. 236 0
      src/lib/cache/tests/message_entry_unittest.cc
  28. 138 0
      src/lib/cache/tests/resolver_cache_unittest.cc
  29. 84 0
      src/lib/cache/tests/rrset_cache_unittest.cc
  30. 106 0
      src/lib/cache/tests/rrset_entry_unittest.cc
  31. 29 0
      src/lib/cache/tests/run_unittests.cc
  32. 22 0
      src/lib/cache/tests/testdata/message_fromWire1
  33. 22 0
      src/lib/cache/tests/testdata/message_fromWire2
  34. 76 0
      src/lib/cache/tests/testdata/message_fromWire3
  35. 80 0
      src/lib/cache/tests/testdata/message_fromWire4
  36. 36 0
      src/lib/cache/tests/testdata/message_fromWire5
  37. 40 0
      src/lib/cache/tests/testdata/message_fromWire6
  38. 5 5
      src/lib/dns/rrset.h

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+  167.  [func]      zhang likun, jelte
+	Added a basic implementation for a resolver cache (though not
+	used yet).
+	(Trac #449, git 756e56a8c683906b1b50bba5675c996fb1295820)
+
   166.  [func]      jelte
 	The resolver now sends back a SERVFAIL when there is a client
 	timeout (timeout_client config setting), but it will not stop

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

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

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

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

+ 12 - 0
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.
+

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 44 - 0
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_
+

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

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

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

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

+ 65 - 0
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());
+}
+
+}

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

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

+ 138 - 0
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
+
+}

+ 84 - 0
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());
+}
+
+}

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

+ 29 - 0
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());
+}

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

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

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

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

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

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

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