client_list.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. // Copyright (C) 2012-2013 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 <datasrc/memory/zone_table_segment.h>
  22. #include <datasrc/zone_table_accessor.h>
  23. #include <vector>
  24. #include <boost/shared_ptr.hpp>
  25. #include <boost/scoped_ptr.hpp>
  26. #include <boost/noncopyable.hpp>
  27. namespace isc {
  28. namespace datasrc {
  29. class ZoneFinder;
  30. typedef boost::shared_ptr<ZoneFinder> ZoneFinderPtr;
  31. class DataSourceClient;
  32. typedef boost::shared_ptr<DataSourceClient> DataSourceClientPtr;
  33. class DataSourceClientContainer;
  34. typedef boost::shared_ptr<DataSourceClientContainer>
  35. DataSourceClientContainerPtr;
  36. // XXX: it's better to even hide the existence of the "memory" namespace.
  37. // We should probably consider pimpl for details of ConfigurableClientList
  38. // and hide real definitions except for itself and tests.
  39. namespace memory {
  40. class InMemoryClient;
  41. class ZoneWriter;
  42. }
  43. namespace internal {
  44. class CacheConfig;
  45. }
  46. /// \brief Segment status of the cache
  47. ///
  48. /// Describes the status in which the memory segment for the in-memory cache of
  49. // /given data source is.
  50. enum MemorySegmentState {
  51. /// \brief No segment used for this data source.
  52. ///
  53. /// This is usually a result of the cache being disabled.
  54. SEGMENT_UNUSED,
  55. /// \brief It is a mapped segment and we wait for information how to map
  56. /// it.
  57. SEGMENT_WAITING,
  58. /// \brief The segment is ready to be used.
  59. SEGMENT_INUSE
  60. };
  61. /// \brief Status of one data source.
  62. ///
  63. /// This indicates the status a data soure is in. It is used with segment
  64. /// and cache management, to discover the data sources that need external
  65. /// mapping or local loading.
  66. ///
  67. /// In future, it may be extended for other purposes, such as performing an
  68. /// operation on named data source.
  69. class DataSourceStatus {
  70. public:
  71. /// \brief Constructor
  72. ///
  73. /// Sets initial values.
  74. DataSourceStatus(const std::string& name, MemorySegmentState state,
  75. const std::string& type) :
  76. name_(name),
  77. type_(type),
  78. state_(state)
  79. {
  80. assert (state != SEGMENT_UNUSED);
  81. assert (!type.empty());
  82. }
  83. /// \brief Constructor
  84. ///
  85. /// Sets initial values. The state is set as SEGMENT_UNUSED and the
  86. /// type is effectively unspecified.
  87. DataSourceStatus(const std::string& name) :
  88. name_(name),
  89. type_(""),
  90. state_(SEGMENT_UNUSED)
  91. {}
  92. /// \brief Get the segment state
  93. MemorySegmentState getSegmentState() const {
  94. return (state_);
  95. }
  96. /// \brief Get the segment type
  97. ///
  98. /// \note Specific values of the type are only meaningful for the
  99. /// corresponding memory segment implementation and modules that
  100. /// directly manage the segments. Other normal applications should
  101. /// treat them as opaque identifiers.
  102. ///
  103. /// \throw isc::InvalidOperation if called and state is SEGMENT_UNUSED.
  104. const std::string& getSegmentType() const {
  105. if (getSegmentState() == SEGMENT_UNUSED) {
  106. isc_throw(isc::InvalidOperation,
  107. "No segment used, no type therefore.");
  108. }
  109. return (type_);
  110. }
  111. /// \brief Get the name.
  112. const std::string& getName() const {
  113. return (name_);
  114. }
  115. private:
  116. std::string name_;
  117. std::string type_;
  118. MemorySegmentState state_;
  119. };
  120. typedef boost::shared_ptr<const ZoneTableAccessor> ConstZoneTableAccessorPtr;
  121. /// \brief The list of data source clients.
  122. ///
  123. /// The purpose of this class is to hold several data source clients and search
  124. /// through them to find one containing a zone best matching a request.
  125. ///
  126. /// All the data source clients should be for the same class. If you need
  127. /// to handle multiple classes, you need to create multiple separate lists.
  128. ///
  129. /// This is an abstract base class. It is not expected we would use multiple
  130. /// implementation inside the servers (but it is not forbidden either), we
  131. /// have it to allow easy testing. It is possible to create a mock-up class
  132. /// instead of creating a full-blown configuration. The real implementation
  133. /// is the ConfigurableClientList.
  134. class ClientList : public boost::noncopyable {
  135. protected:
  136. /// \brief Constructor.
  137. ///
  138. /// It is protected to prevent accidental creation of the abstract base
  139. /// class.
  140. ClientList() {}
  141. public:
  142. /// \brief Virtual destructor
  143. virtual ~ClientList() {}
  144. /// \brief Structure holding the (compound) result of find.
  145. ///
  146. /// As this is read-only structure, we don't bother to create accessors.
  147. /// Instead, all the member variables are defined as const and can be
  148. /// accessed directly.
  149. struct FindResult {
  150. /// \brief Internal class for holding a reference.
  151. ///
  152. /// This is used to make sure the data source client isn't released
  153. /// too soon.
  154. ///
  155. /// \see life_keeper_;
  156. class LifeKeeper {
  157. public:
  158. virtual ~LifeKeeper() {};
  159. };
  160. /// \brief Constructor.
  161. ///
  162. /// It simply fills in the member variables according to the
  163. /// parameters. See the member descriptions for their meaning.
  164. FindResult(DataSourceClient* dsrc_client, const ZoneFinderPtr& finder,
  165. bool exact_match,
  166. const boost::shared_ptr<LifeKeeper>& life_keeper) :
  167. dsrc_client_(dsrc_client),
  168. finder_(finder),
  169. exact_match_(exact_match),
  170. life_keeper_(life_keeper)
  171. {}
  172. /// \brief Negative answer constructor.
  173. ///
  174. /// This constructs a result for negative answer. Both pointers are
  175. /// NULL, and exact_match_ is false.
  176. FindResult() :
  177. dsrc_client_(NULL),
  178. exact_match_(false)
  179. {}
  180. /// \brief Comparison operator.
  181. ///
  182. /// It is needed for tests and it might be of some use elsewhere
  183. /// too.
  184. bool operator ==(const FindResult& other) const {
  185. return (dsrc_client_ == other.dsrc_client_ &&
  186. finder_ == other.finder_ &&
  187. exact_match_ == other.exact_match_);
  188. }
  189. /// \brief The found data source client.
  190. ///
  191. /// The client of the data source containing the best matching zone.
  192. /// If no such data source exists, this is NULL pointer.
  193. ///
  194. /// Note that the pointer is valid only as long the ClientList which
  195. /// returned the pointer is alive and was not reconfigured or you hold
  196. /// a reference to life_keeper_. The ownership is preserved within the
  197. /// ClientList.
  198. DataSourceClient* const dsrc_client_;
  199. /// \brief The finder for the requested zone.
  200. ///
  201. /// This is the finder corresponding to the best matching zone.
  202. /// This may be NULL even in case the datasrc_ is something
  203. /// else, depending on the find options.
  204. ///
  205. /// \see find
  206. const ZoneFinderPtr finder_;
  207. /// \brief If the result is an exact match.
  208. const bool exact_match_;
  209. /// \brief Something that holds the dsrc_client_ valid.
  210. ///
  211. /// As long as you hold the life_keeper_, the dsrc_client_ is
  212. /// guaranteed to be valid.
  213. const boost::shared_ptr<LifeKeeper> life_keeper_;
  214. };
  215. /// \brief Search for a zone through the data sources.
  216. ///
  217. /// This searches the contained data source clients for a one that best
  218. /// matches the zone name.
  219. ///
  220. /// There are two expected usage scenarios. One is answering queries. In
  221. /// this case, the zone finder is needed and the best matching superzone
  222. /// of the searched name is needed. Therefore, the call would look like:
  223. ///
  224. /// \code FindResult result(list->find(queried_name));
  225. /// if (result.dsrc_client_) {
  226. /// if (result.finder_) {
  227. /// createTheAnswer(result.finder_);
  228. /// } else { // broken zone, return SERVFAIL
  229. /// createErrorMessage(Rcode.SERVFAIL());
  230. /// }
  231. /// } else {
  232. /// createNotAuthAnswer();
  233. /// } \endcode
  234. ///
  235. /// Note that it is possible that \c finder_ is NULL while \c datasrc_
  236. /// is not. This happens if the zone is configured to be served from
  237. /// the data source but it is broken in some sense and doesn't hold any
  238. /// zone data, e.g., when the zone file has an error or the secondary
  239. /// zone hasn't been transferred yet. The caller needs to expect the case
  240. /// and handle it accordingly.
  241. ///
  242. /// The other scenario is manipulating zone data (XfrOut, XfrIn, DDNS,
  243. /// ...). In this case, the finder itself is not so important. However,
  244. /// we need an exact match (if we want to manipulate zone data, we must
  245. /// know exactly, which zone we are about to manipulate). Then the call
  246. ///
  247. /// \code FindResult result(list->find(zone_name, true, false));
  248. /// if (result.datasrc_) {
  249. /// ZoneUpdaterPtr updater(result.datasrc_->getUpdater(zone_name);
  250. /// ...
  251. /// } \endcode
  252. ///
  253. /// \param zone The name of the zone to look for.
  254. /// \param want_exact_match If it is true, it returns only exact matches.
  255. /// If the best possible match is partial, a negative result is
  256. /// returned instead. It is possible the caller could check it and
  257. /// act accordingly if the result would be partial match, but with this
  258. /// set to true, the find might be actually faster under some
  259. /// circumstances.
  260. /// \param want_finder If this is false, the finder_ member of FindResult
  261. /// might be NULL even if the corresponding data source is found. This
  262. /// is because of performance, in some cases the finder is a side
  263. /// result of the searching algorithm (therefore asking for it again
  264. /// would be a waste), but under other circumstances it is not, so
  265. /// providing it when it is not needed would also be wasteful.
  266. ///
  267. /// Other things are never the side effect of searching, therefore the
  268. /// caller can get them explicitly (the updater, journal reader and
  269. /// iterator).
  270. /// \return A FindResult describing the data source and zone with the
  271. /// longest match against the zone parameter.
  272. virtual FindResult find(const dns::Name& zone,
  273. bool want_exact_match = false,
  274. bool want_finder = true) const = 0;
  275. /// \brief Creates a ZoneTableAccessor object for the specified data
  276. /// source.
  277. ///
  278. /// \param datasrc_name If not empty, the name of the data source.
  279. /// \param use_cache If true, create a zone table for in-memory cache.
  280. /// \throw NotImplemented if this method is not implemented.
  281. /// \return A pointer to the accessor, or NULL if the requested data
  282. /// source is not found.
  283. virtual ConstZoneTableAccessorPtr
  284. getZoneTableAccessor(const std::string& datasrc_name,
  285. bool use_cache) const = 0;
  286. };
  287. /// \brief Shared pointer to the list.
  288. typedef boost::shared_ptr<ClientList> ClientListPtr;
  289. /// \brief Shared const pointer to the list.
  290. typedef boost::shared_ptr<const ClientList> ConstClientListPtr;
  291. /// \brief Concrete implementation of the ClientList, which is constructed
  292. /// based on configuration.
  293. ///
  294. /// This is the implementation which is expected to be used in the servers.
  295. /// However, it is expected most of the code will use it as the ClientList,
  296. /// only the creation is expected to be direct.
  297. ///
  298. /// While it is possible to inherit this class, it is not expected to be
  299. /// inherited except for tests.
  300. class ConfigurableClientList : public ClientList {
  301. public:
  302. /// \brief Constructor
  303. ///
  304. /// \param rrclass For which class the list should work.
  305. ConfigurableClientList(const isc::dns::RRClass& rrclass);
  306. /// \brief Exception thrown when there's an error in configuration.
  307. class ConfigurationError : public Exception {
  308. public:
  309. ConfigurationError(const char* file, size_t line, const char* what) :
  310. Exception(file, line, what)
  311. {}
  312. };
  313. /// \brief Sets the configuration.
  314. ///
  315. /// This fills the ClientList with data source clients corresponding to the
  316. /// configuration. The data source clients are newly created or recycled
  317. /// from previous configuration.
  318. ///
  319. /// If any error is detected, an exception is thrown and the current
  320. /// configuration is preserved.
  321. ///
  322. /// \param configuration The JSON element describing the configuration to
  323. /// use.
  324. /// \param allow_cache If it is true, the 'cache' option of the
  325. /// configuration is used and some zones are cached into an In-Memory
  326. /// data source according to it. If it is false, it is ignored and
  327. /// no In-Memory data sources are created.
  328. /// \throw DataSourceError if there's a problem creating a data source
  329. /// client.
  330. /// \throw ConfigurationError if the configuration is invalid in some
  331. /// sense.
  332. /// \throw BadValue if configuration is NULL
  333. /// \throw Unexpected if something misbehaves (like the data source
  334. /// returning NULL iterator).
  335. /// \throw NotImplemented if the auto-detection of list of zones is
  336. /// needed.
  337. /// \throw Whatever is propagated from within the data source.
  338. void configure(const isc::data::ConstElementPtr& configuration,
  339. bool allow_cache);
  340. /// \brief Returns the currently active configuration.
  341. ///
  342. /// In case configure was not called yet, it returns an empty
  343. /// list, which corresponds to the default content.
  344. const isc::data::ConstElementPtr& getConfiguration() const {
  345. return (configuration_);
  346. }
  347. /// \brief Resets the zone table segment for a datasource with a new
  348. /// memory segment.
  349. ///
  350. /// See documentation of \c ZoneTableSegment interface
  351. /// implementations (such as \c ZoneTableSegmentMapped) for the
  352. /// syntax of \c config_params.
  353. ///
  354. /// \param datasrc_name The name of the data source whose segment to reset
  355. /// \param mode The open mode for the new memory segment
  356. /// \param config_params The configuration for the new memory segment.
  357. void resetMemorySegment
  358. (const std::string& datasrc_name,
  359. memory::ZoneTableSegment::MemorySegmentOpenMode mode,
  360. isc::data::ConstElementPtr config_params);
  361. /// \brief Convenience type shortcut
  362. typedef boost::shared_ptr<memory::ZoneWriter> ZoneWriterPtr;
  363. /// \brief Codes indicating in-memory cache status for a given zone name.
  364. ///
  365. /// This is used as a result of the getCachedZoneWriter() method.
  366. enum CacheStatus {
  367. CACHE_DISABLED, ///< The cache is not enabled in this list.
  368. ZONE_NOT_CACHED, ///< Zone is not to be cached (including the case
  369. /// where caching is disabled for the specific
  370. /// data source).
  371. ZONE_NOT_FOUND, ///< Zone does not exist in this list.
  372. CACHE_NOT_WRITABLE, ///< The cache is not writable (and zones can't
  373. /// be loaded)
  374. DATASRC_NOT_FOUND, ///< Specific data source for load is specified
  375. /// but it's not in the list
  376. ZONE_SUCCESS ///< Zone to be cached is successfully found and
  377. /// is ready to be loaded
  378. };
  379. /// \brief Return value of getCachedZoneWriter()
  380. ///
  381. /// A pair containing status and the zone writer, for the
  382. /// getCachedZoneWriter() method.
  383. typedef std::pair<CacheStatus, ZoneWriterPtr> ZoneWriterPair;
  384. /// \brief Return a zone writer that can be used to (re)load a zone.
  385. ///
  386. /// By default this method identifies the first data source in the list
  387. /// that should serve the zone of the given name, and returns a ZoneWriter
  388. /// object that can be used to load the content of the zone, in a specific
  389. /// way for that data source.
  390. ///
  391. /// If the optional \c datasrc_name parameter is provided with a non empty
  392. /// string, this method only tries to load the specified zone into or with
  393. /// the data source which has the given name, regardless where in the list
  394. /// that data source is placed. Even if the given name of zone doesn't
  395. /// exist in the data source, other data sources are not searched and
  396. /// this method simply returns ZONE_NOT_FOUND in the first element
  397. /// of the pair.
  398. ///
  399. /// \param zone The origin of the zone to load.
  400. /// \param datasrc_name If not empty, the name of the data source
  401. /// to be used for loading the zone (see above).
  402. /// \return The result has two parts. The first one is a status indicating
  403. /// if it worked or not (and in case it didn't, also why). If the
  404. /// status is ZONE_SUCCESS, the second part contains a shared pointer
  405. /// to the writer. If the status is anything else, the second part is
  406. /// NULL.
  407. /// \throw DataSourceError or anything else that the data source
  408. /// containing the zone might throw is propagated.
  409. ZoneWriterPair getCachedZoneWriter(const dns::Name& zone,
  410. const std::string& datasrc_name = "");
  411. /// \brief Implementation of the ClientList::find.
  412. virtual FindResult find(const dns::Name& zone,
  413. bool want_exact_match = false,
  414. bool want_finder = true) const;
  415. /// \brief This holds one data source client and corresponding information.
  416. ///
  417. /// \todo The content yet to be defined.
  418. struct DataSourceInfo {
  419. DataSourceInfo(DataSourceClient* data_src_client,
  420. const DataSourceClientContainerPtr& container,
  421. boost::shared_ptr<internal::CacheConfig> cache_conf,
  422. const dns::RRClass& rrclass,
  423. const std::string& name);
  424. DataSourceClient* data_src_client_;
  425. DataSourceClientContainerPtr container_;
  426. // Accessor to cache_ in the form of DataSourceClient, hiding
  427. // the existence of InMemoryClient as much as possible. We should
  428. // really consider cleaner abstraction, but for now it works.
  429. // This is also only intended to be used in auth unit tests right now.
  430. // No other applications or tests may use it.
  431. const DataSourceClient* getCacheClient() const;
  432. boost::shared_ptr<memory::InMemoryClient> cache_;
  433. boost::shared_ptr<memory::ZoneTableSegment> ztable_segment_;
  434. std::string name_;
  435. // cache_conf_ can be accessed only from this read-only getter,
  436. // to protect its integrity as much as possible.
  437. const internal::CacheConfig* getCacheConfig() const {
  438. return (cache_conf_.get());
  439. }
  440. private:
  441. boost::shared_ptr<internal::CacheConfig> cache_conf_;
  442. };
  443. /// \brief The collection of data sources.
  444. typedef std::vector<DataSourceInfo> DataSources;
  445. /// \brief Convenience type alias.
  446. ///
  447. /// \see getDataSource
  448. typedef std::pair<DataSourceClient*, DataSourceClientContainerPtr>
  449. DataSourcePair;
  450. /// \brief Create a data source client of given type and configuration.
  451. ///
  452. /// This is a thin wrapper around the DataSourceClientContainer
  453. /// constructor. The function is here to make it possible for tests
  454. /// to replace the DataSourceClientContainer with something else.
  455. /// Also, derived classes could want to create the data source clients
  456. /// in a different way, though inheriting this class is not recommended.
  457. ///
  458. /// Some types of data sources can be internal to the \c ClientList
  459. /// implementation and do not require a corresponding dynamic module
  460. /// loaded via \c DataSourceClientContainer. In such a case, this method
  461. /// simply returns a pair of null pointers. It will help the caller reduce
  462. /// type dependent processing. Currently, "MasterFiles" is considered to
  463. /// be this type of data sources.
  464. ///
  465. /// The parameters are the same as of the constructor.
  466. /// \return Pair containing both the data source client and the container.
  467. /// The container might be NULL in the derived class, it is
  468. /// only stored so the data source client is properly destroyed when
  469. /// not needed. However, in such case, it is the caller's
  470. /// responsibility to ensure the data source client is deleted when
  471. /// needed.
  472. virtual DataSourcePair getDataSourceClient(const std::string& type,
  473. const data::ConstElementPtr&
  474. configuration);
  475. /// \brief Get status information of all internal data sources.
  476. ///
  477. /// Get a DataSourceStatus for current state of each data source client
  478. /// in this list.
  479. ///
  480. /// This may throw standard exceptions, such as std::bad_alloc. Otherwise,
  481. /// it is exception free.
  482. std::vector<DataSourceStatus> getStatus() const;
  483. public:
  484. /// \brief Access to the data source clients.
  485. ///
  486. /// It can be used to examine the loaded list of data sources clients
  487. /// directly. It is not known if it is of any use other than testing, but
  488. /// it might be, so it is just made public (there's no real reason to
  489. /// hide it).
  490. const DataSources& getDataSources() const { return (data_sources_); }
  491. /// \brief Creates a ZoneTableAccessor object for the specified data
  492. /// source.
  493. ///
  494. /// \param datasrc_name If not empty, the name of the data source
  495. /// \param use_cache If true, create a zone table for in-memory cache.
  496. /// \note At present, the only concrete implementation of
  497. /// ZoneTableAccessor is ZoneTableAccessorCache, so \c use_cache must be
  498. /// true.
  499. /// \throw NotImplemented if \c use_cache is false.
  500. /// \return A pointer to the accessor, or NULL if the requested data
  501. /// source is not found.
  502. ConstZoneTableAccessorPtr
  503. getZoneTableAccessor(const std::string& datasrc_name,
  504. bool use_cache) const;
  505. private:
  506. struct MutableResult;
  507. /// \brief Internal implementation of find.
  508. ///
  509. /// The class itself needs to do some internal searches in other methods,
  510. /// so the implementation is shared.
  511. ///
  512. /// The result is returned as parameter because MutableResult is not
  513. /// defined in the header file.
  514. ///
  515. /// If there's no match, the result is not modified. Therefore, this
  516. /// expects to get a fresh result object each time it is called, not
  517. /// to reuse it.
  518. void findInternal(MutableResult& result, const dns::Name& name,
  519. bool want_exact_match, bool want_finder) const;
  520. const isc::dns::RRClass rrclass_;
  521. /// \brief Currently active configuration.
  522. isc::data::ConstElementPtr configuration_;
  523. /// \brief The last set value of allow_cache.
  524. bool allow_cache_;
  525. protected:
  526. /// \brief The data sources held here.
  527. ///
  528. /// All our data sources are stored here. It is protected to let the
  529. /// tests in. You should consider it private if you ever want to
  530. /// derive this class (which is not really recommended anyway).
  531. DataSources data_sources_;
  532. };
  533. /// \brief Shortcut typedef for maps of client_lists.
  534. typedef boost::shared_ptr<std::map<
  535. isc::dns::RRClass, boost::shared_ptr<ConfigurableClientList> > >
  536. ClientListMapPtr;
  537. } // namespace datasrc
  538. } // namespace isc
  539. #endif // DATASRC_CONTAINER_H