BIND 10 #2225: Implement counters into Xfrout (3/3)
BIND 10 Development
do-not-reply at isc.org
Fri Dec 14 10:14:17 UTC 2012
#2225: Implement counters into Xfrout (3/3)
-------------------------------------+-------------------------------------
Reporter: naokikambe | Owner: muks
Type: enhancement | Status:
Priority: medium | reviewing
Component: xfrout | Milestone:
Keywords: | Sprint-20121218
Sensitive: 0 | Resolution:
Sub-Project: DNS | CVSS Scoring:
Estimated Difficulty: 7 | Defect Severity: N/A
Total Hours: 0 | Feature Depending on Ticket:
| Add Hours to Ticket: 0
| Internal?: 0
-------------------------------------+-------------------------------------
Changes (by naokikambe):
* owner: naokikambe => muks
Comment:
Hello, thank you for reviewing.
Replying to [comment:28 muks]:
> 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.
I agreed. Let's focus on reviwing `trac2225_statistics`.
> 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.
In one bind10 module, it is NOT indented that the different spec files are
read in the above way. Maybe I think counters in `counter3` would be
cleared by ``counter1.clear_counters()``.
However in different modules as followings, it is indented that each spec
file is read individually. That is, ``counter1.clear_counters()`` doesn't
clear counters in ``counter2``, and vice versa.
Module Foo (b10-foo):
{{{#!python
from isc.statistics import Counter
counter1 = Counter("/path/to/foo.spec")
counter1.clear_counters()
}}}
Module Bar (b10-bar):
{{{#!python
from isc.statistics import Counter
counter2 = Counter("/path/to/bar.spec")
counter2.clear_counters()
}}}
So if we should consider such equivalence in the above former case, I also
think we would introduce a factory method or something as you mentioned.
Sorry, please suggest whether we should or not. If yes, I'd like to stop
reviewing and try to redesign the interface of the class.
> 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.
Ok, I've renamed:
{{{
d4e066a [trac2225_statistics] rename 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?
Not defined. I've corrected documentation.
{{{
6a4b958 [trac2225_statistics] correct documentation about an undefined
method
}}}
> * 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()`?
Because we don't need to relate `_inc_counter()` with `self`, I did so.
There is no reason other than this.
> * `Counter` class needs documentation (most of the module documentation
should be moved here)
I've added documentation but it might need to be added more.
{{{
4b368b5 [trac2225_statistics] correct and add documentation of the
Counters class
}}}
> * `Counter.__init__()` should be documented to indicate what happens
when `spec_file_name` is passed, and in the case where it is `None`.
I've documented about the cases that the spec file is specified and
omitted.
{{{
dbf92ea [trac2225_statistics] document about cases when a spec file is
specified and omitted
}}}
> * 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.?
It is necessary because counters can be incremented by the different
threads. So it should as you mentioned. Also a timer cannot be update if
it's disabled.
{{{
2f7080c [trac2225_statistics] synchronize when accessing self._disabled
}}}
> * 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)
> }}}
I've added a helper method _concat() and replaced with it.
{{{
301ccaf [trac2225_statistics] add a helper method _concat and its test
}}}
> * 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.
I've added step in kwarg in inc() and directly used it in dec().
{{{
4ae14bd [trac2225_statistics] add step as kwarg into inc() and use it in
dec() with step=-1
}}}
> * 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
> }}}
No, it was not neccesary. Thanks.
{{{
7ec3307 [trac2225_statistics] remove an unnecessary try/expect statement
}}}
> * 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])
> }}}
I've removed the format string, thanks.
{{{
0d0de6a [trac2225_statistics] remove an unnecessary formating
}}}
> * 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).
Sorry, I couldn't understand why `_get_counter()` should add. I think
`_get_counter()` should just return the current value and should not
change the statistics data. OTOH `_set_counter()` and `_inc_counter()` are
intended for adding an entry into statistics data if there is not.
`_get_counter()` is not indended to be used before the counter is
incremented. It's mostly for a testing purpose.
> * 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()`.
I decided to use datetime.now() because of the following python reference:
http://docs.python.org/3.2/library/datetime.html#datetime.datetime.now
{{{
supplies more precision than can be gotten from going through a
time.time() timestamp
}}}
But we can use timedelta.total_seconds() instead of such seconds
computation. I've revised the code.
{{{
868558c [trac2225_statistics] use timedelta.total_seconds() instead of
redundant computation
}}}
> * `Counter.stop()` documentation should say what units of time (seconds,
microseconds, etc.)
I've updated documentaion.
{{{
1f05684 [trac2225_statistics] update document of Counters.stop()
}}}
> * 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've removed 'else', thanks.
{{{
289118e [trac2225_statistics] remove 'else' statement
}}}
> * I suggest renaming `Counter.start()` to indicate that it is a timer
that is started, i.e., `Counter.start_timer()`.
I've renamed start()/stop(), thanks.
{{{
db1ad53 [trac2225_statistics] rename start()/stop() to
start_timer()/stop_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.
I've renamed it to `clear_all()`, thanks. But I left documentation about
the above discussion on singleton.
{{{
bfb0225 [trac2225_statistics] rename to clear_all()
}}}
> * 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]]
> }}}
I've added documents. Is it more helpful?
{{{
2aa30dc [trac2225_statistics] add helpful comments to the complicated
expression
}}}
> * 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
> }}}
It's not correct. I've updated.
{{{
4688552 [trac2225_statistics] update document as it is
}}}
> * Is `get_statistics()` a better name than `dump_statistics()` (as it
returns a dict)?
I've renamed.
{{{
4661800 [trac2225_statistics] rename dump_statistics() to get_statistics()
}}}
> 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.
Thank you very much! I've also updated documentation above but it might
not be enough. Please review again.
Regards,
--
Ticket URL: <http://bind10.isc.org/ticket/2225#comment:29>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list