#ifndef __OCI__LIB__POLL__
#define __OCI__LIB__POLL__
#include "ocilib.h"
#include <iostream>
#include <string>
#include <pthread.h>
using namespace std;
class OraConnPool
{
protected:
OraConnPool();
public:
int createConnPool(const char* username,
const char* passwd,
const char* connectString,
int maxCon,
int minCon,
int incrCon);
void destroyConnPool();
string getErrData(void);
OCI_Connection * getConnection();
void freeConnection(OCI_Connection*);
static OraConnPool* getInstance();
string get_last_error();
int get_error_code();
private:
static void* check_con_thread(void* );
bool check_con();
static OraConnPool* _instance_;
OCI_ConnPool *oci_pool;
bool m_init_flag;
bool m_con_pool_restart;
string sErrInfo;
int error_code;
string m_username;
string m_passwd;
string m_connectString;
int m_maxcon;
int m_mincon;
int m_incr;
};
#endif
#include <stdio.h>
#include <stdlib.h>
#include <fstream>
#include <sstream>
using namespace std;
#include "oraconnpool_poll.h"
#define USING_SINGLE_CONNECTION
#undef USING_SINGLE_CONNECTION
#define USING_TEMP_LOG
static string get_current_time()
{
struct tm *t;
time_t ts;
time(&ts);
t = localtime(&ts);
char buffer[30] = {0};
sprintf(buffer,"[%.4d-%.2d-%.2d %.2d:%.2d:%.2d]",t->tm_year + 1900,
t->tm_mon + 1,
t->tm_mday,
t->tm_hour,
t->tm_min,
t->tm_sec);
return string(buffer);
}
static void temp_log(string content )
{
#ifdef USING_TEMP_LOG
string time_str = get_current_time();
string file_name = "/usr/local/ptest/ngx_oci_state_log";
ofstream fobj(file_name.c_str(), ios::app);
if(fobj.is_open())
{
fobj<<time_str <<" "<<content<<endl;
fobj.close();
}
#endif
}
/******************************************************************************************************/
OraConnPool* OraConnPool::_instance_ = NULL;
OraConnPool::OraConnPool():oci_pool(NULL),m_init_flag(false),m_con_pool_restart(false)
{
}
OraConnPool* OraConnPool::getInstance()
{
if (_instance_ == 0)
{
_instance_ = new OraConnPool;
}
return _instance_;
}
int OraConnPool::createConnPool(const char* username, const char* passwd, const char* connectString, int maxCon, int minCon, int incrCon)
{
#ifndef USING_SINGLE_CONNECTION
temp_log("start create connection pool.................");
if(minCon < 0x00 || maxCon < 0x00 || (minCon > maxCon))
{
char buffer[500] = {0};
sprintf(buffer,"param set error , with minCon=%d, maxCon = %d, incrCon = %d", minCon,maxCon,incrCon);
sErrInfo = string(buffer);
return 0x00;
}
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT | OCI_ENV_CONTEXT | OCI_ENV_THREADED))
{
sErrInfo="Error unexpectd when initlize the OCI environment ! Create DB connection pool FAIL";
return 0x00;
}
if(false == m_init_flag)
oci_pool = OCI_PoolCreate(connectString, username, passwd, OCI_POOL_CONNECTION, OCI_SESSION_DEFAULT, minCon, maxCon, incrCon);
else
oci_pool = OCI_PoolCreate(m_connectString.c_str(), m_username.c_str(), m_passwd.c_str(), OCI_POOL_CONNECTION, OCI_SESSION_DEFAULT, m_mincon, m_maxcon, m_incr);
if(oci_pool == NULL)
{
char buffer[500] = {0};
sprintf(buffer,"Error in creating DB connect Pool.Pool is NULL with parameters sid=%s,user=%s,pwd=%s.", connectString,username,passwd);
sErrInfo = string(buffer);
return 0x00;
}
if(!m_init_flag)
{
m_username = string(username);
m_passwd = string(passwd);
m_connectString = string(connectString);
m_maxcon = maxCon;
m_mincon = minCon;
m_incr = incrCon;
m_init_flag = true;
pthread_t thread_id;
pthread_create( &thread_id, NULL, check_con_thread, (void*)this);
pthread_detach(thread_id);
}
temp_log("start create connection pool ok@@.................");
#else
if (!OCI_Initialize(NULL, NULL, OCI_ENV_DEFAULT | OCI_ENV_CONTEXT | OCI_ENV_THREADED))
{
sErrInfo="Error unexpectd when initlize the OCI environment ! Create DB connection pool FAIL";
return 0x00;
}
if(!m_init_flag)
{
m_username = string(username);
m_passwd = string(passwd);
m_connectString = string(connectString);
m_maxcon = maxCon;
m_mincon = minCon;
m_incr = incrCon;
m_init_flag = true;
pthread_t thread_id;
pthread_create( &thread_id, NULL, check_con_thread, (void*)this);
pthread_detach(thread_id);
}
#endif
return 0x01;
}
void OraConnPool::destroyConnPool()
{
#ifndef USING_SINGLE_CONNECTION
if(oci_pool)
OCI_PoolFree(oci_pool);
oci_pool = NULL;
OCI_Cleanup();
#else
OCI_Cleanup();
#endif
}
OCI_Connection* OraConnPool::getConnection()
{
#ifndef USING_SINGLE_CONNECTION
if(m_con_pool_restart)
{
sErrInfo = "connection pool rebuild ...";
return NULL;
}
if( !oci_pool )
{
sErrInfo = "oci_pool is NULL ...";
return NULL;
}
OCI_Connection* pConn = NULL;
pConn = OCI_PoolGetConnection(oci_pool,NULL);
return pConn;
#else
if(m_con_pool_restart)
{
sErrInfo = "connection pool rebuild ...";
return NULL;
}
OCI_Connection* pConn = NULL;
pConn = OCI_ConnectionCreate( m_connectString.c_str(), m_username.c_str(), m_passwd.c_str(), OCI_SESSION_DEFAULT);
return pConn;
#endif
return NULL;
}
bool OraConnPool::check_con()
{
#ifndef USING_SINGLE_CONNECTION
if( !oci_pool )
{
sErrInfo = "oci_pool is NULL ...";
return false;
}
OCI_Connection* pConn = NULL;
pConn = OCI_PoolGetConnection(oci_pool,NULL);
if(pConn == NULL)
return false;
if(OCI_Ping(pConn))
{
freeConnection(pConn);
return true;
}
freeConnection(pConn);
return false;
#else
OCI_Connection* pConn = NULL;
pConn = getConnection();
if(pConn == NULL)
return false;
if(OCI_Ping(pConn))
{
freeConnection(pConn);
return true;
}
freeConnection(pConn);
return false;
#endif
}
void OraConnPool::freeConnection(OCI_Connection* pConn)
{
#ifndef USING_SINGLE_CONNECTION
if(pConn != NULL)
OCI_ConnectionFree(pConn);
#else
if(pConn != NULL)
OCI_ConnectionFree(pConn);
#endif
}
string OraConnPool::getErrData(void)
{
char buffer[512] = {0x00};
OCI_Error *err = OCI_GetLastError();
sprintf(buffer, "oci: errorcode: %d, errmsg: %s",OCI_ErrorGetOCICode(err), OCI_ErrorGetString(err));
return string(buffer);
return sErrInfo;
}
string OraConnPool::get_last_error()
{
char buffer[512] = {0x00};
OCI_Error *err = OCI_GetLastError();
sprintf(buffer, "oci: errorcode: %d, errmsg: %s",OCI_ErrorGetOCICode(err), OCI_ErrorGetString(err));
return string(buffer);
}
int OraConnPool::get_error_code()
{
OCI_Error *err = OCI_GetLastError();
return int(OCI_ErrorGetOCICode(err));
}
//检测连接的线程函数
void* OraConnPool::check_con_thread(void* param)
{
OraConnPool* pObj = (OraConnPool*)param;
if(!pObj)
return NULL;
int count = 0x00;
bool is_start = true;
while(1)
{
if(is_start)
{
sleep(10);
is_start = false;
}
if((count % 10) == 0x00)
{
temp_log("check connection thread is running......");
if(count >= 1000)
count = 0x00;
}
count++;
bool is_ok = false;
bool flag = pObj->check_con();
string con_str = pObj->get_last_error();
//检测失败则重新建立连接池
if(!flag)
{
temp_log("check connection failed......");
if(!con_str.empty())
{
temp_log(con_str);
}
pObj->m_con_pool_restart = true;
pObj->destroyConnPool();
int ret = pObj->createConnPool(NULL,NULL,NULL,0x00,0x00,0x00);
if(0x00 == ret)
{
ostringstream os;
os<<" create conpool failed....."<<__FILE__<<":"<<__LINE__<<endl;
temp_log(os.str());
}
else
is_ok = true;
}
else if( (count % 20) == 0x00)
temp_log("check connection ok......");
if(!is_ok && !flag)
{
sleep(2);
continue;
}
pObj->m_con_pool_restart = false;
sleep(10);
}
return NULL;
}
这连接池后边有个探测和数据库连接的状态功能,如果要是检测到连接失败,会销毁连接池,再次创建。
不过这样也会存在一些未知的问题,不知道哪位仁兄可以帮忙改进,或给出更好的方法。