C++接続プール


これは私がredisを使用して管理サービスを行う際に使用した接続プールで、主にhiredisをカプセル化したredisObjオブジェクトを接続オブジェクトとして使用しています.接続が生存することを保証するために、空き接続オブジェクトが正常に動作するか(使用中のデフォルトは正常)をタイミングよく検出し、操作に失敗した場合に再接続します.私は使用時に1つの単例redis接続プールを使用して、初期化後に対外的に1つの接続を取得する方法を提供して、インスタンスオブジェクトを構築して1つの接続を取得することができて、クラスの分析方式を利用して、手動で戻す必要がなくて、分析時に戻す方法を呼び出します.
#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();
}