| | |
| | | #include "stdafx.h" |
| | | #include "ConnectionPool.h" |
| | | ConnectionPool::ConnectionPool() |
| | | { |
| | | if (!parseXmlFile()) |
| | | |
| | | #include <fstream> |
| | | #include <iostream> |
| | | #include <thread> |
| | | |
| | | ConnectionPool* ConnectionPool::getInstance() { |
| | | static ConnectionPool connPool; |
| | | return &connPool; |
| | | } |
| | | |
| | | ConnectionPool::ConnectionPool() { |
| | | // å è½½é
ç½®æä»¶ |
| | | if (!parseJsonFile()) { |
| | | std::cout << "parseJsonFile is failed!" << std::endl; |
| | | return; |
| | | for (m_num = 0; m_num < m_minSize;) { |
| | | bool flag = addConnection(); |
| | | if (!flag) { |
| | | return; |
| | | } |
| | | } |
| | | // 妿å线ç¨çä»»å¡å½æ°æ¯ç±»çééæå½æ°ï¼æä»¬éè¦æå®ä»»å¡å½æ°çå°ååä»»å¡å½æ°çææè
|
| | | thread producer(&ConnectionPool::productConnection, this); // åå»ºè¿æ¥ |
| | | thread recycler(&ConnectionPool::recycleConnection, this); // æ£æµå¹¶éæ¯è¿æ¥ |
| | | // 线ç¨å离ï¼é²æ¢é»å¡ä¸»çº¿ç¨ |
| | | for ( int i = 0 ; i < m_min_conn ; i++ ) { |
| | | addConnection( ); |
| | | } |
| | | // å建ä¸ä¸ªçº¿ç¨ï¼å¯¹è¿æ¥æ°è¿è¡çæ§ ï¼è¿æ¥æ°ä¸è¶³å°±åç»§ç»å建 |
| | | std::thread producer(&ConnectionPool::produce, this); |
| | | // å¯¹è¿æ¥æ°è¿è¡çæ§ ï¼å¦ææå¤ªå¤ç©ºé²å¾çº¿ç¨ ï¼é£ä¹å°±å¯¹å
¶è¿è¡éæ¯ |
| | | std::thread recycler( &ConnectionPool::recycle, this); |
| | | |
| | | // 线ç¨å离 |
| | | producer.detach(); |
| | | recycler.detach(); |
| | | } |
| | | ConnectionPool::~ConnectionPool() |
| | | { |
| | | while (!m_connections.empty()) { |
| | | MysqlConn* conn = m_connections.front(); |
| | | m_connections.pop(); |
| | | delete conn; |
| | | } |
| | | } |
| | | bool ConnectionPool::parseXmlFile() |
| | | { |
| | | TiXmlDocument xml("mysql.xml"); |
| | | // å è½½æä»¶ |
| | | bool res = xml.LoadFile(); |
| | | if (!res) { |
| | | return false; // æç¤º |
| | | } |
| | | // æ ¹ |
| | | TiXmlElement* rootElement = xml.RootElement(); |
| | | TiXmlElement* childElement = rootElement->FirstChildElement("mysql"); |
| | | // 读åä¿¡æ¯ |
| | | m_ip = childElement->FirstChildElement("ip")->GetText(); |
| | | m_port = static_cast<unsigned short>(stoi(string(childElement->FirstChildElement("port")->GetText()))); |
| | | m_user = childElement->FirstChildElement("username")->GetText(); |
| | | m_passwd = childElement->FirstChildElement("password")->GetText(); |
| | | m_dbName = childElement->FirstChildElement("dbName")->GetText(); |
| | | m_minSize = static_cast<int>(stoi(string(childElement->FirstChildElement("minSize")->GetText()))); |
| | | m_maxSize = static_cast<int>(stoi(string(childElement->FirstChildElement("maxSize")->GetText()))); |
| | | m_maxIdleTime = static_cast<int>(stoi(string(childElement->FirstChildElement("maxIdleTime")->GetText()))); |
| | | m_timeout = static_cast<int>(stoi(string(childElement->FirstChildElement("timeout")->GetText()))); |
| | | return true; |
| | | } |
| | | bool ConnectionPool::addConnection() |
| | | { |
| | | MysqlConn* conn = new MysqlConn; |
| | | bool res = conn->connect(m_user, m_passwd, m_dbName, m_ip, m_port); |
| | | if (res) { |
| | | // å·æ°ç©ºé²æ¶é´ |
| | | conn->refreashAliveTime(); |
| | | m_connections.push(conn); |
| | | ++m_num; |
| | | |
| | | bool ConnectionPool::parseJsonFile() { |
| | | |
| | | /*std::ifstream ifs("dbconf.json"); |
| | | Reader rd; |
| | | Value root; |
| | | rd.parse(ifs, root); |
| | | if ( root.isObject( ) ) { |
| | | m_ip = root["ip"].asString(); |
| | | m_port = root["port"].asInt(); |
| | | m_userName = root["userName"].asString(); |
| | | m_passwd = root["password"].asString(); |
| | | m_db = root["dbName"].asString(); |
| | | m_min_conn = root["minSize"].asInt(); |
| | | m_max_conn = root["maxSize"].asInt(); |
| | | max_del_time = root["maxDleTime"].asInt(); |
| | | m_timeout = root["timeout"].asInt(); |
| | | return true; |
| | | }*/ |
| | | return false; |
| | | } |
| | | |
| | | void ConnectionPool::description() { |
| | | std::cout << m_ip << ". " << m_userName << ". " << m_passwd << ". " << m_db << ". " |
| | | << m_port << ". " << m_max_conn << ". " << m_min_conn << ". " << m_timeout << ". " |
| | | << max_del_time << std::endl; |
| | | } |
| | | |
| | | ConnectionPool::~ConnectionPool() { |
| | | while (!m_connkQueue.empty()) { |
| | | MysqlConn* conn = m_connkQueue.front(); |
| | | m_connkQueue.pop(); |
| | | delete conn; |
| | | } |
| | | else { |
| | | |
| | | } |
| | | |
| | | void ConnectionPool::addConnection() { |
| | | MysqlConn* conn = new MysqlConn(); |
| | | if ( !conn->connect( m_ip, m_userName, m_passwd, m_db, m_port ) ) { |
| | | std::cout << "ConnectionPool connect to mysql is failed!" << std::endl; |
| | | delete conn; |
| | | return false; // æç¤º |
| | | return; |
| | | } |
| | | conn->refreshActiveTime( ); |
| | | m_connkQueue.push(conn); |
| | | m_cond.notify_one(); // å¤éä¸ä¸ªçº¿ç¨ |
| | | } |
| | | void ConnectionPool::productConnection() |
| | | { |
| | | |
| | | void ConnectionPool::produce(){ |
| | | while (true) { |
| | | unique_lock<mutex> lc(m_mutex); |
| | | m_cond.wait(lc, [this]() {return m_connections.empty(); }); |
| | | if (m_num < m_maxSize) { |
| | | bool flag = addConnection(); |
| | | if (!flag) { |
| | | return; |
| | | } |
| | | std::unique_lock<std::mutex> lock(m_mutex); |
| | | while (m_connkQueue.size() >= m_min_conn) { // è¿æ¥éåçæ°éå¤§äºæå°çè¿æ¥æ° |
| | | m_cond.wait(lock); |
| | | } |
| | | // å¤é |
| | | m_cond1.notify_all(); |
| | | addConnection(); |
| | | } |
| | | } |
| | | void ConnectionPool::recycleConnection() |
| | | { |
| | | while (true) { |
| | | // ä¼ç 䏿®µæ¶é´ 0.5s |
| | | this_thread::sleep_for(milliseconds(500)); |
| | | lock_guard<mutex> lc(m_mutex); |
| | | while (!m_connections.empty() && m_num > m_minSize) { |
| | | MysqlConn* conn = m_connections.front(); |
| | | if (conn->getAliveTime() >= m_maxIdleTime) { |
| | | m_connections.pop(); |
| | | |
| | | // å é¤ç©ºé²è¿æ¥ |
| | | void ConnectionPool::recycle() { |
| | | while ( true ) { |
| | | std::this_thread::sleep_for( std::chrono::milliseconds(500)); // ä¼ç 500 ms |
| | | std::unique_lock<std::mutex>lock(m_mutex); |
| | | while ( m_connkQueue.size() > m_min_conn ) { |
| | | MysqlConn* conn = m_connkQueue.front( ); |
| | | if (conn->getActiveTime() >= max_del_time) { |
| | | m_connkQueue.pop(); |
| | | delete conn; |
| | | --m_num; |
| | | } |
| | | else { |
| | | break; |
| | |
| | | } |
| | | } |
| | | } |
| | | ConnectionPool* ConnectionPool::getConnectPool() |
| | | { |
| | | // ä¸ä½¿ç¨äºæ¥éç线ç¨å®å
¨çææ±æ¨¡å¼ |
| | | static ConnectionPool pool; // åªå¨ç¬¬ä¸æ¬¡è°ç¨å½æ°æ¶åå§å |
| | | return &pool; |
| | | } |
| | | shared_ptr<MysqlConn> ConnectionPool::getConnection() |
| | | { |
| | | unique_lock<mutex> lc(m_mutex); |
| | | while (m_connections.empty()) { |
| | | if (cv_status::timeout == m_cond1.wait_for(lc, chrono::milliseconds(m_timeout))) { |
| | | if (m_connections.empty()) { |
| | | // cout << "out of time" << endl; |
| | | return nullptr; // ç»æ // æç¤º |
| | | // continue; // å©ç¨whileé
åcontinue ç»§ç»é»å¡ |
| | | } |
| | | |
| | | std::shared_ptr<MysqlConn> ConnectionPool::getMysqlConn() { |
| | | |
| | | std::unique_lock<std::mutex>lock(m_mutex); |
| | | while ( m_connkQueue.empty()) { |
| | | // 妿çå¾
䏿®µæ¶é´å,éåè¿æ¯ä¸ºç©º,è¿åä¸ä¸ª null |
| | | if ( std::cv_status::timeout == m_cond.wait_for(lock, std::chrono::milliseconds(m_timeout)) ) { |
| | | if( m_connkQueue.empty( ) ) return nullptr; |
| | | } |
| | | } |
| | | // è¦æå®å é¤å¨destructorï¼æ¥ä¿è¯è¿æ¥çå½è¿ |
| | | shared_ptr<MysqlConn> conn(m_connections.front(), [this](MysqlConn* conn) { |
| | | // å éä¿è¯éå线ç¨å®å
¨ |
| | | // m_mutex.lock(); // 1 |
| | | unique_lock<mutex> lc(m_mutex); // 2 |
| | | // lock_guard<mutex> lc(m_mutex); // 3 |
| | | conn->refreashAliveTime(); |
| | | m_connections.push(conn); |
| | | // m_mutex.unlock(); // 1 |
| | | std::shared_ptr<MysqlConn> connPtr(std::move(m_connkQueue.front()), [this](MysqlConn* conn) { |
| | | std::unique_lock <std::mutex>lock(m_mutex) ; |
| | | conn->refreshActiveTime(); |
| | | m_connkQueue.push(conn); |
| | | }); |
| | | m_connections.pop(); |
| | | m_cond.notify_all(); |
| | | return conn; |
| | | } |
| | | m_connkQueue.pop(); |
| | | m_cond.notify_one(); // å¤éé»å¡çç产è
线ç¨,å¼å§ç产 |
| | | return connPtr; |
| | | } |