BIND 10 #347: Implement query counters in auth module
BIND 10 Development
do-not-reply at isc.org
Wed Dec 22 13:07:56 UTC 2010
#347: Implement query counters in auth module
------------------------------+---------------------------------------------
Reporter: naokikambe | Owner: jinmei
Type: enhancement | Status: reviewing
Priority: major | Milestone: y2 12 month milestone
Component: b10-auth | Resolution:
Keywords: | Sensitive: 0
Estimatedhours: 0.0 | Hours: 0
Billable: 1 | Totalhours: 0
Internal: 0 |
------------------------------+---------------------------------------------
Changes (by y-aharen):
* owner: y-aharen => jinmei
Comment:
Jinmei-san, thank you very much for you review.
Replying to [comment:12 jinmei]:
> Replying to [comment:10 y-aharen]:
>
> Overall, the revised branch looks much better. I have some non
> trivial comments though, which are below.
>
> '''general comment'''
> - I made some trivial suggested changes (r3904). Please check them
> out (and override any of them if necessary)
I've checked them and they looks good. Thank you.
> - While I personally prefer "statistics" over "stats", consistency is
> even more important. Right now there is a mixture of "xxxStatsyyy"
> and "xxxStatisticsyyy" (e.g. setStatsSession() vs
> submitStatistics()), which is not good. If we name something
> "xxxStatistics", everything else should be named with "Statistics"
> (not stats); if we name it "xxxStats", others should also be named
> with "Stats". The choice is ultimately yours, but it should be
> consistent. I've fixed one obvious issue with this regard directly
> in the branch: header guard definition (__STAT(ISTIC)S_H).
Sorry, I forgot to change some name. I changed the names as you suggested.
> '''statistics.h'''
> - now there's no need to include boost/function.hpp. I've removed
> it.
OK, it can be removed.
> - as for the class name:
> > "Counter" class holds a set of query counters. Thus, I renamed it to
> > "QueryCounters". Is it OK? Currently it holds only "UDP" and "TCP"
> > type, but we may extend other types like "Notify", "A/Ixfr" type and
> > so on in the future. I described it as a comment in the code.
> >
> My concern is that with the intent of extension we'll soon encounter
> the need for renaming the class. Note that notify/ixfr/update are not
> even "queries" (to be very accurate about terminology); we may want to
> have other statistics counters that may not be related to DNS protocol
> handling (e.g, we may want to have a counter about the number of
> reloads). I don't know the future plans about these possibilities,
> but unless we want to define separate classes for these different
> types of statistics parameters, I'd choose a more generic name such as
> AuthCounters (but note also that as I pointed out in my previous
> comment it may not even be specific to the authoritative server; we'll
> naturally consider having the same framework for b10-recurse, for
> example. So, eventually, we may want to have a separate library
> module src/lib/statistics or something like that, where we define a
> most generic "Counters" class that can be used for any kinds of
> counter based statistics).
>
> But at the same time, there's a risk of premature overabstraction, so
> it's a tradeoff issue. The choice is basically up to you, but if I
> were the principal author, I'd begin with "AuthCounters" with a note
> that we may eventually want to make it a separate library with a
> higher abstraction level (with the cost of renaming classes and its
> overhead).
I think the name 'AuthCounters' is suitable for the class, so I renamed
it. I also noted the design of the class may change in the future, not
only holding counter values nor specific to Auth.
> '''statistics.cc'''
>
> - getCounters() (effectively) exposes an internal implementation
> details (i.e., that the counters are stored in std::vector), which
> is not a good practice. I'd prefer passing a counter type and
> retrieving that specific counter. BTW: why "shouldn't this be
> called except from tests" as documented in the header file? It may
> not be of much use in general, but I don't see the reason for
> prohibiting it. And, in any case, restricting usage by comment is
> not a reliable way to do so.
To pass 'QueryCounterType' we need definition of it. AuthSrv provides an
interface to getCounters() so I've added '#include <auth/statistics.h>'
into auth_srv.h and modified getCounter() to return single counter value
of specified type.
> - QueryCountersImpl::inc(): is there any reason for converting
> std::out_of_range to InvalidParameter? On one hand that's
> generally a good practice, but we basically allow standard
> exceptions to be propagated through our public interfaces (unlike
> boost exceptions, which we generally try to hide), so we don't have
> to do anything special here. If there's a good reason to catch
> (and convert) the exception internally, we should catch it by
> reference, not as an object.
I removed try-catch which converts std::out_of_range to
InvalidParameter.QueryCountersImpl::inc() throws std::out_of_range.
> > > '''auth_srv.cc'''
>
> - AuthSrv::processMessage
> > > - AuthSrv::processMessage(): in which case we can see getProtocol()
> > > be neither UDP nor TCP? In general, I don't like to handle an
> > > impossible case this way. I'd either throw an exception or even
> > > assert() here.
> > I agree with you. I modified to throw an exception.
> >
> Okay, but the exception case isn't tested. Please also add
> documentation about the exception in auth_srv.h (to make it better
> gradually).
I wrote test case and added documentation about the exception.
> - AuthSrv::processMessage another point: this method handles all
> incoming requests including notify and IXFR, not just normal
> queries. So, technically, incrementing a "query" counter here is
> not correct. See also the discussion about class naming above.
OK. I moved the code to a function and it is called from
AuthSrvImpl::processNormalQuery() and AuthSrvImpl::processAxfrQuery().
> - AuthSrv::submitStatistics: this should be a const member function.
OK. I made it const member function.
> '''asio_link.h'''
> - about the IntervalTimer class description: I'm not sure whether we
> need this note:
> {{{
> /// This class is mainly designed to use for calling
> /// \c QueryCounters::submitStatistics() periodically.
> }}}
> What's the purpose of this note? The interface of interval timer
> seems quite generic and I don't see the need for mentioning the
> "main purpose" here.
Just to describe why I wrote this class. I reconsider it and I think the
comment should not be there (it is also described in ChangeLog). I removed
it.
> - IntervalTimer constructor
> - We should document that "cbfunc" shouldn't be an empty functor.
I added documentation.
> - Can it throw asio::system_error? I was not sure how that could
> happen, but if it really happens:
> - we should catch the exception internally and convert it to our
> own one (we need to hide any asio specific definitions, which is
> the purpose of this wrapper in the first place)
> - we should cover that case in tests.
I misunderstood the asio::deadline_timer library. The constructor won't
throw asio::system_error. I removed the documentation.
> - IntervalTimer destructor: my previous question doesn't seem to be
> addressed in the documentation: "what happens if we destruct
!IntervalTimer before starting a timer?"
If we destruct it before starting a timer, the callback function should
not be called. I wrote a test.
> - setupTimer(): like the constructor, asio::system_error shouldn't be
exposed.
I wrote try-catch to convert asio::system_error to isc::Unexpected and
added documentation. It is hard to modify the library to throw an
exception, so I didn't wrote a test.
> '''asio_link.cc'''
> - IntervalTimerImpl::callback()
> > OK. IntervalTimerImpl::callback() no longer exists. setupTimer()
checks
> > its arguments.
>
> I guess you mean "no longer exits (or asserts)"? BTW with the check
> in setupTimer() I'm okay with the assert() (or may even be a good
> practice, but it's up to you).
It means I removed assertion from IntervalTimerImpl::callback(). I think
throwing an exception is suitable for parameter check, so the code throws
an exception.
> '''asio_link_unittest.cc'''
> - as a general comment, it looks like the added tests make
> ASIOLinkTest unnecessarily big(ger). ASIOLinkTest is already
> pretty complicated due to perform some tricky tests using actual
> socket I/O, while the timer tests don't need anything of these. It
> would be much better to define a different test fixture (say,
> IntervalTimerTest) and enclose all timer related stuff there.
I added a test fixture 'IntervalTimerTest' (partially copied from
ASIOLinkTest). All of all timer related stuff are now in it.
> - there's no need to construct an IntervalTimer::Callback object
> explicitly thanks to the magic of boost::function. e.g., instead
> of:
> {{{
> timer_.setupTimer(IntervalTimer::Callback(
> TimerCallBack(test_obj_)), 1);
> }}}
> we could say:
> {{{
> timer_.setupTimer(TimerCallBack(test_obj_), 1);
> }}}
> This will help make the code simpler and more readable.
I modified the code as you suggested. It is much easier to read.
> - ASIOLinkTest::startIntervalTimer()
> > OK. Almost all of IntervalTimers are now allocated statically, except
in
> > destructIntervalTimer. In the test code we have to delete it.
> > I enclosed it by ASSERT_NO_THROW, is that OK?
> >
> It doesn't address the concern about the exception safety. It's not
> about the case where newing the timer throws an exception. It's about
> an exception triggered after the new before the test terminates. One
> way to make it 100% correct would be to use a smart pointer for the
> itimer, but that would be probably too much in this context; if the
> test throws unexpectedly, the whole program would soon exit anyway, so
> the perfect exception safety wouldn't be worth the code complexity.
> After making the itimers real object whenever possible, my suggestion
> is to ignore the exception safety problem with an explicit comment
> like: "this code isn't exception safe, but we'd rather keep the code
> simpler and more readable as this is only for tests and if it throws
> the program would immediately terminate anyway".
>
> BTW, whether or not adopting this suggestion, these _NO_THROW()s don't
> make sense anyway. I'd remove them.
I removed ASSERT_NO_THROW and added comment as you suggested.
> - the additional tests introduce another 10 seconds of delay. in
> general, imposing a long delay in unit tests is not a good practice
> as unit tests are supposed to be performed "instantly". These types
> of delay have been introduced in our tests already (some of them were
> introduced by myself), and so it's not specific to the timer tests,
> but 10 seconds still look quite substantial. I'd not necessarily
> request it be solved right now, but the timer should eventually have
> finer granularity for the timer duration and use shorter timer
> periods for tests. For the moment I suggest adding some notes about
> this point in comments.
I noted these tests takes long time and this issue should be addressed in
future.
> '''statistics_unittest.cc'''
> - in QueryCountersTest() verbose_mode_ should be initialized to false
> explicitly. Otherwise, it could cause noisy log messages during
> tests depending on the environment (it happened to me).
OK. verbose_mode_ is initialized to false.
> - incrementUDPCounter: I'd test if the counter is initially 0, and
> if it's really incremented by one after counters.inc(). Same for
> incrementTCPCounter, AuthSrvTest::queryCounter{UDP,TCP}.
I added some EXPECTs to these tests to check the counter is initially 0,
and the value is 1 after counters.inc().
> '''ChangeLog'''
> - I couldn't play with the statistics using bindctl just from this
> description. After understanding how it works, I'd suggest revising
> the text as follows:
> {{{
> TBD. [func] y-aharen
> src/bin/auth: Added a feature to count queries and send counter
> values to b10-stats periodically. To support it, added wrapping
> class of asio::deadline_timer to use as interval timer.
> The counters can be seen using the "Stats show" command from
> bindctl. The result would look like:
> ... "auth.queries.tcp": 1, "auth.queries.udp": 1 ...
> Using the "Auth sendstats" command you can make b10-auth send
> the counters to b10-stats immediately.
> (Trac #347, svn rxxxx)
> }}}
> (I used b10-stats in this context instead of generic "statistics
> module" because it would be more helpful for the users)
OK, I changed the text as you suggested.
Thank you again for your review.
--
Ticket URL: <http://bind10.isc.org/ticket/347#comment:13>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list