BIND 10 #2435: implement datasrc version of RRsetCollection
BIND 10 Development
do-not-reply at isc.org
Thu Jan 10 22:04:26 UTC 2013
#2435: implement datasrc version of RRsetCollection
-------------------------------------+-------------------------------------
Reporter: jinmei | Owner:
Type: task | jinmei
Priority: medium | Status:
Component: data source | reviewing
Keywords: | Milestone:
Sensitive: 0 | Sprint-20130122
Sub-Project: DNS | Resolution:
Estimated Difficulty: 4 | CVSS Scoring:
Total Hours: 0 | Defect Severity: N/A
| Feature Depending on Ticket:
| loadzone-ng
| Add Hours to Ticket: 0
| Internal?: 0
-------------------------------------+-------------------------------------
Comment (by jinmei):
'''design issues'''
I've thought more about the tradeoffs between having the updater
create a collector (what the latest version of the branch does) and
constructing a collector using an updater (what the previous version
does).
The former has some negative points. First, I'd generally like to
avoid increasing the responsibility of a class (thus making it more
monolithic) simply because we see it convenient because it will make
the class less maintainable. And, in this particular, I'd also be
concerned that the updater will have two similar interfaces:
`getFinder()` and `getRRsetCollection()`. Such overlap seems to
suggest some clarification is needed.
On the other hand, the main advantage of this approach is that it
allows each specific datasrc implementation to customize internal
details of the collection. When I first mentioned this approach, I
thought it was more advantageous when supporting zone iteration, but
on second thought I'm not so sure. It may suffice to make it possible
to create a zone iterator from an updater. It would be cleaner in
terms of the overlap issues explained above.
There are, however, still some tricky relationships between a
particular (DB-based in particular) data source implementation and the
updater's `RRsetCollection`. I suspect we won't be able to run
multiple iterators (of a collection) at the same time, at least with
SQLite3, and probably with other types of DB. It'd also be impossible
to make further updates while an iterator is running. So I guess we
need to impose some usage restriction, preferably as part of the
behavior, not only by documentation. And I guess it's easier to do
such control if a specific data source implementation can customize
the collection details.
At this moment, I'm still a bit inclined to allow the per-datasrc
customization, but I'm not very confident about it.
I don't know how you reached the conclusion of adopting the current
design as you didn't say anything about it in your comment, but these
design considerations and why we finally ended up the current
design/restrictions should be documented in detail.
'''The derived RRsetCollection class implementation'''
At least for now, it's not specific to the DB-based data source, and,
would work for an in-memory updater if/when we implement it, too. It
may even be the case for a future version with the iteration support.
So I'd introduce an intermediate base collection class that works as
the default for all data source implementations.
Also, as partly discussed above, this `RRsetCollection` will have non
trivial restrictions, not only that it shouldn't be used after the
originating updater is destroyed:
- Strange things will happen if more changes are made after the
collection is constructed, especially about the iterator. One way
to prevent it is to forbid further updates once `RRsetCollection` is
created. At least for the purpose of post-load check, this
restriction is acceptable.
- I suspect it won't work after commit, even if the updater is still
alive.
- use of multiple instances of collection may have some restrictions.
for example, iterator can work in only one of them in the case of
DB-based data sources; on the other hand, in-memory version probably
doesn't have this restriction.
I may be wrong about some of these, so please first examine these
points carefully. Then at least document these. And, preferably,
(after writing tests) the restrictions are enforced in the
implementation (e.g, by throwing an exception in the case of invalid
usage case).
And, now, revisiting the point I raised in
http://bind10.isc.org/ticket/2435#comment:12
I guess the reason for returning a shared pointer is to allow creating
multiple `RRsetCollection` instances. If that's the reason, the
question is whether we want to allow it and/or it makes sense. As
discussed above, it's mostly ineffective to create multiple collection
instances for DB-based data sources because they won't be usable at
the same time (if we assume the general case where iterators might be
used). On the other hand, in-memory version could be a bit more
flexible, and there may be valid cases to create and use multiple
collection instances at the same time.
So we have several choices. One simple way is to restrict the
creation of collection only once per updater. In that case we
shouldn't need to return a shared pointer. Another possibility is to
allow specific derived classes to be flexible when they can, so the
application can use the extended feature if it instantiates that
particular derived version of the updater and collection. In either
case, the base class interface needs to have the most strict
restrictions, though. And all these things should be documented.
'''database_unittest.cc'''
- about the TODO: I think in this case it's okay. But this affects
the characteristic of the datasrc ('s updater) version of
`RRsetCollection`. That is, this collection consists of RRs of the
corresponding zones, including "glue" RRs below a delegation zone
cut, but not external ones like those subject to DNAME substitution
or complete outside of the zone's name space. So, specifically, not
all records added through the updater may necessarily be found by
the collection's find(). That should be documented.
{{{#!cpp
// TODO: "below.dname.example.org." with type A does not return the
// record (see top of file). It needs to be checked if this is what
// we want.
rrset = this->collection->find(Name("below.dname.example.org"),
this->qclass_, RRType::A());
// Is this correct behavior?
EXPECT_FALSE(rrset);
}}}
'''rrset_collection_base.h'''
- The `FindError` class: I've seen mixed styles for exception classes
mainly used with a particular class (like this): define exception
class as the main class and define the exception outside of it.
Previously I didn't have a strong opinion either way except that the
style should be unified, but I'm now more inclined to the latter
style. A subclass like this knows too much internal detail of the
enclosing class; it's effectively defined as a friend of the
encloser and has all the power of the friend, referring to or
modifying its private variables, etc. Obviously that's too much for
exception. All we need is to clarify the context relationship
between these two, and the usual tool for it is namespaces.
(Unfortunately) we normally do not use a separate namespace per
class basis, so we cannot take that approach, but I don't think this
can be used to allow such intrusion of class integrity. So, in
conclusion, I suggest we define this exception outside of
`RRsetCollectionBase` and name it something like
`RRsetCollectionError`. (We should also discuss it and eventual
unification of the style, but that's beyond the scope of this task).
- This doesn't seem to be sufficient. What happens if these types is
given? Why can't we handle them? What will happen in future
versions?
{{{#!cpp
/// This method's implementations currently are not specified to
/// handle \c RRTypes such as RRSIG, NSEC3, ANY, or AXFR.
}}}
- This needs documentation.
{{{#!cpp
typedef boost::shared_ptr<RRsetCollectionBase> RRsetCollectionPtr;
}}}
--
Ticket URL: <https://bind10.isc.org/ticket/2435#comment:16>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list