Browse Source

Commit the latest change

zhanglikun 14 years ago
parent
commit
e7c61f1bb5

+ 3 - 3
src/lib/cache/cache_entry_key.cc

@@ -23,7 +23,7 @@ namespace isc {
 namespace cache {
 const std::string
 genCacheEntryName(const isc::dns::Name& name,
-                 const isc::dns::RRType& type) 
+                 const isc::dns::RRType& type)
 {
     std::string keystr = name.toText();
     ostringstream stream;
@@ -34,7 +34,7 @@ genCacheEntryName(const isc::dns::Name& name,
 
 const std::string
 genCacheEntryName(const std::string& namestr,
-                 const uint16_t type) 
+                 const uint16_t type)
 {
     std::string keystr = namestr;
     ostringstream stream;
@@ -42,7 +42,7 @@ genCacheEntryName(const std::string& namestr,
     keystr += stream.str();
     return keystr;
 }
-    
+
 } // namespace cache
 } // namespace isc
 

+ 5 - 5
src/lib/cache/cache_entry_key.h

@@ -26,19 +26,19 @@ namespace cache {
 
 /// \brief Entry Name Generation Functions
 /// Generate the name for message/rrset entries.
-/// The name is name(name of rrset, for message entry, 
+/// The name is name(name of rrset, for message entry,
 /// the name is query name) + str(type)
 /// Note. the name is text string, not wire format.
 /// eg. if name is 'example.com.', type is 'A', the return
 /// value is 'example.com.1'
 /// \return return the entry name.
 const std::string
-genCacheEntryName(const isc::dns::Name& name, 
+genCacheEntryName(const isc::dns::Name& name,
                  const isc::dns::RRType& type);
-   
-/// 
+
+///
 /// \overload
-/// 
+///
 const std::string
 genCacheEntryName(const std::string& namestr, const uint16_t type);
 

+ 26 - 13
src/lib/cache/local_zone_data.cc

@@ -16,6 +16,8 @@
 
 #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;
@@ -24,28 +26,39 @@ namespace isc {
 namespace cache {
 
 typedef pair<std::string, RRsetPtr> RRsetMapPair;
+typedef map<std::string, RRsetPtr>::iterator RRsetMapIterator;
 
-RRsetPtr
-LocalZoneData::lookup(const isc::dns::Name& qname,
-                      const isc::dns::RRType& qtype)
+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.getRRType());
-    
-    rrsets_map_.insert(RRsetMapPair(key, rrset_ptr));
-}
+    string key = genCacheEntryName(rrset.getName(), rrset.getType());
+    RRset* rrset_copy = new RRset(rrset.getName(), rrset.getClass(),
+                                  rrset.getType(), rrset.getTTL());
 
-    std::map<std::string, RRsetPtr> rrsets_map_; // RRsets of the zone
-    uint16_t class_; // The class of the zone
+    rrsetCopy(rrset, *rrset_copy);
+    RRsetPtr rrset_ptr(rrset_copy);
+    pair<RRsetMapIterator, bool> result = rrsets_map_.insert(RRsetMapPair(key, rrset_ptr));
+    if (!result.second) {
+        // Insert failed, we should remove the existed rrset first,
+        // then insert again.
+        rrsets_map_.erase(result.first);
+        rrsets_map_.insert(RRsetMapPair(key, rrset_ptr));
+    }
+}
 
 } // namespace cache
 } // namespace isc
 
-#endif // _LOCAL_ZONE_DATA
-

+ 9 - 6
src/lib/cache/local_zone_data.h

@@ -35,21 +35,24 @@ public:
     {}
 
     /// \brief Look up one rrset.
-    /// \return return the shared_ptr of rrset if it can 
+    /// \return return the shared_ptr of rrset if it can
     /// found in the local zone, or else, return NULL.
-    RRsetPtr lookup(const isc::dns::Name& qname,
-                    const isc::dns::RRType& qtype);
-    
-    /// \brief Update the rrset in the local zone. If the 
+    isc::dns::RRsetPtr lookup(const isc::dns::Name& qname,
+                              const isc::dns::RRType& qtype);
+
+    /// \brief Update the rrset in the local zone. If the
     /// the rrset doesn't exist, it will be added directly,
     /// or else, the existed one will be overwrited.
     void update(const isc::dns::RRset& rrset);
 
 private:
-    std::map<std::string, RRsetPtr> rrsets_map_; // RRsets of the zone
+    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
 

+ 4 - 4
src/lib/cache/message_cache.cc

@@ -36,7 +36,7 @@ MessageCache::MessageCache(boost::shared_ptr<RRsetCache> rrset_cache,
                   new HashDeleter<MessageEntry>(message_table_))
 {
 }
-    
+
 bool
 MessageCache::lookup(const isc::dns::Name& qname,
                      const isc::dns::RRType& qtype,
@@ -58,7 +58,7 @@ 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.
@@ -71,8 +71,8 @@ MessageCache::update(const Message& msg) {
     }
 
     MessageEntryPtr msg_entry(new MessageEntry(msg, rrset_cache_));
-    message_lru_.add(msg_entry); 
-    return message_table_.add(msg_entry, entry_key, true); 
+    message_lru_.add(msg_entry);
+    return message_table_.add(msg_entry, entry_key, true);
 }
 
 void

+ 7 - 7
src/lib/cache/message_cache.h

@@ -32,7 +32,7 @@ namespace cache {
 class RRsetCache;
 
 /// \brief Message Cache
-/// The object of MessageCache represents the cache for class-specific 
+/// The object of MessageCache represents the cache for class-specific
 /// messages.
 ///
 class MessageCache: public boost::noncopyable {
@@ -40,9 +40,9 @@ 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 
+    /// \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,
@@ -54,7 +54,7 @@ public:
 
     /// \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. 
+    /// directly.
     bool update(const isc::dns::Message& msg);
 
     /// \brief Dump the message cache to specified file.
@@ -65,7 +65,7 @@ public:
     /// \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. 
+    /// \brief Resize the size of message cache in runtime.
     bool resize(uint32_t size);
 
 protected:
@@ -73,7 +73,7 @@ protected:
     /// \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, 
+    HashKey getEntryHashKey(const isc::dns::Name& name,
                             const isc::dns::RRType& type) const;
 
     // Make these variants be protected for easy unittest.
@@ -83,7 +83,7 @@ protected:
     isc::nsas::HashTable<MessageEntry> message_table_;
     isc::nsas::LruList<MessageEntry> message_lru_;
 };
-    
+
 typedef boost::shared_ptr<MessageCache> MessageCachePtr;
 
 } // namespace cache

+ 18 - 18
src/lib/cache/message_entry.cc

@@ -26,7 +26,7 @@ using namespace std;
 namespace isc {
 namespace cache {
 
-static uint32_t MAX_UINT32 = numeric_limits<uint32_t>::max();    
+static uint32_t MAX_UINT32 = numeric_limits<uint32_t>::max();
 
 MessageEntry::MessageEntry(const isc::dns::Message& msg,
                            boost::shared_ptr<RRsetCache> rrset_cache):
@@ -38,14 +38,14 @@ MessageEntry::MessageEntry(const isc::dns::Message& 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, 
+MessageEntry::getRRsetEntries(vector<RRsetEntryPtr>& rrset_entry_vec,
                               const time_t time_now)
 {
     uint16_t entry_count = answer_count_ + authority_count_ + additional_count_;
     for (int index = 0; index < entry_count; ++index) {
-        RRsetEntryPtr rrset_entry = rrset_cache_->lookup(rrsets_[index].name_, 
+        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);
@@ -93,7 +93,7 @@ MessageEntry::genMessage(const time_t& time_now,
             return false;
         }
 
-        // Begin message generation. We don't need to add question 
+        // 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_);
@@ -111,13 +111,13 @@ MessageEntry::genMessage(const time_t& time_now,
 RRsetTrustLevel
 MessageEntry::getRRsetTrustLevel(const Message& message,
                    const isc::dns::RRsetPtr rrset,
-                   const isc::dns::Message::Section& section) 
+                   const isc::dns::Message::Section& section)
 {
     bool aa = message.getHeaderFlag(Message::HEADERFLAG_AA);
     switch(section) {
         case Message::SECTION_ANSWER: {
             if (aa) {
-                // According RFC2181 section 5.4.1, only the record 
+                // 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.
@@ -128,25 +128,25 @@ MessageEntry::getRRsetTrustLevel(const Message& message,
                     } else {
                         return RRSET_TRUST_ANSWER_NONAA;
                     }
-                } 
+                }
 
-                // Here, if the first rrset is DNAME, then assume the 
+                // 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")) {
-                    if ((*rrset_iter).get() == rrset.get() || 
-                        ((++rrset_iter) != message.endSection(section) && 
+                    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 {
@@ -154,7 +154,7 @@ MessageEntry::getRRsetTrustLevel(const Message& message,
             }
             break;
         }
-        
+
         case Message::SECTION_AUTHORITY: {
             if (aa) {
                 return RRSET_TRUST_AUTHORITY_AA;
@@ -181,7 +181,7 @@ MessageEntry::getRRsetTrustLevel(const Message& message,
 void
 MessageEntry::parseSection(const isc::dns::Message& msg,
                          const Message::Section& section,
-                         uint32_t& smaller_ttl, 
+                         uint32_t& smaller_ttl,
                          uint16_t& rrset_count)
 {
     RRsetIterator iter;
@@ -189,7 +189,7 @@ MessageEntry::parseSection(const isc::dns::Message& msg,
     for (iter = msg.beginSection(section);
          iter != msg.endSection(section);
          ++iter) {
-        // Add the rrset entry to rrset_cache or update the existed 
+        // 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;
@@ -216,12 +216,12 @@ MessageEntry::initMessageEntry(const isc::dns::Message& msg) {
 
     // We only cache the first question in question section.
     // TODO, do we need to support muptiple questions?
-    query_count_ = 1; 
+    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_);

+ 28 - 27
src/lib/cache/message_entry.h

@@ -42,38 +42,40 @@ struct RRsetRef{
     {}
 
     isc::dns::Name name_; // Name of rrset.
-    isc::dns::RRType type_; // Type of rrset. 
+    isc::dns::RRType type_; // Type of rrset.
 };
 
 /// \brief Message Entry
 /// The object of MessageEntry represents one response message
-/// answered to the recursor client. 
+/// answered to the recursor client.
 class MessageEntry : public NsasEntry<MessageEntry>,
                      public boost::noncopyable
 {
 public:
 
-    /// \brief Initialize the message entry object with one dns 
+    /// \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 the rrset cache, or the
-    /// existed rrset entries need to be updated.
+    ///        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.
+    /// \brief generate one dns message according
+    ///        the rrsets information of the message.
+    ///
     /// \param response generated dns message.
     /// \param time_now set the ttl of each rrset in the message
-    ///        as "expire_time - time_now" (expire_time is the 
+    ///        as "expire_time - time_now" (expire_time is the
     ///        expiration time of the rrset).
-    /// \return return true if the response message can be generated 
+    /// \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 {
@@ -85,29 +87,28 @@ protected:
     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 
-    /// test.
+    ///        placed in cc file. Put them here just for easy unit
+    ///        test.
     //@{
     /// \brief Parse the rrsets in specified section.
-    /// \param smaller_ttl Get the smallest ttl of rrsets in 
-    /// specified section, if it's smaller than the given value.
-    /// \param rrset_count set the rrset count of the section.
-    /// (TODO for Message, getRRsetCount() should be one interface provided 
-    //  by Message.)
+    /// \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 Trust worthiness
-    /// The algorithm refers to RFC2181 section 5.4.1
+    ///        The algorithm refers to RFC2181 section 5.4.1
+    ///        Only the rrset can be updated by the rrsets
+    ///        with higher trust level.
     ///
-    /// 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 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,
@@ -130,8 +131,8 @@ protected:
     ///        entry's expire time.
     /// \return return false if any rrset entry has expired, or else,
     ///         return false.
-    bool getRRsetEntries(std::vector<RRsetEntryPtr>& rrset_entry_vec, 
-                         const time_t time_now); 
+    bool getRRsetEntries(std::vector<RRsetEntryPtr>& rrset_entry_vec,
+                         const time_t time_now);
     //@}
 protected:
     /// \note Make the variable be protected for easy test.
@@ -157,7 +158,7 @@ private:
     bool headerflag_aa_; // Whether AA bit is set.
     bool headerflag_tc_; // Whether TC bit is set.
 };
-    
+
 typedef boost::shared_ptr<MessageEntry> MessageEntryPtr;
 
 } // namespace cache

+ 95 - 67
src/lib/cache/recursor_cache.cc

@@ -18,6 +18,7 @@
 #include "dns/message.h"
 #include "rrset_cache.h"
 #include <string>
+#include <algorithm>
 
 using namespace isc::dns;
 using namespace std;
@@ -25,20 +26,40 @@ using namespace std;
 namespace isc {
 namespace cache {
 
+RecursorCache::RecursorCache() {
+    uint16_t klass = 1; // class 'IN'
+    class_supported_.push_back(klass);
+    local_zone_data_[klass] = LocalZoneDataPtr(new LocalZoneData(klass));
+    rrsets_cache_[klass] = RRsetCachePtr(new RRsetCache(RRSET_CACHE_DEFAULT_SIZE, klass));
+    messages_cache_[klass] = MessageCachePtr(new MessageCache(rrsets_cache_[klass],
+                                                        MESSAGE_CACHE_DEFAULT_SIZE,
+                                                        klass));
+}
+
 RecursorCache::RecursorCache(std::vector<CacheSizeInfo> caches_size) {
     uint32_t index = 0;
     uint32_t size = caches_size.size();
-    for (; index < size; index++) {
+    for (; index < size; ++index) {
         CacheSizeInfo* infop = &caches_size[index];
-        uint16_t klass = infop->class_;
-        rrsets_cache1_[klass] = RRsetCachePtr(new
-                                     RRsetCache(infop->rrset_cache_size, klass));
-        rrsets_cache2_[klass] = RRsetCachePtr(new
+        uint16_t klass = infop->klass;
+        class_supported_.push_back(klass);
+        // TODO We should find one way to load local zone data.
+        local_zone_data_[klass] = LocalZoneDataPtr(new LocalZoneData(klass));
+        rrsets_cache_[klass] = RRsetCachePtr(new
                                      RRsetCache(infop->rrset_cache_size, klass));
-        messages_cache_[klass] = MessageCachePtr(new MessageCache(rrsets_cache2_[klass],
+        messages_cache_[klass] = MessageCachePtr(new MessageCache(rrsets_cache_[klass],
                                                       infop->message_cache_size,
                                                       klass));
     }
+
+    // Sort the vector, so that binary_find can be used.
+    sort(class_supported_.begin(), class_supported_.end());
+}
+
+bool
+RecursorCache::classIsSupported(uint16_t klass) const {
+    return binary_search(class_supported_.begin(),
+                         class_supported_.end(), klass);
 }
 
 bool
@@ -47,44 +68,27 @@ RecursorCache::lookup(const isc::dns::Name& qname,
                const isc::dns::RRClass& qclass,
                isc::dns::Message& response) const
 {
-    // First, query in rrsets_cache1_, if the rrset(qname, qtype, qclass) can be
-    // found in rrsets_cache1_, generated reply message with only the rrset in
-    // answer section.
-    RRsetCacheMap::const_iterator cache_iter = rrsets_cache1_.find(qclass.getCode());
-    if (cache_iter != rrsets_cache1_.end()) {
-        RRsetEntryPtr rrset_entry = cache_iter->second->lookup(qname, qtype);
-        if (rrset_entry) {
-            boost::shared_ptr<isc::dns::RRset> rrset_ptr = rrset_entry->getRRset();
-            response.addRRset(Message::SECTION_ANSWER, rrset_ptr);
-        }
+    uint16_t class_code = qclass.getCode();
+    if (!classIsSupported(class_code)) {
+        return false;
     }
 
-    // Search in class-specific message cache.
-    MessageCacheMap::const_iterator iter = messages_cache_.find(qclass.getCode());
-    if (iter == messages_cache_.end()) {
-        // Can't find the class-specific message cache, return false.
-        return false;
-    } else {
-        return iter->second->lookup(qname, qtype, response);
+    // message response should has question section already.
+    if (response.beginQuestion() == response.endQuestion()) {
+        isc_throw(MessageNoQuestionSection, "Message has no question section");
     }
-}
 
-isc::dns::RRsetPtr
-RecursorCache::lookup_in_rrset_cache(const isc::dns::Name& qname,
-                      const isc::dns::RRType& qtype,
-                      const isc::dns::RRClass& qclass,
-                      const RRsetCacheMap& rrsets_cache) const
-{
-    RRsetCacheMap::const_iterator cache_iter = rrsets_cache.find(qclass.getCode());
-    if (cache_iter != rrsets_cache.end()) {
-        RRsetEntryPtr rrset_entry = cache_iter->second->lookup(qname, qtype);
-        if (rrset_entry) {
-            return rrset_entry->getRRset();
-        }
+    // 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_[class_code])->lookup(qname, qtype);
+    if (rrset_ptr) {
+        response.addRRset(Message::SECTION_ANSWER, rrset_ptr);
+        return true;
     }
 
-    // Can't find the rrset in specified rrset cache, return NULL.
-    return RRsetPtr();
+    // Search in class-specific message cache.
+    return messages_cache_[class_code]->lookup(qname, qtype, response);
 }
 
 isc::dns::RRsetPtr
@@ -92,61 +96,85 @@ RecursorCache::lookup(const isc::dns::Name& qname,
                const isc::dns::RRType& qtype,
                const isc::dns::RRClass& qclass) const
 {
+    uint16_t klass = qclass.getCode();
+    if (!classIsSupported(klass)) {
+        return RRsetPtr();
+    }
+
     // Algorithm:
-    // 1. Search in rrsets_cache1_ first,
-    // 2. Then do search in rrsets_cache2_.
-    RRsetPtr rrset_ptr = lookup_in_rrset_cache(qname, qtype, qclass, rrsets_cache1_);
+    // 1. Search in local zone data first,
+    // 2. Then do search in rrsets_cache_.
+    RRsetPtr rrset_ptr = local_zone_data_[klass]->lookup(qname, qtype);
     if (rrset_ptr) {
         return rrset_ptr;
     } else {
-        rrset_ptr = lookup_in_rrset_cache(qname, qtype, qclass, rrsets_cache2_);
+        RRsetEntryPtr rrset_entry = rrsets_cache_[klass]->lookup(qname, qtype);
+        if (rrset_entry) {
+            return rrset_entry->getRRset();
+        } else {
+            return RRsetPtr();
+        }
     }
+}
 
-    return rrset_ptr;
+isc::dns::RRsetPtr
+RecursorCache::lookupClosestRRset(const isc::dns::Name& qname,
+                                  const isc::dns::RRType& qtype,
+                                  const isc::dns::RRClass& qclass) const
+{
+    unsigned int count = qname.getLabelCount();
+    unsigned int level = 0;
+    while(level < count) {
+        Name close_name = qname.split(level);
+        RRsetPtr rrset_ptr = lookup(close_name, qtype, qclass);
+        if (rrset_ptr) {
+            return rrset_ptr;
+        } else {
+            ++level;
+        }
+    }
+
+    return RRsetPtr();
 }
 
 bool
 RecursorCache::update(const isc::dns::Message& msg) {
     QuestionIterator iter = msg.beginQuestion();
-    MessageCacheMap::iterator cache_iter = messages_cache_.find((*iter)->getClass().getCode());
-    if (cache_iter == messages_cache_.end()) {
-        // The message is not allowed to cached.
+    uint16_t klass = (*iter)->getClass().getCode();
+    if (!classIsSupported(klass)) {
         return false;
-    } else {
-        return cache_iter->second->update(msg);
     }
+
+    return messages_cache_[klass]->update(msg);
 }
 
 bool
-RecursorCache::updateRRsetCache(const isc::dns::RRset& rrset,
-                                RRsetCacheMap& rrset_cache_map)
+RecursorCache::updateRRsetCache(const isc::dns::ConstRRsetPtr rrset_ptr,
+                                RRsetCachePtr rrset_cache_ptr)
 {
-    uint16_t klass = rrset.getClass().getCode();
-    RRsetCacheMap::iterator cache_iter = rrset_cache_map.find(klass);
-    if (cache_iter == rrset_cache_map.end()) {
-        // The rrset is not allowed to be cached.
-        return false;
+    RRsetTrustLevel level;
+    string typestr = rrset_ptr->getType().toText();
+    if (typestr == "A" || typestr == "AAAA") {
+        level = RRSET_TRUST_PRIM_GLUE;
     } else {
-        RRsetTrustLevel level;
-        string typestr = rrset.getType().toText();
-        if (typestr == "A" || typestr == "AAAA") {
-            level = RRSET_TRUST_PRIM_GLUE;
-        } else {
-            level = RRSET_TRUST_PRIM_ZONE_NONGLUE;
-        }
-
-        cache_iter->second->update(rrset, level);
+        level = RRSET_TRUST_PRIM_ZONE_NONGLUE;
     }
+
+    rrset_cache_ptr->update((*rrset_ptr.get()), level);
     return true;
 }
 
 bool
-RecursorCache::update(const isc::dns::RRset& rrset) {
-    if (!updateRRsetCache(rrset, rrsets_cache1_)) {
+RecursorCache::update(const isc::dns::ConstRRsetPtr rrset_ptr) {
+    uint16_t klass = rrset_ptr->getClass().getCode();
+    if (!classIsSupported(klass)) {
         return false;
     }
 
-    return updateRRsetCache(rrset, rrsets_cache2_);
+    // First update local zone, then update rrset cache.
+    local_zone_data_[klass]->update((*rrset_ptr.get()));
+    updateRRsetCache(rrset_ptr, rrsets_cache_[klass]);
+    return true;
 }
 
 void

+ 96 - 51
src/lib/cache/recursor_cache.h

@@ -21,8 +21,10 @@
 #include <string>
 #include <boost/shared_ptr.hpp>
 #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 {
@@ -30,41 +32,70 @@ class RRsetCache;
 
 typedef std::map<uint16_t, MessageCachePtr> MessageCacheMap;
 typedef std::map<uint16_t, RRsetCachePtr> RRsetCacheMap;
+typedef std::map<uint16_t, LocalZoneDataPtr> LocalZoneDataMap;
 
 //TODO a better proper default cache size
-#define MESSAGE_CACHE_DEFAULT_SIZE 1000000
-#define RRSET_CACHE_DEFAULT_SIZE  10000
+#define MESSAGE_CACHE_DEFAULT_SIZE 10000
+#define RRSET_CACHE_DEFAULT_SIZE   20000
 
 /// \brief Cache Size Information.
-/// It is used to initialize the size of rrset/message.
+/// Used to initialize the size of class-specific rrset/message cache.
 struct CacheSizeInfo
 {
-    uint16_t class_; // class of the cache.
+public:    
+    CacheSizeInfo(uint16_t cls, 
+                  uint32_t msg_cache_size,
+                  uint32_t rst_cache_size):
+                    klass(cls),
+                    message_cache_size(msg_cache_size),
+                    rrset_cache_size(rst_cache_size)
+    {}
+
+    uint16_t klass; // 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 Recursor Cache
-/// The object of RecursorCache represents the cache of the recursor. It holds
-/// a list of message cache and rrset cache.
+/// \brief Recursor Cache.
+/// The object of RecursorCache represents the cache of the recursor. It may holds
+/// a list of message/rrset cache which are in different class.
 ///
 class RecursorCache {
 public:
-    /// \brief Construct Function
+    /// \brief Default Construct Function.
+    ///  Only support for class "IN", and message cache size is
+    /// MESSAGE_CACHE_DEFAULT_SIZE, rrset cache size is
+    /// RRSET_CACHE_DEFAULT_SIZE
+    RecursorCache();
+
+    /// \brief Construct Function.
     /// \param caches_size cache size information for each
-    /// messages/rrsets.
+    ///        messages/rrsets of different classes.
     RecursorCache(std::vector<CacheSizeInfo> caches_size);
 
     /// \name Lookup Interfaces
     //@{
     /// \brief Look up message in cache.
     ///
-    /// \param response the query message (must in RENDER mode),
-    /// if the message can be found in cache, rrsets for the message
-    /// will be added to different sections.
-    ///
-    /// \return return true if the message can be found, or else, return false.
+    /// \param response the query message (must 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,
@@ -72,34 +103,58 @@ public:
 
     /// \brief Look up rrset in cache.
     /// \return return the shared_ptr of rrset if it can be found,
-    /// or else, return NULL. When looking up, cache1(localzone) will
-    /// be searched first, if not found, then search in cache2.
+    ///         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.
+    /// \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.
-    /// \return return true if the message is updated into the cache,
-    /// or else, return false.
+    /// \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.
+    /// \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.
-    /// rrset_cache1_ and rrset_cache2_ should be updated together.
-    /// If the rrset doesn't exist in both of them, then the rrset
-    /// will be added into both of them.
+    ///        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.
     /// \return return false, if the class of the parameter rrset is
-    /// allowed to be cached.
+    ///        allowed to be cached.
     ///
     /// \overload
     ///
-    bool update(const isc::dns::RRset& rrset);
+    bool update(const isc::dns::ConstRRsetPtr rrset_ptr);
+
+    /// \brief Check whether the messages/rrsets of specified class
+    ///        are cached.
+    bool classIsSupported(uint16_t klass) const;
 
     /// \name Cache Serialization
     //@{
@@ -113,40 +168,30 @@ public:
     //@}
 
 protected:
-    /// \brief Look up rrset in one specified rrset cache.
-    /// This function is used internally by lookup()
-    /// \param rrsets_cache the cache for looking up rrset.
-    /// \return return the shared_ptr of the rrset if it can be
-    /// found in the cache.
-    isc::dns::RRsetPtr lookup_in_rrset_cache(const isc::dns::Name& qname,
-                      const isc::dns::RRType& qtype,
-                      const isc::dns::RRClass& qclass,
-                      const RRsetCacheMap& rrsets_cache) const;
-
-    /// \brief Update the rrset in one rrset cache.
+    /// \brief Update rrset cache.
     /// \return return true if the rrset is updated in the rrset cache,
-    /// or else return false.
-    /// \param rrset_cache_map the map of rrset cache, the rrset cache needs
-    /// to be updated should be found first according the class of the rrset.
-    /// If the class-specific rrset cache can't be found in the map, it returns
-    /// false.
-    bool updateRRsetCache(const isc::dns::RRset& rrset,
-                          RRsetCacheMap& rrset_cache_map);
+    ///         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);
+
 protected:
+    /// \brief Classes supported by the cache.
+    std::vector<uint16_t> class_supported_;
 
-    /// \brief the list of message cache for configured classes(message cache
-    /// is class-specific)
-    MessageCacheMap messages_cache_;
+    /// \brief map of message caches for configured classes(each message
+    /// cache is class-specific)
+    mutable MessageCacheMap messages_cache_;
 
     /// \name rrset caches
     //@{
-    /// \brief the list of rrset cache for configured classes.
-    /// rrsets_cache1_ is used to cache the configured rrsets in localzone, rrsets
-    /// in it will never expire.
-    RRsetCacheMap rrsets_cache1_;
+    /// \brief Local Zone data cache
+    /// Cache for rrsets in local zones, rrsets
+    /// in it never expire.
+    mutable LocalZoneDataMap local_zone_data_;
 
     /// \brief cache the rrsets parsed from the received message.
-    RRsetCacheMap rrsets_cache2_;
+    mutable RRsetCacheMap rrsets_cache_;
     //@}
 };
 

+ 5 - 7
src/lib/cache/rrset_copy.cc

@@ -15,28 +15,26 @@
 // $Id$
 
 #include "rrset_copy.h"
-#include <dns/rrset.h>
+
+using namespace isc::dns;
 
 namespace isc {
 namespace cache {
 
 void
-rrset_copy(const isc::dns::RRset& src, isc::dns::RRset& dst) {
+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());
+        dst.addRdata(rdata_itor->getCurrent());
         rdata_itor->next();
     }
 
     RRsetPtr rrsig = src.getRRsig();
     if (rrsig != NULL){
-        dst->addRRsig(rrsig);
+        dst.addRRsig(rrsig);
     }
 }
 
 } // namespace cache
 } // namespace isc
-
-#endif // __RRSET_COPY_
-

+ 3 - 3
src/lib/cache/rrset_copy.h

@@ -17,18 +17,18 @@
 #ifndef __RRSET_COPY_
 #define __RRSET_COPY_
 
+#include <dns/rrset.h>
+
 namespace isc {
 namespace cache {
 
-class RRset;
-
 /// \brief RRset Copy Function
 /// \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
-rrset_copy(const isc::dns::RRset& src, isc::dns::RRset& dst);
+rrsetCopy(const isc::dns::RRset& src, isc::dns::RRset& dst);
 
 } // namespace cache
 } // namespace isc

+ 2 - 11
src/lib/cache/rrset_entry.cc

@@ -18,6 +18,7 @@
 #include <nsas/nsas_entry.h>
 #include <nsas/fetchable.h>
 #include "rrset_entry.h"
+#include "rrset_copy.h"
 
 using namespace isc::dns;
 
@@ -31,17 +32,7 @@ RRsetEntry::RRsetEntry(const isc::dns::RRset& rrset, const RRsetTrustLevel& leve
     rrset_(new RRset(rrset.getName(), rrset.getClass(), rrset.getType(), rrset.getTTL())),
     hash_key_(HashKey(entry_name_, rrset_->getClass()))
 {
-    RdataIteratorPtr rdata_itor = rrset.getRdataIterator();
-    rdata_itor->first();
-    while(!rdata_itor->isLast()){
-        rrset_->addRdata(rdata_itor->getCurrent());
-        rdata_itor->next();
-    }
-
-    RRsetPtr rrsig = rrset.getRRsig();
-    if (rrsig != NULL){
-        rrset_->addRRsig(rrsig);
-    }
+    rrsetCopy(rrset, *(rrset_.get()));
 }
 
 isc::dns::RRsetPtr

+ 2 - 0
src/lib/cache/tests/Makefile.am

@@ -36,6 +36,8 @@ 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  += recursor_cache_unittest.cc
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)

+ 12 - 0
src/lib/cache/tests/cache_test_util.h

@@ -32,5 +32,17 @@ messageFromFile(Message& message, const char* datafile) {
     message.fromWire(buffer);
 }
 
+int
+section_rrset_count(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
 

+ 62 - 0
src/lib/cache/tests/local_zone_data_unittest.cc

@@ -0,0 +1,62 @@
+// 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();
+    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());
+}
+
+}

+ 18 - 1
src/lib/cache/tests/message_cache_unittest.cc

@@ -62,7 +62,7 @@ protected:
     Message message_render;
 };
 
-TEST_F(MessageCacheTest, testUpdate) {
+TEST_F(MessageCacheTest, testLookup) {
     messageFromFile(message_parse, "message_fromWire1");
     EXPECT_TRUE(message_cache_->update(message_parse));
     Name qname("test.example.com.");
@@ -80,5 +80,22 @@ TEST_F(MessageCacheTest, testUpdate) {
     EXPECT_TRUE(message_cache_->lookup(qname1, qtype1, message_render));
 }
 
+TEST_F(MessageCacheTest, testUpdate) {
+    messageFromFile(message_parse, "message_fromWire4");
+    EXPECT_TRUE(message_cache_->update(message_parse));
+
+    Name qname("example.com.");
+    RRType qtype(6);
+    EXPECT_TRUE(message_cache_->lookup(qname, qtype, 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, qtype, new_msg_render));
+    EXPECT_TRUE(new_msg_render.getHeaderFlag(Message::HEADERFLAG_AA));
+}
+
 }   // namespace
 

+ 0 - 12
src/lib/cache/tests/message_entry_unittest.cc

@@ -211,18 +211,6 @@ TEST_F(MessageEntryTest, testGetRRsetEntries) {
     EXPECT_FALSE(message_entry.getRRsetEntriesForTest(vec, expire_time));
 }
 
-static int
-section_rrset_count(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;
-}
-
 TEST_F(MessageEntryTest, testGenMessage) {
     messageFromFile(message_parse, "message_fromWire3");
     DerivedMessageEntry message_entry(message_parse, rrset_cache_);

+ 8 - 0
src/lib/cache/tests/rrset_entry_unittest.cc

@@ -47,6 +47,14 @@ TEST_F(GenCacheKeyTest, genCacheEntryKey2) {
     EXPECT_EQ(keystr, genCacheEntryName(name, type));
 }
 
+class DerivedRRsetEntry: public RRsetEntry {
+public:
+
+    void updateTTLForTest() {
+        
+    }
+};
+
 #define TEST_TTL 100
 class RRsetEntryTest : public ::testing::Test {
 protected: