BIND 10 #1305: auth NSEC support: some more updates to data source
BIND 10 Development
do-not-reply at isc.org
Wed Oct 19 19:51:57 UTC 2011
#1305: auth NSEC support: some more updates to data source
-------------------------------------+-------------------------------------
Reporter: | Owner: jinmei
jinmei | Status: reviewing
Type: task | Milestone:
Priority: major | Sprint-20111025
Component: data | Resolution:
source | Sensitive: 0
Keywords: | Sub-Project: DNS
Defect Severity: N/A | Estimated Difficulty: 0
Feature Depending on Ticket: | Total Hours: 0
Add Hours to Ticket: 0 |
Internal?: 0 |
-------------------------------------+-------------------------------------
Comment (by jinmei):
Replying to [comment:9 stephen]:
> > Do you mean passing as !DatabaseAccessor?& or as
boost::shared_ptr<!DatabaseAccessor?>&?
> The latter.
>
> > In the latter case we'll have to dereference it to acquire the
ownership anyway for the same reason, so I suspect the actual benefit of
saving the copy is marginal
> Well, there is work to do in incrementing and decrementing a reference
count. If passed by value, a copy is made within the function (causing an
increment of the reference count) then that copy is passed as argument to
the accessor_ copy constructor. Finally, the copy is discarded (a
decrement of the reference count). You are right in the the cost saving
is marginal, but we use shared pointers extensively in BIND 10 and all the
costs mount up.
>
> > (in this specific usage, in particular, I guess the compiler will
combine the multiple copy constructions involved in the function call and
the member variable initialization, and the actual benefit would actually
be zero).
> Bear in mind that a copy constructor could contain code unrelated to the
copy (which may be a bad idea but is not prohibited by the C++ standard),
so if the compiler were to do that it could be break required behaviour.
However, since the boost code is mainly headers, it could be that the
compiler is clever enough to see that there are no external calls and to
optimise the copy away. But we don't know that.
I don't deny your points, but in terms of performance considerations
I'd say
- even dereferencing of a reference of a shared pointer is costly if
we care about the marginal overhead of copying a shared pointer
object because it involves a function call. So, if the overhead of
method calls on a shared pointer object really matters (there may be
some such cases like in the middle packet processing), I'd rather
pass a reference to the pointed object at the higher level of code
(in this example, it would be !DatabaseAccessor&).
- I'd generally rather avoid premature optimizations. I don't object
to making this level of optimization when we are at the stage of
performance tuning and if we know the accumulated overhead around
shared pointers is a real bottleneck via benchmarking. But it's not
now.
- In any case, this specific context isn't performance sensitive at
all - the accessor is expected to be created during initialization
of the server and will be used for quite a long period. In some
cases we'll also use ephemeral accessors, but in that case the
performance wouldn't matter much anyway.
But at the same time, I agree we tend to use shared pointers even when
they don't have to be so. I don't think it good, not necessarily for
performance, but rather due to other disadvantages of shared pointers
such as making it unclear who is actually responsible for the
ownership of the object. So, as a matter of cleanup I think it a good
idea to revisit our use of shared pointers. But that will be a rather
larger task outside the scope of this ticket (and, as you noticed,
this interface is not actually part of this branch).
(In this particular, IMO the best would be to have the factory
maintain the accessor in the form of an auto_ptr and pass
it as in that form or bare pointer, and let DatabaseClient maintain it
in the form of scoped pointer. This way we handle the things safely
with minimally powerful tool. But auto_ptrs are often error prone
also, so it may not be a good practice in the end either...)
> > In general, I'd be careful about passing a shared pointer in the form
of reference because it could often lead to break the "shared" nature of
the object. If the called function handles the passed reference carelessly
(e.g., keep storing it somewhere in the form of reference) it can easily
lead to dangling ownership. But such a discussion would be far beyond the
scope of this ticket.
> I'm not sure I follow your line of reasoning here. A function keeping a
pointer (or reference) to a passed-in object if there is no guarantee that
the object will remain in existence when the pointer/reference is next
used is a problem regardless of the object being passed in. In this case,
there is no guarantee about the lifetime of the shared_ptr object (other
than it will exist for the duration of the call to this method), so the
function shouldn't store a pointer or reference to it.
My point is that passing a reference is more error prone, and the
mixture of (effectively) passing a shared pointer (which implicitly
indicates the object is assumed to be shared) and actually passing it
in the form of reference will increase the risk of errors. In
principle, you're right that the fact that something is passed by
reference indicates the caller controls the ownership, but I'm afraid
the fact that the referenced object is a shared pointer can give the
callee a false sense of safety. This is an exaggerated bad example:
{{{
class Foo {
public:
Foo(shared_ptr<Bar>& barptr) : barptr_(barptr) {
// and barptr_ will be used throughout the lifetime of Foo.
}
private:
shared_ptr<Bar>& barptr_;
};
}}}
but I can imagine a more subtle, but essentially the same, bugs like
this. As I said above, if we are sure that the caller should have the
ownership of the original object, I'd rather pass a reference (or,
suboptimally a pointer if it can be NULL) of the object that the
shared pointer points to, not a reference of the shared pointer; if
the ownership is expected to be shared, I'd rather pass it as a real
shared pointer to clarify the intent, rather than hoping that the
callee understands the intent and behaves accordingly. And,
personally, I don't like to sacrifice the clarity of the intent for
possible performance reasons unless we know the performance bottleneck
is real and substantial in our main usage.
> I'll leave it up to you whether you change the method signature. The
code is OK to merge.
So...for various reasons I won't touch this part and merge the rest of
the code for now. Again, I don't mind revisiting how to use shared
pointer throughout of our code. If you want please create a separate
ticket or trigger a discussion at the dev list.
--
Ticket URL: <https://bind10.isc.org/ticket/1305#comment:10>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list