/*================================================================= Copyright (C) 2014 BizStation Corp All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =================================================================*/ #include "connectionPool.h" #ifdef __BCPLUSPLUS__ #ifdef _WIN64 #define BZS_LINK_BOOST_SYSTEM #define BZS_LINK_BOOST_THREAD #define BZS_LINK_BOOST_CHRONO namespace boost { void tss_cleanup_implemented() { } } #else #define BZS_LINK_BOOST_THREAD namespace boost { extern "C" void tss_cleanup_implemented() { } } #endif #include #endif namespace bzs { namespace db { namespace protocol { namespace tdap { namespace client { #ifdef TRANSACTD_RB_CALL_WITHOUT_GVL struct busyWaitArguments { mutable boost::condition* m_busy; mutable boost::mutex* m_mutex2; }; void scopedLock(boost::mutex::scoped_lock* lck) { lck->lock(); } void busyWait(busyWaitArguments* args) { boost::mutex::scoped_lock lck(*(args->m_mutex2)); args->m_busy->wait(lck); } #endif // TRANSACTD_RB_CALL_WITHOUT_GVL void releaseConnection(stdDbmCconnectionPool* pool) { pool->releaseOne(); } template connectionPool::connectionPool(int maxConnections) : m_maxConnections(maxConnections) { #ifdef _WIN32 m_shutdownFunc = nsdatabase::getWinTPoolShutdownFunc(); #else m_shutdownFunc = NULL; #endif } template connectionPool::~connectionPool() { if (m_shutdownFunc) { m_shutdownFunc(); #ifndef SWIGRUBY reset(0); #endif } } template Database_Ptr connectionPool::addOne(const connectParams& param) { Database_Ptr db; db = createDatabaseForConnectionPool(db); connectOpen(db, param, true /* new connection*/); m_dbs.push_back(db); return m_dbs[m_dbs.size() - 1]; } template int connectionPool::usingCount() const { boost::mutex::scoped_lock lck(m_mutex, boost::defer_lock); #ifdef TRANSACTD_RB_CALL_WITHOUT_GVL TRANSACTD_RB_CALL_WITHOUT_GVL(scopedLock, lck); #else lck.lock(); #endif int n = 0; for (size_t i = 0; i < m_dbs.size(); i++) { if (m_dbs[i].use_count() > 1) ++n; } return n; } /** Delivery database instance If a connect error is occured then bzs::rtl::exception exception is thrown. */ template Database_Ptr connectionPool::get(const connectParams* param) { boost::mutex::scoped_lock lck(m_mutex, boost::defer_lock); #ifdef TRANSACTD_RB_CALL_WITHOUT_GVL TRANSACTD_RB_CALL_WITHOUT_GVL(scopedLock, lck); #else lck.lock(); #endif assert((param && m_maxConnections) || m_dbs.size()); while (1) { for (size_t i = 0; i < m_dbs.size(); i++) { if (m_dbs[i].use_count() == 1) { if (param) { Database_Ptr db = m_dbs[i]; if (isSameUri(param, db)) return db; } else return m_dbs[i]; } } // create a new database object if there is no free one. if (param && (m_maxConnections > (int)m_dbs.size())) return addOne(*param); // Wait until releaseOne() called #ifdef TRANSACTD_RB_CALL_WITHOUT_GVL busyWaitArguments bwArgs; bwArgs.m_busy = &m_busy; bwArgs.m_mutex2 = &m_mutex2; TRANSACTD_RB_CALL_WITHOUT_GVL(busyWait, bwArgs); #else boost::mutex::scoped_lock lck(m_mutex2); m_busy.wait(lck); #endif } } /** Create database and login the server with each connection. If a connect error is occured then bzs::rtl::exception exception is thrown. */ template void connectionPool::reserve(size_t size, const connectParams& param) { boost::mutex::scoped_lock lck(m_mutex, boost::defer_lock); #ifdef TRANSACTD_RB_CALL_WITHOUT_GVL TRANSACTD_RB_CALL_WITHOUT_GVL(scopedLock, lck); #else lck.lock(); #endif m_maxConnections = (int)size; for (size_t i = 0; i < size; ++i) addOne(param); } /** Set max connections.*/ template void connectionPool::setMaxConnections(int n) { boost::mutex::scoped_lock lck(m_mutex, boost::defer_lock); #ifdef TRANSACTD_RB_CALL_WITHOUT_GVL TRANSACTD_RB_CALL_WITHOUT_GVL(scopedLock, lck); #else lck.lock(); #endif m_maxConnections = n; } /** Return max connections. */ template int connectionPool::maxConnections() const { return m_maxConnections; } template void connectionPool::releaseOne() { m_busy.notify_one(); } // max 5second template bool connectionPool::reset(int waitSec) { boost::mutex::scoped_lock lck(m_mutex, boost::defer_lock); #ifdef TRANSACTD_RB_CALL_WITHOUT_GVL TRANSACTD_RB_CALL_WITHOUT_GVL(scopedLock, lck); #else lck.lock(); #endif bool flag = true; for (int j = 0; j < waitSec * 10; j++) { flag = false; for (size_t i = 0; i < m_dbs.size(); i++) if (m_dbs[i].use_count() != 1) flag = true; if (!flag) break; Sleep(100); } m_dbs.clear(); return flag; } #ifdef USE_DBM_CONNECTION_POOL template class connectionPool; #else template class connectionPool; #endif stdCconnectionPool cpool; } // namespace client } // namespace tdap } // namespace protocol } // namespace db } // namespace bzs