BIND 10 #2225: Implement counters into Xfrout (3/3)

BIND 10 Development do-not-reply at isc.org
Thu Dec 13 11:43:02 UTC 2012


#2225: Implement counters into Xfrout (3/3)
-------------------------------------+-------------------------------------
            Reporter:  naokikambe    |                        Owner:
                Type:  enhancement   |  naokikambe
            Priority:  medium        |                       Status:
           Component:  xfrout        |  reviewing
            Keywords:                |                    Milestone:
           Sensitive:  0             |  Sprint-20121218
         Sub-Project:  DNS           |                   Resolution:
Estimated Difficulty:  7             |                 CVSS Scoring:
         Total Hours:  0             |              Defect Severity:  N/A
                                     |  Feature Depending on Ticket:
                                     |          Add Hours to Ticket:  0
                                     |                    Internal?:  0
-------------------------------------+-------------------------------------
Changes (by muks):

 * owner:  muks => naokikambe


Comment:

 Hi Kambe san

 We decided during the daily status call yesterday that first we'll first
 review just the `trac2225_statistics` branch. After it is reviewed and
 merged, the other branch `trac2225_xfrout` can be reviewed, either in this
 ticket or as part of another ticket if required. So, here is my first
 review of the `trac2225_statistics` branch.

 First, I don't understand if `Counter` is expected to behave somewhat like
 a singleton, or I don't follow why some code is written the way it is (the
 `_Statistics` class, and some `Counter` initialization outside
 `__init__()`). Is it expected to create equivalent `Counter` objects,
 based on what spec file is passed? Suppose that you have the following
 code:
 {{{
   from isc.statistics import Counter
   counter1 = Counter("/path/to/foo.spec")
   counter2 = Counter("/path/to/bar.spec")
   counter3 = Counter("/path/to/foo.spec")
   counter1.clear_counters()
 }}}

 Are `counter1` and `counter3` supposed to be equivalent? They aren't based
 on the current code, but are they intended to be equivalent? With the last
 statement in the block of code above, are counters in `counter3` also
 supposed to be cleared? (I think they are not, currently). If such
 equivalence is desired, it's better to rewrite it such that there is a
 factory method in the `counter` module, that returns a `Counter` object
 based on the passed spec file.

 I am wondering about the above, because a singleton was in use before and
 I want to know what the intention was.

 Assuming that the code is as-is, the following are my comments:

 * I suggest renaming the class to the plural form (`Counters`) as it
 manages multiple counters.

 * The module's documentation says that `init()` must be called. Where is
 `init()` defined?

 * Some methods are declared at static scope to the module, rather than as
 a part of `Counter` class itself. We can indicate them as private by
 prefixing an underscore. Is there a reason why `Counter.inc()` calls
 `_inc_counter()` and not `self._inc_counter()`?

 * `Counter` class needs documentation (most of the module documentation
 should be moved here)

 * `Counter.__init__()` should be documented to indicate what happens when
 `spec_file_name` is passed, and in the case where it is `None`.

 * What is the purpose of `Counter._rlock`? If it is necessary, shouldn't
 access to `Counter._disabled` also be synchronized by using it, in
 `.enable()`, `.disable()`, `.inc()`, `.dec()`, etc.?

 * The following repeated code is best moved to a function, so that we have
 a single place to update if we change how the key is computed from the
 args.
 {{{
         identifier = '/'.join(args)
 }}}

 * If `Counter.inc()` and `.dec()` are largely similar, except for the
 `step`, they should be unified by moving most of the code to a common
 function.

 * In `_add_counter()`, is the `try` necessary?
 {{{
     try:
         isc.config.find_spec_part(spec, identifier)
     except isc.cc.data.DataNotFoundError:
         # spec or identifier is wrong
         raise
 }}}

 * Is there a test for the reason why the format string is used here:
 {{{
     spec_ = isc.config.find_spec_part(
         spec, '%s' % identifier.split('/')[0])
 }}}

 * The behavior of `_set_counter()`, `_get_counter()` and `_inc_counter()`
 seem inconsistent when `identifier` isn't already known. `_set_counter()`
 and `_inc_counter()` both add it if necessary, but `_get_counter()`
 doesn't (and throws).

 * If the timer sets the delta time in seconds, isn't it simpler to use
 `time.time()` instead of `datetime` and `timedelta`? It would also avoid
 the `timedelta` to seconds computation in `_stop_timer()`.

 * `Counter.stop()` documentation should say what units of time (seconds,
 microseconds, etc.)

 * In `Counter.stop()`, I suggest changing it so it returns upon
 `isc.cc.data.DataNotFoundError` instead of using the `else`, but it's just
 a matter of personal style I guess. Please consider it and decide what you
 prefer best.

 * I suggest renaming `Counter.start()` to indicate that it is a timer that
 is started, i.e., `Counter.start_timer()`.

 * I also suggest renaming `Counter.clear_counters()` to `Counter.clear()`
 or `.clear_all()` (see also the suggestion above about renaming the class
 to `Counters`). I don't know if `Counter` is intended to have any
 singleton behavior, but if it does, its doc should also be updated to
 indicate that.

 * The expression below should be commented (I see what it does, but a
 comment would help a reader quickly understand). You may be able to get
 this from the `args` argument itself rather than splitting `identifier`.
 Also as I mentioned above, it's best to do such key computation in a
 separate method so it can be understood and updated easily.
 {{{
                 '/'.join(identifier.split('/')[0:-1]))\
                 [identifier.split('/')[-1]]
 }}}

 * In `Counter.dump_statistics()`, is the comment always correct?
 {{{
         # If self.statistics_data contains nothing of zone name, it
         # returns an empty dict.
         if self._perzone_prefix not in statistics_data:
             return statistics_data
 }}}

 * Is `get_statistics()` a better name than `dump_statistics()` (as it
 returns a dict)?

 Locally I also updated the module documentation to make it more clear, but
 now I think it's best we address the comments above first. I'll update the
 resulting docs after that which you can review.

-- 
Ticket URL: <https://bind10.isc.org/ticket/2225#comment:28>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list