LCOV - code coverage report
Current view: top level - datasrc - client.h (source / functions) Hit Total Coverage
Test: report.info Lines: 6 6 100.0 %
Date: 2012-05-15 Functions: 1 3 33.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 2 4 50.0 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #ifndef __DATA_SOURCE_CLIENT_H
      16                 :            : #define __DATA_SOURCE_CLIENT_H 1
      17                 :            : 
      18                 :            : #include <utility>
      19                 :            : 
      20                 :            : #include <boost/noncopyable.hpp>
      21                 :            : #include <boost/shared_ptr.hpp>
      22                 :            : 
      23                 :            : #include <exceptions/exceptions.h>
      24                 :            : 
      25                 :            : #include <datasrc/zone.h>
      26                 :            : 
      27                 :            : /// \file
      28                 :            : /// Datasource clients
      29                 :            : ///
      30                 :            : /// The data source client API is specified in client.h, and provides the
      31                 :            : /// functionality to query and modify data in the data sources. There are
      32                 :            : /// multiple datasource implementations, and by subclassing DataSourceClient or
      33                 :            : /// DatabaseClient, more can be added.
      34                 :            : ///
      35                 :            : /// All datasources are implemented as loadable modules, with a name of the
      36                 :            : /// form "<type>_ds.so". This has been chosen intentionally, to minimize
      37                 :            : /// confusion and potential mistakes.
      38                 :            : ///
      39                 :            : /// In order to use a datasource client backend, the class
      40                 :            : /// DataSourceClientContainer is provided in factory.h; this will load the
      41                 :            : /// library, set up the instance, and clean everything up once it is destroyed.
      42                 :            : ///
      43                 :            : /// Access to the actual instance is provided with the getInstance() method
      44                 :            : /// in DataSourceClientContainer
      45                 :            : ///
      46                 :            : /// \note Depending on actual usage, we might consider making the container
      47                 :            : /// a transparent abstraction layer, so it can be used as a DataSourceClient
      48                 :            : /// directly. This has some other implications though so for now the only access
      49                 :            : /// provided is through getInstance()).
      50                 :            : ///
      51                 :            : /// For datasource backends, we use a dynamically loaded library system (with
      52                 :            : /// dlopen()). This library must contain the following things;
      53                 :            : /// - A subclass of DataSourceClient or DatabaseClient (which itself is a
      54                 :            : ///   subclass of DataSourceClient)
      55                 :            : /// - A creator function for an instance of that subclass, of the form:
      56                 :            : /// \code
      57                 :            : /// extern "C" DataSourceClient* createInstance(isc::data::ConstElementPtr cfg);
      58                 :            : /// \endcode
      59                 :            : /// - A destructor for said instance, of the form:
      60                 :            : /// \code
      61                 :            : /// extern "C" void destroyInstance(isc::data::DataSourceClient* instance);
      62                 :            : /// \endcode
      63                 :            : ///
      64                 :            : /// See the documentation for the \link DataSourceClient \endlink class for
      65                 :            : /// more information on implementing subclasses of it.
      66                 :            : ///
      67                 :            : 
      68                 :            : namespace isc {
      69                 :            : namespace datasrc {
      70                 :            : 
      71                 :            : // The iterator.h is not included on purpose, most application won't need it
      72                 :            : class ZoneIterator;
      73                 :            : typedef boost::shared_ptr<ZoneIterator> ZoneIteratorPtr;
      74                 :            : 
      75                 :            : /// \brief The base class of data source clients.
      76                 :            : ///
      77                 :            : /// This is an abstract base class that defines the common interface for
      78                 :            : /// various types of data source clients.  A data source client is a top level
      79                 :            : /// access point to a data source, allowing various operations on the data
      80                 :            : /// source such as lookups, traversing or updates.  The client class itself
      81                 :            : /// has limited focus and delegates the responsibility for these specific
      82                 :            : /// operations to other classes; in general methods of this class act as
      83                 :            : /// factories of these other classes.
      84                 :            : ///
      85                 :            : /// See \link datasrc/client.h datasrc/client.h \endlink for more information
      86                 :            : /// on adding datasource implementations.
      87                 :            : ///
      88                 :            : /// The following derived classes are currently (expected to be) provided:
      89                 :            : /// - \c InMemoryClient: A client of a conceptual data source that stores
      90                 :            : /// all necessary data in memory for faster lookups
      91                 :            : /// - \c DatabaseClient: A client that uses a real database backend (such as
      92                 :            : /// an SQL database).  It would internally hold a connection to the underlying
      93                 :            : /// database system.
      94                 :            : ///
      95                 :            : /// \note It is intentional that while the term these derived classes don't
      96                 :            : /// contain "DataSource" unlike their base class.  It's also noteworthy
      97                 :            : /// that the naming of the base class is somewhat redundant because the
      98                 :            : /// namespace \c datasrc would indicate that it's related to a data source.
      99                 :            : /// The redundant naming comes from the observation that namespaces are
     100                 :            : /// often omitted with \c using directives, in which case "Client"
     101                 :            : /// would be too generic.  On the other hand, concrete derived classes are
     102                 :            : /// generally not expected to be referenced directly from other modules and
     103                 :            : /// applications, so we'll give them more concise names such as InMemoryClient.
     104                 :            : ///
     105                 :            : /// A single \c DataSourceClient object is expected to handle only a single
     106                 :            : /// RR class even if the underlying data source contains records for multiple
     107                 :            : /// RR classes.  Likewise, (when we support views) a \c DataSourceClient
     108                 :            : /// object is expected to handle only a single view.
     109                 :            : ///
     110                 :            : /// If the application uses multiple threads, each thread will need to
     111                 :            : /// create and use a separate DataSourceClient.  This is because some
     112                 :            : /// database backend doesn't allow multiple threads to share the same
     113                 :            : /// connection to the database.
     114                 :            : ///
     115                 :            : /// \note For a client using an in memory backend, this may result in
     116                 :            : /// having a multiple copies of the same data in memory, increasing the
     117                 :            : /// memory footprint substantially.  Depending on how to support multiple
     118                 :            : /// CPU cores for concurrent lookups on the same single data source (which
     119                 :            : /// is not fully fixed yet, and for which multiple threads may be used),
     120                 :            : /// this design may have to be revisited.
     121                 :            : ///
     122                 :            : /// This class (and therefore its derived classes) are not copyable.
     123                 :            : /// This is because the derived classes would generally contain attributes
     124                 :            : /// that are not easy to copy (such as a large size of in memory data or a
     125                 :            : /// network connection to a database server).  In order to avoid a surprising
     126                 :            : /// disruption with a naive copy it's prohibited explicitly.  For the expected
     127                 :            : /// usage of the client classes the restriction should be acceptable.
     128                 :            : ///
     129                 :            : /// \todo This class is still not complete. It will need more factory methods,
     130                 :            : /// e.g. for (re)loading a zone.
     131                 :            : class DataSourceClient : boost::noncopyable {
     132                 :            : public:
     133                 :            :     /// \brief A helper structure to represent the search result of
     134                 :            :     /// \c find().
     135                 :            :     ///
     136                 :            :     /// This is a straightforward pair of the result code and a share pointer
     137                 :            :     /// to the found zone to represent the result of \c find().
     138                 :            :     /// We use this in order to avoid overloading the return value for both
     139                 :            :     /// the result code ("success" or "not found") and the found object,
     140                 :            :     /// i.e., avoid using \c NULL to mean "not found", etc.
     141                 :            :     ///
     142                 :            :     /// This is a simple value class with no internal state, so for
     143                 :            :     /// convenience we allow the applications to refer to the members
     144                 :            :     /// directly.
     145                 :            :     ///
     146                 :            :     /// See the description of \c find() for the semantics of the member
     147                 :            :     /// variables.
     148                 :        569 :     struct FindResult {
     149                 :            :         FindResult(result::Result param_code,
     150                 :            :                    const ZoneFinderPtr param_zone_finder) :
     151                 :        569 :             code(param_code), zone_finder(param_zone_finder)
     152                 :            :         {}
     153                 :            :         const result::Result code;
     154                 :            :         const ZoneFinderPtr zone_finder;
     155                 :            :     };
     156                 :            : 
     157                 :            :     ///
     158                 :            :     /// \name Constructors and Destructor.
     159                 :            :     ///
     160                 :            : protected:
     161                 :            :     /// Default constructor.
     162                 :            :     ///
     163                 :            :     /// This is intentionally defined as protected as this base class
     164                 :            :     /// should never be instantiated directly.
     165                 :            :     ///
     166                 :            :     /// The constructor of a concrete derived class may throw an exception.
     167                 :            :     /// This interface does not specify which exceptions can happen (at least
     168                 :            :     /// at this moment), and the caller should expect any type of exception
     169                 :            :     /// and react accordingly.
     170                 :        406 :     DataSourceClient() {}
     171                 :            : 
     172                 :            : public:
     173                 :            :     /// The destructor.
     174                 :        406 :     virtual ~DataSourceClient() {}
     175                 :            :     //@}
     176                 :            : 
     177                 :            :     /// Returns a \c ZoneFinder for a zone that best matches the given name.
     178                 :            :     ///
     179                 :            :     /// A concrete derived version of this method gets access to its backend
     180                 :            :     /// data source to search for a zone whose origin gives the longest match
     181                 :            :     /// against \c name.  It returns the search result in the form of a
     182                 :            :     /// \c FindResult object as follows:
     183                 :            :     /// - \c code: The result code of the operation.
     184                 :            :     ///   - \c result::SUCCESS: A zone that gives an exact match is found
     185                 :            :     ///   - \c result::PARTIALMATCH: A zone whose origin is a
     186                 :            :     ///   super domain of \c name is found (but there is no exact match)
     187                 :            :     ///   - \c result::NOTFOUND: For all other cases.
     188                 :            :     /// - \c zone_finder: Pointer to a \c ZoneFinder object for the found zone
     189                 :            :     /// if one is found; otherwise \c NULL.
     190                 :            :     ///
     191                 :            :     /// A specific derived version of this method may throw an exception.
     192                 :            :     /// This interface does not specify which exceptions can happen (at least
     193                 :            :     /// at this moment), and the caller should expect any type of exception
     194                 :            :     /// and react accordingly.
     195                 :            :     ///
     196                 :            :     /// \param name A domain name for which the search is performed.
     197                 :            :     /// \return A \c FindResult object enclosing the search result (see above).
     198                 :            :     virtual FindResult findZone(const isc::dns::Name& name) const = 0;
     199                 :            : 
     200                 :            :     /// \brief Returns an iterator to the given zone
     201                 :            :     ///
     202                 :            :     /// This allows for traversing the whole zone. The returned object can
     203                 :            :     /// provide the RRsets one by one.
     204                 :            :     ///
     205                 :            :     /// This throws DataSourceError when the zone does not exist in the
     206                 :            :     /// datasource.
     207                 :            :     ///
     208                 :            :     /// The default implementation throws isc::NotImplemented. This allows
     209                 :            :     /// for easy and fast deployment of minimal custom data sources, where
     210                 :            :     /// the user/implementator doesn't have to care about anything else but
     211                 :            :     /// the actual queries. Also, in some cases, it isn't possible to traverse
     212                 :            :     /// the zone from logic point of view (eg. dynamically generated zone
     213                 :            :     /// data).
     214                 :            :     ///
     215                 :            :     /// It is not fixed if a concrete implementation of this method can throw
     216                 :            :     /// anything else.
     217                 :            :     ///
     218                 :            :     /// \param name The name of zone apex to be traversed. It doesn't do
     219                 :            :     ///     nearest match as findZone.
     220                 :            :     /// \param separate_rrs If true, the iterator will return each RR as a
     221                 :            :     ///                     new RRset object. If false, the iterator will
     222                 :            :     ///                     combine consecutive RRs with the name and type
     223                 :            :     ///                     into 1 RRset. The capitalization of the RRset will
     224                 :            :     ///                     be that of the first RR read, and TTLs will be
     225                 :            :     ///                     adjusted to the lowest one found.
     226                 :            :     /// \return Pointer to the iterator.
     227                 :          1 :     virtual ZoneIteratorPtr getIterator(const isc::dns::Name& name,
     228                 :            :                                         bool separate_rrs = false) const {
     229                 :            :         // This is here to both document the parameter in doxygen (therefore it
     230                 :            :         // needs a name) and avoid unused parameter warning.
     231                 :            :         static_cast<void>(name);
     232                 :            :         static_cast<void>(separate_rrs);
     233                 :            : 
     234 [ +  - ][ +  - ]:          2 :         isc_throw(isc::NotImplemented,
     235                 :            :                   "Data source doesn't support iteration");
     236                 :            :     }
     237                 :            : 
     238                 :            :     /// Return an updater to make updates to a specific zone.
     239                 :            :     ///
     240                 :            :     /// The RR class of the zone is the one that the client is expected to
     241                 :            :     /// handle (see the detailed description of this class).
     242                 :            :     ///
     243                 :            :     /// If the specified zone is not found via the client, a NULL pointer
     244                 :            :     /// will be returned; in other words a completely new zone cannot be
     245                 :            :     /// created using an updater.  It must be created beforehand (even if
     246                 :            :     /// it's an empty placeholder) in a way specific to the underlying data
     247                 :            :     /// source.
     248                 :            :     ///
     249                 :            :     /// Conceptually, the updater will trigger a separate transaction for
     250                 :            :     /// subsequent updates to the zone within the context of the updater
     251                 :            :     /// (the actual implementation of the "transaction" may vary for the
     252                 :            :     /// specific underlying data source).  Until \c commit() is performed
     253                 :            :     /// on the updater, the intermediate updates won't affect the results
     254                 :            :     /// of other methods (and the result of the object's methods created
     255                 :            :     /// by other factory methods).  Likewise, if the updater is destructed
     256                 :            :     /// without performing \c commit(), the intermediate updates will be
     257                 :            :     /// effectively canceled and will never affect other methods.
     258                 :            :     ///
     259                 :            :     /// If the underlying data source allows concurrent updates, this method
     260                 :            :     /// can be called multiple times while the previously returned updater(s)
     261                 :            :     /// are still active.  In this case each updater triggers a different
     262                 :            :     /// "transaction".  Normally it would be for different zones for such a
     263                 :            :     /// case as handling multiple incoming AXFR streams concurrently, but
     264                 :            :     /// this interface does not even prohibit an attempt of getting more than
     265                 :            :     /// one updater for the same zone, as long as the underlying data source
     266                 :            :     /// allows such an operation (and any conflict resolution is left to the
     267                 :            :     /// specific derived class implementation).
     268                 :            :     ///
     269                 :            :     /// If \c replace is true, any existing RRs of the zone will be
     270                 :            :     /// deleted on successful completion of updates (after \c commit() on
     271                 :            :     /// the updater); if it's false, the existing RRs will be
     272                 :            :     /// intact unless explicitly deleted by \c deleteRRset() on the updater.
     273                 :            :     ///
     274                 :            :     /// A data source can be "read only" or can prohibit partial updates.
     275                 :            :     /// In such cases this method will result in an \c isc::NotImplemented
     276                 :            :     /// exception unconditionally or when \c replace is false).
     277                 :            :     ///
     278                 :            :     /// If \c journaling is true, the data source should store a journal
     279                 :            :     /// of changes. These can be used later on by, for example, IXFR-out.
     280                 :            :     /// However, the parameter is a hint only. It might be unable to store
     281                 :            :     /// them and they would be silently discarded. Or it might need to
     282                 :            :     /// store them no matter what (for example a git-based data source would
     283                 :            :     /// store journal implicitly). When the \c journaling is true, it
     284                 :            :     /// requires that the following update be formatted as IXFR transfer
     285                 :            :     /// (SOA to be removed, bunch of RRs to be removed, SOA to be added,
     286                 :            :     /// bunch of RRs to be added, and possibly repeated). However, it is not
     287                 :            :     /// required that the updater checks that. If it is false, it must not
     288                 :            :     /// require so and must accept any order of changes.
     289                 :            :     ///
     290                 :            :     /// We don't support erasing the whole zone (by replace being true) and
     291                 :            :     /// saving a journal at the same time. In such situation, BadValue is
     292                 :            :     /// thrown.
     293                 :            :     ///
     294                 :            :     /// \note To avoid throwing the exception accidentally with a lazy
     295                 :            :     /// implementation, we still keep this method pure virtual without
     296                 :            :     /// an implementation.  All derived classes must explicitly define this
     297                 :            :     /// method, even if it simply throws the NotImplemented exception.
     298                 :            :     ///
     299                 :            :     /// \exception NotImplemented The underlying data source does not support
     300                 :            :     /// updates.
     301                 :            :     /// \exception DataSourceError Internal error in the underlying data
     302                 :            :     /// source.
     303                 :            :     /// \exception std::bad_alloc Resource allocation failure.
     304                 :            :     /// \exception BadValue if both replace and journaling are true.
     305                 :            :     ///
     306                 :            :     /// \param name The zone name to be updated
     307                 :            :     /// \param replace Whether to delete existing RRs before making updates
     308                 :            :     /// \param journaling The zone updater should store a journal of the
     309                 :            :     ///     changes.
     310                 :            :     ///
     311                 :            :     /// \return A pointer to the updater; it will be NULL if the specified
     312                 :            :     /// zone isn't found.
     313                 :            :     virtual ZoneUpdaterPtr getUpdater(const isc::dns::Name& name,
     314                 :            :                                       bool replace, bool journaling = false)
     315                 :            :         const = 0;
     316                 :            : 
     317                 :            :     /// Return a journal reader to retrieve differences of a zone.
     318                 :            :     ///
     319                 :            :     /// A derived version of this method creates a concrete
     320                 :            :     /// \c ZoneJournalReader object specific to the underlying data source
     321                 :            :     /// for the specified name of zone and differences between the versions
     322                 :            :     /// specified by the beginning and ending serials of the corresponding
     323                 :            :     /// SOA RRs.
     324                 :            :     /// The RR class of the zone is the one that the client is expected to
     325                 :            :     /// handle (see the detailed description of this class).
     326                 :            :     ///
     327                 :            :     /// Note that the SOA serials are compared by the semantics of the serial
     328                 :            :     /// number arithmetic.  So, for example, \c begin_serial can be larger than
     329                 :            :     /// \c end_serial as bare unsigned integers.  The underlying data source
     330                 :            :     /// implementation is assumed to keep track of sufficient history to
     331                 :            :     /// identify (if exist) the corresponding difference between the specified
     332                 :            :     /// versions.
     333                 :            :     ///
     334                 :            :     /// This method returns the result as a pair of a result code and
     335                 :            :     /// a pointer to a \c ZoneJournalReader object.  On success, the result
     336                 :            :     /// code is \c SUCCESS and the pointer must be non NULL; otherwise
     337                 :            :     /// the result code is something other than \c SUCCESS and the pinter
     338                 :            :     /// must be NULL.
     339                 :            :     ///
     340                 :            :     /// If the specified zone is not found in the data source, the result
     341                 :            :     /// code is \c NO_SUCH_ZONE.
     342                 :            :     /// Otherwise, if specified range of difference for the zone is not found
     343                 :            :     /// in the data source, the result code is \c NO_SUCH_VERSION.
     344                 :            :     ///
     345                 :            :     /// Handling differences is an optional feature of data source.
     346                 :            :     /// If the underlying data source does not support difference handling,
     347                 :            :     /// this method for that type of data source can throw an exception of
     348                 :            :     /// class \c NotImplemented.
     349                 :            :     ///
     350                 :            :     /// \exception NotImplemented The data source does not support differences.
     351                 :            :     /// \exception DataSourceError Other operational errors at the data source
     352                 :            :     /// level.
     353                 :            :     ///
     354                 :            :     /// \param zone The name of the zone for which the difference should be
     355                 :            :     /// retrieved.
     356                 :            :     /// \param begin_serial The SOA serial of the beginning version of the
     357                 :            :     /// differences.
     358                 :            :     /// \param end_serial The SOA serial of the ending version of the
     359                 :            :     /// differences.
     360                 :            :     ///
     361                 :            :     /// \return A pair of result code and a pointer to \c ZoneJournalReader.
     362                 :            :     virtual std::pair<ZoneJournalReader::Result, ZoneJournalReaderPtr>
     363                 :            :     getJournalReader(const isc::dns::Name& zone, uint32_t begin_serial,
     364                 :            :                      uint32_t end_serial) const = 0;
     365                 :            : };
     366                 :            : }
     367                 :            : }
     368                 :            : #endif  // DATA_SOURCE_CLIENT_H
     369                 :            : // Local Variables:
     370                 :            : // mode: c++
     371                 :            : // End:

Generated by: LCOV version 1.9