BIND 10 #449: Implementation of the resolver cache

BIND 10 Development do-not-reply at isc.org
Thu Jan 27 16:28:09 UTC 2011


#449: Implementation of the resolver cache
-------------------------------------+-------------------------------------
                 Reporter:           |                Owner:  zhanglikun
  zhanglikun                         |               Status:  reviewing
                     Type:  task     |            Milestone:  R-Team-
                 Priority:  major    |  Sprint-20110208
                Component:           |           Resolution:
  resolver                           |            Sensitive:  0
                 Keywords:           |  Add Hours to Ticket:  0
Estimated Number of Hours:  8.0      |          Total Hours:  0
                Billable?:  1        |
                Internal?:  0        |
-------------------------------------+-------------------------------------
Changes (by stephen):

 * owner:  stephen => zhanglikun


Comment:

 Reviewed commit a8746fb17e10db78330cf69b2850515020f5cd56

 '''General'''[[BR]]
 The following apply to all the files examined:

  * Return values should be enclosed in brackets according to the style
 guide.
  * A number of methods don't have the doxygen tags to describe all the
 parameters.  These should be added.
  * Comments appear to be restricted to 50 characters wide in a number of
 files.  Suggest that 80 characters would be more usual.  (This also
 appears to be the cause of some method declarations being split across
 multiple lines.)

 Comment: there is an inconsistency in how classes make themselves non-
 copyable. Some inherit from boost::noncopyable, but others take the
 approach of making the copy constructor and assignment operator private.
 Both work, but a consistent approach would be good.


 '''cache_entry_key.cc'''[[BR]]
 The function definitions (not including the return type, which according
 to the style guide should be on a line by itself) could each fit onto a
 single 80-character line - there does not appear to be the need to split
 them across multiple lines.

 The code is perhaps simple enough to inline in the header file.  It could
 be even simpler using boost::lexical_cast, i.e.:
 {{{
 const std::string
 getCachedEntryName(const std::string& namestr, const uint16_t type) {
     return (namestr + boost::lexical_cast<std::string>(type));
 }
 }}}
 This would eliminate the ".cc" file as well as remove the overhead of a
 call/return.

 '''rrset_copy.h'''[[BR]]
 '''rrset_copy.cc'''[[BR]]
 Both OK.

 Comment: strictly speaking, this class does not copy a RRset, it copies
 the Rdata (and RRSIGs) pointed to by that RRset.  However, used in
 conjunction with the initialization of "rrset_" in the RRsetEntry
 constructor, the effect is a copy.  As you note, this operation logically
 belongs in the isc::dns::RRset class.  Since this is a definite need to
 copy an RRset, I suggest that you raise this in bind10-dev, and get a
 consensus to add a copy constructor and assignment operator to that class.
 (This does not need to be done as part of this task - if consensus is
 reached, a task for it can be added to the task backlog.)

 '''message_entry.h'''[[BR]]
 Comment: the fact that the RRsetRef object is used here makes me wonder
 whether this should be part of the basic RRset class hierarchy.  The
 comments in src/lib/dns/rrset.h suggests that the design is not final and
 should be revisited.  Thoughts?

 genMessage(): the parameter description in the header suggests that
 "response" is the first argument and time_now the second.

 Presumably the reason that a number of methods are "protected" instead of
 "private" is to allow for testing?  If so, a one-line comment in the
 header file explaining that would be helpful.

 '''message_entry.cc'''[[BR]]
 getRRsetTrustLevel(): should the second argument (rrset) be passed by
 reference instead of by value to avoid a copy operation?

 getRRsetEntries(): perhaps mark a possible optimisation for the future: as
 we know that we will put at most entry_count entries in the vector,
 vector.reserve(entry_count) could be called to allocate enough space prior
 to entering the loop.

 addRRset(): should the rrset_entry_vec and section arguments be passed by
 reference instead of by value?

 addRRset(): perhaps add an "assert" to catch/log a possible programming
 error if SECTION_QUESTION is passed by mistake?

 genMessage(): the check for expiration is with "t > expire_time"; suggest
 that the ">" should be ">=".  (getRRsetEntries() checks that something has
 not expired with "t < expire_time", which leaves open the question of what
 happens if "t == expire_time"?)

 genMessage(): to check if any of the RRsets in the message have expired,
 getRRsetEntries() is called.  Although only the return status is used, a
 vector of RRsetEntryPtrs is created in the process which is discarded
 without being used.  The construction/destruction of the vector is
 additional overhead; perhaps a method should be added purely to check if a
 message has expired?

 getTrustLevel(): in the processing of Message::SECTION_ANSWER, the code
 assumes that the first RRset in the section is the one that corresponds to
 the QNAME.  Some servers can return CNAME/DNAME chains, but is there
 anywhere in the protocol that stipulates the ordering of RRsets in the
 section?  It would be safer to iterate through the answer section until
 the RRset that matches the QNAME is found.

 '''rrset_entry.cc'''[[BR]]
 updateTTL(): coding standards require braces even for single line blocks.

 '''rrset_cache.cc'''[[BR]]
 update(): Need to add a "TODO" that if the RRset being updated is an NS
 RRset, the NSAS should be updated as well.

 '''message_cache.h'''[[BR]]
 #include <map> is not needed, as the class does not reference a std::map
 object.  (Was this left over from an earlier iteration of the code?)

 '''message_cache.cc'''[[BR]]
 Comment: regarding the suggestion in update() for a better way to replace
 the entry.  In the short term (and for the hash table only) call add() and
 supply a third argument of "true".  A longer-term solution has been
 proposed in ticket #535.

 '''resolver_cache.h'''[[BR]]
 In the header comments there is a spurious bracket after the name of the
 exception being thrown.

 '''resolver_cache.cc'''[[BR]]
 Suggest the three-argument lookup() method be split into "lookup()" which
 checks the class and calls the second part in another method (e.g.
 "lookupInternal()") to do the actual lookup.  This would allow
 "lookupClosest()" to bypass the "classIsSupported()" call in "lookup()"
 (which does a binary search on a vector) by calling "lookupInternal()".

 Every access to one of the sub-caches (RRset, Message and !LocalZone)
 requires a lookup in a std::map, something that may be done multiple times
 in a method.  I would suggest that support for classes be done at a higher
 level - call this class something like !ResolverClassCache and call the
 containing class !ResolverCache.  When a method is called on
 !ResolverCache, it chooses a !ResolverClassCache based on the qclass then
 calls a corresponding method on that.  It simplifies the current class by
 getting rid of the indexing on the sub-caches and reduces map lookups to a
 single lookup per method call.

 '''local_zone_data.cc'''[[BR]]
 update(): the call to map::insert() followed by a call to map::erase() and
 map::insert() again can be replaced by the simpler:
 {{{
 rrsets_map_[key] = rrset_ptr;
 }}}
 (This replaces the value if "key" exists, and adds a new element if it
 doesn't.)

 '''cache_test_util.h'''[[BR]]
 Should really have header comments for these methods.

 '''local_zone_data_unittest.cc'''[[BR]]
 An assertion that the TTL is non-zero (i.e. TTL/2 != TTL) should be added.
 This is an added check that the data in message_fromWire3 is such that the
 test truly checks that the RRset has been updated.

 '''message_cache_unittest.cc'''[[BR]]
 Constructor: A qclass of 1 is IN, but RRClass::IN().getCode(), although
 more verbose, avoids making any assumptions about class values,

 testLookup: A qtype of 1 is "A", but more descriptive is using the static
 method in RRType class (i.e. RRType::A()).

 testUpdate: a qtype of 6 is "SOA", more descriptive would be to use
 RRType::SOA().

 '''resolver_cache_unittest.cc'''[[BR]]
 See comments in message_cache_unittest.cc for specifying qclass and qtype
 variables.

 '''rrset_entry_unittest.cc'''[[BR]]
 Suggest that a test be added to ensure that when the TTL drops to zero, it
 stays there and does not wrap round to a high value.  (It shouldn't with
 the current code in rrset_entry.cc, but this is an error that could be
 made if that code were modified.)

-- 
Ticket URL: <http://bind10.isc.org/ticket/449#comment:6>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list