base
This commit is contained in:
@@ -0,0 +1,576 @@
|
||||
/***************************************************************************
|
||||
Database Connection Pool ( DbConnPool.cpp )
|
||||
-----------------------------------------
|
||||
|
||||
begin : 2013/02/26
|
||||
copyright : (C) 2013 Solbox Inc.
|
||||
author : Development 1 Team
|
||||
- 2013/02/26 - 1st dadamin
|
||||
email : dev1@solbox.com
|
||||
version : 3.2.0
|
||||
|
||||
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
||||
Redistribution and use in source and binary forms, with or with out
|
||||
modification, are not permitted in outside of SolutionBox Inc.
|
||||
***************************************************************************/
|
||||
#include "rc_mngd.h"
|
||||
#include "Configs.h"
|
||||
#include "DbConnPool.h"
|
||||
#include "Database.h"
|
||||
#include "Logger.h"
|
||||
#include "UtilFn.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
|
||||
#define GET_SLEEP 1000 // microsecond
|
||||
|
||||
CMasterDBpool *CMasterDBpool::m_inst = NULL;
|
||||
CSlaveDBpool *CSlaveDBpool::m_inst = NULL;
|
||||
|
||||
CConnDBpool::CConnDBpool(CDatabaseInfo info)
|
||||
: m_dbinfo(info), m_exitpool(false), m_lastset(NULL)
|
||||
,m_poolcnt(0), m_isrecreate(false), m_alivetime(-1)
|
||||
,m_tabletype(-1)
|
||||
{
|
||||
pthread_mutex_init(&m_mutex, NULL);
|
||||
pthread_mutex_init(&m_alivemutex, NULL);
|
||||
pthread_cond_init(&m_alivecond, NULL);
|
||||
}
|
||||
|
||||
CConnDBpool::~CConnDBpool()
|
||||
{
|
||||
pthread_mutex_destroy(&m_mutex);
|
||||
pthread_mutex_destroy(&m_alivemutex);
|
||||
pthread_cond_destroy(&m_alivecond);
|
||||
}
|
||||
|
||||
int CConnDBpool::MakeConnect( int pool )
|
||||
{
|
||||
ostringstream msg;
|
||||
for(int i=0 ; i < pool ; i++)
|
||||
{
|
||||
DataBase * tmp = new DataBase();
|
||||
|
||||
if( tmp->PgOpenDB( m_dbinfo.m_szRcdbIp, m_dbinfo.m_nRcdbPort,
|
||||
m_dbinfo.m_szRcdbName, m_dbinfo.m_szRcdbAcct, m_dbinfo.m_szRcdbAcctPw ) == NULL )
|
||||
{
|
||||
msg << "Database connect error : " << tmp->GetErrorMessage();
|
||||
LOGACONSOLE(LERR, msg);
|
||||
delete tmp;
|
||||
continue;
|
||||
}
|
||||
|
||||
// XML library(UTF-8 자동 변환) 인코딩 문자를 지원하기 위해서 DB client UTF-8 설정함
|
||||
if (tmp->PgSetClientEncoding("UTF-8") != 0)
|
||||
{
|
||||
msg << "Database Set Client Encoding error : " << tmp->GetErrorMessage();
|
||||
LOGACONSOLE(LERR, msg);
|
||||
delete tmp;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 2014.06.06 dadamin
|
||||
// Pool 생성 시 현재 생성된 DB의 형상을 체크한다.
|
||||
if (m_tabletype < 0)
|
||||
{
|
||||
if (SetTargetTableType(tmp) == false)
|
||||
{
|
||||
delete tmp;
|
||||
DestroyPool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_poolmap.insert(make_pair(tmp, CConnDBpool::POOL_FREE));
|
||||
}
|
||||
|
||||
return m_poolmap.size();
|
||||
}
|
||||
|
||||
int CConnDBpool::CreatePool( int poolcnt /* = 4 */ )
|
||||
{
|
||||
ostringstream msg;
|
||||
// keep alive thread
|
||||
int nRet = pthread_create(&m_keepalive, 0, CConnDBpool::KeepPoolAlive, this);
|
||||
if( nRet )
|
||||
{
|
||||
msg << "Thread create failed.: errno: " << errno;
|
||||
LOGACONSOLE(LERR, msg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// pool
|
||||
m_poolcnt = MakeConnect(poolcnt);
|
||||
|
||||
if (m_poolcnt == 0)
|
||||
{
|
||||
// alive thread end
|
||||
m_exitpool = true;
|
||||
pthread_cond_signal(&m_alivecond);
|
||||
pthread_join(m_keepalive, NULL);
|
||||
m_exitpool = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return m_poolcnt;
|
||||
}
|
||||
|
||||
int CConnDBpool::DestroyPool()
|
||||
{
|
||||
m_exitpool = true;
|
||||
map<DataBase*, short>::iterator iter;
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
while(m_poolmap.size() > 0 )
|
||||
{
|
||||
iter = m_poolmap.begin();
|
||||
if(iter->second == CConnDBpool::POOL_FREE
|
||||
|| iter->second == CConnDBpool::POOL_ERR
|
||||
|| iter->second == CConnDBpool::POOL_CLOSE )
|
||||
{
|
||||
DataBase *data = static_cast<DataBase *>(iter->first);
|
||||
delete (DataBase *) data;
|
||||
m_poolmap.erase(iter);
|
||||
}
|
||||
else
|
||||
sleep(1);
|
||||
}
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
//
|
||||
pthread_cond_signal(&m_alivecond);
|
||||
pthread_join(m_keepalive, NULL);
|
||||
|
||||
/*
|
||||
for( iter = m_poolmap.begin(); !m_poolmap.empty()&& iter != m_poolmap.end(); iter++ )
|
||||
{
|
||||
if(iter->second == conndbpool::POOL_FREE)
|
||||
{
|
||||
DataBase *data = static_cast<DataBase *>(iter->first);
|
||||
delete (DataBase *) data;
|
||||
m_poolmap.f
|
||||
m_poolmap.erase(iter);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return m_poolmap.size();
|
||||
}
|
||||
|
||||
DataBase * CConnDBpool::GetConnFromPool(int timeout)
|
||||
{
|
||||
ostringstream msg;
|
||||
DataBase * r = NULL;
|
||||
|
||||
int64_t usetime = 0;
|
||||
int64_t out = timeout*1000*1000;
|
||||
|
||||
time_t t = time(NULL);
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
map<DataBase*, short>::iterator iter = m_poolmap.begin();
|
||||
if(m_lastset)
|
||||
{
|
||||
iter = m_poolmap.find(m_lastset);
|
||||
if( iter != m_poolmap.end() )
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
|
||||
if( m_poolmap.empty() )
|
||||
{
|
||||
int make = 0;
|
||||
if(m_isrecreate)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
msg << "DB Pool ReCeate.";
|
||||
LOGACONSOLE(LDBG, msg);
|
||||
#endif // _DEBUG
|
||||
make = MakeConnect(m_poolcnt);
|
||||
}
|
||||
|
||||
if (make == 0)
|
||||
{
|
||||
msg << "DB Pool empty.";
|
||||
LOGACONSOLE(LERR, msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( iter == m_poolmap.end() )
|
||||
{
|
||||
iter = m_poolmap.begin();
|
||||
}
|
||||
|
||||
for( ; !m_poolmap.empty()&& iter != m_poolmap.end(); )
|
||||
{
|
||||
if(iter->second == CConnDBpool::POOL_FREE)
|
||||
{
|
||||
iter->second = CConnDBpool::POOL_USE;
|
||||
r = iter->first;
|
||||
m_lastset = r;
|
||||
break;
|
||||
}
|
||||
else if (iter->second == CConnDBpool::POOL_ERR
|
||||
|| iter->second == CConnDBpool::POOL_CLOSE)
|
||||
{
|
||||
bool is_closed = (iter->second == CConnDBpool::POOL_CLOSE);
|
||||
DataBase * d = iter->first;
|
||||
|
||||
if(is_closed)
|
||||
{
|
||||
msg << "Force Closed. And Add Database object.";
|
||||
LOGACONSOLE(LDBG, msg);
|
||||
MakeConnect(1);
|
||||
}
|
||||
|
||||
m_poolmap.erase(iter++);
|
||||
if(d == m_lastset)
|
||||
m_lastset = NULL;
|
||||
delete d;
|
||||
}
|
||||
else
|
||||
iter++;
|
||||
}
|
||||
|
||||
if( r == NULL)
|
||||
{
|
||||
solusleep(GET_SLEEP);
|
||||
if( usetime > 10*1000*1000)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
msg << "GetConnFromPool have waited longer than 10 seconds.";
|
||||
LOGACONSOLE(LDBG, msg);
|
||||
#endif // _DEBUG
|
||||
}
|
||||
|
||||
if( out > 0 )
|
||||
{
|
||||
usetime += GET_SLEEP;
|
||||
|
||||
if(usetime > out)
|
||||
{
|
||||
msg << "GetConnFromPool Timeout." << usetime << "," << out <<
|
||||
"," << time(NULL) -t;
|
||||
LOGACONSOLE(LWAR, msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (r == NULL);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void CConnDBpool::ReleaseConnToPool(DataBase * t, short nMode /* = CConnDBpool::POOL_USE */)
|
||||
{
|
||||
//pthread_mutex_lock(&m_mutex);
|
||||
|
||||
map<DataBase*, short>::iterator iter = m_poolmap.find(t);
|
||||
if( iter != m_poolmap.end() )
|
||||
{
|
||||
if(iter->second==CConnDBpool::POOL_USE)
|
||||
{
|
||||
if( nMode == CConnDBpool::POOL_USE)
|
||||
{
|
||||
iter->second = CConnDBpool::POOL_FREE;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->second = nMode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
bool CConnDBpool::IsTimeoutAlive()
|
||||
{
|
||||
bool r = false;
|
||||
pthread_mutex_lock(&m_alivemutex);
|
||||
struct timespec to;
|
||||
|
||||
if(m_alivetime > 0 )
|
||||
to.tv_sec = time(NULL) + m_alivetime;
|
||||
else
|
||||
to.tv_sec = time(NULL) + 5;
|
||||
|
||||
to.tv_nsec = 0;
|
||||
|
||||
int err = pthread_cond_timedwait(&m_alivecond, &m_alivemutex, &to);
|
||||
|
||||
if (err == ETIMEDOUT)
|
||||
{
|
||||
if( m_alivetime > 0 )
|
||||
r = true;
|
||||
}
|
||||
else if ( err == 0 )
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
cout << "Set Keep alive Timeout : " << m_alivetime << endl;
|
||||
#endif //_DEBUG
|
||||
r = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&m_alivemutex);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CConnDBpool::SendAliveMsg()
|
||||
{
|
||||
ostringstream msg;
|
||||
ostringstream sql;
|
||||
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
map<DataBase*, short>::iterator iter = m_poolmap.begin();
|
||||
map<DataBase*, short>::iterator enditer = m_poolmap.end();
|
||||
|
||||
sql << "SELECT sp_user_seq, sp_svc_tran_id FROM t_sms_sp_svc_product LIMIT 1";
|
||||
while(iter != enditer)
|
||||
{
|
||||
DataBase * d = iter->first;
|
||||
if(iter->second == CConnDBpool::POOL_FREE)
|
||||
{
|
||||
iter->second = CConnDBpool::POOL_USE;
|
||||
d->PgDoExec( const_cast<char*> (sql.str().c_str()) );
|
||||
if( d->PgResult(DataBase::CLEAR) < 0 )
|
||||
{
|
||||
msg << "Send alive : message failed : " << iter->first->GetErrorMessage();
|
||||
LOGACONSOLE(LERR, msg);
|
||||
iter->second=CConnDBpool::POOL_ERR;
|
||||
iter++;
|
||||
//m_poolmap.erase(iter++);
|
||||
//delete d;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->second = CConnDBpool::POOL_FREE;
|
||||
msg << "Send alive : message success.";
|
||||
LOGACONSOLE(LDBG, msg);
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
else if (iter->second == CConnDBpool::POOL_ERR)
|
||||
{
|
||||
msg << "Send alive : Error Pool remove.";
|
||||
LOGACONSOLE(LINF, msg);
|
||||
m_poolmap.erase(iter++);
|
||||
delete d;
|
||||
}
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
|
||||
if( m_poolmap.empty() )
|
||||
{
|
||||
int make = 0;
|
||||
if(m_isrecreate)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
msg << "DB Pool ReCeate.";
|
||||
LOGACONSOLE(LDBG, msg);
|
||||
#endif // _DEBUG
|
||||
make = MakeConnect(m_poolcnt);
|
||||
}
|
||||
|
||||
if (make == 0)
|
||||
{
|
||||
msg << "DB Pool empty.";
|
||||
LOGACONSOLE(LERR, msg);
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
void* CConnDBpool::KeepPoolAlive( void* pdata )
|
||||
{
|
||||
CConnDBpool* pObject = reinterpret_cast<CConnDBpool *>(pdata);
|
||||
ostringstream msg;
|
||||
|
||||
while( pObject->IsExit() == false )
|
||||
{
|
||||
bool b = pObject->IsTimeoutAlive();
|
||||
msg << "KeepPoolAlive Timeout - run : " << b;
|
||||
LOGACONSOLE(LDBG, msg);
|
||||
if( pObject->IsExit() == false && b )
|
||||
{
|
||||
// send keep alive message
|
||||
pObject->SendAliveMsg();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CConnDBpool::SetKeepAliveTimeout(int sec)
|
||||
{
|
||||
m_alivetime = sec;
|
||||
pthread_cond_signal(&m_alivecond);
|
||||
return m_alivetime;
|
||||
}
|
||||
|
||||
int CConnDBpool::GetFreePoolCnt()
|
||||
{
|
||||
int r = 0;
|
||||
map<DataBase*, short>::iterator iter;
|
||||
// pthread_mutex_lock(&m_mutex);
|
||||
for( iter = m_poolmap.begin(); !m_poolmap.empty()&& iter != m_poolmap.end(); iter++ )
|
||||
{
|
||||
if(iter->second == CConnDBpool::POOL_FREE)
|
||||
{
|
||||
r++;
|
||||
}
|
||||
}
|
||||
// pthread_mutex_unlock(&m_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
void CConnDBpool::printstatus(string prefixed)
|
||||
{
|
||||
int f = 0, u = 0;
|
||||
map<DataBase*, short>::iterator iter;
|
||||
|
||||
if(m_exitpool == true ) return;
|
||||
// pthread_mutex_lock(&m_mutex);
|
||||
for( iter = m_poolmap.begin(); !m_poolmap.empty()&& iter != m_poolmap.end(); iter++ )
|
||||
{
|
||||
if(iter->second == CConnDBpool::POOL_FREE)
|
||||
{
|
||||
f++;
|
||||
}
|
||||
else
|
||||
{
|
||||
u++;
|
||||
}
|
||||
}
|
||||
|
||||
ostringstream msg;
|
||||
if( prefixed.empty() == false )
|
||||
msg << "["<< prefixed <<"]";
|
||||
|
||||
msg <<"DB connection Pool - " <<"total : " << m_poolmap.size() << "(" << u <<
|
||||
"/" << f << ")";
|
||||
|
||||
LOGACONSOLE(LINF, msg);
|
||||
}
|
||||
|
||||
// 2014.06.07 dadamin
|
||||
// 현재 DB 형상 체크
|
||||
bool CConnDBpool::SetTargetTableType(DataBase * d)
|
||||
{
|
||||
ostringstream msg;
|
||||
|
||||
if (d == NULL)
|
||||
return false;
|
||||
|
||||
d->PgDoExec("SELECT * FROM pg_tables WHERE schemaname = 'public' AND tablename = 't_dav_resource'");
|
||||
if (d->PgResult(DataBase::NOT_CLEAR) < 0)
|
||||
{
|
||||
d->PgClear();
|
||||
msg << "Set Target Table Type failed : " << d->GetErrorMessage();
|
||||
LOGACONSOLE(LERR, msg);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (d->GetNoTuples() > 0)
|
||||
{
|
||||
m_tabletype = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tabletype = 1;
|
||||
}
|
||||
|
||||
d->PgClear();
|
||||
msg << "Set Target Table Type : " << m_tabletype;
|
||||
|
||||
LOG(LDBG, msg.str().c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// master db pool
|
||||
CMasterDBpool::CMasterDBpool(CDatabaseInfo info)
|
||||
: CConnDBpool(info)
|
||||
{
|
||||
}
|
||||
|
||||
CMasterDBpool::~CMasterDBpool()
|
||||
{
|
||||
}
|
||||
|
||||
void CMasterDBpool::init(CDatabaseInfo info)
|
||||
{
|
||||
if( CMasterDBpool::m_inst == NULL )
|
||||
{
|
||||
CMasterDBpool::m_inst = new CMasterDBpool(info);
|
||||
}
|
||||
}
|
||||
|
||||
CMasterDBpool* CMasterDBpool::getInstance()
|
||||
{
|
||||
return CMasterDBpool::m_inst;
|
||||
}
|
||||
|
||||
int CMasterDBpool::release()
|
||||
{
|
||||
int r = -1;
|
||||
if( CMasterDBpool::m_inst != NULL )
|
||||
{
|
||||
r = CMasterDBpool::m_inst->DestroyPool();
|
||||
delete CMasterDBpool::m_inst;
|
||||
CMasterDBpool::m_inst = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
// slave db pool
|
||||
CSlaveDBpool::CSlaveDBpool(CDatabaseInfo info)
|
||||
: CConnDBpool(info)
|
||||
{
|
||||
}
|
||||
|
||||
CSlaveDBpool::~CSlaveDBpool()
|
||||
{
|
||||
}
|
||||
|
||||
void CSlaveDBpool::init(CDatabaseInfo info)
|
||||
{
|
||||
if( CSlaveDBpool::m_inst == NULL )
|
||||
{
|
||||
CSlaveDBpool::m_inst = new CSlaveDBpool(info);
|
||||
}
|
||||
}
|
||||
|
||||
CSlaveDBpool* CSlaveDBpool::getInstance()
|
||||
{
|
||||
return CSlaveDBpool::m_inst;
|
||||
}
|
||||
|
||||
int CSlaveDBpool::release()
|
||||
{
|
||||
int r = -1;
|
||||
if(CSlaveDBpool::m_inst != NULL )
|
||||
{
|
||||
r = CSlaveDBpool::m_inst->DestroyPool();
|
||||
delete CSlaveDBpool::m_inst;
|
||||
CSlaveDBpool::m_inst = NULL;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
Reference in New Issue
Block a user