client_list.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. // Copyright (C) 2012 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 DATASRC_CONTAINER_H
  15. #define DATASRC_CONTAINER_H
  16. #include <util/memory_segment.h>
  17. #include <dns/name.h>
  18. #include <dns/rrclass.h>
  19. #include <cc/data.h>
  20. #include <exceptions/exceptions.h>
  21. #include "memory/zone_table_segment.h"
  22. #include <vector>
  23. #include <boost/shared_ptr.hpp>
  24. #include <boost/scoped_ptr.hpp>
  25. #include <boost/noncopyable.hpp>
  26. namespace isc {
  27. namespace datasrc {
  28. class ZoneFinder;
  29. typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
  30. class DataSourceClient;
  31. typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
  32. class DataSourceClientContainer;
  33. typedef boost::shared_ptr<DataSourceClientContainer>
  34. DataSourceClientContainerPtr;
  35. // XXX: it's better to even hide the existence of the "memory" namespace.
  36. // We should probably consider pimpl for details of ConfigurableClientList
  37. // and hide real definitions except for itself and tests.
  38. namespace memory {
  39. class InMemoryClient;
  40. class ZoneWriter;
  41. }
  42. /// \brief Segment status of the cache
  43. ///
  44. /// Describes the status in which the memory segment of given data source
  45. /// is.
  46. enum MemorySegmentState {
  47. /// \brief The segment is local one.
  48. MSS_LOCAL,
  49. /// \brief No segment used for this data source.
  50. MSS_UNUSED,
  51. /// \brief It is a mapped segment and we wait for information how to map
  52. /// it.
  53. MSS_WAITING,
  54. /// \brief A mapped segment and in active use.
  55. MSS_MAPPED
  56. };
  57. /// \brief Status of one data source.
  58. ///
  59. /// This indicates the status a data soure is in. It is used with segment
  60. /// and cache management, to discover the data sources that need external
  61. /// mapping or local loading.
  62. class DataSourceStatus {
  63. public:
  64. /// \brief Constructor
  65. ///
  66. /// Sets initial values.
  67. DataSourceStatus(const std::string& name, MemorySegmentState state) :
  68. name_(name),
  69. state_(state)
  70. {}
  71. /// \brief Get the current segment state
  72. MemorySegmentState getSegmentState() const {
  73. return (state_);
  74. }
  75. /// \brief Get the current name.
  76. ///
  77. /// \note The name may not be changed once the object is constructed.
  78. const std::string& getName() const {
  79. return (name_);
  80. }
  81. private:
  82. std::string name_;
  83. MemorySegmentState state_;
  84. };
  85. /// \brief The list of data source clients.
  86. ///
  87. /// The purpose of this class is to hold several data source clients and search
  88. /// through them to find one containing a zone best matching a request.
  89. ///
  90. /// All the data source clients should be for the same class. If you need
  91. /// to handle multiple classes, you need to create multiple separate lists.
  92. ///
  93. /// This is an abstract base class. It is not expected we would use multiple
  94. /// implementation inside the servers (but it is not forbidden either), we
  95. /// have it to allow easy testing. It is possible to create a mock-up class
  96. /// instead of creating a full-blown configuration. The real implementation
  97. /// is the ConfigurableClientList.
  98. class ClientList : public boost::noncopyable {
  99. protected:
  100. /// \brief Constructor.
  101. ///
  102. /// It is protected to prevent accidental creation of the abstract base
  103. /// class.
  104. ClientList() {}
  105. public:
  106. /// \brief Virtual destructor
  107. virtual ~ClientList() {}
  108. /// \brief Structure holding the (compound) result of find.
  109. ///
  110. /// As this is read-only structure, we don't bother to create accessors.
  111. /// Instead, all the member variables are defined as const and can be
  112. /// accessed directly.
  113. struct FindResult {
  114. /// \brief Internal class for holding a reference.
  115. ///
  116. /// This is used to make sure the data source client isn't released
  117. /// too soon.
  118. ///
  119. /// \see life_keeper_;
  120. class LifeKeeper {
  121. public:
  122. virtual ~LifeKeeper() {};
  123. };
  124. /// \brief Constructor.
  125. ///
  126. /// It simply fills in the member variables according to the
  127. /// parameters. See the member descriptions for their meaning.
  128. FindResult(DataSourceClient* dsrc_client, const ZoneFinderPtr& finder,
  129. bool exact_match,
  130. const boost::shared_ptr<LifeKeeper>& life_keeper) :
  131. dsrc_client_(dsrc_client),
  132. finder_(finder),
  133. exact_match_(exact_match),
  134. life_keeper_(life_keeper)
  135. {}
  136. /// \brief Negative answer constructor.
  137. ///
  138. /// This conscructs a result for negative answer. Both pointers are
  139. /// NULL, and exact_match_ is false.
  140. FindResult() :
  141. dsrc_client_(NULL),
  142. exact_match_(false)
  143. {}
  144. /// \brief Comparison operator.
  145. ///
  146. /// It is needed for tests and it might be of some use elsewhere
  147. /// too.
  148. bool operator ==(const FindResult& other) const {
  149. return (dsrc_client_ == other.dsrc_client_ &&
  150. finder_ == other.finder_ &&
  151. exact_match_ == other.exact_match_);
  152. }
  153. /// \brief The found data source client.
  154. ///
  155. /// The client of the data source containing the best matching zone.
  156. /// If no such data source exists, this is NULL pointer.
  157. ///
  158. /// Note that the pointer is valid only as long the ClientList which
  159. /// returned the pointer is alive and was not reconfigured or you hold
  160. /// a reference to life_keeper_. The ownership is preserved within the
  161. /// ClientList.
  162. DataSourceClient* const dsrc_client_;
  163. /// \brief The finder for the requested zone.
  164. ///
  165. /// This is the finder corresponding to the best matching zone.
  166. /// This may be NULL even in case the datasrc_ is something
  167. /// else, depending on the find options.
  168. ///
  169. /// \see find
  170. const ZoneFinderPtr finder_;
  171. /// \brief If the result is an exact match.
  172. const bool exact_match_;
  173. /// \brief Something that holds the dsrc_client_ valid.
  174. ///
  175. /// As long as you hold the life_keeper_, the dsrc_client_ is
  176. /// guaranteed to be valid.
  177. const boost::shared_ptr<LifeKeeper> life_keeper_;
  178. };
  179. /// \brief Search for a zone through the data sources.
  180. ///
  181. /// This searches the contained data source clients for a one that best
  182. /// matches the zone name.
  183. ///
  184. /// There are two expected usage scenarios. One is answering queries. In
  185. /// this case, the zone finder is needed and the best matching superzone
  186. /// of the searched name is needed. Therefore, the call would look like:
  187. ///
  188. /// \code FindResult result(list->find(queried_name));
  189. /// FindResult result(list->find(queried_name));
  190. /// if (result.datasrc_) {
  191. /// createTheAnswer(result.finder_);
  192. /// } else {
  193. /// createNotAuthAnswer();
  194. /// } \endcode
  195. ///
  196. /// The other scenario is manipulating zone data (XfrOut, XfrIn, DDNS,
  197. /// ...). In this case, the finder itself is not so important. However,
  198. /// we need an exact match (if we want to manipulate zone data, we must
  199. /// know exactly, which zone we are about to manipulate). Then the call
  200. ///
  201. /// \code FindResult result(list->find(zone_name, true, false));
  202. /// FindResult result(list->find(zone_name, true, false));
  203. /// if (result.datasrc_) {
  204. /// ZoneUpdaterPtr updater(result.datasrc_->getUpdater(zone_name);
  205. /// ...
  206. /// } \endcode
  207. ///
  208. /// \param zone The name of the zone to look for.
  209. /// \param want_exact_match If it is true, it returns only exact matches.
  210. /// If the best possible match is partial, a negative result is
  211. /// returned instead. It is possible the caller could check it and
  212. /// act accordingly if the result would be partial match, but with this
  213. /// set to true, the find might be actually faster under some
  214. /// circumstances.
  215. /// \param want_finder If this is false, the finder_ member of FindResult
  216. /// might be NULL even if the corresponding data source is found. This
  217. /// is because of performance, in some cases the finder is a side
  218. /// result of the searching algorithm (therefore asking for it again
  219. /// would be a waste), but under other circumstances it is not, so
  220. /// providing it when it is not needed would also be wasteful.
  221. ///
  222. /// Other things are never the side effect of searching, therefore the
  223. /// caller can get them explicitly (the updater, journal reader and
  224. /// iterator).
  225. /// \return A FindResult describing the data source and zone with the
  226. /// longest match against the zone parameter.
  227. virtual FindResult find(const dns::Name& zone,
  228. bool want_exact_match = false,
  229. bool want_finder = true) const = 0;
  230. };
  231. /// \brief Shared pointer to the list.
  232. typedef boost::shared_ptr<ClientList> ClientListPtr;
  233. /// \brief Shared const pointer to the list.
  234. typedef boost::shared_ptr<const ClientList> ConstClientListPtr;
  235. /// \Concrete implementation of the ClientList, which is constructed based on
  236. /// configuration.
  237. ///
  238. /// This is the implementation which is expected to be used in the servers.
  239. /// However, it is expected most of the code will use it as the ClientList,
  240. /// only the creation is expected to be direct.
  241. ///
  242. /// While it is possible to inherit this class, it is not expected to be
  243. /// inherited except for tests.
  244. class ConfigurableClientList : public ClientList {
  245. public:
  246. /// \brief Constructor
  247. ///
  248. /// \param rrclass For which class the list should work.
  249. ConfigurableClientList(const isc::dns::RRClass& rrclass);
  250. /// \brief Exception thrown when there's an error in configuration.
  251. class ConfigurationError : public Exception {
  252. public:
  253. ConfigurationError(const char* file, size_t line, const char* what) :
  254. Exception(file, line, what)
  255. {}
  256. };
  257. /// \brief Sets the configuration.
  258. ///
  259. /// This fills the ClientList with data source clients corresponding to the
  260. /// configuration. The data source clients are newly created or recycled
  261. /// from previous configuration.
  262. ///
  263. /// If any error is detected, an exception is thrown and the current
  264. /// configuration is preserved.
  265. ///
  266. /// \param configuration The JSON element describing the configuration to
  267. /// use.
  268. /// \param allow_cache If it is true, the 'cache' option of the
  269. /// configuration is used and some zones are cached into an In-Memory
  270. /// data source according to it. If it is false, it is ignored and
  271. /// no In-Memory data sources are created.
  272. /// \throw DataSourceError if there's a problem creating a data source
  273. /// client.
  274. /// \throw ConfigurationError if the configuration is invalid in some
  275. /// sense.
  276. /// \throw BadValue if configuration is NULL
  277. /// \throw Unexpected if something misbehaves (like the data source
  278. /// returning NULL iterator).
  279. /// \throw NotImplemented if the auto-detection of list of zones is
  280. /// needed.
  281. /// \throw Whatever is propagated from within the data source.
  282. void configure(const isc::data::ConstElementPtr& configuration,
  283. bool allow_cache);
  284. /// \brief Returns the currently active configuration.
  285. ///
  286. /// In case configure was not called yet, it returns an empty
  287. /// list, which corresponds to the default content.
  288. const isc::data::ConstElementPtr& getConfiguration() const {
  289. return (configuration_);
  290. }
  291. /// \brief Result of the reload() method.
  292. enum ReloadResult {
  293. CACHE_DISABLED, ///< The cache is not enabled in this list.
  294. ZONE_NOT_CACHED, ///< Zone is served directly, not from cache.
  295. ZONE_NOT_FOUND, ///< Zone does not exist or not cached.
  296. ZONE_SUCCESS ///< The zone was successfully reloaded or
  297. /// the writer provided.
  298. };
  299. /// \brief Reloads a cached zone.
  300. ///
  301. /// This method finds a zone which is loaded into a cache and reloads it.
  302. /// This may be used to renew the cache when the underlying data source
  303. /// changes.
  304. ///
  305. /// \param zone The origin of the zone to reload.
  306. /// \return A status if the command worked.
  307. /// \throw DataSourceError or anything else that the data source
  308. /// containing the zone might throw is propagated.
  309. /// \throw DataSourceError if something unexpected happens, like when
  310. /// the original data source no longer contains the cached zone.
  311. ReloadResult reload(const dns::Name& zone);
  312. private:
  313. /// \brief Convenience type shortcut
  314. typedef boost::shared_ptr<memory::ZoneWriter> ZoneWriterPtr;
  315. public:
  316. /// \brief Return value of getCachedZoneWriter()
  317. ///
  318. /// A pair containing status and the zone writer, for the
  319. /// getCachedZoneWriter() method.
  320. typedef std::pair<ReloadResult, ZoneWriterPtr> ZoneWriterPair;
  321. /// \brief Return a zone writer that can be used to reload a zone.
  322. ///
  323. /// This looks up a cached copy of zone and returns the ZoneWriter
  324. /// that can be used to reload the content of the zone. This can
  325. /// be used instead of reload() -- reload() works synchronously, which
  326. /// is not what is needed every time.
  327. ///
  328. /// \param zone The origin of the zone to reload.
  329. /// \return The result has two parts. The first one is a status describing
  330. /// if it worked or not (and in case it didn't, also why). If the
  331. /// status is ZONE_SUCCESS, the second part contains a shared pointer
  332. /// to the writer. If the status is anything else, the second part is
  333. /// NULL.
  334. /// \throw DataSourceError or anything else that the data source
  335. /// containing the zone might throw is propagated.
  336. /// \throw DataSourceError if something unexpected happens, like when
  337. /// the original data source no longer contains the cached zone.
  338. ZoneWriterPair getCachedZoneWriter(const dns::Name& zone);
  339. /// \brief Implementation of the ClientList::find.
  340. virtual FindResult find(const dns::Name& zone,
  341. bool want_exact_match = false,
  342. bool want_finder = true) const;
  343. /// \brief This holds one data source client and corresponding information.
  344. ///
  345. /// \todo The content yet to be defined.
  346. struct DataSourceInfo {
  347. // Plays a role of default constructor too (for vector)
  348. DataSourceInfo(const dns::RRClass& rrclass,
  349. const boost::shared_ptr
  350. <isc::datasrc::memory::ZoneTableSegment>&
  351. ztable_segment,
  352. bool has_cache = false,
  353. const std::string& name = std::string());
  354. DataSourceInfo(DataSourceClient* data_src_client,
  355. const DataSourceClientContainerPtr& container,
  356. bool has_cache, const dns::RRClass& rrclass,
  357. const boost::shared_ptr
  358. <isc::datasrc::memory::ZoneTableSegment>&
  359. ztable_segment, const std::string& name);
  360. DataSourceClient* data_src_client_;
  361. DataSourceClientContainerPtr container_;
  362. // Accessor to cache_ in the form of DataSourceClient, hiding
  363. // the existence of InMemoryClient as much as possible. We should
  364. // really consider cleaner abstraction, but for now it works.
  365. // This is also only intended to be used in auth unit tests right now.
  366. // No other applications or tests may use it.
  367. const DataSourceClient* getCacheClient() const;
  368. boost::shared_ptr<memory::InMemoryClient> cache_;
  369. boost::shared_ptr<memory::ZoneTableSegment> ztable_segment_;
  370. std::string name_;
  371. };
  372. /// \brief The collection of data sources.
  373. typedef std::vector<DataSourceInfo> DataSources;
  374. /// \brief Convenience type alias.
  375. ///
  376. /// \see getDataSource
  377. typedef std::pair<DataSourceClient*, DataSourceClientContainerPtr>
  378. DataSourcePair;
  379. /// \brief Create a data source client of given type and configuration.
  380. ///
  381. /// This is a thin wrapper around the DataSourceClientContainer
  382. /// constructor. The function is here to make it possible for tests
  383. /// to replace the DataSourceClientContainer with something else.
  384. /// Also, derived classes could want to create the data source clients
  385. /// in a different way, though inheriting this class is not recommended.
  386. ///
  387. /// The parameters are the same as of the constructor.
  388. /// \return Pair containing both the data source client and the container.
  389. /// The container might be NULL in the derived class, it is
  390. /// only stored so the data source client is properly destroyed when
  391. /// not needed. However, in such case, it is the caller's
  392. /// responsibility to ensure the data source client is deleted when
  393. /// needed.
  394. virtual DataSourcePair getDataSourceClient(const std::string& type,
  395. const data::ConstElementPtr&
  396. configuration);
  397. /// \brief Get status information of all internal data sources.
  398. ///
  399. /// Get a DataSourceStatus for current state of each data source client
  400. /// in this list.
  401. std::vector<DataSourceStatus> getStatus() const;
  402. public:
  403. /// \brief Access to the data source clients.
  404. ///
  405. /// It can be used to examine the loaded list of data sources clients
  406. /// directly. It is not known if it is of any use other than testing, but
  407. /// it might be, so it is just made public (there's no real reason to
  408. /// hide it).
  409. const DataSources& getDataSources() const { return (data_sources_); }
  410. private:
  411. struct MutableResult;
  412. /// \brief Internal implementation of find.
  413. ///
  414. /// The class itself needs to do some internal searches in other methods,
  415. /// so the implementation is shared.
  416. ///
  417. /// The result is returned as parameter because MutableResult is not
  418. /// defined in the header file.
  419. ///
  420. /// If there's no match, the result is not modified. Therefore, this
  421. /// expects to get a fresh result object each time it is called, not
  422. /// to reuse it.
  423. void findInternal(MutableResult& result, const dns::Name& name,
  424. bool want_exact_match, bool want_finder) const;
  425. const isc::dns::RRClass rrclass_;
  426. /// \brief Currently active configuration.
  427. isc::data::ConstElementPtr configuration_;
  428. /// \brief The last set value of allow_cache.
  429. bool allow_cache_;
  430. protected:
  431. /// \brief The data sources held here.
  432. ///
  433. /// All our data sources are stored here. It is protected to let the
  434. /// tests in. You should consider it private if you ever want to
  435. /// derive this class (which is not really recommended anyway).
  436. DataSources data_sources_;
  437. };
  438. /// \brief Shortcut typedef for maps of client_lists.
  439. typedef boost::shared_ptr<std::map<
  440. isc::dns::RRClass, boost::shared_ptr<ConfigurableClientList> > >
  441. ClientListMapPtr;
  442. } // namespace datasrc
  443. } // namespace isc
  444. #endif // DATASRC_CONTAINER_H