BIND 10 #449: Implementation of the resolver cache
BIND 10 Development
do-not-reply at isc.org
Fri Feb 11 10:25:37 UTC 2011
#449: Implementation of the resolver cache
-------------------------------------+-------------------------------------
Reporter: | Owner: stephen
zhanglikun | Status: reviewing
Type: task | Milestone: R-Team-
Priority: major | Sprint-20110222
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 jelte):
* owner: jelte => stephen
Comment:
Replying to [comment:6 stephen]:
> 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.)
I think i got most of this.
>
> 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.
>
removed the boost::noncopyable ones (when there's two reasonably simple
ways to do it i prefer the one that has no dependencies)
>
> '''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.
>
done
> 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.
>
true, but I'd like use to try and reduce the usage of boost in our
headers, so for now i'm leaving this as is
> '''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.)
+1
>
> '''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?
>
add to discussion on copy?
> 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.
>
we'll have to ask likun
> '''message_entry.cc'''[[BR]]
> getRRsetTrustLevel(): should the second argument (rrset) be passed by
reference instead of by value to avoid a copy operation?
>
ack
> 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.
>
done
> addRRset(): should the rrset_entry_vec and section arguments be passed
by reference instead of by value?
>
ack
> addRRset(): perhaps add an "assert" to catch/log a possible programming
error if SECTION_QUESTION is passed by mistake?
>
why not, added.
> 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"?)
>
changed
> 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?
>
hmm, not sure if that would cause extra overhead, since that vector is
used if nothing has expired. (i don't know which would be the most common
path)
> 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.
looping over until both qname and type match
found what i think is two errors that were tested wrong (in the case where
a CNAME is returned *with* the target added (which is not a cname, the
test extpected that target to be RRSET_TRUST_ANSWER_NONAA where i think it
should have been RRSET_TRUST_ANSWER_AA)
I don't know the specific way this code is called yet, but i suspect that
doing the comparison by pointer is not the right thing here and we should
have an equals() in RRset (which we don't), or we should explicelty and
loudly put in the api docs that you are only to use this code with the
same pointers
>
> '''rrset_entry.cc'''[[BR]]
> updateTTL(): coding standards require braces even for single line
blocks.
done
>
> '''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.
er, but not from here i hope
>
> '''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?)
>
removed
> '''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.
>
it already called add() with true, i've removed the remove()
> '''resolver_cache.h'''[[BR]]
> In the header comments there is a spurious bracket after the name of the
exception being thrown.
>
removed
> '''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.
Right, I've renamed ResolverCache to ResolverClassCache, and made it
specific for one class specified at creation time. Then I created a new
ResolverCache that does its magic (now with a basic vector, some hints as
to how to optimise better, but for now good enough i hope).
Some code got moved, some got removed. I am undecided as of yet whether
the ResolverClassCache should go into its own header or whether we should
hide it completely, and only provide the 'high-level' header for
ResolverCache. (so for now it's in the same header file, resolver_cache.h)
>
> '''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.)
done
>
> '''cache_test_util.h'''[[BR]]
> Should really have header comments for these methods.
>
Done. Also renamed section_rrset_count to sectionRRsetCount. Is that
function worthy to add to libdns++ as well?
> '''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.
done
>
> '''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,
done
>
> testLookup: A qtype of 1 is "A", but more descriptive is using the
static method in RRType class (i.e. RRType::A()).
done
>
> testUpdate: a qtype of 6 is "SOA", more descriptive would be to use
RRType::SOA().
done
>
> '''resolver_cache_unittest.cc'''[[BR]]
> See comments in message_cache_unittest.cc for specifying qclass and
qtype variables.
done
>
> '''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.)
done
--
Ticket URL: <http://bind10.isc.org/ticket/449#comment:9>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list