PageRenderTime 32ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/pq/connectionpool.cpp

http://github.com/mozy/mordor
C++ | 130 lines | 109 code | 15 blank | 6 comment | 14 complexity | a3137778e8a7ef51b1b3434d35103624 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2010 Mozy, Inc.
  2. #include "connectionpool.h"
  3. #include <boost/bind.hpp>
  4. #include "mordor/config.h"
  5. #include "mordor/iomanager.h"
  6. #include "mordor/log.h"
  7. #include "mordor/timer.h"
  8. #include "mordor/util.h"
  9. #include "connection.h"
  10. namespace Mordor {
  11. namespace PQ {
  12. static Logger::ptr g_logger = Log::lookup("mordor:pq:connectionpool");
  13. ConnectionPool::ConnectionPool(
  14. const std::string &conninfo, IOManager *iomanager,
  15. size_t num, unsigned long long idleTolerance)
  16. : m_conninfo(conninfo)
  17. , m_iomanager(iomanager)
  18. , m_mutex()
  19. , m_condition(m_mutex)
  20. , m_total(num)
  21. , m_idleTolerance(idleTolerance) {
  22. FiberMutex::ScopedLock lock(m_mutex);
  23. try {
  24. for (size_t i = 0; i < m_total; i++) {
  25. m_freeConnections.push_back(
  26. std::make_pair(boost::shared_ptr<Connection>(
  27. new Connection(m_conninfo, m_iomanager, 0, false)), TimerManager::now()));
  28. }
  29. } catch(...) {
  30. MORDOR_LOG_ERROR(g_logger)
  31. << boost::current_exception_diagnostic_information();
  32. throw;
  33. }
  34. }
  35. ConnectionPool::~ConnectionPool() {
  36. FiberMutex::ScopedLock lock(m_mutex);
  37. while(!m_busyConnections.empty()) {
  38. m_condition.wait();
  39. }
  40. }
  41. bool ConnectionPool::connectionExpired(unsigned long long freeTime) const
  42. {
  43. return (m_idleTolerance != 0) && (TimerManager::now() > (freeTime + m_idleTolerance));
  44. }
  45. boost::shared_ptr<Connection> ConnectionPool::getConnection() {
  46. FiberMutex::ScopedLock lock(m_mutex);
  47. MORDOR_LOG_DEBUG(g_logger) << "Trying to get connection, pool size is "
  48. << m_freeConnections.size();
  49. if (m_freeConnections.empty() && m_busyConnections.size() < m_total) {
  50. MORDOR_LOG_DEBUG(g_logger) << "Trying to creat new connection";
  51. try {
  52. m_freeConnections.push_back(
  53. std::make_pair(boost::shared_ptr<Connection>(
  54. new Connection(m_conninfo, m_iomanager, 0, false)), TimerManager::now()));
  55. } catch(...) {
  56. MORDOR_LOG_ERROR(g_logger)
  57. << boost::current_exception_diagnostic_information();
  58. }
  59. }
  60. while (m_freeConnections.empty()) {
  61. m_condition.wait();
  62. }
  63. MORDOR_ASSERT(!m_freeConnections.empty());
  64. boost::shared_ptr<Connection> conn = (*m_freeConnections.begin()).first;
  65. // For connection which was pre-allocated in constructor but not connected,
  66. // its status is CONNECTION_BAD, so we'd always connect it here.
  67. if (connectionExpired((*m_freeConnections.begin()).second) || conn->status() == CONNECTION_BAD) {
  68. MORDOR_LOG_WARNING(g_logger) << "Connection is expired or bad, try to re-connect";
  69. conn->connect();
  70. }
  71. if (conn->status() != CONNECTION_OK) {
  72. MORDOR_LOG_WARNING(g_logger) << "Connection is bad, try to reset";
  73. try {
  74. conn->reset();
  75. }catch(...) {
  76. MORDOR_LOG_ERROR(g_logger)
  77. << boost::current_exception_diagnostic_information();
  78. throw;
  79. }
  80. }
  81. //The ret is for return value, which has separate counter than
  82. //the share_ptr stored in m_free/m_busyConnections
  83. boost::shared_ptr<Connection> ret(
  84. conn.get(),
  85. boost::bind(&ConnectionPool::releaseConnection, this, _1));
  86. m_busyConnections.push_back(conn);
  87. m_freeConnections.erase(m_freeConnections.begin());
  88. return ret;
  89. }
  90. void ConnectionPool::resize(size_t num) {
  91. FiberMutex::ScopedLock lock(m_mutex);
  92. m_total = num;
  93. while (m_busyConnections.size() + m_freeConnections.size() > m_total &&
  94. !m_freeConnections.empty()) {
  95. m_freeConnections.erase(m_freeConnections.begin());
  96. }
  97. }
  98. void ConnectionPool::releaseConnection(Connection* conn) {
  99. FiberMutex::ScopedLock lock(m_mutex);
  100. MORDOR_LOG_DEBUG(g_logger) << "Release connection " << conn;
  101. boost::shared_ptr<Connection> c(conn, &nop<Connection*>);
  102. std::list<boost::shared_ptr<Connection> >::iterator it
  103. = std::find(m_busyConnections.begin(), m_busyConnections.end(), c);
  104. MORDOR_ASSERT(it != m_busyConnections.end());
  105. c = *it; //This line is necessary,
  106. //or the pointer hold by it will be deleted after the second line
  107. m_busyConnections.erase(it);
  108. if (m_busyConnections.size() + m_freeConnections.size() < m_total) {
  109. m_freeConnections.push_front(std::make_pair(c, TimerManager::now()));
  110. m_condition.signal();
  111. }
  112. MORDOR_LOG_DEBUG(g_logger) << "Free connections "
  113. << m_freeConnections.size();
  114. }
  115. }}