BIND 10 #2218: update InMemoryZoneFinder::findNSEC3 using memory-efficient version
BIND 10 Development
do-not-reply at isc.org
Thu Sep 20 06:31:29 UTC 2012
#2218: update InMemoryZoneFinder::findNSEC3 using memory-efficient version
-------------------------------------+-------------------------------------
Reporter: | Owner: jinmei
jinmei | Status: reviewing
Type: task | Milestone:
Priority: | Sprint-20120925
medium | Resolution:
Component: data | Sensitive: 0
source | Sub-Project: DNS
Keywords: | Estimated Difficulty: 5
Defect Severity: N/A | Total Hours: 0
Feature Depending on Ticket: |
scalable inmemory |
Add Hours to Ticket: 0 |
Internal?: 0 |
-------------------------------------+-------------------------------------
Comment (by jinmei):
I've not completed full review, but found several substantial issues.
So I'm dumping the current review comments and giving ticket back to
mukund. Please address (or discuss to resolve) these points first.
'''general'''
- According to the commit sequence, this branch doesn't seem to be
developed "test driven". It's not what we should do.
- zone_finder_unittest and faked_nsec3 test have a lot of duplicates.
Please unify them.
'''memory_client.cc'''
- In addNSEC3(), I believe we can (now) simply add the owner name of
the NSEC3 RRset:
{{{#!cpp
ZoneNode* node;
nsec3_data->insertName(mem_sgmt_, rrset->getName(), &node);
}}}
In fact, all tests pass with this version (and if this isn't
supposed to work, it means we don't have sufficient tests).
- I don't like to have something like iterateSHA1 in the zone_finder
code. The data source code is basically supposed to use a higher
level abstraction, the `NSEC3Hash` class. The current code doesn't
only rely on the low level concept, but also rely on in-house SHA1
implementation, which we'd probably replace with Botan.
- The original code takes care of the case where there's no NSEC3 (but
there maybe NSEC3PARAM). Shouldn't we do the same?
- maybe a matter of taste, but this expression doesn't look very
readable (very long and with ?:):
{{{#!cpp
const std::string hlabel = (nsec3_calculate_)(
((labels == qlabels ?
name : name.split(qlabels - labels, labels)),
nsec3_data->iterations,
nsec3_data->getSaltData(),
nsec3_data->getSaltLen());
}}}
I'd introduce a variable to the main expression concise:
{{{#!cpp
const Name& hname = (labels == qlabels ?
name : name.split(qlabels - labels, labels));
const std::string hlabel = (nsec3_calculate_)(
hname, nsec3_data->iterations, nsec3_data->getSaltData(),
nsec3_data->getSaltLen());
}}}
- also maybe a matter of taste, but maybe it's slightly more
lightweight if define `chain` outside the for loop and clear it:
{{{#!cpp
ZoneChain chain;
for (unsigned int labels = qlabels; labels >= olabels; --labels) {
...
//ZoneChain chain; <= instead of this
chain.clear();
}}}
- I'd move the definition of `tree` outside of the for loop:
{{{#!cpp
const ZoneTree& tree = nsec3_data->getNSEC3Tree();
for (unsigned int labels = qlabels; labels >= olabels; --labels) {
...
//const ZoneTree& tree = nsec3_data->getNSEC3Tree();
}}}
- this seems to be unnecessarily expensive:
{{{#!cpp
const ZoneTree::Result result =
tree.find(Name(hlabel + "." + getOrigin().toText()), &node,
chain);
}}}
due to the mix of toText(), string concatenation and name
construction from string. I'd do it:
{{{#!cpp
const ZoneTree::Result result =
tree.find(Name(hlabel).concatenate(getOrigin()), &node,
chain);
}}}
- I'd rename `set` to `rdataset` or `rdset`. `set` sounds too
generic.
- couldn't the construction of `next` be simpler, like this?
{{{#!cpp
ConstRRsetPtr next = (covering_node == NULL) ? ConstRRsetPtr()
:
createTreeNodeRRset(covering_node,
covering_node->getData(),
getClass());
}}}
- this implementation assumes `ZoneNode->getData()` is non NULL and is
the NSEC3 RRset. That should be correct, but could be fragile as it
heavily relies on how the NSEC3 is constructed. I'd be a bit more
proactive, e.g. by asserting the type is NSEC3.
- these comments don't match the actual code any more. please update:
{{{#!cpp
// If the given hash is larger than the largest stored hash or
// the first label doesn't match the target, identify the
// "previous" hash value and remember it as the candidate next
// closer proof.
...
// Otherwise, H(found_entry-1) < given_hash <
H(found_entry).
// The covering proof is the first one (and it's valid
// because found is neither begin nor end)
}}}
This type of mismatch seems to be commonly observed in your
branches. If this is something you often forget to check, please
include in your personal check list for future tasks if that is
mainly updating existing code.
- the non-exact match case seems to have many issues.
- first off, it doesn't seem correct. Consider a name whose hash is
02UDEMVP1J2F7EG6JEBPS17VP3N8I58H. If we do non recursive search
for this name, the covering hash should be
01UDEMVP1J2F7EG6JEBPS17VP3N8I58H, but this implementation actually
returns some bogus (not just incorrect) result.
- secondly, I don't like to expose too much of `DomainTreeNode`
internals. Specifically, I don't like to make predecessor() and
successor() just for this purpose. Likewise, I don't like to
introduce things like getLargestInSubTree() as a public method of
`DomainTreeNode`. In general, I prefer extending the node chain
interfaces for operations that require moving inside the tree.
Also, due to the special structure of the NSEC3 tree, "in sub
tree" property is not really necessary. While exploiting this
fact itself may be controversial, I personally like to exploit it
than tweaking the node class (and this code already exploits some
of the special nature of the NSEC3 anyway).
- Even if this code were accurate, it seems to be unnecessarily
expensive. It always compute predecessor() and successor(), which
are not super cheap. In the vast majority cases we'd have a non
NULL previous node, and we should simply be able to use it in this
case.
--
Ticket URL: <http://bind10.isc.org/ticket/2218#comment:8>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list