d2_update_mgr.h 11 KB

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