|
@@ -210,42 +210,206 @@ typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
|
|
|
typedef boost::shared_ptr<const ZoneFinder> ConstZoneFinderPtr;
|
|
|
|
|
|
/// The base class to make updates to a single zone.
|
|
|
+///
|
|
|
+/// On construction, each derived class object will start a "transaction"
|
|
|
+/// for making updates to a specific zone (this means a constructor of
|
|
|
+/// a derived class would normally take parameters to identify the zone
|
|
|
+/// to be updated). The underlying realization of a "transaction" will defer
|
|
|
+/// for different derived classes; if it uses a general purpose database
|
|
|
+/// as a backend, it will involve performing some form of "begin transaction"
|
|
|
+/// statement for the database.
|
|
|
+///
|
|
|
+/// Updates (adding or deleting RRs) are made via \c addRRset() and
|
|
|
+/// \c deleteRRset() methods. Until the \c commit() method is called the
|
|
|
+/// changes are local to the updater object. For example, they won't be
|
|
|
+/// visible via a \c ZoneFinder object except the one returned by the
|
|
|
+/// updater's own \c getFinder() method. The \c commit() completes the
|
|
|
+/// transaction and makes the changes visible to others.
|
|
|
+///
|
|
|
+/// This class does not provide an explicit "rollback" interface. If
|
|
|
+/// something wrong or unexpected happens during the updates and the
|
|
|
+/// caller wants to cancel the intermediate updates, the caller should
|
|
|
+/// simply destruct the updater object without calling \c commit().
|
|
|
+/// The destructor is supposed to perform the "rollback" operation,
|
|
|
+/// depending on the internal details of the derived class.
|
|
|
+///
|
|
|
+/// \note This initial implementation provides a quite simple interface of
|
|
|
+/// adding and deleting RRs (see the description of the related methods).
|
|
|
+/// It may be revisited as we gain more experiences.
|
|
|
class ZoneUpdater {
|
|
|
protected:
|
|
|
+ /// The default constructor.
|
|
|
+ ///
|
|
|
+ /// This is intentionally defined as protected to ensure that this base
|
|
|
+ /// class is never instantiated directly.
|
|
|
ZoneUpdater() {}
|
|
|
|
|
|
public:
|
|
|
+ /// The destructor
|
|
|
+ ///
|
|
|
+ /// Each derived class implementation must ensure that if \c commit()
|
|
|
+ /// has not been performed by the time of the call to it, then it
|
|
|
+ /// "rollbacks" the updates made via the updater so far.
|
|
|
virtual ~ZoneUpdater() {}
|
|
|
|
|
|
- /// TBD
|
|
|
+ /// Return a finder for the zone being updated.
|
|
|
+ ///
|
|
|
+ /// The returned finder provides the functionalities of \c ZoneFinder
|
|
|
+ /// for the zone as updates are made via the updater. That is, before
|
|
|
+ /// making any update, the finder will be able to find all RRsets that
|
|
|
+ /// exist in the zone at the time the updater is created. If RRsets
|
|
|
+ /// are added or deleted via \c addRRset() or \c deleteRRset(),
|
|
|
+ /// this finder will find the added ones or miss the deleted ones
|
|
|
+ /// respectively.
|
|
|
+ ///
|
|
|
+ /// The finder returned by this method is effective only while the updates
|
|
|
+ /// are performed, i.e., from the construction of the corresponding
|
|
|
+ /// updater until \c commit() is performed or the updater is destructed
|
|
|
+ /// without commit. The result of a subsequent call to this method (or
|
|
|
+ /// the use of the result) after that is undefined.
|
|
|
///
|
|
|
- /// The finder is not expected to provide meaningful data once commit()
|
|
|
- /// was performed.
|
|
|
+ /// \return A reference to a \c ZoneFinder for the updated zone
|
|
|
virtual ZoneFinder& getFinder() = 0;
|
|
|
|
|
|
- /// TBD
|
|
|
+ /// Add an RRset to a zone via the updater
|
|
|
+ ///
|
|
|
+ /// This may be revisited in a future version, but right now the intended
|
|
|
+ /// behavior of this method is simple: It "naively" adds the specified
|
|
|
+ /// RRset to the zone specified on creation of the updater.
|
|
|
+ /// It performs minimum level of validation on the specified RRset:
|
|
|
+ /// - Whether the RR class is identical to that for the zone to be updated
|
|
|
+ /// - Whether the RRset is not empty, i.e., it has at least one RDATA
|
|
|
+ ///
|
|
|
+ /// and otherwise does not check any oddity. For example, it doesn't
|
|
|
+ /// check whether the owner name of the specified RRset is a subdomain
|
|
|
+ /// of the zone's origin; it doesn't care whether or not there is already
|
|
|
+ /// an RRset of the same name and RR type in the zone, and if there is,
|
|
|
+ /// whether any of the existing RRs have duplicate RDATA with the added
|
|
|
+ /// ones. If these conditions matter the calling application must examine
|
|
|
+ /// the existing data beforehand using the \c ZoneFinder returned by
|
|
|
+ /// \c getFinder().
|
|
|
+ ///
|
|
|
+ /// Conceptually, on successful call to this method, the zone will have
|
|
|
+ /// the specified RRset, and if there is already an RRset of the same
|
|
|
+ /// name and RR type, these two sets will be "merged". "Merged" means
|
|
|
+ /// that a subsequent call to \c ZoneFinder::find() for the name and type
|
|
|
+ /// will result in success and the returned RRset will contain all
|
|
|
+ /// previously existing and newly added RDATAs with the TTL being the
|
|
|
+ /// minimum of the two RRsets. The underlying representation of the
|
|
|
+ /// "merged" RRsets may vary depending on the characteristic of the
|
|
|
+ /// underlying data source. For example, if it uses a general purpose
|
|
|
+ /// database that stores each RR of the same RRset separately, it may
|
|
|
+ /// simply be a larger sets of RRs based on both the existing and added
|
|
|
+ /// RRsets; the TTLs of the RRs may be different within the database, and
|
|
|
+ /// there may even be duplicate RRs in different database rows. As long
|
|
|
+ /// as the RRset returned via \c ZoneFinder::find() conforms to the
|
|
|
+ /// concept of "merge", the actual internal representation is up to the
|
|
|
+ /// implementation.
|
|
|
///
|
|
|
- /// Notes about unexpected input: class mismatch will be rejected.
|
|
|
- /// The owner name isn't checked; it's the caller's responsibility.
|
|
|
+ /// This method must not be called once commit() is performed. If it
|
|
|
+ /// calls after \c commit() the implementation must throw a
|
|
|
+ /// \c DataSourceError exception.
|
|
|
///
|
|
|
- /// Open issues: we may eventually want to return result values such as
|
|
|
- /// there's a duplicate, etc.
|
|
|
+ /// \todo As noted above we may have to revisit the design details as we
|
|
|
+ /// gain experiences:
|
|
|
///
|
|
|
- /// The added RRset must not be empty (i.e., it must have at least one
|
|
|
- /// RDATA).
|
|
|
+ /// - we may want to check (and maybe reject) if there is already a
|
|
|
+ /// duplicate RR (that has the same RDATA).
|
|
|
+ /// - we may want to check (and maybe reject) if there is already an
|
|
|
+ /// RRset of the same name and RR type with different TTL
|
|
|
+ /// - we may even want to check if there is already any RRset of the
|
|
|
+ /// same name and RR type.
|
|
|
+ /// - we may want to add an "options" parameter that can control the
|
|
|
+ /// above points
|
|
|
+ /// - we may want to have this method return a value containing the
|
|
|
+ /// information on whether there's a duplicate, etc.
|
|
|
///
|
|
|
- /// This method must not be called once commit() is performed.
|
|
|
+ /// \exception DataSourceError Called after \c commit(), RRset is invalid
|
|
|
+ /// (see above), internal data source error
|
|
|
+ /// \exception std::bad_alloc Resource allocation failure
|
|
|
+ ///
|
|
|
+ /// \param rrset The RRset to be added
|
|
|
virtual void addRRset(const isc::dns::RRset& rrset) = 0;
|
|
|
|
|
|
- /// TBD
|
|
|
+ /// Delete an RRset from a zone via the updater
|
|
|
+ ///
|
|
|
+ /// Like \c addRRset(), the detailed semantics and behavior of this method
|
|
|
+ /// may have to be revisited in a future version. The following are
|
|
|
+ /// based on the initial implementation decisions.
|
|
|
+ ///
|
|
|
+ /// On successful completion of this method, it will remove from the zone
|
|
|
+ /// the RRs of the specified owner name and RR type that match one of
|
|
|
+ /// the RDATAs of the specified RRset. There are several points to be
|
|
|
+ /// noted:
|
|
|
+ /// - Existing RRs that don't match any of the specified RDATAs will
|
|
|
+ /// remain in the zone.
|
|
|
+ /// - Any RRs of the specified RRset that doesn't exist in the zone will
|
|
|
+ /// simply be ignored; the implementation of this method is not supposed
|
|
|
+ /// to check that condition.
|
|
|
+ /// - The TTL of the RRset is ignored; matching is only performed by
|
|
|
+ /// the owner name, RR type and RDATA
|
|
|
+ ///
|
|
|
+ /// Ignoring the TTL may not look sensible, but it's based on the
|
|
|
+ /// observation that it will result in more intuitive result, especially
|
|
|
+ /// when the underlying data source is a general purpose database.
|
|
|
+ /// See also \c DatabaseAccessor::deleteRecordInZone() on this point.
|
|
|
+ /// It also matches the dynamic update protocol (RFC2136), where TTLs
|
|
|
+ /// are ignored when deleting RRs.
|
|
|
+ ///
|
|
|
+ /// \note Since the TTL is ignored, this method could take the RRset
|
|
|
+ /// to be deleted as a tuple of name, RR type, and a list of RDATAs.
|
|
|
+ /// But in practice, it's quite likely that the caller has the RRset
|
|
|
+ /// in the form of the \c RRset object (e.g., extracted from a dynamic
|
|
|
+ /// update request message), so this interface would rather be more
|
|
|
+ /// convenient. If it turns out not to be true we can change or extend
|
|
|
+ /// the method signature.
|
|
|
+ ///
|
|
|
+ /// This method performs minimum level of validation on the specified
|
|
|
+ /// RRset:
|
|
|
+ /// - Whether the RR class is identical to that for the zone to be updated
|
|
|
+ /// - Whether the RRset is not empty, i.e., it has at least one RDATA
|
|
|
///
|
|
|
- /// how to handle TTL?
|
|
|
+ /// This method must not be called once commit() is performed. If it
|
|
|
+ /// calls after \c commit() the implementation must throw a
|
|
|
+ /// \c DataSourceError exception.
|
|
|
+ ///
|
|
|
+ /// \todo As noted above we may have to revisit the design details as we
|
|
|
+ /// gain experiences:
|
|
|
+ ///
|
|
|
+ /// - we may want to check (and maybe reject) if some or all of the RRs
|
|
|
+ /// for the specified RRset don't exist in the zone
|
|
|
+ /// - we may want to allow an option to "delete everything" for specified
|
|
|
+ /// name and/or specified name + RR type.
|
|
|
+ /// - as mentioned above, we may want to include the TTL in matching the
|
|
|
+ /// deleted RRs
|
|
|
+ /// - we may want to add an "options" parameter that can control the
|
|
|
+ /// above points
|
|
|
+ /// - we may want to have this method return a value containing the
|
|
|
+ /// information on whether there's any RRs that are specified but don't
|
|
|
+ /// exit, the number of actually deleted RRs, etc.
|
|
|
+ ///
|
|
|
+ /// \exception DataSourceError Called after \c commit(), RRset is invalid
|
|
|
+ /// (see above), internal data source error
|
|
|
+ /// \exception std::bad_alloc Resource allocation failure
|
|
|
+ ///
|
|
|
+ /// \param rrset The RRset to be deleted
|
|
|
virtual void deleteRRset(const isc::dns::RRset& rrset) = 0;
|
|
|
|
|
|
- /// TBD
|
|
|
+ /// Commit the updates made in the updater to the zone
|
|
|
+ ///
|
|
|
+ /// This method completes the "transaction" started at the creation
|
|
|
+ /// of the updater. After successful completion of this method, the
|
|
|
+ /// updates will be visible outside the scope of the updater.
|
|
|
+ /// The actual internal behavior will defer for different derived classes.
|
|
|
+ /// For a derived class with a general purpose database as a backend,
|
|
|
+ /// for example, this method would perform a "commit" statement for the
|
|
|
+ /// database.
|
|
|
///
|
|
|
/// This operation can only be performed at most once. A duplicate call
|
|
|
/// must result in a DatasourceError exception.
|
|
|
+ ///
|
|
|
+ /// \exception DataSourceError Duplicate call of the method,
|
|
|
+ /// internal data source error
|
|
|
virtual void commit() = 0;
|
|
|
};
|
|
|
|