C++接続プール
これは私がredisを使用して管理サービスを行う際に使用した接続プールで、主にhiredisをカプセル化したredisObjオブジェクトを接続オブジェクトとして使用しています.接続が生存することを保証するために、空き接続オブジェクトが正常に動作するか(使用中のデフォルトは正常)をタイミングよく検出し、操作に失敗した場合に再接続します.私は使用時に1つの単例redis接続プールを使用して、初期化後に対外的に1つの接続を取得する方法を提供して、インスタンスオブジェクトを構築して1つの接続を取得することができて、クラスの分析方式を利用して、手動で戻す必要がなくて、分析時に戻す方法を呼び出します.
.cppファイル
#ifndef __REDISSOURCE_H__
#define __REDISSOURCE_H__
#include
#include
#include "TimeWheel.h"//
#include "Condition.h"//
struct RedisTimerArg;
class RedisObj;// , , cpp
class RedisSource{
public:
static void initRedisSource(std::string strIP,int port,std::string strPassword,
int initConnectNum,int holdConnectNum,int maxConnectNum,int connectTimeOut);
static RedisSource* getRedisSourceInstance();
private:
RedisSource(void);
RedisSource(std::string strIP, int port = 6379, int initConnectNum = 5, int holdConnectNum = 10, int maxConnectNum = 100);
~RedisSource(void);
static RedisSource *instance;//
static TempLock* instanceLock;//
bool isConnect;
volatile bool isInit;
std::string strIP;
int port;
int initConnectNum;
int holdConnectNum;
int maxConnectNum;
int idleTime;
unsigned int checkConnIsAliveTimeVal;//
std::list connectList;//
int haveConnNum;
private:
TempLock tempLock;
Condition cond;
TimeWheel timer;
std::map monitorConnMap;// map
// , ,
public:
void SetIp(std::string & strIP);
void SetPort(int port);
void SetInitConnectNum(int initConnectNum);
void SetHoldConnectNum(int holdConnectNum);
void SetMaxConnectNum(int maxConnectNum);
void SetIdleTime(long millisecond);
void SetCheckConnAliveTime(int checkTimeVal);
void InitRedisSource();
int AvailConNum();
public:
RedisObj* OpenConnection();//
void CloseConnection(RedisObj* connection);//
private:
RedisObj* connectRedis();
void closeAllConnection();
RedisObj* getAndRemoveConn();
void addMonitorConn(RedisObj* conn);
void addMonitorConn(RedisTimerArg* arg);
void cancelMonitorConn(RedisObj* conn);
void removeAbandonConn(RedisTimerArg* rsTimeArg);
private:
bool validateParam();
public:
static void CheckAliveAndCloseIdle(void *conn);
};
#endif
.cppファイル
#pragma once
#include "RedisSource.h"
#include "RedisAPI.h"
//
RedisSource* RedisSource::instance = NULL;
TempLock* RedisSource::instanceLock = new TempLock();
struct RedisTimerArg
{
RedisSource* rs;//
RedisObj* conn;//
int timeNodeId;// ID
};
// ,
RedisSource::RedisSource(void) :
strIP(""),
port(6379),
initConnectNum(5),
holdConnectNum(10),
maxConnectNum(100),
isInit(false),
haveConnNum(0),
idleTime(10 * 60 * 1000),
checkConnIsAliveTimeVal(10 * 60 * 1000)
{
}
bool RedisSource::validateParam() {
return true;
}
//
void RedisSource::InitRedisSource(){
if (isInit || !validateParam()) // init
{
return;
}
isInit = true;
for (int i = 0; i < initConnectNum; i++)
{
RedisObj* conn = new RedisObj();//
if (conn->initRedisConnect(strIP, port))// , bool
{
this->connectList.push_back(conn);//
}
}
}
// ,
RedisSource::RedisSource(std::string strIP, int port, int initConnectNum, int holdConnectNum, int maxConnectNum) :
strIP(strIP)
, port(port)
, initConnectNum(initConnectNum)
, holdConnectNum(holdConnectNum)
, maxConnectNum(maxConnectNum)
, isInit(false)
, haveConnNum(0)
, idleTime(10 * 60 * 1000)
, checkConnIsAliveTimeVal(4 * 60 * 60 * 1000)
{
InitRedisSource();
}
// , ,redis password
void RedisSource::initRedisSource(std::string strIP, int port, std::string strPassword,
int initConnectNum, int holdConnectNum, int maxConnectNum, int connectTimeOut)
{
if (instance == NULL) {
instanceLock->lock();//
if (instance == NULL) {
instance = new RedisSource(strIP, port, initConnectNum, holdConnectNum, maxConnectNum);
}
instanceLock->unlock();
}
}
//
RedisSource* RedisSource::getRedisSourceInstance()
{
return instance ? instance : NULL;
}
// , , , ,
void RedisSource::closeAllConnection()
{
tempLock.lock();
for (auto it = connectList.begin(); it != connectList.end(); ++it)
{
(*it)->freeRedisReply();// ,
(*it)->freeRedisHandler();
it = connectList.erase(it);//
}
for (auto it = monitorConnMap.begin(); it != monitorConnMap.end(); ++it)
{
delete it->second;// map
it = monitorConnMap.erase(it);
}
tempLock.unlock();
}
RedisSource::~RedisSource(void) {
closeAllConnection();
}
void RedisSource::SetIp(std::string& strIP) {
this->strIP = strIP;
}
void RedisSource::SetPort(int port) {
this->port = port;
}
void RedisSource::SetInitConnectNum(int initConnectNum) {
this->initConnectNum = initConnectNum;
InitRedisSource();
}
void RedisSource::SetHoldConnectNum(int holdConnectNum) {
this->holdConnectNum = holdConnectNum;
InitRedisSource();
}
void RedisSource::SetMaxConnectNum(int maxConnectNum) {
this->maxConnectNum = maxConnectNum;
InitRedisSource();
}
void RedisSource::SetIdleTime(long idleTime) {
this->idleTime = idleTime;
InitRedisSource();
}
//
RedisObj* RedisSource::getAndRemoveConn()
{
tempLock.lock();
while (connectList.size() == 0)
{
cond.wait(&tempLock);// ,
}
RedisObj* conn = connectList.front();//
connectList.pop_front();//
cancelMonitorConn(conn);//
tempLock.unlock();
return conn;
}
//
int RedisSource::AvailConNum()
{
tempLock.lock();
int availConNum = static_cast<int>(connectList.size());
tempLock.unlock();
return availConNum;
}
//
RedisObj* RedisSource::OpenConnection()
{
RedisObj* conn = NULL;
tempLock.lock();
if (AvailConNum() == 0 && (haveConnNum < maxConnectNum))// 0 ,
{
conn = new RedisObj();
conn->initRedisConnect(strIP,port);//
tempLock.unlock();
}
else
{
tempLock.unlock();
conn = getAndRemoveConn();//
}
return conn;
}
void RedisSource::cancelMonitorConn(RedisObj* conn)
{
RedisTimerArg *rsTimerArg = monitorConnMap[conn];//
if (rsTimerArg != NULL)
{
timer.cancelTimer(rsTimerArg->timeNodeId);// ,
monitorConnMap.erase(conn);//
delete rsTimerArg;
}
}
//
void RedisSource::addMonitorConn(RedisTimerArg *arg)
{
arg->timeNodeId = timer.setTimer(checkConnIsAliveTimeVal, CheckAliveAndCloseIdle, arg, NULL);
monitorConnMap[arg->conn] = arg;
}
//
void RedisSource::addMonitorConn(RedisObj* conn)
{
RedisTimerArg* arg = new RedisTimerArg;
arg->rs = this;
arg->conn = conn;
addMonitorConn(arg);
}
//
void RedisSource::CloseConnection(RedisObj* conn)
{
tempLock.lock();
addMonitorConn(conn);
connectList.push_back(conn);
cond.notify_one();
tempLock.unlock();
}
void RedisSource::removeAbandonConn(RedisTimerArg *rsTimeArg)
{
rsTimeArg->rs->monitorConnMap.erase(rsTimeArg->conn);// map
rsTimeArg->rs->connectList.remove(rsTimeArg->conn);//
rsTimeArg->conn->freeRedisHandler();//
delete rsTimeArg;//
}
// ,
void RedisSource::CheckAliveAndCloseIdle(void *rsArg)
{
RedisTimerArg* rsTimeArg = (RedisTimerArg*)rsArg;
rsTimeArg->rs->tempLock.lock();
if (rsTimeArg->rs->connectList.size() > rsTimeArg->rs->holdConnectNum)
{
rsTimeArg->rs->removeAbandonConn(rsTimeArg);//
rsTimeArg->rs->tempLock.unlock();
return;
}
else
{
std::string cmd = "test";
int len;
rsTimeArg->conn->ListLen(cmd, len);// ,
if (rsTimeArg->conn->r_queryReply == NULL)
{
rsTimeArg->rs->removeAbandonConn(rsTimeArg);
rsTimeArg->rs->tempLock.unlock();
return;
}
rsTimeArg->conn->freeRedisReply();
}
rsTimeArg->rs->addMonitorConn(rsTimeArg);//
rsTimeArg->rs->tempLock.unlock();
}