BIND 10 #2836: update in-memory zone loading so it can work with shmem segment

BIND 10 Development do-not-reply at isc.org
Wed May 8 22:09:03 UTC 2013


#2836: update in-memory zone loading so it can work with shmem segment
-------------------------------------+-------------------------------------
            Reporter:  jinmei        |                        Owner:
                Type:  task          |  jinmei
            Priority:  high          |                       Status:
           Component:  data source   |  reviewing
            Keywords:                |                    Milestone:
           Sensitive:  0             |  Sprint-20130514
         Sub-Project:  DNS           |                   Resolution:
Estimated Difficulty:  4             |                 CVSS Scoring:
         Total Hours:  0             |              Defect Severity:  N/A
                                     |  Feature Depending on Ticket:
                                     |  shared memory data source
                                     |          Add Hours to Ticket:  0
                                     |                    Internal?:  0
-------------------------------------+-------------------------------------

Comment (by jinmei):

 '''other !MemorySegmentGrown cases'''

 I was wrong, and we'd need some more checks for the
 `MemorySegmentGrown` exception.

 - First is `ZoneData::create()`.  Any of `ZoneTree::create`,
   `ZoneTree::insert`, and direct `MemorySegment::allocate()` can
   result in `MemorySegmentGrown`.  In this case it's probably better
   to catch the exception and retry in `ZoneData::create()` (and
   document that this factory doesn't throw `MemorySegmentGrown`)
 - Regarding this, we need some additional tricks for general exception
   safety: `SegmentObjectHolder` cannot simply call destroy() with the
   stored `obj_`, because it may be remapped by the time of the call to
   destroy().
 - `loadZoneDataInternal` also has to be aware that the address
   returned by `holder.get()` might be remapped after the completion of
   load.

 '''others'''

 - as usual, I made some trivial/minor changes.  they are basically
 - editorial/style matters.
 - It's probably worth clarifying the `MemorySegmentGrown`
   consideration for `DomainTree::insert()` in its documentation.  That
   is, this method can throw `MemorySegmentGrown`, and (as already
   documented) as it doesn't provide the strong guarantee, some
   internal nodes may have been added to the tree by the time of
   exception, and they are not removed from the tree due to the
   exception.  But the data integrity shouldn't be broken, so a retry
   (or possibly, though less likely, a few retries) of insert() should
   succeed and provide the originally expected result.

 '''zone_data_updater.cc'''

 - not critical, but is there a reason for extracting `addInternal` as
   a separate method?  It's pretty small and only called from add().
 - add(): I'm not sure if we want to do `set/clearNamedAddress` in
   every call to the method.  This is relatively expensive, yet
   should normally be unnecessary (`MemorySegmentGrown` is a possible
   but very rare event).  I think it's better to set the address in the
   constructor of `ZoneDataUpdater`, and clear it in its destructor.
 - whether it's in add() or the constructor, there's a very slight
   chance that `setNamedAddress()` itself causes address remapping.
   In #2850 we are discussing making it safer/more convenient.
   You may want to use the result (and in any case you may have to
   update this branch if it causes interface change), or otherwise
   you'll have to call `getNamedAddress()` immediately after
   `setNamedAddress()` to make sure the address is really the latest
   one.
 - In #2850 we updated the interface of `getNamedAddress()`  This
   branch will have to be updated due to that, or you may want to
   cherry-pick 68343c845a46a9be3f38c38388ec02a8bb4ef884 (which
   I believe is enough, and it won't be affected in the rest of the
   #2850 review process).

 '''zone_data_updater.h'''

 - Do we really need to expose zone_data_ as a protected member
   variable?  See below for the relevant discussion, but even if we
   really need to allow a derived class to access/modify `ZoneData`
   directly, I'd like to protect integrity as much as possible.  That
   is, unless we need to allow derived classes to modify zone_data_
   (the pointer value itself, not the zone data it points to), I'd only
   allow them to access it via an accessor:
 {{{#!cpp
 protected:
     // zone_data_ itself is still private
     ZoneData* getZoneData() { return (zone_data_); }
 }}}

 '''zone_data_updater_unittest.cc'''

 - memory_segment_mapped will only be available if `--with-shared-memory`
   is specified.  You'll need something like
   10386454c422828a5d46a3b927b1c284e6216372.

 '''zone_data_updater_unittest.cc'''

 - to be very safe it would be better to define a virtual destructor
   for `SegmentCreator`.
 - according to the code it should be possible to use the parameter
   type for ZoneDataUpdaterTest as const:
 {{{#!cpp
 class ZoneDataUpdaterTest : public ::testing::TestWithParam<const
 SegmentCreator*> {
 }}}
   Although it somehow didn't compile in my environment.
 - Likewise `test_segment_creator` etc should be able to be const
 {{{#!cpp
 TestSegmentCreator test_segment_creator;
 }}}
   and we shouldn't need cast
 {{{#!cpp
 INSTANTIATE_TEST_CASE_P(TestSegment, ZoneDataUpdaterTest,
                         ::testing::Values(static_cast<SegmentCreator*>(
                             &test_segment_creator)));
 }}}
   But these don't seem to work in my environment either.
 - `TestZoneDataUpdater`: if I understand the tests correctly, I
   believe we can do the tests without this: we'd first create
   `ZoneData` in `ZoneDataUpdaterTest`, set it in the memory segment
   with a name, and let the tests get the zone data when necessary
   via (maybe a wrapper of) `getNamedAddress()`.  This will certainly
   make the test setup more complicated, but I personally would like to
   pay this cost if the alternative is to provide a mutable accessor
   which wouldn't be necessary otherwise.  With this approach, we
   shouldn't even need the `getZoneData()` protected method mentioned
   above, let alone making `zone_data_` itself protected.
 - `ZoneDataUpdaterTest`: is there a reason `mem_sgmt_` is a shared
   pointer, not scoped?
 - `ZoneDataUpdaterTest` constructor: technically this doesn't seem to
   be exception safe:
 {{{#!cpp
         updater_(new
                  TestZoneDataUpdater(*mem_sgmt_, zclass_, zname_,
                                      *ZoneData::create(*mem_sgmt_,
 zname_)))
 }}}
   if constructing `TestZoneDataUpdater` throws.  same for
 `clearZoneData()`.
 - `ZoneDataUpdaterTest` destructor: as far as I can see `updater_`
   should be always non NULL here:
 {{{#!cpp
         if (updater_) {
             ZoneData::destroy(*mem_sgmt_, updater_->getZoneData(),
 zclass_);
         }
 }}}
 - `MappedSegmentCreator::cleanup`:
 `boost::interprocess::file_mapping::remove`
   is probably better than unlink.  It would be more portable (at least
   to the extent of the theory that Boost is expected to be portable),
   and it also seems to have some consideration on mmap specifics (and
   so safer).
 - `manySmallRRsets`: is this guaranteed, or is this just a guess?  I
   thought we cannot completely predict the grow timing as it highly
   depends on the boost implementation internal.  If this is a guess,
   I'd clarify the wording accordingly as it's not clear to me.
 {{{#!cpp
 // Some of the grows will happen inserting the RRSIG, some with the TXT.
 }}}

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


More information about the bind10-tickets mailing list