BIND 10 #2218: update InMemoryZoneFinder::findNSEC3 using memory-efficient version

BIND 10 Development do-not-reply at isc.org
Fri Sep 21 11:27:27 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      |
-------------------------------------+-------------------------------------
Changes (by muks):

 * owner:  muks => jinmei


Comment:

 Hi Jinmei

 Replying to [comment:8 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.

 Sorry about that. In many cases I was working on the problem at hand
 (which used the method being added), and had to come back to properly add
 testcases.

 > - zone_finder_unittest and faked_nsec3 test have a lot of duplicates.
 >   Please unify them.

 Done.

 >
 > '''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).

 You are right. As we use `ZoneTree::find()` now, there's no need to change
 the first label to uppercase. Many of the review issues are because this
 was a direct translation of the map based `findNSEC3()`, but I've updated
 it now.

 > - 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.

 These have been moved to the `NSEC3Hash` class. I can't think of a better
 way to do it than have a static function there as we deal with raw data.

 > - The original code takes care of the case where there's no NSEC3 (but
 >   there maybe NSEC3PARAM).  Shouldn't we do the same?

 We do in the loader. I am not following where in the original code that
 you are referring to.

 > - 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());
 > }}}

 Updated.

 > - 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();
 > }}}

 Updated.

 > - 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();
 > }}}
 >

 Updated.

 > - 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);
 > }}}

 Updated.

 > - I'd rename `set` to `rdataset` or `rdset`.  `set` sounds too
 >   generic.

 Done.

 > - couldn't the construction of `next` be simpler, like this?
 > {{{#!cpp
 >             ConstRRsetPtr next = (covering_node == NULL) ?
 ConstRRsetPtr() :
 >                 createTreeNodeRRset(covering_node,
 covering_node->getData(),
 >                                     getClass());
 > }}}

 Updated.

 > - 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.

 Added.

 > - 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.
 >   - 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.

 The code was indeed buggy and has been rewritten. A tree walk test has
 also been added which looks for hashes on both sides of each node, and
 also existing nodes (exact matches), both recursive and non-recursive. The
 old comments are also gone.

 >   - 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.

 For this case, I want to disagree. `DomainTree` is more or less a BST with
 walking capability. `predecessor()` and `successor()` are basic operations
 on such a data structure, and if there is the use-case, I don't think we
 should force to keep these hidden. The added methods are operations on
 nodes, and are basic operations. I feel adding them in the node chain
 would not be ideal. I thought of adding a method like
 `getNSEC3CoverNode()` to the node chain, but such things seem to be
 misplaced in the `DomainTree`.

 >     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).

 I don't follow what you mean by exploit here. Do you mean not have the
 tree-of-tree structure? `TreeNodeRRset` gets its name directly from the
 node in the tree-of-trees.

-- 
Ticket URL: <http://bind10.isc.org/ticket/2218#comment:10>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development


More information about the bind10-tickets mailing list