BIND 10 #2207: define and implement (datasrc::memory::)ZoneUpdater class
BIND 10 Development
do-not-reply at isc.org
Tue Oct 16 21:56:25 UTC 2012
#2207: define and implement (datasrc::memory::)ZoneUpdater class
-------------------------------------+-------------------------------------
Reporter: | Owner: jinmei
jinmei | Status: reviewing
Type: task | Milestone:
Priority: | Sprint-20121023
medium | Resolution:
Component: data | Sensitive: 0
source | Sub-Project: DNS
Keywords: | Estimated Difficulty: 7
Defect Severity: N/A | Total Hours: 0
Feature Depending on Ticket: |
background zone loading |
Add Hours to Ticket: 0 |
Internal?: 0 |
-------------------------------------+-------------------------------------
Comment (by jinmei):
Replying to [comment:7 vorner]:
> > If you can come up with an idea on how to do it cleanly, please make
> > it happen within this branch (I've not fully thought about it and
> > haven't had a specific idea). If not, just keep the current design at
> > the moment and defer the further design cleanup to a later phase.
>
> I don't think the interface itself is problematic. How I'd see it is:
> * With the Local versions, we pass the load_action, it used to load
data into
> the memory. Just as it is now.
> * In case of the shared memory, the load_action is ignored. The updater
(now
> renamed to reloader) asks the memory manager for the data by the
origin and
> class, then waits for confirmation and maps the shared memory to the
address
> space.
> * In the memory manager, we just reuse the „local“ reloader on top of
the
> shared segment.
>
> Or did I miss something why this couldn't work?
Hmm, it sounds not as bad as I previously thought. I cannot be sure
until we actually try to cover other cases like the share memory
version, but for now I'm fine with this.
> > - in retrospect `ZoneUpdater` (and file name of zone_updater.xx) might
> > not be a good choice because it could be confused with
> > `datasrc::ZoneUpdater`. If possible, please consider less confusing
> > name.
>
> Renamed to ZoneReloader. Is it better?
"*re*loader" still doesn't sound like a good choice to me because
it'll also be used for the initial load (although in that sense
`datasrc::ZoneUpdater` may be suboptimal, too). `ZoneWriter` just
occurred to me - how about that? Basically not so different from
"updater" but just to have a different name so it's less confusing.
> > - In `ZoneUpdaterLocal::install()`, the original intent is to update
> > the zone table within this method (because this is a local-memory-
segment
> > specific detail and we want to hide it from
`ConfigurableClientList`).
> > In the local version, at the moment install_action() is mostly
> > meaningless, so we could simply pass NULL.
>
> Thinking about that, I just removed the install_action completely.
There's no
> need for the local reloader to take it as a parameter on construction
and then
> not use it. If there's need for one later on in other reloaders, the
factory
> function (`getZoneReloader`) will just get another parameter.
Okay, but there's still some important gap between what I originally
intended and the actual implementation (probably because the ticket
description wasn't clear enough). See specific comments below.
'''general'''
- on the interface design: maybe just expose the same single
method, like doNextStep(), instead of load()/install()/cleanup()?
In fact, the caller doesn't have to know what these methods are
supposed to do; the only important point for the caller is whether
the next step must be considered a critical section (when called in
multi-thread environment). So, one idea would be to provide a
single method that returns whether there's still more step(s) and in
that case whether it must be in a critical section (and the first
call would have to be guaranteed to be thread safe). Then the
application code would look like this:
{{{#!cpp
ZoneReloader* reloader; // get from somewhere
// result.first = need more step; result.second = need mutex for next
step
std::pair<bool, bool> result(true, false);
while (result.first) {
if (result.second) {
Locker locker(mutex);
result = reloader->doNextStep();
} else {
result = reloader->doNextStep();
}
}
}}}
This way, we can give the specific derived reloader more freedom of
skipping some of the steps or adding extra steps, and neither the
reloader nor the application has to worry about most of the call
ordering issues. But I'm going to complete my review below based on
the current interfaces.
- this is not in the guideline, but I though we have general agreement
about adding a blank line before the `\brief` comment line:
{{{#!cpp
/// \throw isc::Unexpected if called second time.
virtual void load() = 0;
/// \brief Put the changes to effect.
}}}
because without explicit separation it's not immediately clear which
method the description is for. I actually would like to propose
including this in the guideline.
'''load_action.h'''
I'm afraid it's not clear specifically how this type is used just from
this documentation. For example, it doesn't explain how an
implementation of this type gets the source of the zone data
(e.g. zone name, master file name).
'''zone_reloader.h/cc'''
- I'd request derived class implementation provide the strong
exception guarantee, i.e, when any of the methods throws, the
underlying data should be kept in the state before the method call
(either by not making actual change until it's safe or by safely
rolling back to the original state) as part of the API contract.
- I'd hide `ZoneReloaderLocal` in some a "private" header (not in the
public zone_reloader.h)
- I suspect `segment` parameter of the `ZoneReloaderLocal` constructor
should be of `ZoneTableSegmentLocal`, and we can safely do that
because this class should be constructed only by a
`ZoneTableSegmentLocal` object.
- On a related note, `ZoneReloaderLocal` needs some way to get access
to the `ZoneTable` that should be stored in `ZoneTableSegmentLocal`
because otherwise it cannot update an existing table for reloading
one of the zones in it (see also comment on install() below).
- `ZoneReloaderLocal::load()` description: this seems to be an older
version of description; it doesn't prepare an empty `ZoneData`
by itself anymore. Same for install().
- `ZoneReloaderLocal` implementation in general: I'd throw something
different from `Unexpected` to indicate a caller's misbehavior (such
as passing an invalid parameter or calling a specific method at a
bad timing). `Unexpected` was intended to mean really unexpected
event like an unexpected system error.
- `ZoneReloaderLocal` general: are both loaded_ and data_ready_
necessary?
- `ZoneReloaderLocal::install()` implementation: the zone table is not
expected to be created here, but is passed from the
`ZoneTableSegmentLocal` that created `ZoneReloaderLocal` (either as
`ZoneTableSegmentLocal` itself or as an explicit parameter).
'''zone_table_segment_local'''
- Not really for this branch, but if we return bare pointer via
getZoneReloader(), we should clarify who is responsible for freeing
it in the (base class) documentation.
'''zone_table_segment.h'''
- The `table` member should be set on the construction of
`ZoneTableHeader`, and like things like `ZoneData` or `RdataSet`
it would only be created and destroyed via separate static
create()/destroy() methods that take `MemorySegment`. (Sorry, I
admit this point wasn't clear).
- `getZoneReloader()` interface: I'm not sure if it makes sense to
pass rrclass to this factory because the zone table segment should
know that (at least in theory).
'''zone_reloader_unittest.cc'''
- Does this test the case where we don't call cleanup() to confirm the
previous data are still cleaned up?
'''zone_table_segment_unittest.cc'''
- s/load_action/loadAction/
--
Ticket URL: <http://bind10.isc.org/ticket/2207#comment:11>
BIND 10 Development <http://bind10.isc.org>
BIND 10 Development
More information about the bind10-tickets
mailing list