d2_update_mgr.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Copyright (C) 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 D2_UPDATE_MGR_H
  15. #define D2_UPDATE_MGR_H
  16. /// @file d2_update_mgr.h This file defines the class D2UpdateMgr.
  17. #include <exceptions/exceptions.h>
  18. #include <d2/d2_asio.h>
  19. #include <d2/d2_log.h>
  20. #include <d2/d2_queue_mgr.h>
  21. #include <d2/d2_cfg_mgr.h>
  22. #include <d2/nc_trans.h>
  23. #include <boost/noncopyable.hpp>
  24. #include <boost/shared_ptr.hpp>
  25. #include <map>
  26. namespace isc {
  27. namespace d2 {
  28. /// @brief Thrown if the update manager encounters a general error.
  29. class D2UpdateMgrError : public isc::Exception {
  30. public:
  31. D2UpdateMgrError(const char* file, size_t line, const char* what) :
  32. isc::Exception(file, line, what) { };
  33. };
  34. /// @brief Defines a list of transactions.
  35. typedef std::map<TransactionKey, NameChangeTransactionPtr> TransactionList;
  36. /// @brief D2UpdateMgr creates and manages update transactions.
  37. ///
  38. /// D2UpdateMgr is the DHCP_DDNS task master, instantiating and then supervising
  39. /// transactions that execute the DNS updates needed to fulfill the requests
  40. /// (NameChangeRequests) received from DHCP_DDNS clients (e.g. DHCP servers).
  41. ///
  42. /// D2UpdateMgr uses the services of D2QueueMgr to monitor the queue of
  43. /// NameChangeRequests and select and dequeue requests for processing.
  44. /// When request is dequeued for processing it is removed from the queue and
  45. /// wrapped in NameChangeTransaction and added to the D2UpdateMgr's list of
  46. /// transactions.
  47. ///
  48. /// As part of the process of forming transactions, D2UpdateMgr matches each
  49. /// request with the appropriate list of DNS servers. This matching is based
  50. /// upon request attributes, primarily the FQDN and update direction (forward
  51. /// or reverse). D2UpdateMgr uses the services of D2CfgMgr to match requests
  52. /// to DNS server lists.
  53. ///
  54. /// Once created, each transaction is responsible for carrying out the steps
  55. /// required to fulfill its specific request. These steps typically consist of
  56. /// one or more DNS packet exchanges with the appropriate DNS server. As
  57. /// transactions complete, D2UpdateMgr removes them from the transaction list,
  58. /// replacing them with new transactions.
  59. ///
  60. /// D2UpdateMgr carries out each of the above steps, from with a method called
  61. /// sweep(). This method is intended to be called as IO events complete.
  62. /// The upper layer(s) are responsible for calling sweep in a timely and cyclic
  63. /// manner.
  64. ///
  65. class D2UpdateMgr : public boost::noncopyable {
  66. public:
  67. /// @brief Maximum number of concurrent transactions
  68. /// NOTE that 32 is an arbitrary choice picked for the initial
  69. /// implementation.
  70. static const size_t MAX_TRANSACTIONS_DEFAULT = 32;
  71. // @todo This structure is not yet used. It is here in anticipation of
  72. // enabled statistics capture.
  73. struct Stats {
  74. uint64_t start_time_;
  75. uint64_t stop_time_;
  76. uint64_t update_count_;
  77. uint64_t min_update_time_;
  78. uint64_t max_update_time_;
  79. uint64_t server_rejects_;
  80. uint64_t server_timeouts_;
  81. };
  82. /// @brief Constructor
  83. ///
  84. /// @param queue_mgr reference to the queue manager receiving requests
  85. /// @param cfg_mgr reference to the configuration manager
  86. /// @param io_service IO service used by the upper layer(s) to manage
  87. /// IO events
  88. /// @param max_transactions the maximum number of concurrent transactions
  89. ///
  90. /// @throw D2UpdateMgrError if either the queue manager or configuration
  91. /// managers are NULL, or max transactions is less than one.
  92. D2UpdateMgr(D2QueueMgrPtr& queue_mgr, D2CfgMgrPtr& cfg_mgr,
  93. IOServicePtr& io_service,
  94. const size_t max_transactions = MAX_TRANSACTIONS_DEFAULT);
  95. /// @brief Destructor
  96. virtual ~D2UpdateMgr();
  97. /// @brief Check current transactions; start transactions for new requests.
  98. ///
  99. /// This method is the primary public interface used by the upper layer. It
  100. /// should be called as IO events complete. During each invocation it does
  101. /// the following:
  102. ///
  103. /// - Removes all completed transactions from the transaction list.
  104. ///
  105. /// - If the request queue is not empty and the number of transactions
  106. /// in the transaction list has not reached maximum allowed, then select
  107. /// a request from the queue.
  108. ///
  109. /// - If a request was selected, start a new transaction for it and
  110. /// add the transaction to the list of transactions.
  111. void sweep();
  112. protected:
  113. /// @brief Performs post-completion cleanup on completed transactions.
  114. ///
  115. /// Iterates through the list of transactions and removes any that have
  116. /// reached completion. This method may expand in complexity or even
  117. /// disappear altogether as the implementation matures.
  118. void checkFinishedTransactions();
  119. /// @brief Starts a transaction for the next eligible request in the queue.
  120. ///
  121. /// This method will scan the request queue for the next request to
  122. /// dequeue. The current implementation starts at the front of the queue
  123. /// and looks for the first request for whose DHCID there is no current
  124. /// transaction in progress.
  125. ///
  126. /// If a request is selected, it is removed from the queue and transaction
  127. /// is constructed for it.
  128. ///
  129. /// It is possible that no such request exists, though this is likely to be
  130. /// rather rare unless a system is frequently seeing requests for the same
  131. /// clients in quick succession.
  132. void pickNextJob();
  133. /// @brief Create a new transaction for the given request.
  134. ///
  135. /// This method will attempt to match the request to a list of configured
  136. /// DNS servers. If a list of servers is found, it will instantiate a
  137. /// transaction for it and add the transaction to the transaction list.
  138. ///
  139. /// If no servers are found that match the request, this constitutes a
  140. /// configuration error. The error will be logged and the request will
  141. /// be discarded.
  142. ///
  143. /// @param ncr the NameChangeRequest for which to create a transaction.
  144. ///
  145. /// @throw D2UpdateMgrError if a transaction for this DHCID already
  146. /// exists. Note this would be programmatic error.
  147. void makeTransaction(isc::dhcp_ddns::NameChangeRequestPtr& ncr);
  148. public:
  149. /// @brief Gets the UpdateMgr's IOService.
  150. ///
  151. /// @return returns a reference to the IOService
  152. const IOServicePtr& getIOService() {
  153. return (io_service_);
  154. }
  155. /// @brief Returns the maximum number of concurrent transactions.
  156. size_t getMaxTransactions() const {
  157. return (max_transactions_);
  158. }
  159. /// @brief Sets the maximum number of entries allowed in the queue.
  160. ///
  161. /// @param max_transactions is the new maximum number of transactions
  162. ///
  163. /// @throw Throws D2QueueMgrError if the new value is less than one or if
  164. /// the new value is less than the number of entries currently in the
  165. /// queue.
  166. void setMaxTransactions(const size_t max_transactions);
  167. /// @brief Search the transaction list for the given key.
  168. ///
  169. /// @param key the transaction key value for which to search.
  170. ///
  171. /// @return Iterator pointing to the entry found. If no entry is
  172. /// it will point to the list end position.
  173. TransactionList::iterator findTransaction(const TransactionKey& key);
  174. /// @brief Returns the transaction list end position.
  175. TransactionList::iterator transactionListEnd();
  176. /// @brief Returns the transaction list beg position.
  177. TransactionList::iterator transactionListBegin();
  178. /// @brief Convenience method that checks transaction list for the given key
  179. ///
  180. /// @param key the transaction key value for which to search.
  181. ///
  182. /// @return Returns true if the key is found within the list, false
  183. /// otherwise.
  184. bool hasTransaction(const TransactionKey& key);
  185. /// @brief Removes the entry pointed to by key from the transaction list.
  186. ///
  187. /// Removes the entry referred to by key if it exists. It has no effect
  188. /// if the entry is not found.
  189. ///
  190. /// @param key of the transaction to remove
  191. void removeTransaction(const TransactionKey& key);
  192. /// @brief Immediately discards all entries in the transaction list.
  193. ///
  194. /// @todo For now this just wipes them out. We might need something
  195. /// more elegant, that allows a cancel first.
  196. void clearTransactionList();
  197. /// @brief Convenience method that returns the number of requests queued.
  198. size_t getQueueCount() const;
  199. /// @brief Returns the current number of transactions.
  200. size_t getTransactionCount() const;
  201. private:
  202. /// @brief Pointer to the queue manager.
  203. D2QueueMgrPtr queue_mgr_;
  204. /// @brief Pointer to the configuration manager.
  205. D2CfgMgrPtr cfg_mgr_;
  206. /// @brief Primary IOService instance.
  207. /// This is the IOService that the upper layer(s) use for IO events, such
  208. /// as shutdown and configuration commands. It is the IOService that is
  209. /// passed into transactions to manager their IO events.
  210. /// (For future reference, multi-threaded transactions would each use their
  211. /// own IOService instance.)
  212. IOServicePtr io_service_;
  213. /// @brief Maximum number of concurrent transactions.
  214. size_t max_transactions_;
  215. /// @brief List of transactions.
  216. TransactionList transaction_list_;
  217. };
  218. /// @brief Defines a pointer to a D2UpdateMgr instance.
  219. typedef boost::shared_ptr<D2UpdateMgr> D2UpdateMgrPtr;
  220. } // namespace isc::d2
  221. } // namespace isc
  222. #endif