BIND 10 #1975: implement meta-or-container-of data source
BIND 10 Development
do-not-reply at isc.org
Sat Jun 9 01:07:11 UTC 2012
#1975: implement meta-or-container-of data source
-------------------------------------+-------------------------------------
Reporter: | Owner: jinmei
jinmei | Status: reviewing
Type: task | Milestone:
Priority: | Sprint-20120612
medium | Resolution:
Component: data | Sensitive: 0
source | Sub-Project: DNS
Keywords: | Estimated Difficulty: 9
Defect Severity: N/A | Total Hours: 0
Feature Depending on Ticket: |
Add Hours to Ticket: 0 |
Internal?: 0 |
-------------------------------------+-------------------------------------
Comment (by jinmei):
'''design/general'''
- I made a few editorial/style cleanups.
- as for the build issue due to EXPECT_EQ, I tentatively fixed it
using EXPECT_TRUE and operator==. If you want please override it.
- (note: I'm not requesting a change to this branch by this). While
it's understandable to introduce the trick with `DataSourcePair` to
avoid handling `DataSourceClientContainer`, it seems to make the
code fragile; we need to be careful about the integrity between the
bare pointer and its container (see also the related note about
`DataSourceInfo` below - maybe we could mitigate it by imposing some
restrictions to the access of `DataSourceInfo`). This seems to me
to indicate we need more flexibility for `DataSourceClientContainer`
as we discussed it in #1207 (see the second bullet for the factory.h
comments of http://bind10.isc.org/ticket/1207#comment:12).
If `DataSourceClientContainer` is completely abstract, we can more
easily introduce a test version, without requiring tricky dy load
stuff, and we could make its user like the `Container` (as defined
in this branch) much simpler. But even if this idea makes sense,
that's certainly beyond the scope of this ticket.
- I see general confusion between the concept of "data sources" and of
"data source clients". Throughout this branch, things tend to be
called "data source" while they are actually used/defined in terms
of their role/nature. Maybe one underlying issue is that adding
`Client` tends to make the class/variable names longer, and it
probably acts as a barrier against giving them better names. I
don't know what's the best way to get a better balance, but I
suggest revisiting the names that have just "data source" to see
whether we can make it less confusing and yet not so verbose.
- It's not clear to me what's the purpose of the base `Container`
class. In the test, you introduce a direct derived class of
`ConfigurableContainer`, so essentially the pure base class is just
a redundant layer. While it might look cleaner in terms of the
object oriented design, if it's basically a compromise for better
testability (and the actual inheritance for the test is actually
quite ugly anyway), I'm not sure if the purity is worth the
overhead and complexity due to the additional layer.
- On a related point, I'm concerned about the protected members of
`ConfigurableContainer`, and, in particular, `data_sources_`. Such
a mutable bare member variable makes the class design very fragile;
a naively implemented new derived class can break implicit/explicit
assumptions in the base class, and can break applications that use
the base class interface on top of the assumption. If it's only for
better tests and it's not expected to be derived in other way, I can
probably live with it, but this comment seems to suggest that it's
actually (possibly) assumed to be derived by other general-purpose
classes:
{{{#!cpp
/// Also, derived classes might want to create the data sources
/// in a different way.
}}}
If that's the intent, I'd like to make the class design more
robust so a derived class cannot easily break the assumptions in the
base class. If it's actually not intended and
`ConfigurableContainer` is only expected be derived for testing
purposes, I'd like to clarify that in the comment, which would
strongly discourage others to introduce a derived class of it.
'''container.h'''
- I'd like to clarify in the doc that a container is expected to
contain data source clients for the same single RR class (is my
understanding correct?).
- ConfigurableContainer: is it supposed to be "inheritable" in general?
- ConfigurableContainer::configure: it seems that the type of
'configuration' can be a reference not a pointer (then we don't have
to worry about the case it's NULL).
- ConfigurableContainer::search: maybe 'find' is a better name for
compatibility with STL containers (in terms of naming convention)?
- ConfigurableContainer::search: I'd clarify in the doc the lifetime
and ownership of the returned data source (client) (in the form of a
pointer). They are valid (only) as long as the container is alive
(without being reconfigured), and the ownership isn't transferred to
the caller (so the caller doesn't have to / should not delete it),
right? I think it should be explicitly clarified.
- ConfigurableContainer::data_sources_: better alternative? If not,
at least emphasize more strongly that it shouldn't be used for other
purposes (and maybe the class shouldn't even be inherited by others
except for tests).
- ConfigurableContainer::DataSourceInfo: isn't it better to introduce
a constructor to initialize the struct than letting the caller
assign them one-by-one? Also, if it's supposed to be read-only
after construction, I'd make members const. Together, we can ensure
the integrity of the struct as a whole. (hmm, maybe it doesn't work
really well if we want to store it in the vector?)
- ConfigurableContainer::dataSources(): per our naming convention, it
should probably be named getDataSources
'''container.cc''
- - ConfigurableContainer::configure: (minor) is "recyclation" an
English word? My dictionaries don't seem to have it (not critical
though, I think I understand what this means in this context anyway)
- ConfigurableContainer::configure: what if config is a NULL pointer?
- ConfigurableContainer::configure: is `TypeError` the only possible
exception that can be thrown from the element module (excluding
bad_alloc-like things)?
- ConfigurableContainer::search: use of dynamic allocation. Also
about performance consideration in general.
- ConfigurableContainer::search: I don't understand why we need the
curly braces for each case. Can't we do it like this?
{{{#!cpp
case result::SUCCESS:
// If we found an exact match, we have no hope to getting
// a better one. Stop right here.
// TODO: In case we have only the datasource and not the
finder
// and the need_updater parameter is true, get the zone
there.
return (SearchResult(info.data_src_, result.zone_finder,
name.getLabelCount(), true));
}}}
- ConfigurableContainer::getDataSource: why '::' before
`ConstElementPtr`?
{{{#!cpp
ConfigurableContainer::getDataSource(const string& type,
const ::ConstElementPtr&
configuration)
}}}
not incorrect, but unnecessary and looks quite awkward/confusing to
me. At least as far as I know we normally don't add it in such a
case.
'''container_unittest'''
- I'd name it `TestDS` differently in terms of differentiating "data
source" and "data source client'. At the risk of sounding verbose,
TestDataSourceClient (I personally don't like the abbrev of "DS"
because it could be confused with the DS RR type) or if we want to
make it short, maybe TestDSC.
- is this safe?
{{{#!cpp
set<Name>::const_iterator it(zones.upper_bound(name));
--it;
}}}
what if upper_bound returns begin() or end() iterator?
- about ds_count: this hardcoding can be avoided this way:
{{{#!cpp
const char* ds_zones[][3] = {
...
};
const size_t ds_count = (sizeof (ds_zones) / sizeof (ds_zones[0]));
}}}
This will be more robust when you change the number of data source
(client)s.
- considering a bare pointer as boolean is against our style
guideline:
{{{#!cpp
// Comparing with NULL does not work
ASSERT_TRUE(ds);
}}}
Though awkward, our usual workaround in this case is:
{{{#!cpp
// Comparing with NULL does not work
ASSERT_NE(static_cast<const TestDS*>(NULL), ds);
}}}
(or at least this one works, right?)
{{{#!cpp
// Comparing with NULL does not work
ASSERT_TRUE(ds != NULL);
}}}
- multiConfiguration: what's `ds3`? `ds_[2]`?
{{{#!cpp
// The ds3 is empty. We just check that it doesn't confuse
// us. Fall through to the case 0.
}}}
- multiConfiguration: what's '2' in 'as 2'? `ds_[1]`?
{{{#!cpp
// It is the same as 2, but we take from the first one.
// The first one to match is the correct one.
}}}
- selfTest: I'd adding cases like these:
{{{#!cpp
EXPECT_EQ(result::NOTFOUND, ds_[0]->findZone(Name("aaa")).code);
}}}
(see the comment about upper_bound above - hmm, the sub.example.org
case seems to indicate --end() works as expected. but is it
guaranteed?)
- singleDSBestMatch: this comment is incorrect (seemingly a naive
copy-paste):
{{{#!cpp
// When asking for a sub zone of a zone there, we get nothing
// (we want exact match, this would be partial one)
positiveResult(container_->search(Name("sub.example.org.")),
ds_[0], Name("example.org"), false, "Subdomain match");
}}}
- multiExactMatch: hardcoding of 4 can be avoided:
{{{#!cpp
for (size_t i(0); i < sizeof(test_names) / sizeof(test_names[0]); ++i)
{
}}}
and should be more robust against future extensions. same for
multiBestMatch.
- wrongConfig: technically, this test is not ideal
{{{
// Still untouched
checkDS(0, "test_type", "{}");
}}}
because the whole new config is broken in the test. Ideally, we
first include a validly configured data source (client) followed by
a broken one, and see the valid one doesn't happen in the config and
the old one is intact.
--
Ticket URL: <http://bind10.isc.org/ticket/1975#comment:9>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list