client.h 21 KB

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