2019-07-27 22:44:32 +08:00
|
|
|
|
#pragma once
|
2017-06-02 14:47:24 +08:00
|
|
|
|
#include "../acl_cpp_define.hpp"
|
|
|
|
|
#include "../stdlib/string.hpp"
|
|
|
|
|
#include "../stdlib/locker.hpp"
|
2019-05-09 13:57:51 +08:00
|
|
|
|
#include "../stdlib/noncopyable.hpp"
|
2014-11-19 00:25:21 +08:00
|
|
|
|
#include <vector>
|
2018-12-15 23:32:41 +08:00
|
|
|
|
#include <map>
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
struct ACL_EVENT;
|
|
|
|
|
|
|
|
|
|
namespace acl
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
class connect_pool;
|
|
|
|
|
class connect_monitor;
|
|
|
|
|
|
2019-07-27 22:44:32 +08:00
|
|
|
|
// 内部使用数据结构
|
2018-12-16 14:12:50 +08:00
|
|
|
|
struct conns_pools {
|
|
|
|
|
std::vector<connect_pool*> pools;
|
2019-07-27 22:44:32 +08:00
|
|
|
|
size_t check_next; // 连接检测时的检测点下标
|
|
|
|
|
size_t conns_next; // 下一个要访问的的下标值
|
2018-12-16 14:12:50 +08:00
|
|
|
|
conns_pools(void)
|
|
|
|
|
{
|
|
|
|
|
check_next = 0;
|
|
|
|
|
conns_next = 0;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2014-11-19 00:25:21 +08:00
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* connect pool 服务管理器,有获取连接池等功能
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2019-05-09 13:57:51 +08:00
|
|
|
|
class ACL_CPP_API connect_manager : public noncopyable
|
2014-11-19 00:25:21 +08:00
|
|
|
|
{
|
|
|
|
|
public:
|
2016-01-17 13:35:12 +08:00
|
|
|
|
connect_manager(void);
|
|
|
|
|
virtual ~connect_manager(void);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
2018-12-14 20:19:19 +08:00
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 是否将连接池与线程自动绑定,主要用于协程环境中,内部缺省值为 false,该方法
|
|
|
|
|
* 在本对象创建后仅能调用一次
|
2018-12-14 20:19:19 +08:00
|
|
|
|
* @param yes {bool}
|
|
|
|
|
*/
|
|
|
|
|
void bind_thread(bool yes);
|
|
|
|
|
|
2014-11-19 00:25:21 +08:00
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 初始化所有服务器的连接池,该函数调用 set 过程添加每个服务的连接池
|
|
|
|
|
* @param default_addr {const char*} 缺省的服务器地址,如果非空,
|
|
|
|
|
* 则在查询时优先使用此服务器
|
|
|
|
|
* @param addr_list {const char*} 所有服务器列表,可以为空
|
|
|
|
|
* 格式: IP:PORT:COUNT;IP:PORT:COUNT;IP:PORT;IP:PORT ...
|
|
|
|
|
* 或 IP:PORT:COUNT,IP:PORT:COUNT,IP:PORT;IP:PORT ...
|
|
|
|
|
* 如:127.0.0.1:7777:50;192.168.1.1:7777:10;127.0.0.1:7778
|
|
|
|
|
* @param count {size_t} 当 addr_list 中分隔的某个服务没有
|
|
|
|
|
* COUNT 信息时便用此值,当此值为 0 时,则不限制连接数上限
|
|
|
|
|
* @param conn_timeout {int} 网络连接时间(秒)
|
|
|
|
|
* @param rw_timeout {int} 网络 IO 超时时间(秒)
|
|
|
|
|
* 注:default_addr 和 addr_list 不能同时为空
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
|
|
|
|
void init(const char* default_addr, const char* addr_list,
|
2015-11-14 00:32:27 +08:00
|
|
|
|
size_t count, int conn_timeout = 30, int rw_timeout = 30);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 添加服务器的客户端连接池,该函数可以在程序运行时被调用,内部自动加锁
|
|
|
|
|
* @param addr {const char*} 服务器地址,格式:ip:port
|
|
|
|
|
* 注意:调用本函数时每次仅能添加一个服务器地址,可以循环调用本方法
|
|
|
|
|
* @param count {size_t} 连接池数量限制, 如果该值设为 0,则不设置
|
|
|
|
|
* 连接池的连接上限
|
|
|
|
|
* @param conn_timeout {int} 网络连接时间(秒)
|
|
|
|
|
* @param rw_timeout {int} 网络 IO 超时时间(秒)
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2018-12-15 23:32:41 +08:00
|
|
|
|
void set(const char* addr, size_t count,
|
2015-11-14 00:32:27 +08:00
|
|
|
|
int conn_timeout = 30, int rw_timeout = 30);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 设置连接池失败后重试的时间时间隔(秒),该函数可以在程序运行时被
|
|
|
|
|
* 调用,内部自动加锁
|
|
|
|
|
* @param n {int} 当该值 <= 0 时,若连接池出现问题则会立即被重试
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
|
|
|
|
void set_retry_inter(int n);
|
|
|
|
|
|
2016-01-17 13:35:12 +08:00
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 设置连接池中空闲连接的空闲生存周期
|
|
|
|
|
* @param ttl {time_t} 空闲连接的生存周期,当该值 < 0 则表示空闲连接
|
|
|
|
|
* 不过期,== 0 时表示立刻过期,> 0 表示空闲该时间段后将被释放
|
2016-01-17 13:35:12 +08:00
|
|
|
|
*/
|
|
|
|
|
void set_idle_ttl(time_t ttl);
|
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 设置自动检查空闲连接的时间间隔,缺省值为 30 秒
|
|
|
|
|
* @param n {int} 时间间隔
|
2016-01-17 13:35:12 +08:00
|
|
|
|
*/
|
|
|
|
|
void set_check_inter(int n);
|
|
|
|
|
|
2014-11-19 00:25:21 +08:00
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 从连接池集群中删除某个地址的连接池,该函数可以在程序运行过程中
|
|
|
|
|
* 被调用,因为内部会自动加锁
|
|
|
|
|
* @param addr {const char*} 服务器地址(ip:port)
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2018-12-15 23:32:41 +08:00
|
|
|
|
void remove(const char* addr);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 根据服务端地址获得该服务器的连接池
|
|
|
|
|
* @param addr {const char*} redis 服务器地址(ip:port)
|
|
|
|
|
* @param exclusive {bool} 是否需要互斥访问连接池数组,当需要动态
|
|
|
|
|
* 管理连接池集群时,该值应为 true
|
|
|
|
|
* @param restore {bool} 当该服务结点被置为不可用时,该参数决定是否
|
|
|
|
|
* 自动将之恢复为可用状态
|
|
|
|
|
* @return {connect_pool*} 返回空表示没有此服务
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2015-03-08 21:34:00 +08:00
|
|
|
|
connect_pool* get(const char* addr, bool exclusive = true,
|
|
|
|
|
bool restore = false);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 从连接池集群中获得一个连接池,该函数采用轮循方式从连接池集合中获取
|
|
|
|
|
* 一个后端服务器的连接池,从而保证了完全的均匀性;该函数内部会自动对
|
|
|
|
|
* 连接池管理队列加锁
|
|
|
|
|
* 此外,该函数为虚接口,允许子类实现自己的轮循方式
|
|
|
|
|
* @return {connect_pool*} 返回一个连接池,返回指针永远非空
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2018-12-14 20:19:19 +08:00
|
|
|
|
virtual connect_pool* peek(void);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 从连接池集群中获得一个连接池,该函数采用哈希定位方式从集合中获取一个
|
|
|
|
|
* 后端服务器的连接池;子类可以重载此虚函数,采用自己的集群获取方式
|
|
|
|
|
* 该虚函数内部缺省采用 CRC32 的哈希算法;
|
|
|
|
|
* @param key {const char*} 键值字符串,如果该值为 NULL,则内部
|
|
|
|
|
* 自动切换到轮循方式
|
|
|
|
|
* @param exclusive {bool} 是否需要互斥访问连接池数组,当需要动态
|
|
|
|
|
* 管理连接池集群时,该值应为 true
|
|
|
|
|
* @return {connect_pool*} 返回一个可用的连接池,返回指针永远非空
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
|
|
|
|
virtual connect_pool* peek(const char* key, bool exclusive = true);
|
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 当用户重载了 peek 函数时,可以调用此函数对连接池管理过程加锁
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2018-12-14 20:19:19 +08:00
|
|
|
|
void lock(void);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 当用户重载了 peek 函数时,可以调用此函数对连接池管理过程加锁
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2018-12-14 20:19:19 +08:00
|
|
|
|
void unlock(void);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 获得所有的服务器的连接池,该连接池中包含缺省的服务连接池
|
2014-11-19 00:25:21 +08:00
|
|
|
|
* @return {std::vector<connect_pool*>&}
|
|
|
|
|
*/
|
2018-12-15 23:32:41 +08:00
|
|
|
|
std::vector<connect_pool*>& get_pools(void);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
2018-05-14 15:28:39 +08:00
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 检测连接池中的空闲连接,将过期的连接释放掉
|
|
|
|
|
* @param step {size_t} 每次检测连接池的个数
|
|
|
|
|
* @param left {size_t*} 非空时,将存储所有剩余连接个数总和
|
|
|
|
|
* @return {size_t} 被释放的空闲连接数
|
2018-05-14 15:28:39 +08:00
|
|
|
|
*/
|
|
|
|
|
size_t check_idle(size_t step, size_t* left = NULL);
|
|
|
|
|
|
2014-11-19 00:25:21 +08:00
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 获得连接池集合中连接池对象的个数
|
2014-11-19 00:25:21 +08:00
|
|
|
|
* @return {size_t}
|
|
|
|
|
*/
|
2018-12-15 23:32:41 +08:00
|
|
|
|
size_t size(void) const;
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 获得缺省的服务器连接池
|
|
|
|
|
* @return {connect_pool*} 当调用 init 函数的 default_addr 为空时
|
|
|
|
|
* 该函数返回 NULL
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2018-12-14 20:19:19 +08:00
|
|
|
|
connect_pool* get_default_pool(void)
|
2014-11-19 00:25:21 +08:00
|
|
|
|
{
|
|
|
|
|
return default_pool_;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 打印当前所有 redis 连接池的访问量
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2018-12-14 20:19:19 +08:00
|
|
|
|
void statistics(void);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 启动后台非阻塞检测线程检测所有连接池连接状态
|
|
|
|
|
* @param monitor {connect_monitor*} 连接检测对象
|
|
|
|
|
* @return {bool} 是否正常启动了连接检测器,当返回 false 说明当前还有
|
|
|
|
|
* 正在运行的连接检测器,当想再次启动检测器时需要先调用 stop_monitor
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2015-04-04 15:25:29 +08:00
|
|
|
|
bool start_monitor(connect_monitor* monitor);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 停止后台检测线程
|
|
|
|
|
* @param graceful {bool} 是否在关闭检测线程时需要等待所有的检测连接
|
|
|
|
|
* 关闭后才返回,当连接池集群对象为进程空间内不会多次分配与释放时,
|
|
|
|
|
* 则该值可以设为 false 从而使检测线程快速退出,否则应该等待所有检测
|
|
|
|
|
* 连接关闭后再使检测线程退出
|
|
|
|
|
* @return {connect_monitor*} 返回 start_monitor 设置的检测器,同时
|
|
|
|
|
* 内部的 monitor_ 成员自动置 NULL
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
2015-04-04 15:25:29 +08:00
|
|
|
|
connect_monitor* stop_monitor(bool graceful = true);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 设置某个连接池服务的存活状态,内部会自动加锁
|
|
|
|
|
* @param addr {const char*} 服务器地址,格式:ip:port
|
|
|
|
|
* @param alive {bool} 该服务器是否正常
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
|
|
|
|
void set_pools_status(const char* addr, bool alive);
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
/**
|
2019-07-27 22:44:32 +08:00
|
|
|
|
* 纯虚函数,子类必须实现此函数用来创建连接池对象
|
|
|
|
|
* @param addr {const char*} 服务器监听地址,格式:ip:port
|
|
|
|
|
* @param count {size_t} 连接池的大小限制,为 0 时,则连接池没有限制
|
|
|
|
|
* @param idx {size_t} 该连接池对象在集合中的下标位置(从 0 开始)
|
|
|
|
|
* @return {connect_pool*} 返回创建的连接池对象
|
2014-11-19 00:25:21 +08:00
|
|
|
|
*/
|
|
|
|
|
virtual connect_pool* create_pool(const char* addr,
|
2015-08-14 17:28:30 +08:00
|
|
|
|
size_t count, size_t idx) = 0;
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
2015-11-13 16:26:30 +08:00
|
|
|
|
protected:
|
2018-12-15 23:32:41 +08:00
|
|
|
|
typedef std::vector<connect_pool*> pools_t;
|
2018-12-16 14:12:50 +08:00
|
|
|
|
typedef pools_t::iterator pools_it;
|
|
|
|
|
typedef pools_t::const_iterator pools_cit;
|
|
|
|
|
|
|
|
|
|
typedef std::map<unsigned long, conns_pools*> manager_t;
|
|
|
|
|
typedef manager_t::iterator manager_it;
|
|
|
|
|
typedef manager_t::const_iterator manager_cit;
|
2018-12-15 23:32:41 +08:00
|
|
|
|
|
2019-07-27 22:44:32 +08:00
|
|
|
|
bool thread_binding_; // 用于协程环境中与每个线程绑定
|
|
|
|
|
string default_addr_; // 缺省的服务地址
|
|
|
|
|
connect_pool* default_pool_; // 缺省的服务连接池
|
2018-12-15 23:32:41 +08:00
|
|
|
|
|
2018-12-16 14:12:50 +08:00
|
|
|
|
struct conn_config {
|
2018-12-15 23:32:41 +08:00
|
|
|
|
string addr;
|
|
|
|
|
size_t count;
|
|
|
|
|
int conn_timeout;
|
|
|
|
|
int rw_timeout;
|
|
|
|
|
};
|
2019-07-27 22:44:32 +08:00
|
|
|
|
std::map<string, conn_config> addrs_;// 所有的服务端地址
|
2018-12-16 14:12:50 +08:00
|
|
|
|
manager_t manager_;
|
2018-12-15 23:32:41 +08:00
|
|
|
|
|
2019-07-27 22:44:32 +08:00
|
|
|
|
locker lock_; // 访问 pools_ 时的互斥锁
|
|
|
|
|
int stat_inter_; // 统计访问量的定时器间隔
|
|
|
|
|
int retry_inter_; // 连接池失败后重试的时间间隔
|
|
|
|
|
time_t idle_ttl_; // 空闲连接的生命周期
|
|
|
|
|
int check_inter_; // 检查空闲连接的时间间隔
|
|
|
|
|
connect_monitor* monitor_; // 后台检测线程句柄
|
2014-11-19 00:25:21 +08:00
|
|
|
|
|
2019-07-27 22:44:32 +08:00
|
|
|
|
// 设置除缺省服务之外的服务器集群
|
2015-11-14 00:32:27 +08:00
|
|
|
|
void set_service_list(const char* addr_list, int count,
|
|
|
|
|
int conn_timeout, int rw_timeout);
|
2018-12-16 14:12:50 +08:00
|
|
|
|
conns_pools& get_pools_by_id(unsigned long id);
|
|
|
|
|
connect_pool* create_pool(const conn_config& cf, size_t idx);
|
|
|
|
|
void create_pools_for(pools_t& pools);
|
|
|
|
|
|
2018-12-15 23:32:41 +08:00
|
|
|
|
void remove(pools_t& pools, const char* addr);
|
|
|
|
|
void set_status(pools_t& pools, const char* addr, bool alive);
|
|
|
|
|
|
|
|
|
|
unsigned long get_id(void) const;
|
2018-12-14 20:19:19 +08:00
|
|
|
|
void get_key(const char* addr, string& key);
|
|
|
|
|
void get_addr(const char* key, string& addr);
|
2018-12-15 23:32:41 +08:00
|
|
|
|
connect_pool* add_pool(const char* addr);
|
2018-12-16 14:12:50 +08:00
|
|
|
|
|
2019-07-27 22:44:32 +08:00
|
|
|
|
// 线程局部变量初始化时的回调方法
|
2018-12-16 14:12:50 +08:00
|
|
|
|
static void thread_oninit(void);
|
2019-07-27 22:44:32 +08:00
|
|
|
|
// 线程退出前需要回调此方法,用来释放内部创建的线程局部变量
|
2018-12-16 14:12:50 +08:00
|
|
|
|
static void thread_onexit(void* ctx);
|
2014-11-19 00:25:21 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
} // namespace acl
|