d2_process.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // Copyright (C) 2013-2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this
  5. // file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. #ifndef D2_PROCESS_H
  7. #define D2_PROCESS_H
  8. #include <d2/d_process.h>
  9. #include <d2/d2_queue_mgr.h>
  10. #include <d2/d2_update_mgr.h>
  11. namespace isc {
  12. namespace d2 {
  13. /// @brief DHCP-DDNS Application Process
  14. ///
  15. /// D2Process provides the top level application logic for DHCP-driven DDNS
  16. /// update processing. It provides the asynchronous event processing required
  17. /// to receive DNS mapping change requests and carry them out.
  18. /// It implements the DProcessBase interface, which structures it such that it
  19. /// is a managed "application", controlled by a management layer.
  20. class D2Process : public DProcessBase {
  21. public:
  22. /// @brief Defines the shutdown types supported by D2Process
  23. ///
  24. /// * SD_NORMAL - Stops the queue manager and finishes all current
  25. /// transactions before exiting. This is the default.
  26. ///
  27. /// * SD_DRAIN_FIRST - Stops the queue manager but continues processing
  28. /// requests from the queue until it is empty.
  29. ///
  30. /// * SD_NOW - Exits immediately.
  31. enum ShutdownType {
  32. SD_NORMAL,
  33. SD_DRAIN_FIRST,
  34. SD_NOW
  35. };
  36. /// @brief Defines the point at which to resume receiving requests.
  37. /// If the receive queue has become full, D2Process will "pause" the
  38. /// reception of requests by putting the queue manager in the stopped
  39. /// state. Once the number of entries has decreased to this percentage
  40. /// of the maximum allowed, D2Process will "resume" receiving requests
  41. /// by restarting the queue manager.
  42. static const unsigned int QUEUE_RESTART_PERCENT;
  43. /// @brief Constructor
  44. ///
  45. /// Construction creates the configuration manager, the queue
  46. /// manager, and the update manager.
  47. ///
  48. /// @param name name is a text label for the process. Generally used
  49. /// in log statements, but otherwise arbitrary.
  50. /// @param io_service is the io_service used by the caller for
  51. /// asynchronous event handling.
  52. ///
  53. /// @throw DProcessBaseError if io_service is NULL.
  54. D2Process(const char* name, const asiolink::IOServicePtr& io_service);
  55. /// @brief Called after instantiation to perform initialization unique to
  56. /// D2.
  57. ///
  58. /// This is invoked by the controller after command line arguments but
  59. /// PRIOR to configuration reception. The base class provides this method
  60. /// as a place to perform any derivation-specific initialization steps
  61. /// that are inapppropriate for the constructor but necessary prior to
  62. /// launch. So far, no such steps have been identified for D2, so its
  63. /// implementantion is empty but required.
  64. ///
  65. /// @throw DProcessBaseError if the initialization fails.
  66. virtual void init();
  67. /// @brief Implements the process's event loop.
  68. ///
  69. /// Once entered, the main control thread remains inside this method
  70. /// until shutdown. The event loop logic is as follows:
  71. /// @code
  72. /// while should not shutdown {
  73. /// process queue manager state change
  74. /// process completed jobs
  75. /// dequeue new jobs
  76. /// wait for IO event(s)
  77. ///
  78. /// ON an exception, exit with fatal error
  79. /// }
  80. /// @endcode
  81. ///
  82. /// To summarize, each pass through the event loop first checks the state
  83. /// of the received queue and takes any steps required to ensure it is
  84. /// operating in the manner necessary. Next the update manager is given
  85. /// a chance to clean up any completed transactions and start new
  86. /// transactions by dequeuing jobs from the request queue. Lastly, it
  87. /// allows IOService to process until one or more event handlers are
  88. /// called. Note that this last step will block until at least one
  89. /// ready handler is invoked. In other words, if no IO events have occurred
  90. /// since it was last called, the event loop will block at this step until
  91. /// an IO event occurs. At that time we return to the top of the loop.
  92. ///
  93. /// @throw DProcessBaseError if an error is encountered. Note that
  94. /// exceptions thrown at this point are assumed to be FATAL exceptions.
  95. /// This includes exceptions generated but not caught by IO callbacks.
  96. /// Services which rely on callbacks are expected to be well behaved and
  97. /// any errors they encounter handled internally.
  98. virtual void run();
  99. /// @brief Initiates the D2Process shutdown process.
  100. ///
  101. /// This is last step in the shutdown event callback chain. It is invoked
  102. /// to notify D2Process that it needs to begin its shutdown procedure.
  103. /// Note that shutting down may be neither instantaneous nor synchronous,
  104. /// This method records the request for and the type of shutdown desired.
  105. /// Generally it will require one or more subsequent events to complete,
  106. /// dependent on the type of shutdown requested. The type of shutdown is
  107. /// specified as an optional argument of the shutdown command. The types
  108. /// of shutdown supported are:
  109. ///
  110. /// * "normal" - Stops the queue manager and finishes all current
  111. /// transactions before exiting. This is the default.
  112. ///
  113. /// * "drain_first" - Stops the queue manager but continues processing
  114. /// requests from the queue until it is empty.
  115. ///
  116. /// * "now" - Exits immediately.
  117. ///
  118. /// @param args Specifies the shutdown "type" as "normal", "drain_first",
  119. /// or "now"
  120. ///
  121. /// @return an Element that contains the results of argument processing,
  122. /// consisting of an integer status value (0 means successful,
  123. /// non-zero means failure), and a string explanation of the outcome.
  124. virtual isc::data::ConstElementPtr
  125. shutdown(isc::data::ConstElementPtr args);
  126. /// @brief Processes the given configuration.
  127. ///
  128. /// This method may be called multiple times during the process lifetime.
  129. /// Certainly once during process startup, and possibly later if the user
  130. /// alters the configuration. This method must not throw, it should catch any
  131. /// processing errors and return a success or failure answer as described
  132. /// below.
  133. ///
  134. /// This method passes the newly received configuration to the configuration
  135. /// manager instance for parsing. The configuration manager parses the
  136. /// configuration and updates the necessary values within the context,
  137. /// assuming it parses correctly. If that's the case this method sets the
  138. /// flag to reconfigure the queue manager and returns a successful response
  139. /// as described below.
  140. ///
  141. /// If the new configuration fails to parse, then the current configuration
  142. /// is retained and a failure response is returned as described below.
  143. ///
  144. /// @param config_set a new configuration (JSON) for the process
  145. /// @return an Element that contains the results of configuration composed
  146. /// of an integer status value (0 means successful, non-zero means failure),
  147. /// and a string explanation of the outcome.
  148. virtual isc::data::ConstElementPtr configure(isc::data::ConstElementPtr
  149. config_set);
  150. /// @brief Processes the given command.
  151. ///
  152. /// This method is called to execute any custom commands supported by the
  153. /// process. This method must not throw, it should catch any processing
  154. /// errors and return a success or failure answer as described below.
  155. ///
  156. /// @param command is a string label representing the command to execute.
  157. /// @param args is a set of arguments (if any) required for the given
  158. /// command. It can be a NULL pointer if no arguments exist for a command.
  159. /// @return an Element that contains the results of command composed
  160. /// of an integer status value (0 means successful, non-zero means failure),
  161. /// and a string explanation of the outcome.
  162. virtual isc::data::ConstElementPtr command(const std::string& command,
  163. isc::data::ConstElementPtr args);
  164. /// @brief Destructor
  165. virtual ~D2Process();
  166. protected:
  167. /// @brief Monitors current queue manager state, takes action accordingly
  168. ///
  169. /// This method ensures that the queue manager transitions to the state
  170. /// most appropriate to the operational state of the D2Process and any
  171. /// events that may have occurred since it was last called. It is called
  172. /// once for each iteration of the event loop. It is essentially a
  173. /// switch statement based on the D2QueueMgr's current state. The logic
  174. /// is as follows:
  175. ///
  176. /// If the state is D2QueueMgr::RUNNING, and the queue manager needs to be
  177. /// reconfigured or we have been told to shutdown, then instruct the queue
  178. /// manager to stop listening. Exit the method.
  179. ///
  180. /// If the state is D2QueueMgr::STOPPED_QUEUE_FULL, then check if the
  181. /// number of entries in the queue has fallen below the "resume threshold".
  182. /// If it has, then instruct the queue manager to start listening. Exit
  183. /// the method.
  184. ///
  185. /// If the state is D2QueueMgr::STOPPED_RECV_ERROR, then attempt to recover
  186. /// by calling reconfigureQueueMgr(). Exit the method.
  187. ///
  188. /// If the state is D2QueueMgr::STOPPING, simply exit the method. This is
  189. /// a NOP condition as we are waiting for the IO cancel event
  190. ///
  191. /// For any other state, (NOT_INITTED,INITTED,STOPPED), if the reconfigure
  192. /// queue flag is set, call reconfigureQueueMgr(). Exit the method.
  193. ///
  194. /// This method is exception safe.
  195. virtual void checkQueueStatus();
  196. /// @brief Initializes then starts the queue manager.
  197. ///
  198. /// This method initializes the queue manager with the current
  199. /// configuration parameters and instructs it to start listening.
  200. /// Note the existing listener instance (if it exists) is destroyed,
  201. /// and that a new listener is created during initialization.
  202. ///
  203. /// This method is exception safe.
  204. virtual void reconfigureQueueMgr();
  205. /// @brief Allows IO processing to run until at least callback is invoked.
  206. ///
  207. /// This method is called from within the D2Process main event loop and is
  208. /// the point at which the D2Process blocks, waiting for IO events to
  209. /// cause IO event callbacks to be invoked.
  210. ///
  211. /// If callbacks are ready to be executed upon entry, the method will
  212. /// return as soon as these callbacks have completed. If no callbacks
  213. /// are ready, then it will wait (indefinitely) until at least one callback
  214. /// is executed.
  215. ///
  216. /// @note: Should become desirable to periodically force an
  217. /// event, an interval timer could be used to do so.
  218. ///
  219. /// @return The number of callback handlers executed, or 0 if the IO
  220. /// service has been stopped.
  221. ///
  222. /// @throw This method does not throw directly, but the execution of
  223. /// callbacks invoked in response to IO events might. If so, these
  224. /// will propagate upward out of this method.
  225. virtual size_t runIO();
  226. /// @brief Indicates whether or not the process can perform a shutdown.
  227. ///
  228. /// Determines if the process has been instructed to shutdown and if
  229. /// the criteria for performing the type of shutdown requested has been
  230. /// met.
  231. ///
  232. /// @return Returns true if the criteria has been met, false otherwise.
  233. virtual bool canShutdown() const;
  234. /// @brief Sets queue reconfigure indicator to the given value.
  235. ///
  236. /// @param value is the new value to assign to the indicator
  237. ///
  238. /// @note this method is really only intended for testing purposes.
  239. void setReconfQueueFlag(const bool value) {
  240. reconf_queue_flag_ = value;
  241. }
  242. /// @brief Sets the shutdown type to the given value.
  243. ///
  244. /// @param value is the new value to assign to shutdown type.
  245. ///
  246. /// @note this method is really only intended for testing purposes.
  247. void setShutdownType(const ShutdownType& value) {
  248. shutdown_type_ = value;
  249. }
  250. public:
  251. /// @brief Returns a pointer to the configuration manager.
  252. /// Note, this method cannot return a reference as it uses dynamic
  253. /// pointer casting of the base class configuration manager.
  254. D2CfgMgrPtr getD2CfgMgr();
  255. /// @brief Returns a reference to the queue manager.
  256. const D2QueueMgrPtr& getD2QueueMgr() const {
  257. return (queue_mgr_);
  258. }
  259. /// @brief Returns a reference to the update manager.
  260. const D2UpdateMgrPtr& getD2UpdateMgr() const {
  261. return (update_mgr_);
  262. }
  263. /// @brief Returns true if the queue manager should be reconfigured.
  264. bool getReconfQueueFlag() const {
  265. return (reconf_queue_flag_);
  266. }
  267. /// @brief Returns the type of shutdown requested.
  268. ///
  269. /// Note, this value is meaningless unless shouldShutdown() returns true.
  270. ShutdownType getShutdownType() const {
  271. return (shutdown_type_);
  272. }
  273. /// @brief Returns a text label for the given shutdown type.
  274. ///
  275. /// @param type the numerical shutdown type for which the label is desired.
  276. ///
  277. /// @return A text label corresponding the value or "invalid" if the
  278. /// value is not a valid value.
  279. static const char* getShutdownTypeStr(const ShutdownType& type);
  280. private:
  281. /// @brief Pointer to our queue manager instance.
  282. D2QueueMgrPtr queue_mgr_;
  283. /// @brief Pointer to our update manager instance.
  284. D2UpdateMgrPtr update_mgr_;
  285. /// @brief Indicates if the queue manager should be reconfigured.
  286. bool reconf_queue_flag_;
  287. /// @brief Indicates the type of shutdown requested.
  288. ShutdownType shutdown_type_;
  289. };
  290. /// @brief Defines a shared pointer to D2Process.
  291. typedef boost::shared_ptr<D2Process> D2ProcessPtr;
  292. }; // namespace isc::d2
  293. }; // namespace isc
  294. #endif