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

BIND 10 Development do-not-reply at isc.org
Fri Sep 21 19:54:51 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):

 Replying to [comment:10 muks]:

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

 I meant this by "original":
 {{{#!cpp
     const NSEC3Map& map = impl_->zone_data_->nsec3_data_->map_;
     if (map.empty()) {
         isc_throw(DataSourceError,
                   "findNSEC3 attempt but zone has no NSEC3 RR: " <<
                   impl_->origin_ << "/" << impl_->zone_class_);
     }
 }}}
 and, as far as I can see, loader doesn't ensure we can skip the same
 check.  See relevant comments for the tests below.

 Rest of my code comments follow::

 '''domaintree.h'''

 - I don't see the need for `getSubTreeRoot()`.  Why was this added?
   (I've not reviewed corresponding tests as I was not sure if we
   really need this method).
 - Why did you change the type of node_count_ to size_t?  I suspect
   sizeof(size_t) can often be 8 for 64-bit machines, and with the
   existence of `needsReturnEmptyNode_` it would make the
   `sizeof(DomainTree)` unnecessarily large.  It can be a waste if we
   support millions of zones.  I admit 'unsigned int' might not be a
   good choice either, though.  Maybe the best one is uint32_t, and
   explain why we specifically choose it.

 '''memory_client.h/cc'''

 - maybe not really related to this branch, but I suspect we shouldn't
   make findZone2() a const member function, because it effectively
   returns a mutable internal state.  Also, it would better to be not
   virtual (so it won't be misleading).  I'd probably choose a
   different name.  And, if it's mainly for tests I'd note that in the
   documentation (if it's expected to be used for general use, I think
   we should reconsider it - returning internal zone data seems to be a
   risky interface).
 - This now-removed comment makes me nervous
 {{{#!cpp
 -    // This variant of findZone() is not implemented and should be
 -    // removed eventually. It currently throws an exception. It is
 -    // required right now to derive from DataSourceClient.
 -    virtual isc::datasrc::DataSourceClient::FindResult
 -    findZone(const isc::dns::Name& name) const;
 }}}
   It said "should be removed eventually", but this branch did the exact
   opposite.  What happened?

 '''treenode_rrset'''

 - I don't see why we need to implement getRRsig() in this branch.  But
   if you wanted to implement it, please be responsible for providing
   tests.  The documentation needed to be updated too. (But I did both
   in #2219, so you don't have to address these in this branch).

 '''zone_finder_unittest.cc'''

 - I'd avoid initializing nsec3_hash_map in the namespace level.  I've
   committed my suggested change to address this (2fdacd8).
 - should this be removed?
 {{{#!cpp
     // This needs to be updated and checked when implementing #2118
 }}}

 - this is invalid if salt_data_2 is empty:
 {{{#!cpp
                  (std::memcmp(&salt_data_2[0], salt_data, salt_len) != 0))
 {
 }}}

 - I don't understand this comment:
 {{{#!cpp
         // We assume that rrsig has already been checked to match rrset
         // by the caller.
 }}}

 - I don't think this test really does what it claims:
 {{{#!cpp
     // Only having NSEC3PARAM isn't enough
     addZoneData(textToRRset("example.org. 300 IN NSEC3PARAM "
                             "1 0 12 aabbccdd"));
 }}}
   because in the actual implementation, "only having NSEC3PARAM"
   enables `NSEC3Data`.  So findNSEC3 actually wouldn't throw.

 - the comment doesn't really seem to be 100% accurate.  It's indeed
   for `InMemoryZoneFinder`, but in this context it's NSEC3 specific.
 {{{#!cpp
 /// \brief Test fixture for the InMemoryZoneFinder class
 class InMemoryZoneFinderNSEC3Test : public InMemoryZoneFinderTest {
 }}}

 - can you add some comments on findNSEC3Walk and its the data?  What's
   the point of the test, meaning of `TestData` member variables, how
   the hash values are chosen (whether they are randomly chosen or
   intended to test some specific case - I suspect the latter, but it's
   not immediately obvious from the definitions).

 '''nsec3hash'''

 Frankly, I don't like this hack.  It breaks some design principles of
 the class (e.g., reusing internal resources for multiple hash
 calculations - for that matter, this branch doesn't update the
 documentation on this).  Also, defining `NSEC3Hash::calculate` for
 SHA1 only seems ad hoc.

 To me, a better approach is to extend the factory interface so that we
 can create an `NSEC3Hash` instance from the algorithm, iterations and
 salt.

 the in-memory implementation would have a function pointer to a
 specific factory instance for the normal and test cases, not the
 calculation function itself.

 '''zone_finder.h'''

 nsec3_calculate_: In general, I don't like to introduce a public or
 protected member variable, especially if it's mutable, as it can
 easily break class integrity due to a careless application or derived
 class implementation.  In this case, if there's no better way to allow
 tests to use a faked calculator, please at least leave comment that
 this protected member variable is only intended for test purposes
 (isn't it?), and other derived class shouldn't try to tweak it.  Also,
 I suspect the in-memory finder class isn't really expected to be
 further derived except for testing.  If that's the case, please also
 document that.

 '''zone_finder.cc'''

 In addition to other points that were already discussed, I've noticed
 the same patter like this repeated:
 {{{#!cpp
             const RdataSet* rdataset = node->getData();
             assert(rdataset != NULL);
             assert(rdataset->type == RRType::NSEC3());

             ConstRRsetPtr closest = createTreeNodeRRset(node, rdataset,
                                                         getClass());
 }}}
 and it makes the method longer and less readable.  I'd introduce a
 helper function to unify the logic:
 {{{#!cpp
 ConstRRsetPtr
 createNSEC3RRset(const ZoneNode* node, const RRClass& rrclass) {
     const RdataSet* rdataset = node->getData();
     // add comment why we can assert these
     assert(rdataset != NULL);
     assert(rdataset->type == RRType::NSEC3());

     return (createTreeNodeRRset(node, rdataset, rrclass));
 }
 }}}
 and replace the above with this:
 {{{#!cpp
             ConstRRsetPtr closest = createNSEC3RRset(node, getClass());
 }}}

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


More information about the bind10-tickets mailing list