datasrc_clients_mgr.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  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_CLIENTS_MGR_H
  15. #define DATASRC_CLIENTS_MGR_H 1
  16. #include <util/threads/thread.h>
  17. #include <util/threads/lock.h>
  18. #include <log/logger_support.h>
  19. #include <log/log_dbglevels.h>
  20. #include <cc/data.h>
  21. #include <auth/auth_log.h>
  22. #include <boost/bind.hpp>
  23. #include <list>
  24. #include <utility>
  25. namespace isc {
  26. namespace auth {
  27. namespace datasrc_clientmgr_internal {
  28. enum CommandID {
  29. NOOP, ///< Do nothing. Only useful for tests
  30. SHUTDOWN ///< Shutdown the builder.
  31. };
  32. typedef std::pair<CommandID, data::ConstElementPtr> Command;
  33. } // namespace datasrc_clientmgr_internal
  34. template <typename ThreadType, typename BuilderType, typename MutexType,
  35. typename CondVarType>
  36. class DataSrcClientsMgrBase {
  37. public:
  38. DataSrcClientsMgrBase() :
  39. builder_(&command_queue_, &cond_, &queue_mutex_),
  40. builder_thread_(boost::bind(&BuilderType::run, &builder_))
  41. {}
  42. ~DataSrcClientsMgrBase() {
  43. // We share class member variables with the builder, which will be
  44. // invalidated after the call to the destructor, so we need to make
  45. // sure the builder thread is terminated. Depending on the timing
  46. // this could time; if we don't want that to happen in this context,
  47. // we may want to introduce a separate 'shutdown()' method.
  48. // Also, since we don't want to propagate exceptions from a destructor,
  49. // we catch any possible ones. In fact the only really expected one
  50. // is Thread::UncaughtException when the builder thread died due to
  51. // an exception. We specifically log it and just ignore others.
  52. try {
  53. sendCommand(datasrc_clientmgr_internal::SHUTDOWN,
  54. data::ConstElementPtr());
  55. builder_thread_.wait();
  56. } catch (const util::thread::Thread::UncaughtException& ex) {
  57. LOG_ERROR(auth_logger, AUTH_DATASRC_CLIENTS_SHUTDOWN_ERROR).
  58. arg(ex.what());
  59. } catch (...) {}
  60. }
  61. private:
  62. void sendCommand(datasrc_clientmgr_internal::CommandID command,
  63. data::ConstElementPtr arg) {
  64. {
  65. typename MutexType::Locker locker(queue_mutex_);
  66. command_queue_.push_back(
  67. datasrc_clientmgr_internal::Command(command, arg));
  68. }
  69. cond_.signal();
  70. }
  71. std::list<datasrc_clientmgr_internal::Command> command_queue_;
  72. CondVarType cond_;
  73. MutexType queue_mutex_;
  74. BuilderType builder_;
  75. ThreadType builder_thread_;
  76. };
  77. namespace datasrc_clientmgr_internal {
  78. template <typename MutexType, typename CondVarType>
  79. class DataSrcClientsBuilderBase {
  80. public:
  81. DataSrcClientsBuilderBase(std::list<Command>* command_queue,
  82. CondVarType* cond, MutexType* queue_mutex) :
  83. command_queue_(command_queue), cond_(cond), queue_mutex_(queue_mutex)
  84. {}
  85. /// Not sure if we need this. It depends on test details.
  86. /// \brief Destructor.
  87. ///
  88. /// This does nothing, but explicitly defined to silence 'unused variable'
  89. /// warnings from some versions of clang++.
  90. ///~DataSrcClientsBuilderBase() {}
  91. void run();
  92. /// separated from run() and made public for the purpose of tests.
  93. ///
  94. /// \return true if it the builder should keep running; false otherwise.
  95. bool handleCommand(const Command& command);
  96. private:
  97. // NOOP command handler. We use this so tests can override it.
  98. void doNoop() {}
  99. // end-in, front-out queue
  100. std::list<Command>* command_queue_;
  101. CondVarType* cond_;
  102. MutexType* queue_mutex_;
  103. //boost::shared_ptr<DataSrcClientListMap>* map;
  104. //MutexType* data_mutex_;
  105. };
  106. // Shortcut typedef for normal use
  107. typedef DataSrcClientsBuilderBase<util::thread::Mutex, util::thread::CondVar>
  108. DataSrcClientsBuilder;
  109. template <typename MutexType, typename CondVarType>
  110. void
  111. DataSrcClientsBuilderBase<MutexType, CondVarType>::run() {
  112. LOG_INFO(auth_logger, AUTH_DATASRC_CLIENTS_BUILDER_STARTED);
  113. try {
  114. bool keep_running = true;
  115. while (keep_running) {
  116. std::list<Command> current_commands;
  117. {
  118. // Move all new commands to local queue under the protection of
  119. // queue_mutex_. Note that list::splice() should never throw.
  120. typename MutexType::Locker locker(*queue_mutex_);
  121. while (command_queue_->empty()) {
  122. cond_->wait(*queue_mutex_);
  123. }
  124. current_commands.splice(current_commands.end(),
  125. *command_queue_);
  126. } // the lock is release here.
  127. while (keep_running && !current_commands.empty()) {
  128. keep_running = handleCommand(current_commands.front());
  129. current_commands.pop_front();
  130. }
  131. }
  132. LOG_INFO(auth_logger, AUTH_DATASRC_CLIENTS_BUILDER_STOPPED);
  133. } catch (const std::exception& ex) {
  134. // We explicitly catch exceptions so we can log it as soon as possible.
  135. LOG_ERROR(auth_logger, AUTH_DATASRC_CLIENTS_BUILDER_FAILED).
  136. arg(ex.what());
  137. throw;
  138. } catch (...) {
  139. LOG_ERROR(auth_logger, AUTH_DATASRC_CLIENTS_BUILDER_FAILED_UNEXPECTED);
  140. throw;
  141. }
  142. }
  143. template <typename MutexType, typename CondVarType>
  144. bool
  145. DataSrcClientsBuilderBase<MutexType, CondVarType>::handleCommand(
  146. const Command& command)
  147. {
  148. LOG_DEBUG(auth_logger, DBGLVL_TRACE_BASIC,
  149. AUTH_DATASRC_CLIENTS_BUILDER_COMMAND).arg(command.first);
  150. switch (command.first) {
  151. case SHUTDOWN:
  152. return (false);
  153. case NOOP:
  154. doNoop();
  155. }
  156. return (true);
  157. }
  158. } // namespace datasrc_clientmgr_internal
  159. /// \brief Shortcut type for normal data source clients manager.
  160. ///
  161. /// In fact, for non test applications this is the only type of this kind
  162. /// to be considered.
  163. typedef DataSrcClientsMgrBase<
  164. util::thread::Thread,
  165. datasrc_clientmgr_internal::DataSrcClientsBuilder,
  166. util::thread::Mutex, util::thread::CondVar> DataSrcClientsMgr;
  167. } // namespace auth
  168. } // namespace isc
  169. #endif // DATASRC_CLIENTS_MGR_H
  170. // Local Variables:
  171. // mode: c++
  172. // End: