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