网站建站免费,张家界网站建设方案,wordpress转移整站,泰州网站制作方案文章目录 1、Ubuntu安装redis服务端2、hiredis库的安装3、同步API接口的使用3.1、连接redis数据库redisConnect3.2、发送需要执行的命令redisCommand3.3、redisCommandArgv函数3.4、redisAppendCommand*函数支持管道命令3.5、释放资源3.6、同步连接代码 3.7、异步连接4、redis连… 文章目录 1、Ubuntu安装redis服务端2、hiredis库的安装3、同步API接口的使用3.1、连接redis数据库redisConnect3.2、发送需要执行的命令redisCommand3.3、redisCommandArgv函数3.4、redisAppendCommand*函数支持管道命令3.5、释放资源3.6、同步连接代码 3.7、异步连接4、redis连接池实现 Hiredis是一个Redis的C客户端库函数基本实现了Redis的协议的最小集。这里对hiredis的api作基本的介绍以及应用主要参考hiredis的README文件以及相关源码。 1、Ubuntu安装redis服务端 Redis全称为Remote Dictionary Server远程数据服务是一款开源的基于内存的键值对存储系统其主要被用作高性能缓存服务器使用当然也可以作为消息中间件和Session共享等。Redis独特的键值对模型使之支持丰富的数据结构类型即它的值可以是字符串、哈希、列表、集合、有序集合而不像Memcached要求的键和值都是字符串。同时由于Redis是基于内存的方式免去了磁盘I/O速度的影响因此其读写性能极高。 1、在Ubuntu中打开终端输入下列命令下载Redis安装包
wget http://download.redis.io/releases/redis-4.0.9.tar.gz2、对安装包进行解压并将其移动放到usr/local⽬录下 命令如下 解压
tar xzf redis-4.0.9.tar.gz
移动到
sudo mv ./redis-4.0.9 /usr/local/redis/3、进入redis⽬录编译生成 命令
cd /usr/local/redis/
sudo make测试
sudo make test4、安装,将redis的命令安装到/usr/local/bin/⽬录
sudo make install5、安装完成后我们进入目录/usr/local/bin中查看
cd /usr/local/bin
ls -all6、配置⽂件移动到/etc/⽬录下 配置⽂件⽬录为/usr/local/redis/redis.conf
sudo cp /usr/local/redis/redis.conf /etc/redis/7、Redis的配置信息在/etc/redis/redis.conf下
sudo vi /etc/redis/redis.conf绑定ip如果需要远程访问可将此⾏注释或绑定⼀个真实ip
bind 127.0.0.1端⼝默认为6379
port 6379是否以守护进程运⾏
如果以守护进程运⾏则不会在命令⾏阻塞类似于服务
如果以⾮守护进程运⾏则当前终端被阻塞
设置为yes表示守护进程设置为no表示⾮守护进程
推荐设置为yes
daemonize yes数据⽂件
dbfilename dump.rdb数据⽂件存储路径
dir /var/lib/redis⽇志⽂件
logfile /var/log/redis/redis-server.log数据库默认有16个
database 16主从复制类似于双机备份。
slaveof连接服务端 ./redis-cli -h 127.0.0.1 -p 6379 2、hiredis库的安装
官网https://redislabs.com/lp/hiredis/ 发行版本https://github.com/redis/hiredis/releases 目前最新的版本https://codeload.github.com/redis/hiredis/tar.gz/v0.14.0
1、解压tar -zxvf hiredis-0.14.0.tar.gz 2、编译make 3、安装make install
也可以直接将文件编译到自己的工程代码。
3、同步API接口的使用 我们的项目中使用的hireds接口都是同步的API所谓同步意思就是使用阻塞的方式向redis server下发消息。 接口的主要部分为下面三个部分下面分别介绍。 /**连接数据库*/
redisContext *redisConnect(const char *ip, int port);
/**发送命令请求*/
void *redisCommand(redisContext *c, const char *format, ...);
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
/*释放资源*/
void freeReplyObject(void *reply);
void redisFree(redisContext *c);3.1、连接redis数据库redisConnect
redisContext *redisConnect(const char *ip, int port);参数说明 ● port为redis数据监听的端口号redis默认监听的端口号为6379 ● ip为redis数据库的IP地址可以是远程的也可以是本地的127.0.0.1 返回值 返回值是一个指向redisContext对象可以不用了解这个对象的具体组成部分只需要知道怎么使用就可以了。下面是其定义。
typedef struct redisContext {int err; /* Error flags, 0 when there is no error */char errstr[128]; /* String representation of error when applicable */int fd;int flags;char *obuf; /* Write buffer */redisReader *reader; /* Protocol reader */enum redisConnectionType connection_type;struct timeval *timeout;struct {char *host;char *source_addr;int port;} tcp;struct {char *path;} unix_sock;
} redisContext;3.2、发送需要执行的命令redisCommand
void *redisCommand(redisContext *c, const char *format, ...);参数说明 这个函数是一个带有不定参数的。可以按着format格式给出对应的参数这就和printf函数类似。 c 是一个reidsConnect函数返回的一个对象。 返回值 返回值是一个void类型的指针实际为指向一个redisReply类型的指针。
/* This is the reply object returned by redisCommand() */
typedef struct redisReply {/*命令执行结果的返回类型*/int type; /* REDIS_REPLY_* *//*存储执行结果返回为整数*/long long integer; /* The integer when type is REDIS_REPLY_INTEGER *//*字符串值的长度*/size_t len; /* Length of string *//*存储命令执行结果返回是字符串*/char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING *//*返回结果是数组的大小*/size_t elements; /* number of elements, for REDIS_REPLY_ARRAY *//*存储执行结果返回是数组*/struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;返回结果的类型reply-type,reply 为redisReply* 类型。
● REDIS_REPLY_STRING 1:返回值是字符串,字符串储存在redis-str当中,字符串长度为redis-len。
● REDIS_REPLY_ARRAY 2返回值是数组数组大小存在redis-elements里面数组值存储在redis-element[i]里面。数组里面存储的是指向redisReply的指针数组里面的返回值可以通过redis-element[i]-str来访问数组的结果里全是typeREDIS_REPLY_STRING的redisReply对象指针。
● REDIS_REPLY_INTEGER 3返回值为整数 long long。
● REDIS_REPLY_NIL4返回值为空表示执行结果为空。
● REDIS_REPLY_STATUS 5返回命令执行的状态比如set foo bar 返回的状态为OK存储在str当中 reply-str OK。
● REDIS_REPLY_ERROR 6 命令执行错误,错误信息存放在 reply-str当中。3.3、redisCommandArgv函数
void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);参数说明 argvlen这个数组存储了命令参数中每一个参数的长度包含命令本身比如 set foo bar 则argvlen {3,3,3},如果argvlen为空那么这个函数内部会自动调用strlen函数对每个参数进行求长度。 argv 存放每个命令参数的指针argv{“set”,“foo”,“bar”} argc 存放命令参数的个数上面的例子中argc3 c 为redisContext对象。 为每一个参数指定长度可以是二进制安全的函数。函数会按着长度来决定字符串的终止而不是’\0’.
char hkey[] 123456;
char hset[] hset;
char key[] testkey;
char hvalue[] 3210;
int argc 4;
char *argv[] {hset,key,hkey,hvalue};
size_t argvlen[] {4,6,4,3};
redisCommandArgv(context,argc,argv,argvlen);hgetall testkey 会得到321并不会得到和hvalue一样的值3210因为在hset命令中指定了长度只会读取前面的三个字符。
3.4、redisAppendCommand*函数支持管道命令
void redisAppendCommand(redisContext *c, const char *format, ...);
void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
int redisGetReply(redisContext *context,redisReply** reply);参数说明 redisAppendCommand函数和redisCommand函数参数一致format可以指定特定参数的类型。 c 为redisContext对象 redisAppendCommandArgv函数和redisCommandArgv函数类似参数含义也相同。 redisGetReply函数用来获得执行的结果的一条返回并存储在reply所指的对象当中。成功返回REDIS_OK,否则返回REIDS_ERR。多条命令的一次性返回结果都存放在redisContext里面。 所不同的是这个两个命令的结果。这两个函数是把多个命令存放在缓冲区内然后一起发送给redis服务器一次执行。可以通过redisGetReply函数从 redisContext中取出返回的结果。 使用例子
redisReply *reply;
/*添加命令set */
redisAppendCommand(context,SET foo bar);
/*添加命令get */
redisAppendCommand(context,GET foo);
/*获取set命令结果*/
redisGetReply(context,reply); // reply for SET
freeReplyObject(reply);
/*获取get命令结果*/
redisGetReply(context,reply); // reply for GET
freeReplyObject(reply);3.5、释放资源
void freeReplyObject(void *reply);
void redisFree(redisContext *c);参数说明 freeReplyObject函数中reply 实际为指向redisReply结构体的指针可能是redisCommand的返回值后续可以看到以也能是管道命令执行结果的返回值。 redisFree函数中c实际为指向redisContext对象这个函数会清理连接资源并释放连接。
3.6、同步连接代码
#include stdio.h
#include stdlib.h
#include string.h
#include time.h
#include hiredis/hiredis.hint main(int argc,char *argv[])
{unsigned int j,isunix 0;redisContext *c;redisReply *reply;const char *hostname 127.0.0.1;int port 6379;struct timeval timeout {1,500000}; // 1.5 secondsc redisConnectWithTimeout(hostname,port,timeout);if(c NULL || c-err){if(c){printf(Connection error:%s\n,c-errstr);redisFree(c);} else {printf(Connection error:cant allocate redis context\n);}exit(1);}int num 1000;for(int i0;inum;i){// INCR counter 是 Redis 的一个命令它用于将名为 counter 的键的值递增1。如果该键不存在它将被创建并初始化为0reply redisCommand(c,INCR counter);printf(INCR counter:%lld\n,reply-integer);freeReplyObject(reply);}redisFree(c);return 0;
}如果执行的时候报这个错误 解决办法 确保你的/etc/ld.so.conf里面有 /usr/local/lib 这一行 没有的话vim编辑在尾行加上 然后 sudo ldconfig
2、 ldconfig介绍 ldconfig是一个动态链接库管理命令其目的为了让动态链接库为系统所共享。 当进程需要链接相应的库文件时候会默认搜寻/lilb和/usr/lib以及配置文件/etc/ld.so.conf内所列的目录下的库文件。若找不到的话就会出现如上图的错误。 ldconfig通常在系统启动时运行而当用户安装了一个新的动态链接库时就需要手工运行这个命令。 ldconfig需要注意的地方
往/lib和/usr/lib里面加东西是不用修改/etc/ld.so.conf文件的但是添加完后需要调用下ldconfig不然添加的library会找不到。如果添加的library不在/lib和/usr/lib里面的话就一定要修改/etc/ld.so.conf文件往该文件追加library所在的路径然后也需要重新调用下ldconfig命令。比如在安装MySQL的时候其库文件/usr/local/mysql/lib就需要追加到/etc/ld.so.conf文件中。命令如下echo /usr/local/mysql/lib /etc/ld.so.confldconfig -v | grep mysql最后注意
如果添加的library不在/lib或/usr/lib下但是却没有权限操作写/etc/ld.so.conf文件的话这时就需要往export里写一个全局变量LD_LIBRARY_PATH就可以了。3.7、异步连接
#include hiredis/hiredis.h
#include hiredis/async.h
#include reactor.h
#include adapter.h
#include time.hstatic reactor_t *R;
static int cnt, before, num;int current_tick() {int t 0;struct timespec ti;clock_gettime(CLOCK_MONOTONIC, ti);t (int)ti.tv_sec * 1000;t ti.tv_nsec / 1000000;return t;
}void getCallback(redisAsyncContext *c, void *r, void *privdata) {redisReply *reply r;if (reply NULL) return;printf(argv[%s]: %lld\n, (char*)privdata, reply-integer);/* Disconnect after receiving the reply to GET */cnt;if (cnt num) {int used current_tick()-before;printf(after %d exec redis command, used %d ms\n, num, used);redisAsyncDisconnect(c);}
}void connectCallback(const redisAsyncContext *c, int status) {if (status ! REDIS_OK) {printf(Error: %s\n, c-errstr);stop_eventloop(R);return;}printf(Connected...\n);
}void disconnectCallback(const redisAsyncContext *c, int status) {if (status ! REDIS_OK) {printf(Error: %s\n, c-errstr);stop_eventloop(R);return;}printf(Disconnected...\n);stop_eventloop(R);
}int main(int argc, char **argv) {redisAsyncContext *c redisAsyncConnect(127.0.0.1, 6379);if (c-err) {/* Let *c leak for now... */printf(Error: %s\n, c-errstr);return 1;}R create_reactor();redisAttach(R, c);redisAsyncSetConnectCallback(c, connectCallback);redisAsyncSetDisconnectCallback(c, disconnectCallback);before current_tick();num (argc 1) ? atoi(argv[1]) : 1000;for (int i 0; i num; i) {redisAsyncCommand(c, getCallback, count, INCR counter);}eventloop(R);release_reactor(R);return 0;
}// gcc main.c -o main -L./hiredis -lhiredis
4、redis连接池实现
1、Thread.h头文件
#ifndef __THREAD_H__
#define __THREAD_H__
#include stdint.h
#include pthread.hclass CThreadNotify
{
public:CThreadNotify(){pthread_mutexattr_init(m_mutexattr);pthread_mutexattr_settype(m_mutexattr, PTHREAD_MUTEX_RECURSIVE);pthread_mutex_init(m_mutex, m_mutexattr);pthread_cond_init(m_cond, NULL);}~CThreadNotify(){pthread_mutexattr_destroy(m_mutexattr);pthread_mutex_destroy(m_mutex);pthread_cond_destroy(m_cond);}void Lock(){pthread_mutex_lock(m_mutex);}void Unlock(){pthread_mutex_unlock(m_mutex);}void Wait(){pthread_cond_wait(m_cond, m_mutex);}// 返回0则正常其他值为异常int WaitTime(int ms){//获取时间struct timespec outtime;clock_gettime(CLOCK_MONOTONIC, outtime);//ms为毫秒换算成秒outtime.tv_sec ms / 1000;//在outtime的基础上增加ms毫秒//outtime.tv_nsec为纳秒1微秒1000纳秒//tv_nsec此值再加上剩余的毫秒数 ms%1000有可能超过1秒。需要特殊处理uint64_t us outtime.tv_nsec / 1000 1000 * (ms % 1000); //微秒//us的值有可能超过1秒outtime.tv_sec us / 1000000;us us % 1000000;outtime.tv_nsec us * 1000; //换算成纳秒return pthread_cond_timedwait(m_cond, m_mutex, outtime);}void Signal(){pthread_cond_signal(m_cond);}private:pthread_mutex_t m_mutex;pthread_mutexattr_t m_mutexattr;pthread_cond_t m_cond;
};#endif
2、头文件CachePool.h
/** Author: your name* Date: 2019-12-07 10:54:57* LastEditTime : 2020-01-10 16:35:13* LastEditors : Please set LastEditors* Description: In User Settings Edit* FilePath: \src\cache_pool\CachePool.h*/
#ifndef CACHEPOOL_H_
#define CACHEPOOL_H_#include iostream
#include vector
#include map
#include list#include Thread.h#include hiredis.husing std::string;
using std::list;
using std::map;
using std::vector; class CachePool;class CacheConn {
public:CacheConn(const char* server_ip, int server_port, int db_index, const char* password, const char *pool_name );CacheConn(CachePool* pCachePool); virtual ~CacheConn();int Init();void DeInit();const char* GetPoolName();// 通用操作// 判断一个key是否存在bool isExists(string key);// 删除某个keylong del(string key);// ------------------- 字符串相关 -------------------string get(string key);string set(string key, string value);string setex(string key, int timeout, string value);// string mset(string key, map);//批量获取bool mget(const vectorstring keys, mapstring, string ret_value);//原子加减1long incr(string key);long decr(string key);// ---------------- 哈希相关 ------------------------long hdel(string key, string field);string hget(string key, string field);bool hgetAll(string key, mapstring, string ret_value);long hset(string key, string field, string value);long hincrBy(string key, string field, long value);long incrBy(string key, long value);string hmset(string key, mapstring, string hash);bool hmget(string key, liststring fields, liststring ret_value);// ------------ 链表相关 ------------long lpush(string key, string value);long rpush(string key, string value);long llen(string key);bool lrange(string key, long start, long end, liststring ret_value);bool flushdb();private:CachePool* m_pCachePool;redisContext* m_pContext;uint64_t m_last_connect_time;uint16_t m_server_port;string m_server_ip;string m_password;uint16_t m_db_index;string m_pool_name;
};class CachePool {
public:// db_index和mysql不同的地方 CachePool(const char* pool_name, const char* server_ip, int server_port, int db_index, const char *password, int max_conn_cnt);virtual ~CachePool();int Init();// 获取空闲的连接资源CacheConn* GetCacheConn();// Pool回收连接资源void RelCacheConn(CacheConn* pCacheConn);const char* GetPoolName() { return m_pool_name.c_str(); }const char* GetServerIP() { return m_server_ip.c_str(); }const char* GetPassword() { return m_password.c_str(); }int GetServerPort() { return m_server_port; }int GetDBIndex() { return m_db_index; }
private:string m_pool_name;string m_server_ip;string m_password;int m_server_port;int m_db_index; // mysql 数据库名字 redis db indexint m_cur_conn_cnt;int m_max_conn_cnt;listCacheConn* m_free_list;CThreadNotify m_free_notify;
};#endif /* CACHEPOOL_H_ */
3、CachePool.cpp文件
#include CachePool.h#include stdlib.h
#include string.h
#include Thread.h#define log_error printf
#define log_info printf#define MIN_CACHE_CONN_CNT 2
#define MAX_CACHE_CONN_FAIL_NUM 10CacheConn::CacheConn(const char *server_ip, int server_port, int db_index, const char *password,const char *pool_name)
{m_server_ip server_ip;m_server_port server_port;m_db_index db_index;m_password password;m_pool_name pool_name;m_pContext NULL;m_last_connect_time 0;
}CacheConn::CacheConn(CachePool *pCachePool)
{m_pCachePool pCachePool;if (pCachePool){m_server_ip pCachePool-GetServerIP();m_server_port pCachePool-GetServerPort();m_db_index pCachePool-GetDBIndex();m_password pCachePool-GetPassword();m_pool_name pCachePool-GetPoolName();}else{log_error(pCachePool is NULL\n);}m_pContext NULL;m_last_connect_time 0;
}CacheConn::~CacheConn()
{if (m_pContext){redisFree(m_pContext);m_pContext NULL;}
}/** redis初始化连接和重连操作类似mysql_ping()*/
int CacheConn::Init()
{if (m_pContext) // 非空连接是正常的{return 0;}// 1s 尝试重连一次uint64_t cur_time (uint64_t)time(NULL);if (cur_time m_last_connect_time 1) // 重连尝试 间隔1秒 {printf(cur_time:%lu, m_last_connect_time:%lu\n, cur_time, m_last_connect_time);return 1;}// printf(m_last_connect_time cur_time\n);m_last_connect_time cur_time;// 1000ms超时struct timeval timeout {0, 1000000};// 建立连接后使用 redisContext 来保存连接状态。// redisContext 在每次操作后会修改其中的 err 和 errstr 字段来表示发生的错误码大于0和对应的描述。m_pContext redisConnectWithTimeout(m_server_ip.c_str(), m_server_port, timeout);if (!m_pContext || m_pContext-err){if (m_pContext){log_error(redisConnect failed: %s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;}else{log_error(redisConnect failed\n);}return 1;}redisReply *reply;// 验证if (!m_password.empty()){reply (redisReply *)redisCommand(m_pContext, AUTH %s, m_password.c_str());if (!reply || reply-type REDIS_REPLY_ERROR){log_error(Authentication failure:%p\n, reply);if (reply)freeReplyObject(reply);return -1;}else{// log_info(Authentication success\n);}freeReplyObject(reply);}reply (redisReply *)redisCommand(m_pContext, SELECT %d, 0);if (reply (reply-type REDIS_REPLY_STATUS) (strncmp(reply-str, OK, 2) 0)){freeReplyObject(reply);return 0;}else{if (reply)log_error(select cache db failed:%s\n, reply-str);return 2;}
}void CacheConn::DeInit()
{if (m_pContext){redisFree(m_pContext);m_pContext NULL;}
}const char *CacheConn::GetPoolName()
{return m_pool_name.c_str();
}string CacheConn::get(string key)
{string value;if (Init()){return value;}redisReply *reply (redisReply *)redisCommand(m_pContext, GET %s, key.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return value;}if (reply-type REDIS_REPLY_STRING){value.append(reply-str, reply-len);}freeReplyObject(reply);return value;
}string CacheConn::set(string key, string value)
{string ret_value;if (Init()){return ret_value;}// 返回的结果存放在redisReplyredisReply *reply (redisReply *)redisCommand(m_pContext, SET %s %s, key.c_str(), value.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return ret_value;}ret_value.append(reply-str, reply-len);freeReplyObject(reply); // 释放资源return ret_value;
}string CacheConn::setex(string key, int timeout, string value)
{string ret_value;if (Init()){return ret_value;}redisReply *reply (redisReply *)redisCommand(m_pContext, SETEX %s %d %s, key.c_str(), timeout, value.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return ret_value;}ret_value.append(reply-str, reply-len);freeReplyObject(reply);return ret_value;
}bool CacheConn::mget(const vectorstring keys, mapstring, string ret_value)
{if (Init()){return false;}if (keys.empty()){return false;}string strKey;bool bFirst true;for (vectorstring::const_iterator it keys.begin(); it ! keys.end(); it){if (bFirst){bFirst false;strKey *it;}else{strKey *it;}}if (strKey.empty()){return false;}strKey MGET strKey;redisReply *reply (redisReply *)redisCommand(m_pContext, strKey.c_str());if (!reply){log_info(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return false;}if (reply-type REDIS_REPLY_ARRAY){for (size_t i 0; i reply-elements; i){redisReply *child_reply reply-element[i];if (child_reply-type REDIS_REPLY_STRING){ret_value[keys[i]] child_reply-str;}}}freeReplyObject(reply);return true;
}bool CacheConn::isExists(string key)
{if (Init()){return false;}redisReply *reply (redisReply *)redisCommand(m_pContext, EXISTS %s, key.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return false;}long ret_value reply-integer;freeReplyObject(reply);if (0 ret_value){return false;}else{return true;}
}long CacheConn::del(string key)
{if (Init()){return 0;}redisReply *reply (redisReply *)redisCommand(m_pContext, DEL %s, key.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return 0;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}long CacheConn::hdel(string key, string field)
{if (Init()){return 0;}redisReply *reply (redisReply *)redisCommand(m_pContext, HDEL %s %s, key.c_str(), field.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return 0;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}string CacheConn::hget(string key, string field)
{string ret_value;if (Init()){return ret_value;}redisReply *reply (redisReply *)redisCommand(m_pContext, HGET %s %s, key.c_str(), field.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return ret_value;}if (reply-type REDIS_REPLY_STRING){ret_value.append(reply-str, reply-len);}freeReplyObject(reply);return ret_value;
}bool CacheConn::hgetAll(string key, mapstring, string ret_value)
{if (Init()){return false;}redisReply *reply (redisReply *)redisCommand(m_pContext, HGETALL %s, key.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return false;}if ((reply-type REDIS_REPLY_ARRAY) (reply-elements % 2 0)){for (size_t i 0; i reply-elements; i 2){redisReply *field_reply reply-element[i];redisReply *value_reply reply-element[i 1];string field(field_reply-str, field_reply-len);string value(value_reply-str, value_reply-len);ret_value.insert(make_pair(field, value));}}freeReplyObject(reply);return true;
}long CacheConn::hset(string key, string field, string value)
{if (Init()){return -1;}redisReply *reply (redisReply *)redisCommand(m_pContext, HSET %s %s %s, key.c_str(), field.c_str(), value.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return -1;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}long CacheConn::hincrBy(string key, string field, long value)
{if (Init()){return -1;}redisReply *reply (redisReply *)redisCommand(m_pContext, HINCRBY %s %s %ld, key.c_str(), field.c_str(), value);if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return -1;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}long CacheConn::incrBy(string key, long value)
{if (Init()){return -1;}redisReply *reply (redisReply *)redisCommand(m_pContext, INCRBY %s %ld, key.c_str(), value);if (!reply){log_error(redis Command failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return -1;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}string CacheConn::hmset(string key, mapstring, string hash)
{string ret_value;if (Init()){return ret_value;}int argc hash.size() * 2 2;const char **argv new const char *[argc];if (!argv){return ret_value;}argv[0] HMSET;argv[1] key.c_str();int i 2;for (mapstring, string::iterator it hash.begin(); it ! hash.end(); it){argv[i] it-first.c_str();argv[i] it-second.c_str();}redisReply *reply (redisReply *)redisCommandArgv(m_pContext, argc, argv, NULL);if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);delete[] argv;redisFree(m_pContext);m_pContext NULL;return ret_value;}ret_value.append(reply-str, reply-len);delete[] argv;freeReplyObject(reply);return ret_value;
}bool CacheConn::hmget(string key, liststring fields, liststring ret_value)
{if (Init()){return false;}int argc fields.size() 2;const char **argv new const char *[argc];if (!argv){return false;}argv[0] HMGET;argv[1] key.c_str();int i 2;for (liststring::iterator it fields.begin(); it ! fields.end(); it){argv[i] it-c_str();}redisReply *reply (redisReply *)redisCommandArgv(m_pContext, argc, (const char **)argv, NULL);if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);delete[] argv;redisFree(m_pContext);m_pContext NULL;return false;}if (reply-type REDIS_REPLY_ARRAY){for (size_t i 0; i reply-elements; i){redisReply *value_reply reply-element[i];string value(value_reply-str, value_reply-len);ret_value.push_back(value);}}delete[] argv;freeReplyObject(reply);return true;
}long CacheConn::incr(string key)
{if (Init()){return -1;}redisReply *reply (redisReply *)redisCommand(m_pContext, INCR %s, key.c_str());if (!reply){log_error(redis Command failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return -1;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}long CacheConn::decr(string key)
{if (Init()){return -1;}redisReply *reply (redisReply *)redisCommand(m_pContext, DECR %s, key.c_str());if (!reply){log_error(redis Command failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return -1;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}long CacheConn::lpush(string key, string value)
{if (Init()){return -1;}redisReply *reply (redisReply *)redisCommand(m_pContext, LPUSH %s %s, key.c_str(), value.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return -1;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}long CacheConn::rpush(string key, string value)
{if (Init()){return -1;}redisReply *reply (redisReply *)redisCommand(m_pContext, RPUSH %s %s, key.c_str(), value.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return -1;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}long CacheConn::llen(string key)
{if (Init()){return -1;}redisReply *reply (redisReply *)redisCommand(m_pContext, LLEN %s, key.c_str());if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return -1;}long ret_value reply-integer;freeReplyObject(reply);return ret_value;
}bool CacheConn::lrange(string key, long start, long end, liststring ret_value)
{if (Init()){return false;}redisReply *reply (redisReply *)redisCommand(m_pContext, LRANGE %s %d %d, key.c_str(), start, end);if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return false;}if (reply-type REDIS_REPLY_ARRAY){for (size_t i 0; i reply-elements; i){redisReply *value_reply reply-element[i];string value(value_reply-str, value_reply-len);ret_value.push_back(value);}}freeReplyObject(reply);return true;
}bool CacheConn::flushdb()
{bool ret false;if (Init()){return false;}redisReply *reply (redisReply *)redisCommand(m_pContext, FLUSHDB);if (!reply){log_error(redisCommand failed:%s\n, m_pContext-errstr);redisFree(m_pContext);m_pContext NULL;return false;}if (reply-type REDIS_REPLY_STRING strncmp(reply-str, OK, 2) 0){ret true;}freeReplyObject(reply);return ret;
}
///
CachePool::CachePool(const char *pool_name, const char *server_ip, int server_port, int db_index,const char *password, int max_conn_cnt)
{m_pool_name pool_name;m_server_ip server_ip;m_server_port server_port;m_db_index db_index;m_password password;m_max_conn_cnt max_conn_cnt;m_cur_conn_cnt MIN_CACHE_CONN_CNT;
}CachePool::~CachePool()
{m_free_notify.Lock();for (listCacheConn *::iterator it m_free_list.begin(); it ! m_free_list.end(); it){CacheConn *pConn *it;delete pConn;}m_free_list.clear();m_cur_conn_cnt 0;m_free_notify.Unlock();
}int CachePool::Init()
{for (int i 0; i m_cur_conn_cnt; i){CacheConn *pConn new CacheConn(m_server_ip.c_str(), m_server_port,m_db_index, m_password.c_str(), m_pool_name.c_str());if (pConn-Init()){delete pConn;return 1;}m_free_list.push_back(pConn);}log_info(cache pool: %s, list size: %lu\n, m_pool_name.c_str(), m_free_list.size());return 0;
}CacheConn *CachePool::GetCacheConn()
{m_free_notify.Lock();while (m_free_list.empty()){if (m_cur_conn_cnt m_max_conn_cnt){m_free_notify.Wait();}else{CacheConn *p_cache_conn new CacheConn(m_server_ip.c_str(), m_server_port,m_db_index, m_password.c_str(), m_pool_name.c_str());int ret p_cache_conn-Init();if (ret){log_error(Init CacheConn failed\n);delete p_cache_conn;m_free_notify.Unlock();return NULL;}else{m_free_list.push_back(p_cache_conn);m_cur_conn_cnt;log_info(new cache connection: %s, conn_cnt: %d\n, m_pool_name.c_str(), m_cur_conn_cnt);}}}CacheConn *pConn m_free_list.front();m_free_list.pop_front();m_free_notify.Unlock();return pConn;
}void CachePool::RelCacheConn(CacheConn *p_cache_conn)
{m_free_notify.Lock();listCacheConn *::iterator it m_free_list.begin();for (; it ! m_free_list.end(); it){if (*it p_cache_conn){break;}}if (it m_free_list.end()){m_free_list.push_back(p_cache_conn);}m_free_notify.Signal();m_free_notify.Unlock();
}