├── .gitignore ├── .travis.yml ├── .vscode └── settings.json ├── LICENSE ├── README-cn.md ├── README.md ├── doc ├── xRedis编译安装.md ├── xredis_0.png ├── 使用xRedis连接官方集群.md └── 使用xRedis连接自定义数据分片集群.md ├── examples ├── Makefile ├── cluster-cli.cpp ├── demo.cpp ├── demo_multi_slice.cpp ├── demo_slice.cpp ├── redis-cluster-client.cpp ├── xRedisClusterClient_test.cpp ├── xredis-example-Consistent-hash │ ├── CMd5.cpp │ ├── CMd5.h │ ├── redis-test.cpp │ └── xredis-example-Consistent-hash.cpp └── xredis-example.cpp ├── makefile ├── src ├── xLock.h ├── xRedisClient.cpp ├── xRedisClient.h ├── xRedisClient_connection.cpp ├── xRedisClient_hashs.cpp ├── xRedisClient_keys.cpp ├── xRedisClient_lists.cpp ├── xRedisClient_pubsub.cpp ├── xRedisClient_sets.cpp ├── xRedisClient_sortedsets.cpp ├── xRedisClient_strings.cpp ├── xRedisClusterClient.cpp ├── xRedisClusterClient.h ├── xRedisClusterManager.h ├── xRedisLog.cpp ├── xRedisLog.h ├── xRedisPool.cpp └── xRedisPool.h └── test └── xredis-test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Compiled Dynamic libraries 8 | *.so 9 | *.dylib 10 | *.dll 11 | 12 | # Compiled Static libraries 13 | *.lai 14 | *.la 15 | *.a 16 | *.lib 17 | 18 | # Executables 19 | *.exe 20 | *.out 21 | *.app 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false # 开启基于容器的Travis CI任务,让编译效率更高。 2 | language: cpp 3 | os: 4 | - linux 5 | 6 | compiler: 7 | - gcc 8 | 9 | branches: 10 | only: 11 | - master 12 | 13 | env: 14 | matrix: 15 | - REDIS=1 16 | global: 17 | - CURPATH=$(pwd) 18 | - TOOLSDIR=$HOME/Tools 19 | - HIREDISDIR=$TOOLSDIR/redis 20 | - LD_LIBRARY_PATH=$HIREDISDIR:$LD_LIBRARY_PATH 21 | - COMPILER=g++-7 22 | 23 | before_install: 24 | - mkdir -p $TOOLSDIR 25 | - cd $TOOLSDIR 26 | - wget http://download.redis.io/releases/redis-3.0.6.tar.gz 27 | - tar zxf redis-3.0.6.tar.gz 28 | 29 | before_script: 30 | - export 31 | 32 | - cd redis-3.0.6/deps/hiredis 33 | - make 34 | - sudo make install 35 | 36 | script: 37 | - export 38 | - cd $TRAVIS_BUILD_DIR 39 | - make 40 | 41 | - sudo make install 42 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.clang_format_fallbackStyle": "WebKit" 3 | } -------------------------------------------------------------------------------- /README-cn.md: -------------------------------------------------------------------------------- 1 | xRedis 2 | ====== 3 | 4 | xRedis 是一个C++开发的redis客户端,是对hiredis的C++封装,提供易用的redis命令操作接口. 5 | 6 | ***功能与特点:*** 7 | * 支持数据多节点分布存储,可自定义分片规则; 8 | * 支持同时连接到每个分片的主从节点,支持主从读写分离; 9 | * 支持对每个存储节点建立连接池; 10 | * 支持同时连接多个数据分片集群; 11 | * 支持连接到官方集群,支持单个节点和多个节点 12 | 建立到每个节点的连接池,client端自动计算slot分布。 13 | 支持自动计算节点索引位置,支持REDIS集群节点变化连接自动切换; 14 | 当官方集群节点有添加/删除/slot分布变化时,到集群的连接池会自动更新。 15 | * 提供简单易用的C++接口封装,已实现大部分REDIS命令; 16 | * 只依赖hiredis库; 17 | * 多线程安全 18 | * 支持带密码连接; 19 | * 支持linux、windows平台 20 | 21 | 22 | ### Dependencies 23 | 24 | xredis 依赖 hiredis , 在使用xRedis前需要安装[hiredis](https://github.com/redis/hiredis/)库 25 | 26 | ### Install 27 | 28 | 第一步 安装libhiredis 29 | 在Debian系统上: 30 | ```bash 31 | sudo apt-get install libhiredis-dev 32 | ``` 33 | 34 | xRedis源码安装 35 | ```bash 36 | git clone https://github.com/0xsky/xredis 37 | cd xredis 38 | make 39 | sudo make install 40 | ``` 41 | 使用说明 42 | ```C++ 43 | #使用 xRedisClusterClient类 访问 redis节点或是官方集群(redis cluster) 44 | 45 | #include "xRedisClusterClient.h" 46 | int main(int argc, char **argv) { 47 | xRedisClusterClient redisclient; 48 | # 连接到REDIS,建立大小为4的连接池, 49 | # 若此节点是官方集群的成员,则会自动对集群每个主节点建立大小为4的连接池。 50 | std::string passwd = "passwd123"; 51 | bool bRet = redisclient.connect("127.0.0.1", 6379, passwd, 4); 52 | 53 | RedisResult result; 54 | redisclient.command(result, "set %s %s", "key", "hello"); 55 | 56 | printf("type:%d integer:%lld str:%s \r\n", 57 | result.type(), result.integer(), result.str()); 58 | 59 | while (true) { 60 | usleep(1000*1000*6); 61 | // 定时调用 keepalive 检测断线重连接,以及集群状态变化。 62 | redisclient.keepalive(); 63 | } 64 | 65 | return 0; 66 | } 67 | ``` 68 | 69 | 更多使用示例 70 | 使用示例 [examples]目录(https://github.com/0xsky/xredis/blob/master/examples) 71 | 72 | demo.cpp 使用xredisclient访问单个redis节点示例 73 | demo_slice.cpp 使用xredisclient访问单组多分片(节点)redis分片集群示例 74 | demo_multi_slice.cpp 使用xredisclient访问多组多分片(节点)redis分片集群示例 75 | xredis-example.cpp 使用xredisclient 批量操作示例 76 | xredis-example-Consistent-hash xredisclient使用一致性hash,自定义数据分片存储demo 77 | 78 | xRedisClusterClient_test.cpp 使用xRedisClusterClient实现简单的redis官方集群客户端示例 79 | cluster-cli.cpp 使用 xRedisClusterClient 实现的连接redis集群的client,支持集群节增加/删除、slot分布变化时,自动切换。 80 | 81 | /test/xredis-test.cpp 多个redis命令的使用示例 82 | 83 | ### 相关文档 84 | 85 | 86 | ### 计划 87 | 添加 Redis 哨兵模式支持 88 | 89 | 90 | ##### xRedis 分片存储架构图 91 | ![xredis](doc/xredis_0.png) 92 | 93 | [xRedis API](http://xredis.0xsky.com/)
94 | 使用示例 [examples](https://github.com/0xsky/xredis/blob/master/examples) directory for some examples
95 | xRedis开源社区QQ群: 190107312
96 | 97 | 作者: xSky
98 | 博客: [xSky's Blog](https://0xsky.com/)
99 | xRedis QQ 群: 190107312 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | xRedis 2 | [![Build Status](https://travis-ci.org/freeeyes/PSS.svg?branch=master)](https://travis-ci.org/freeeyes/PSS) 3 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0 ) 4 | [![GitHub version](https://badge.fury.io/gh/0xsky%2Fxredis.svg)](https://badge.fury.io/gh/0xsky%2Fxredis) 5 | ====== 6 | 7 | C++ Redis client, support the data slice storage, redis cluster, connection pool, read/write separation. 8 | 9 | **Features:** 10 | * Support multi-node distributed storage of data, can customize the sharding rules; 11 | * Support to connect to master and slave nodes of each shard at the same time, support separation of master and slave reads and writes; 12 | * Support connection pooling for each storage node; 13 | * Support simultaneous connection of multiple data sharding clusters; 14 | * Support for connecting to official clusters, single or multiple nodes 15 | Support to set up a connection pool to each node, the client side automatically calculates the slot distribution. 16 | Support automatic calculation of node index position, support Redis cluster node change connection automatic switch; 17 | The connection pool to the cluster is automatically updated when the add/delete /slot distribution of the official cluster node changes. 18 | * Provide easy to use C++ interface encapsulation, has implemented most of the Redis command; 19 | * Only rely on the Hiredis library; 20 | * Multi-thread safety 21 | * Support password connection; 22 | * Support Linux and Windows platforms 23 | 24 | 中文版说明文档[点这里](https://github.com/0xsky/xredis/blob/master/README-cn.md) 25 | 26 | ### Dependencies 27 | 28 | xredis requires hiredis only 29 | 30 | ### Install 31 | 32 | First step install libhiredis, on a Debian system you can use: 33 | 34 | ```bash 35 | sudo apt-get install libhiredis-dev 36 | ``` 37 | 38 | on centos/redhat/fedora system you can use: 39 | ```bash 40 | sudo yum install hiredis-devel 41 | ``` 42 | 43 | Then checkout the code and compile it 44 | ```bash 45 | git clone https://github.com/0xsky/xredis 46 | cd xredis 47 | make 48 | sudo make install 49 | ``` 50 | 51 | Usage 52 | ```C++ 53 | #Accessing redis or redis Cluster using the xRedisClusterClient class 54 | 55 | #include "xRedisClusterClient.h" 56 | int main(int argc, char **argv) { 57 | xRedisClusterClient redisclient; 58 | # Connect to REDIS and establish a connection pool 59 | # If this node is a member of the REDIS cluster, 60 | # a connection pool is automatically established for each primary node in the cluster. 61 | std::string passwd = "passwd123"; 62 | bool bRet = redisclient.connect("127.0.0.1", 6379, passwd, 4); 63 | 64 | RedisResult result; 65 | redisclient.command(result, "set %s %s", "key", "hello"); 66 | 67 | printf("type:%d integer:%lld str:%s \r\n", 68 | result.type(), result.integer(), result.str()); 69 | 70 | while (true) { 71 | usleep(1000*1000*6); 72 | redisclient.keepalive(); 73 | } 74 | 75 | return 0; 76 | } 77 | ``` 78 | ### Todo 79 | Support redis sentinel 80 | 81 | ### Documentation 82 | ![xredis](doc/xredis_0.png) 83 | 84 | [xRedis API Site](http://xredis.0xsky.com/)
85 | See [examples](https://github.com/0xsky/xredis/blob/master/examples) directory for some examples
86 | 87 | blog: [xSky's Blog](https://0xsky.com/)
88 | xRedis QQ Group: 190107312 89 | 90 | -------------------------------------------------------------------------------- /doc/xRedis编译安装.md: -------------------------------------------------------------------------------- 1 | xRedis 2 | ====== 3 | 4 | xRedis 是一个C++开发的redis客户端,是对hiredis的C++封装,提供易用的redis命令操作接口. 5 | 6 | ***功能与特点:*** 7 | * 支持数据多节点分布存储,可自定义分片规则; 8 | * 支持同时连接到每个分片的主从节点,支持主从读写分离; 9 | * 支持对每个存储节点建立连接池; 10 | * 支持同时连接多个数据分片集群; 11 | * 支持连接到官方集群,支持单个节点和多个节点 12 | 建立到每个节点的连接池,client端自动计算slot分布。 13 | 支持自动计算节点索引位置,支持REDIS集群节点变化连接自动切换; 14 | 当官方集群节点有添加/删除/slot分布变化时,到集群的连接池会自动更新。 15 | * 提供简单易用的C++接口封装,已实现大部分REDIS命令; 16 | * 只依赖hiredis库; 17 | * 多线程安全 18 | * 支持带密码连接; 19 | * 支持linux、windows平台 20 | 21 | 22 | ### Dependencies 23 | 24 | xredis 依赖 hiredis , 在使用xRedis前需要安装[hiredis](https://github.com/redis/hiredis/)库 25 | 26 | ### Install 27 | 28 | 第一步 安装libhiredis 29 | 在Debian系统上: 30 | ```bash 31 | sudo apt-get install libhiredis-dev 32 | ``` 33 | 34 | xRedis源码安装 35 | ```bash 36 | git clone https://github.com/0xsky/xredis 37 | cd xredis 38 | make 39 | sudo make install 40 | ``` 41 | 使用说明 42 | ```C++ 43 | #使用 xRedisClusterClient类 访问 redis节点或是官方集群(redis cluster) 44 | 45 | #include "xRedisClusterClient.h" 46 | int main(int argc, char **argv) { 47 | xRedisClusterClient redisclient; 48 | # 连接到REDIS,建立大小为4的连接池, 49 | # 若此节点是官方集群的成员,则会自动对集群每个主节点建立大小为4的连接池。 50 | std::string passwd = "passwd123"; 51 | bool bRet = redisclient.connect("127.0.0.1", 6379, passwd, 4); 52 | 53 | RedisResult result; 54 | redisclient.command(result, "set %s %s", "key", "hello"); 55 | 56 | printf("type:%d integer:%lld str:%s \r\n", 57 | result.type(), result.integer(), result.str()); 58 | 59 | while (true) { 60 | usleep(1000*1000*6); 61 | // 定时调用 keepalive 检测断线重连接,以及集群状态变化。 62 | redisclient.keepalive(); 63 | } 64 | 65 | return 0; 66 | } 67 | ``` 68 | 69 | 更多使用示例 70 | 使用示例 [examples]目录(https://github.com/0xsky/xredis/blob/master/examples) 71 | 72 | demo.cpp 使用xredisclient访问单个redis节点示例 73 | demo_slice.cpp 使用xredisclient访问单组多分片(节点)redis分片集群示例 74 | demo_multi_slice.cpp 使用xredisclient访问多组多分片(节点)redis分片集群示例 75 | xredis-example.cpp 使用xredisclient 批量操作示例 76 | xredis-example-Consistent-hash xredisclient使用一致性hash,自定义数据分片存储demo 77 | 78 | xRedisClusterClient_test.cpp 使用xRedisClusterClient实现简单的redis官方集群客户端示例 79 | cluster-cli.cpp 使用 xRedisClusterClient 实现的连接redis集群的client,支持集群节增加/删除、slot分布变化时,自动切换。 80 | 81 | /test/xredis-test.cpp 多个redis命令的使用示例 82 | 83 | -------------------------------------------------------------------------------- /doc/xredis_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xsky/xredis/39c20a584c62cfa24895fd444f63d1e22ddff8e7/doc/xredis_0.png -------------------------------------------------------------------------------- /doc/使用xRedis连接官方集群.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xsky/xredis/39c20a584c62cfa24895fd444f63d1e22ddff8e7/doc/使用xRedis连接官方集群.md -------------------------------------------------------------------------------- /doc/使用xRedis连接自定义数据分片集群.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xsky/xredis/39c20a584c62cfa24895fd444f63d1e22ddff8e7/doc/使用xRedis连接自定义数据分片集群.md -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | 2 | LIBS=-L../ -I../src -lhiredis -lpthread 3 | all: demo demo_slice demo_multi_slice xredis-example xRedisClusterClient_test 4 | 5 | demo: 6 | g++ ${LIBS} demo.cpp -o demo 7 | demo_slice: 8 | g++ ${LIBS} demo_slice.cpp -o demo_slice 9 | demo_multi_slice: 10 | g++ ${LIBS} demo_multi_slice.cpp -o demo_multi_slice 11 | xredis-example: 12 | g++ ${LIBS} xredis-example.cpp -o xredis-example 13 | xRedisClusterClient_test: 14 | g++ ${LIBS} -I/usr/local/include/hiredis xRedisClusterClient_test.cpp -o xRedisClusterClient_test 15 | 16 | clean: 17 | rm -f demo 18 | rm -f demo_slice 19 | rm -f demo_multi_slice 20 | rm -f xredis-example 21 | rm -f xRedisClusterClient_test 22 | rm -f cluster-cli 23 | 24 | -------------------------------------------------------------------------------- /examples/cluster-cli.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | /** \example cluster-cli.cpp 10 | * This is an example used by XredisClusterClient 11 | * Implemented a simple Redis console client 12 | * Connecting a single Redis node and an official Redis cluster is supported 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | 24 | using std::cin; 25 | using std::cout; 26 | using std::endl; 27 | 28 | #include "xRedisClusterClient.h" 29 | using namespace xrc; 30 | 31 | xRedisClusterClient* redis = NULL; 32 | 33 | static int str2Vect(const char* pSrc, std::vector& vDest, const char* pSep = ",") 34 | { 35 | if (NULL == pSrc) { 36 | return -1; 37 | } 38 | 39 | int iLen = strlen(pSrc); 40 | if (iLen == 0) { 41 | return -1; 42 | } 43 | 44 | char* pTmp = new char[iLen + 1]; 45 | if (pTmp == NULL) { 46 | return -1; 47 | } 48 | 49 | memcpy(pTmp, pSrc, iLen); 50 | pTmp[iLen] = '\0'; 51 | 52 | char* pCurr = strtok(pTmp, pSep); 53 | while (pCurr) { 54 | vDest.push_back(pCurr); 55 | pCurr = strtok(NULL, pSep); 56 | } 57 | 58 | delete[] pTmp; 59 | return 0; 60 | } 61 | 62 | void timer_handle(int sig) 63 | { 64 | (void)sig; 65 | 66 | redis->keepalive(); 67 | } 68 | 69 | void init_timer() 70 | { 71 | struct sigevent evp; 72 | struct itimerspec ts; 73 | timer_t timer; 74 | 75 | memset(&evp, 0, sizeof(struct sigevent)); 76 | evp.sigev_value.sival_ptr = &timer; 77 | evp.sigev_notify = SIGEV_SIGNAL; 78 | evp.sigev_signo = SIGUSR1; 79 | signal(SIGUSR1, timer_handle); 80 | 81 | int ret = timer_create(CLOCK_REALTIME, &evp, &timer); 82 | if (ret) { 83 | perror("timer_create"); 84 | return; 85 | } 86 | 87 | ts.it_interval.tv_sec = 5; 88 | ts.it_interval.tv_nsec = 0; 89 | ts.it_value.tv_sec = 5; 90 | ts.it_value.tv_nsec = 0; 91 | 92 | ret = timer_settime(timer, 0, &ts, NULL); 93 | if (ret) 94 | perror("timer_settime"); 95 | } 96 | 97 | void log_demo(int level, const char* line) 98 | { 99 | printf("xRedis %u %s", level, line); 100 | } 101 | 102 | int main(int argc, char** argv) 103 | { 104 | (void)argc; 105 | (void)argv; 106 | 107 | std::string pass; 108 | 109 | if (argc<3) { 110 | printf("Usage:%s host port pass \r\n", argv[0]); 111 | return -1; 112 | } else if (4==argc) { 113 | pass = argv[3]; 114 | } 115 | 116 | init_timer(); 117 | xRedisClusterClient redisclient; 118 | //redisclient.setLogLevel(LOG_LEVEL_DEBUG, log_demo); 119 | redis = &redisclient; 120 | bool bRet = redisclient.connect(argv[1], atoi(argv[2]), pass, 4); 121 | 122 | if (!bRet) { 123 | fprintf(stderr, "Connect to %s:%s error\r\n", argv[0], argv[1]); 124 | return -1; 125 | } 126 | 127 | std::string strInput; 128 | while (true) { 129 | cout << "\033[32mxRedis> \033[0m"; 130 | getline(cin, strInput); 131 | if (!cin) 132 | return 0; 133 | 134 | if (strInput.length() < 1) { 135 | cout << "input again" << endl; 136 | } else { 137 | RedisResult result; 138 | VString vDataIn; 139 | 140 | str2Vect(strInput.c_str(), vDataIn, " "); 141 | redisclient.commandArgv(vDataIn, result); 142 | 143 | switch (result.type()) { 144 | case REDIS_REPLY_INTEGER: { 145 | printf("%lld \r\n", result.integer()); 146 | break; 147 | } 148 | case REDIS_REPLY_NIL: { 149 | printf("%lld %s \r\n", result.integer(), result.str()); 150 | break; 151 | } 152 | case REDIS_REPLY_STATUS: { 153 | printf("%s \r\n", result.str()); 154 | break; 155 | } 156 | case REDIS_REPLY_ERROR: { 157 | printf("%s \r\n", result.str()); 158 | break; 159 | } 160 | case REDIS_REPLY_STRING: { 161 | printf("%s \r\n", result.str()); 162 | break; 163 | } 164 | case REDIS_REPLY_ARRAY: { 165 | for (size_t i = 0; i < result.elements(); ++i) { 166 | RedisResult::RedisReply reply = result.element(i); 167 | printf("type:%d integer:%lld str:%s \r\n", 168 | reply.type(), reply.integer(), reply.str()); 169 | } 170 | break; 171 | } 172 | } 173 | } 174 | } 175 | 176 | return 0; 177 | } 178 | -------------------------------------------------------------------------------- /examples/demo.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ---------------------------------------------------------------------------- 4 | * Copyright (c) 2013-2021, xSky 5 | * All rights reserved. 6 | * Distributed under GPL license. 7 | * ---------------------------------------------------------------------------- 8 | */ 9 | 10 | /** \example demo.cpp 11 | * This is an example of how to use the xRedis. 12 | *
This demo connect to single redis server with connection pool 13 | *
More details about this example. 14 | */ 15 | 16 | #include "xRedisClient.h" 17 | #include 18 | #include 19 | 20 | using namespace xrc; 21 | 22 | enum { 23 | CACHE_TYPE_1, 24 | CACHE_TYPE_MAX, 25 | }; 26 | 27 | /* 配置单个redis存储节点 */ 28 | RedisNode RedisList1[1] = { 29 | { .dbindex = 0, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER } 30 | }; 31 | 32 | void log_demo(int level, const char* line) 33 | { 34 | printf("xRedis %u %s", level, line); 35 | } 36 | 37 | int main(int argc, char** argv) 38 | { 39 | (void)argc; 40 | (void)argv; 41 | 42 | xRedisClient xRedis; 43 | //xRedis.SetLogLevel(LOG_LEVEL_DEBUG, log_demo ); 44 | xRedis.Init(CACHE_TYPE_MAX); 45 | xRedis.ConnectRedisCache(RedisList1, sizeof(RedisList1) / sizeof(RedisNode), 46 | 1, CACHE_TYPE_1); 47 | 48 | const char* key = "test"; 49 | const char* value = "test value"; 50 | SliceIndex index(&xRedis, CACHE_TYPE_1); 51 | index.Create(key); 52 | 53 | bool bRet = xRedis.set(index, key, value); 54 | if (bRet) { 55 | printf("success \r\n"); 56 | } else { 57 | printf("error %s \r\n", index.GetErrInfo()); 58 | } 59 | 60 | std::string strValue; 61 | bRet = xRedis.get(index, key, strValue); 62 | if (bRet) { 63 | printf("%s \r\n", strValue.c_str()); 64 | } else { 65 | printf("error %s ", index.GetErrInfo()); 66 | } 67 | 68 | while (true) 69 | { 70 | usleep(1000*1000*6); 71 | xRedis.Keepalive(); 72 | } 73 | 74 | 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /examples/demo_multi_slice.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ---------------------------------------------------------------------------- 4 | * Copyright (c) 2013-2021, xSky 5 | * All rights reserved. 6 | * Distributed under GPL license. 7 | * ---------------------------------------------------------------------------- 8 | */ 9 | 10 | /** \example demo_multi_slice.cpp 11 | * This is an example of how to use the xRedis. 12 | *
connect to multi redis clusters 13 | *
every redis cluster have multi redis server nodes 14 | *
every redis node have a connection pool 15 | *
More details about this example. 16 | */ 17 | 18 | #include 19 | 20 | #include "xRedisClient.h" 21 | 22 | using namespace xrc; 23 | 24 | enum { 25 | CACHE_TYPE_1, 26 | CACHE_TYPE_2, 27 | CACHE_TYPE_MAX, 28 | }; 29 | 30 | /* 配置一个3分片存储xRedis集群 CACHE_TYPE_1:共3个存储主节点 */ 31 | RedisNode RedisList1[3] = { 32 | { .dbindex = 0, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 33 | { .dbindex = 1, .host = "127.0.0.2", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 34 | { .dbindex = 2, .host = "127.0.0.3", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER } 35 | }; 36 | 37 | /* 配置一个5分片存储xRedis集群 CACHE_TYPE_2:共5个存储主节点 */ 38 | RedisNode RedisList2[5] = { 39 | { .dbindex = 0, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 40 | { .dbindex = 1, .host = "127.0.0.2", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 41 | { .dbindex = 2, .host = "127.0.0.3", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 42 | { .dbindex = 3, .host = "127.0.0.4", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 43 | { .dbindex = 4, .host = "127.0.0.5", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 44 | }; 45 | 46 | int main(int argc, char** argv) 47 | { 48 | (void)argc; 49 | (void)argv; 50 | 51 | xRedisClient xRedis; 52 | xRedis.Init(CACHE_TYPE_MAX); 53 | xRedis.ConnectRedisCache(RedisList1, sizeof(RedisList1) / sizeof(RedisNode), 54 | 3, CACHE_TYPE_1); 55 | xRedis.ConnectRedisCache(RedisList2, sizeof(RedisList2) / sizeof(RedisNode), 56 | 5, CACHE_TYPE_2); 57 | 58 | const char* key = "test"; 59 | const char* value = "test value"; 60 | 61 | SliceIndex index(&xRedis, CACHE_TYPE_1); 62 | bool bRet = index.Create(key); 63 | if (!bRet) { 64 | return 0; 65 | } 66 | 67 | bRet = xRedis.set(index, key, value); 68 | if (bRet) { 69 | printf("success \r\n"); 70 | } else { 71 | printf("error [%s] \r\n", index.GetErrInfo()); 72 | } 73 | 74 | std::string strValue; 75 | bRet = xRedis.get(index, key, strValue); 76 | if (bRet) { 77 | printf("%s \r\n", strValue.c_str()); 78 | } else { 79 | printf("error [%s] \r\n", index.GetErrInfo()); 80 | } 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /examples/demo_slice.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | /** \example demo_slice.cpp 10 | * This is an example of how to use the xRedis. 11 | *
Connect to a redis cluster which contains three redis node 12 | *
More details about this example. 13 | */ 14 | 15 | #include "xRedisClient.h" 16 | #include 17 | 18 | using namespace xrc; 19 | 20 | enum { 21 | CACHE_TYPE_1, 22 | CACHE_TYPE_2, 23 | CACHE_TYPE_MAX, 24 | }; 25 | 26 | /* 配置一个3分片存储xRedis集群:共3个存储主节点 */ 27 | RedisNode RedisList1[3] = { 28 | { .dbindex = 0, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 29 | { .dbindex = 1, .host = "127.0.0.2", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 30 | { .dbindex = 2, .host = "127.0.0.3", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER } 31 | }; 32 | 33 | int main(int argc, char** argv) 34 | { 35 | (void)argc; 36 | (void)argv; 37 | 38 | xRedisClient xRedis; 39 | xRedis.Init(CACHE_TYPE_MAX); 40 | xRedis.ConnectRedisCache(RedisList1, sizeof(RedisList1) / sizeof(RedisNode), 41 | 3, CACHE_TYPE_1); 42 | 43 | const char* key = "test"; 44 | const char* value = "test value"; 45 | 46 | SliceIndex index(&xRedis, CACHE_TYPE_1); 47 | bool bRet = index.Create(key); 48 | if (!bRet) { 49 | return 0; 50 | } 51 | 52 | bRet = xRedis.set(index, key, value); 53 | if (bRet) { 54 | printf("success \r\n"); 55 | } else { 56 | printf("error [%s] \r\n", index.GetErrInfo()); 57 | } 58 | 59 | std::string strValue; 60 | bRet = xRedis.get(index, key, strValue); 61 | if (bRet) { 62 | printf("%s \r\n", strValue.c_str()); 63 | } else { 64 | printf("error [%s] \r\n", index.GetErrInfo()); 65 | } 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /examples/redis-cluster-client.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | /** \example redis-cluster-client.cpp 10 | * This is an example of how to use the xRedis. 11 | *
This demo connect to single redis server with connection pool 12 | *
More details about this example. 13 | */ 14 | 15 | #include "xRedisClusterClient.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | using std::cin; 22 | using std::cout; 23 | using std::endl; 24 | 25 | /* 26 | 这是连接redis官方集群客户端的一个示例 27 | */ 28 | 29 | int main(int argc, char** argv) 30 | { 31 | (void)argc; 32 | (void)argv; 33 | 34 | xRedisClusterClient ClusterClient; 35 | 36 | bool bRet = ClusterClient.Connect(argv[1], atoi(argv[2]), 2); 37 | if (!bRet) { 38 | return -1; 39 | } 40 | 41 | std::string strInput; 42 | while (true) { 43 | cout << "\033[32mxRedis> \033[0m"; 44 | getline(cin, strInput); 45 | if (!cin) 46 | return 0; 47 | 48 | if (strInput.length() < 1) { 49 | cout << "input again" << endl; 50 | } else { 51 | RedisResult result; 52 | VSTRING vDataIn; 53 | 54 | xRedisClusterClient::str2Vect(strInput.c_str(), vDataIn, " "); 55 | ClusterClient.RedisCommandArgv(vDataIn, result); 56 | 57 | switch (result.type()) { 58 | case REDIS_REPLY_INTEGER: { 59 | printf("%lld \r\n", result.integer()); 60 | break; 61 | } 62 | case REDIS_REPLY_NIL: { 63 | printf("%lld %s \r\n", result.integer(), result.str()); 64 | break; 65 | } 66 | case REDIS_REPLY_STATUS: { 67 | printf("%s \r\n", result.str()); 68 | break; 69 | } 70 | case REDIS_REPLY_ERROR: { 71 | printf("%s \r\n", result.str()); 72 | break; 73 | } 74 | case REDIS_REPLY_STRING: { 75 | printf("%s \r\n", result.str()); 76 | break; 77 | } 78 | case REDIS_REPLY_ARRAY: { 79 | for (size_t i = 0; i < result.elements(); ++i) { 80 | RedisResult::RedisReply reply = result.element(i); 81 | printf("type:%d integer:%lld str:%s \r\n", reply.type(), 82 | reply.integer(), reply.str()); 83 | } 84 | break; 85 | } 86 | } 87 | } 88 | } 89 | 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /examples/xRedisClusterClient_test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | /** \example xRedisClusterClient_test.cpp 10 | * This is an example of how to use the xRedis. 11 | *
This demo connect to single redis server with connection pool 12 | *
More details about this example. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "xRedisClusterClient.h" 21 | 22 | using namespace xrc; 23 | 24 | int main(int argc, char** argv) 25 | { 26 | (void)argc; 27 | (void)argv; 28 | 29 | xRedisClusterClient redisClusterClient; 30 | std::string pass; 31 | bool bRet = redisClusterClient.connect("127.0.0.1", 7001, pass, 4); 32 | //bool bRet = redisClusterClient.ConnectRedis(argv[1], atoi(argv[2]), argv[3], 4); 33 | if (!bRet) { 34 | return -1; 35 | } 36 | 37 | // VSTRING redis_arg; 38 | // redis_arg.push_back("hgetall"); 39 | // redis_arg.push_back("htest"); 40 | 41 | RedisResult result; 42 | redisClusterClient.command(result, "hgetall %s", "htest"); 43 | 44 | printf("type:%d integer:%lld str:%s \r\n", result.type(), result.integer(), 45 | result.str()); 46 | 47 | for (size_t i = 0; i < result.elements(); ++i) { 48 | RedisResult::RedisReply reply = result.element(i); 49 | printf("type:%d integer:%lld str:%s \r\n", reply.type(), reply.integer(), 50 | reply.str()); 51 | } 52 | 53 | while (true) { 54 | usleep(1000 * 1000 * 6); 55 | redisClusterClient.keepalive(); 56 | } 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /examples/xredis-example-Consistent-hash/CMd5.cpp: -------------------------------------------------------------------------------- 1 | #include "CMd5.h" 2 | #include 3 | #include 4 | 5 | #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ 6 | #ifdef ARCH_IS_BIG_ENDIAN 7 | # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) 8 | #else 9 | # define BYTE_ORDER 0 10 | #endif 11 | 12 | #define T_MASK ((md5_word_t)~0) 13 | #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) 14 | #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) 15 | #define T3 0x242070db 16 | #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) 17 | #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) 18 | #define T6 0x4787c62a 19 | #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) 20 | #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) 21 | #define T9 0x698098d8 22 | #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) 23 | #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) 24 | #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) 25 | #define T13 0x6b901122 26 | #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) 27 | #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) 28 | #define T16 0x49b40821 29 | #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) 30 | #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) 31 | #define T19 0x265e5a51 32 | #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) 33 | #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) 34 | #define T22 0x02441453 35 | #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) 36 | #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) 37 | #define T25 0x21e1cde6 38 | #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) 39 | #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) 40 | #define T28 0x455a14ed 41 | #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) 42 | #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) 43 | #define T31 0x676f02d9 44 | #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) 45 | #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) 46 | #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) 47 | #define T35 0x6d9d6122 48 | #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) 49 | #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) 50 | #define T38 0x4bdecfa9 51 | #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) 52 | #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) 53 | #define T41 0x289b7ec6 54 | #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) 55 | #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) 56 | #define T44 0x04881d05 57 | #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) 58 | #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) 59 | #define T47 0x1fa27cf8 60 | #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) 61 | #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) 62 | #define T50 0x432aff97 63 | #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) 64 | #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) 65 | #define T53 0x655b59c3 66 | #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) 67 | #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) 68 | #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) 69 | #define T57 0x6fa87e4f 70 | #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) 71 | #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) 72 | #define T60 0x4e0811a1 73 | #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) 74 | #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) 75 | #define T63 0x2ad7d2bb 76 | #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) 77 | 78 | 79 | static void 80 | md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) 81 | { 82 | md5_word_t 83 | a = pms->abcd[0], b = pms->abcd[1], 84 | c = pms->abcd[2], d = pms->abcd[3]; 85 | md5_word_t t; 86 | #if BYTE_ORDER > 0 87 | /* Define storage only for big-endian CPUs. */ 88 | md5_word_t X[16]; 89 | #else 90 | /* Define storage for little-endian or both types of CPUs. */ 91 | md5_word_t xbuf[16]; 92 | const md5_word_t *X; 93 | #endif 94 | 95 | { 96 | #if BYTE_ORDER == 0 97 | /* 98 | * Determine dynamically whether this is a big-endian or 99 | * little-endian machine, since we can use a more efficient 100 | * algorithm on the latter. 101 | */ 102 | static const int w = 1; 103 | 104 | if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ 105 | #endif 106 | #if BYTE_ORDER <= 0 /* little-endian */ 107 | { 108 | /* 109 | * On little-endian machines, we can process properly aligned 110 | * data without copying it. 111 | */ 112 | if (!((data - (const md5_byte_t *)0) & 3)) { 113 | /* data are properly aligned */ 114 | X = (const md5_word_t *)data; 115 | } else { 116 | /* not aligned */ 117 | memcpy(xbuf, data, 64); 118 | X = xbuf; 119 | } 120 | } 121 | #endif 122 | #if BYTE_ORDER == 0 123 | else /* dynamic big-endian */ 124 | #endif 125 | #if BYTE_ORDER >= 0 /* big-endian */ 126 | { 127 | /* 128 | * On big-endian machines, we must arrange the bytes in the 129 | * right order. 130 | */ 131 | const md5_byte_t *xp = data; 132 | int i; 133 | 134 | # if BYTE_ORDER == 0 135 | X = xbuf; /* (dynamic only) */ 136 | # else 137 | # define xbuf X /* (static only) */ 138 | # endif 139 | for (i = 0; i < 16; ++i, xp += 4) 140 | xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); 141 | } 142 | #endif 143 | } 144 | 145 | #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) 146 | 147 | /* Round 1. */ 148 | /* Let [abcd k s i] denote the operation 149 | a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ 150 | #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) 151 | #define SET(a, b, c, d, k, s, Ti)\ 152 | t = a + F(b,c,d) + X[k] + Ti;\ 153 | a = ROTATE_LEFT(t, s) + b 154 | /* Do the following 16 operations. */ 155 | SET(a, b, c, d, 0, 7, T1); 156 | SET(d, a, b, c, 1, 12, T2); 157 | SET(c, d, a, b, 2, 17, T3); 158 | SET(b, c, d, a, 3, 22, T4); 159 | SET(a, b, c, d, 4, 7, T5); 160 | SET(d, a, b, c, 5, 12, T6); 161 | SET(c, d, a, b, 6, 17, T7); 162 | SET(b, c, d, a, 7, 22, T8); 163 | SET(a, b, c, d, 8, 7, T9); 164 | SET(d, a, b, c, 9, 12, T10); 165 | SET(c, d, a, b, 10, 17, T11); 166 | SET(b, c, d, a, 11, 22, T12); 167 | SET(a, b, c, d, 12, 7, T13); 168 | SET(d, a, b, c, 13, 12, T14); 169 | SET(c, d, a, b, 14, 17, T15); 170 | SET(b, c, d, a, 15, 22, T16); 171 | #undef SET 172 | 173 | /* Round 2. */ 174 | /* Let [abcd k s i] denote the operation 175 | a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ 176 | #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) 177 | #define SET(a, b, c, d, k, s, Ti)\ 178 | t = a + G(b,c,d) + X[k] + Ti;\ 179 | a = ROTATE_LEFT(t, s) + b 180 | /* Do the following 16 operations. */ 181 | SET(a, b, c, d, 1, 5, T17); 182 | SET(d, a, b, c, 6, 9, T18); 183 | SET(c, d, a, b, 11, 14, T19); 184 | SET(b, c, d, a, 0, 20, T20); 185 | SET(a, b, c, d, 5, 5, T21); 186 | SET(d, a, b, c, 10, 9, T22); 187 | SET(c, d, a, b, 15, 14, T23); 188 | SET(b, c, d, a, 4, 20, T24); 189 | SET(a, b, c, d, 9, 5, T25); 190 | SET(d, a, b, c, 14, 9, T26); 191 | SET(c, d, a, b, 3, 14, T27); 192 | SET(b, c, d, a, 8, 20, T28); 193 | SET(a, b, c, d, 13, 5, T29); 194 | SET(d, a, b, c, 2, 9, T30); 195 | SET(c, d, a, b, 7, 14, T31); 196 | SET(b, c, d, a, 12, 20, T32); 197 | #undef SET 198 | 199 | /* Round 3. */ 200 | /* Let [abcd k s t] denote the operation 201 | a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ 202 | #define H(x, y, z) ((x) ^ (y) ^ (z)) 203 | #define SET(a, b, c, d, k, s, Ti)\ 204 | t = a + H(b,c,d) + X[k] + Ti;\ 205 | a = ROTATE_LEFT(t, s) + b 206 | /* Do the following 16 operations. */ 207 | SET(a, b, c, d, 5, 4, T33); 208 | SET(d, a, b, c, 8, 11, T34); 209 | SET(c, d, a, b, 11, 16, T35); 210 | SET(b, c, d, a, 14, 23, T36); 211 | SET(a, b, c, d, 1, 4, T37); 212 | SET(d, a, b, c, 4, 11, T38); 213 | SET(c, d, a, b, 7, 16, T39); 214 | SET(b, c, d, a, 10, 23, T40); 215 | SET(a, b, c, d, 13, 4, T41); 216 | SET(d, a, b, c, 0, 11, T42); 217 | SET(c, d, a, b, 3, 16, T43); 218 | SET(b, c, d, a, 6, 23, T44); 219 | SET(a, b, c, d, 9, 4, T45); 220 | SET(d, a, b, c, 12, 11, T46); 221 | SET(c, d, a, b, 15, 16, T47); 222 | SET(b, c, d, a, 2, 23, T48); 223 | #undef SET 224 | 225 | /* Round 4. */ 226 | /* Let [abcd k s t] denote the operation 227 | a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ 228 | #define I(x, y, z) ((y) ^ ((x) | ~(z))) 229 | #define SET(a, b, c, d, k, s, Ti)\ 230 | t = a + I(b,c,d) + X[k] + Ti;\ 231 | a = ROTATE_LEFT(t, s) + b 232 | /* Do the following 16 operations. */ 233 | SET(a, b, c, d, 0, 6, T49); 234 | SET(d, a, b, c, 7, 10, T50); 235 | SET(c, d, a, b, 14, 15, T51); 236 | SET(b, c, d, a, 5, 21, T52); 237 | SET(a, b, c, d, 12, 6, T53); 238 | SET(d, a, b, c, 3, 10, T54); 239 | SET(c, d, a, b, 10, 15, T55); 240 | SET(b, c, d, a, 1, 21, T56); 241 | SET(a, b, c, d, 8, 6, T57); 242 | SET(d, a, b, c, 15, 10, T58); 243 | SET(c, d, a, b, 6, 15, T59); 244 | SET(b, c, d, a, 13, 21, T60); 245 | SET(a, b, c, d, 4, 6, T61); 246 | SET(d, a, b, c, 11, 10, T62); 247 | SET(c, d, a, b, 2, 15, T63); 248 | SET(b, c, d, a, 9, 21, T64); 249 | #undef SET 250 | 251 | /* Then perform the following additions. (That is increment each 252 | of the four registers by the value it had before this block 253 | was started.) */ 254 | pms->abcd[0] += a; 255 | pms->abcd[1] += b; 256 | pms->abcd[2] += c; 257 | pms->abcd[3] += d; 258 | } 259 | 260 | void 261 | md5_init(md5_state_t *pms) 262 | { 263 | pms->count[0] = pms->count[1] = 0; 264 | pms->abcd[0] = 0x67452301; 265 | pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; 266 | pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; 267 | pms->abcd[3] = 0x10325476; 268 | } 269 | 270 | void 271 | md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) 272 | { 273 | const md5_byte_t *p = data; 274 | int left = nbytes; 275 | int offset = (pms->count[0] >> 3) & 63; 276 | md5_word_t nbits = (md5_word_t)(nbytes << 3); 277 | 278 | if (nbytes <= 0) 279 | return; 280 | 281 | /* Update the message length. */ 282 | pms->count[1] += nbytes >> 29; 283 | pms->count[0] += nbits; 284 | if (pms->count[0] < nbits) 285 | pms->count[1]++; 286 | 287 | /* Process an initial partial block. */ 288 | if (offset) { 289 | int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); 290 | 291 | memcpy(pms->buf + offset, p, copy); 292 | if (offset + copy < 64) 293 | return; 294 | p += copy; 295 | left -= copy; 296 | md5_process(pms, pms->buf); 297 | } 298 | 299 | /* Process full blocks. */ 300 | for (; left >= 64; p += 64, left -= 64) 301 | md5_process(pms, p); 302 | 303 | /* Process a final partial block. */ 304 | if (left) 305 | memcpy(pms->buf, p, left); 306 | } 307 | 308 | void 309 | md5_finish(md5_state_t *pms, md5_byte_t digest[16]) 310 | { 311 | static const md5_byte_t pad[64] = { 312 | 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 313 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 314 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 315 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 316 | }; 317 | md5_byte_t data[8]; 318 | int i; 319 | 320 | /* Save the length before padding. */ 321 | for (i = 0; i < 8; ++i) 322 | data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); 323 | /* Pad to 56 bytes mod 64. */ 324 | md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); 325 | /* Append the length. */ 326 | md5_append(pms, data, 8); 327 | for (i = 0; i < 16; ++i) 328 | digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); 329 | } 330 | 331 | void getMd5String(char *inbuf, md5_byte_t digest[16]) 332 | { 333 | for (int j = 0; j < 16; j++) { 334 | sprintf(inbuf + j * 2, "%02x", ((unsigned char*)digest)[j]); 335 | } 336 | } 337 | 338 | void getMd5Str(const char *str, char *strhash) 339 | { 340 | unsigned char digest[16]; 341 | md5_state_t md5state; 342 | md5_init(&md5state); 343 | md5_append(&md5state, (const unsigned char *)str, strlen(str)); 344 | md5_finish(&md5state, digest); 345 | 346 | getMd5String(strhash, digest); 347 | } 348 | 349 | -------------------------------------------------------------------------------- /examples/xredis-example-Consistent-hash/CMd5.h: -------------------------------------------------------------------------------- 1 | #ifndef md5_INCLUDED 2 | #define md5_INCLUDED 3 | 4 | typedef unsigned char md5_byte_t; /* 8-bit byte */ 5 | typedef unsigned int md5_word_t; /* 32-bit word */ 6 | 7 | /* Define the state of the MD5 Algorithm. */ 8 | typedef struct md5_state_s { 9 | md5_word_t count[2]; /* message length in bits, lsw first */ 10 | md5_word_t abcd[4]; /* digest buffer */ 11 | md5_byte_t buf[64]; /* accumulate block */ 12 | } md5_state_t; 13 | 14 | void md5_init(md5_state_t *pms); 15 | void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); 16 | void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); 17 | void getMd5String(char *inbuf, md5_byte_t digest[16]); 18 | void getMd5Str(const char *str, char *strhash); 19 | 20 | #endif /* md5_INCLUDED */ 21 | -------------------------------------------------------------------------------- /examples/xredis-example-Consistent-hash/redis-test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "CMd5.h" 6 | #include "xRedisClient.h" 7 | 8 | // AP Hash Function 9 | unsigned int APHash(const char* str) 10 | { 11 | unsigned int hash = 0; 12 | int i; 13 | 14 | for (i = 0; *str; i++) { 15 | if ((i & 1) == 0) { 16 | hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3)); 17 | } else { 18 | hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5))); 19 | } 20 | } 21 | 22 | return (hash & 0x7FFFFFFF); 23 | } 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | typedef std::map USMAP; 34 | typedef std::set SSET; 35 | typedef std::map USSMAP; 36 | typedef std::list SLIST; 37 | typedef std::map SUMAP; 38 | 39 | typedef unsigned int (*HASHFUNC)(const char* str); 40 | 41 | struct vnode_t { 42 | unsigned int id; 43 | string rIden; 44 | const RedisNode* data; 45 | }; 46 | 47 | typedef std::map VNODEMAP; 48 | typedef std::map RNODELIST; 49 | 50 | class ConHashIdx : public RedisDBIdx { 51 | private: 52 | USMAP _node_info; // nodeid to server 53 | USSMAP _node_slot; // nodeid to keys 54 | HASHFUNC _hash; // hash function 55 | int _vnode_num; // vnode number per server 56 | 57 | VNODEMAP vNodeMap; 58 | RNODELIST rNodeMap; 59 | 60 | public: 61 | ConHashIdx(const RedisNode* rNode, int size, HASHFUNC hash, int vnode_num); 62 | ~ConHashIdx(); 63 | 64 | void del_server(const RedisNode* rNode); 65 | 66 | unsigned int get_index(const char* key); 67 | 68 | private: 69 | bool _add_node(const RedisNode* rNode, int vnode_num); 70 | }; 71 | 72 | ConHashIdx::ConHashIdx(const RedisNode* rNode, int size, HASHFUNC hash, int vnode_num) 73 | { 74 | _hash = hash; 75 | _vnode_num = vnode_num; 76 | 77 | for (int i = 0; i < size; i++) { 78 | _add_node(&rNode[i], vnode_num); 79 | } 80 | } 81 | 82 | ConHashIdx::~ConHashIdx() 83 | { 84 | } 85 | 86 | bool ConHashIdx::_add_node(const RedisNode* rNode, int vnode_num) 87 | { 88 | 89 | char szIden[128] = { 0 }; 90 | VNODEMAP vMap; 91 | getMd5Str(rNode->host, szIden); 92 | 93 | for (int i = 0; i < vnode_num; i++) { 94 | char sztmp[256] = { 0 }; 95 | char vNodekey[256] = { 0 }; 96 | sprintf(sztmp, "%s-%06d", szIden, i); 97 | getMd5Str(sztmp, vNodekey); 98 | unsigned int hval = _hash(vNodekey); 99 | vnode_t* pVnode = new vnode_t; 100 | pVnode->id = hval; 101 | pVnode->data = rNode; 102 | pVnode->rIden = szIden; 103 | printf("%s %u %s \r\n", vNodekey, pVnode->id, pVnode->data->host); 104 | std::pair ret; 105 | ret = vNodeMap.insert(make_pair(hval, pVnode)); 106 | if (ret.second) { 107 | vMap.insert(make_pair(hval, pVnode)); 108 | } else { 109 | printf("�ڵ��ͻ: %s-%u \r\n", vNodekey, hval); 110 | delete pVnode; 111 | return false; 112 | } 113 | } 114 | 115 | rNodeMap.insert(make_pair(szIden, vMap)); 116 | } 117 | 118 | unsigned int ConHashIdx::get_index(const char* key) 119 | { 120 | unsigned int hval = _hash(key); 121 | VNODEMAP::iterator iter = vNodeMap.upper_bound(hval); 122 | if (iter == vNodeMap.end() && 0 != vNodeMap.size()) { 123 | iter = vNodeMap.begin(); 124 | } 125 | 126 | return iter->second->data->dbindex; 127 | } 128 | 129 | void ConHashIdx::del_server(const RedisNode* rNode) 130 | { 131 | char szIden[128] = { 0 }; 132 | getMd5Str(rNode->host, szIden); 133 | VNODEMAP::iterator iter = vNodeMap.begin(); 134 | for (; iter != vNodeMap.end();) { 135 | if (0 == strcasecmp(szIden, iter->second->rIden.c_str())) { 136 | vNodeMap.erase(iter++); 137 | } else { 138 | iter++; 139 | } 140 | } 141 | } 142 | 143 | RedisNode RedisList1[3] = { 144 | { 0, "127.0.0.1", 6379, "", 2, 5 }, 145 | { 1, "127.0.0.2", 6379, "", 2, 5 }, 146 | { 2, "127.0.0.3", 6379, "", 2, 5 } 147 | }; 148 | 149 | RedisNode RedisList2[5] = { 150 | { 0, "127.0.0.1", 6379, "", 2, 5 }, 151 | { 1, "127.0.0.2", 6379, "", 2, 5 }, 152 | { 2, "127.0.0.3", 6379, "", 2, 5 }, 153 | { 3, "127.0.0.4", 6379, "", 2, 5 }, 154 | { 4, "127.0.0.5", 6379, "", 2, 5 }, 155 | }; 156 | 157 | #define CACHE_TYPE_1 1 158 | #define CACHE_TYPE_2 2 159 | 160 | int main(int argc, char** argv) 161 | { 162 | 163 | xRedisClient xRedis; 164 | xRedis.Init(3); 165 | xRedis.ConnectRedisCache(RedisList1, 3, CACHE_TYPE_1); 166 | xRedis.ConnectRedisCache(RedisList2, 5, CACHE_TYPE_2); 167 | 168 | ConHashIdx cIdx(RedisList2, 5, APHash, 10); 169 | 170 | for (int i = 0; i < 100; ++i) { 171 | char szKey[256] = { 0 }; 172 | char szHash[256] = { 0 }; 173 | sprintf(szKey, "test_%d_%u", i * 8888, i + 888); 174 | getMd5Str(szKey, szHash); 175 | printf("%s index: %u \r\n", szKey, cIdx.get_index(szHash)); 176 | } 177 | 178 | for (int n = 0; n < 1000; n++) { 179 | char szKey[256] = { 0 }; 180 | sprintf(szKey, "test_%d", n); 181 | RedisDBIdx dbi(&xRedis); 182 | dbi.CreateDBIndex(szKey, APHash, CACHE_TYPE_1); 183 | bool bRet = xRedis.set(dbi, szKey, "hello redis!"); 184 | if (!bRet) { 185 | printf(" %s %s \n", szKey, dbi.GetErrInfo()); 186 | } 187 | } 188 | 189 | for (int n = 0; n < 1000; n++) { 190 | char szKey[256] = { 0 }; 191 | sprintf(szKey, "test_%d", n); 192 | RedisDBIdx dbi(&xRedis); 193 | dbi.CreateDBIndex(szKey, APHash, CACHE_TYPE_1); 194 | string strValue; 195 | xRedis.get(dbi, szKey, strValue); 196 | printf("%s \r\n", strValue.c_str()); 197 | } 198 | 199 | int n = 10; 200 | while (n--) { 201 | xRedis.KeepAlive(); 202 | usleep(1000 * 1000 * 10); 203 | } 204 | 205 | xRedis.release(); 206 | 207 | return 0; 208 | } 209 | -------------------------------------------------------------------------------- /examples/xredis-example-Consistent-hash/xredis-example-Consistent-hash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "xRedisClient.h" 6 | 7 | // AP Hash Function 8 | unsigned int APHash(const char* str) 9 | { 10 | unsigned int hash = 0; 11 | int i; 12 | 13 | for (i = 0; *str; i++) { 14 | if ((i & 1) == 0) { 15 | hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3)); 16 | } else { 17 | hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5))); 18 | } 19 | } 20 | 21 | return (hash & 0x7FFFFFFF); 22 | } 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | typedef std::map USMAP; 33 | typedef std::set SSET; 34 | typedef std::map USSMAP; 35 | typedef std::list SLIST; 36 | typedef std::map SUMAP; 37 | 38 | typedef unsigned int (*HASHFUNC)(const char* str); 39 | 40 | struct vnode_t { 41 | unsigned int id; 42 | const RedisNode* data; 43 | }; 44 | 45 | typedef std::map VNODEMAP; 46 | 47 | class ConHashIdx : public RedisDBIdx { 48 | private: 49 | USMAP _node_info; // nodeid to server 50 | USSMAP _node_slot; // nodeid to keys 51 | HASHFUNC _hash; // hash function 52 | int _vnode_num; // vnode number per server 53 | 54 | VNODEMAP vNodeMap; 55 | 56 | public: 57 | ConHashIdx(const RedisNode* rNode, int size, HASHFUNC hash, int vnode_num); 58 | ~ConHashIdx(); 59 | void put_key(const std::string& key); 60 | void del_key(const std::string& key); 61 | std::string get_server(const std::string& key); 62 | 63 | unsigned int get_index(const char* key); 64 | 65 | private: 66 | void _add_node(const RedisNode* rNode, int vnode_num); 67 | }; 68 | 69 | void ConHashIdx::_add_node(const RedisNode* rNode, int vnode_num) 70 | { 71 | for (int i = 0; i < vnode_num; i++) { 72 | char buf[256]; 73 | sprintf(buf, "%s-%010d-%u", rNode->host, i, time(NULL)); 74 | unsigned int hval = _hash(buf); 75 | vnode_t* pVnode = new vnode_t; 76 | pVnode->id = hval; 77 | pVnode->data = rNode; 78 | printf("%u %s \r\n", pVnode->id, pVnode->data->host); 79 | vNodeMap.insert(make_pair(hval, pVnode)); 80 | } 81 | } 82 | 83 | ConHashIdx::ConHashIdx(const RedisNode* rNode, int size, HASHFUNC hash, int vnode_num) 84 | { 85 | _hash = hash; 86 | _vnode_num = vnode_num; 87 | 88 | for (int i = 0; i < size; i++) { 89 | _add_node(&rNode[i], vnode_num); 90 | } 91 | } 92 | 93 | ConHashIdx::~ConHashIdx() 94 | { 95 | } 96 | 97 | unsigned int ConHashIdx::get_index(const char* key) 98 | { 99 | unsigned int hval = _hash(key); 100 | VNODEMAP::iterator iter = vNodeMap.upper_bound(hval); 101 | if (iter == vNodeMap.end() && 0 != vNodeMap.size()) { 102 | iter = vNodeMap.begin(); 103 | } 104 | 105 | return iter->second->data->dbindex; 106 | } 107 | 108 | std::string ConHashIdx::get_server(const std::string& key) 109 | { 110 | unsigned int hval = _hash(key.c_str()); 111 | USMAP::iterator iter = _node_info.upper_bound(hval); 112 | if (iter == _node_info.end() && 0 != _node_info.size()) { 113 | iter = _node_info.begin(); 114 | } 115 | 116 | return iter->second; 117 | } 118 | 119 | RedisNode RedisList1[3] = { 120 | { 0, "127.0.0.1", 6379, "", 2, 5 }, 121 | { 1, "127.0.0.2", 6379, "", 2, 5 }, 122 | { 2, "127.0.0.3", 6379, "", 2, 5 } 123 | }; 124 | 125 | RedisNode RedisList2[5] = { 126 | { 0, "127.0.0.1", 6379, "", 2, 5 }, 127 | { 1, "127.0.0.2", 6379, "", 2, 5 }, 128 | { 2, "127.0.0.3", 6379, "", 2, 5 }, 129 | { 3, "127.0.0.4", 6379, "", 2, 5 }, 130 | { 4, "127.0.0.5", 6379, "", 2, 5 }, 131 | }; 132 | 133 | #define CACHE_TYPE_1 1 134 | #define CACHE_TYPE_2 2 135 | 136 | int main(int argc, char** argv) 137 | { 138 | 139 | xRedisClient xRedis; 140 | xRedis.Init(3); 141 | xRedis.ConnectRedisCache(RedisList1, 3, CACHE_TYPE_1); 142 | xRedis.ConnectRedisCache(RedisList2, 5, CACHE_TYPE_2); 143 | 144 | ConHashIdx cIdx(RedisList2, 5, APHash, 10); 145 | 146 | for (int i = 0; i < 100; ++i) { 147 | char szKey[256] = { 0 }; 148 | sprintf(szKey, "test_%d_%u", i * 8888, time(NULL)); 149 | printf("%s index: %u \r\n", szKey, cIdx.get_index(szKey)); 150 | } 151 | 152 | for (int n = 0; n < 1000; n++) { 153 | char szKey[256] = { 0 }; 154 | sprintf(szKey, "test_%d", n); 155 | RedisDBIdx dbi(&xRedis); 156 | dbi.CreateDBIndex(szKey, APHash, CACHE_TYPE_1); 157 | bool bRet = xRedis.set(dbi, szKey, "hello redis!"); 158 | if (!bRet) { 159 | printf(" %s %s \n", szKey, dbi.GetErrInfo()); 160 | } 161 | } 162 | 163 | for (int n = 0; n < 1000; n++) { 164 | char szKey[256] = { 0 }; 165 | sprintf(szKey, "test_%d", n); 166 | RedisDBIdx dbi(&xRedis); 167 | dbi.CreateDBIndex(szKey, APHash, CACHE_TYPE_1); 168 | string strValue; 169 | xRedis.get(dbi, szKey, strValue); 170 | printf("%s \r\n", strValue.c_str()); 171 | } 172 | 173 | int n = 10; 174 | while (n--) { 175 | xRedis.KeepAlive(); 176 | usleep(1000 * 1000 * 10); 177 | } 178 | 179 | xRedis.release(); 180 | 181 | return 0; 182 | } 183 | -------------------------------------------------------------------------------- /examples/xredis-example.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | /** \example xredis-example.cpp 10 | * This is an example of how to use the xRedis. 11 | *
This demo connect to single redis server with connection pool 12 | *
More details about this example. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "xRedisClient.h" 21 | 22 | using namespace xrc; 23 | 24 | enum { 25 | CACHE_TYPE_1, 26 | CACHE_TYPE_2, 27 | CACHE_TYPE_MAX, 28 | }; 29 | 30 | RedisNode RedisList1[3] = { 31 | {.dbindex = 0, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 32 | {.dbindex = 1, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 33 | {.dbindex = 2, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER } 34 | }; 35 | 36 | RedisNode RedisList2[5] = { 37 | { .dbindex = 0, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 38 | { .dbindex = 1, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 39 | { .dbindex = 2, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 40 | { .dbindex = 3, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 41 | { .dbindex = 4, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER } 42 | }; 43 | 44 | int main(int argc, char** argv) 45 | { 46 | 47 | (void)argc; 48 | (void)argv; 49 | 50 | xRedisClient xRedis; 51 | xRedis.Init(CACHE_TYPE_MAX); 52 | xRedis.ConnectRedisCache(RedisList1, sizeof(RedisList1) / sizeof(RedisNode), 53 | 3, CACHE_TYPE_1); 54 | xRedis.ConnectRedisCache(RedisList2, sizeof(RedisList2) / sizeof(RedisNode), 55 | 5, CACHE_TYPE_2); 56 | 57 | for (int n = 0; n < 1000; n++) { 58 | char szKey[256] = { 0 }; 59 | sprintf(szKey, "test_%d", n); 60 | SliceIndex index(&xRedis, CACHE_TYPE_1); 61 | index.Create(szKey); 62 | bool bRet = xRedis.set(index, szKey, "hello redis!"); 63 | if (!bRet) { 64 | printf(" %s %s \n", szKey, index.GetErrInfo()); 65 | } 66 | } 67 | 68 | for (int n = 0; n < 1000; n++) { 69 | char szKey[256] = { 0 }; 70 | sprintf(szKey, "test_%d", n); 71 | SliceIndex index(&xRedis, CACHE_TYPE_1); 72 | index.Create(szKey); 73 | std::string strValue; 74 | xRedis.get(index, szKey, strValue); 75 | printf("%s \r\n", strValue.c_str()); 76 | } 77 | 78 | int n = 10; 79 | while (n--) { 80 | xRedis.Keepalive(); 81 | usleep(1000 * 1000 * 10); 82 | } 83 | 84 | xRedis.Release(); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # xredis Makefile 2 | # Copyright (C) 2010-2011 Salvatore Sanfilippo 3 | # Copyright (C) 2010-2011 Pieter Noordhuis 4 | # Copyright (C) 2013-2016 xsky 5 | # This file is released under the BSD license, see the COPYING file 6 | 7 | OBJ=src/xRedisClient.o src/xRedisClient_keys.o src/xRedisClient_sets.o src/xRedisClient_strings.o src/xRedisClient_pubsub.o src/xRedisClusterClient.o \ 8 | src/xRedisClient_connection.o src/xRedisClient_hashs.o src/xRedisClient_lists.o src/xRedisClient_sortedsets.o src/xRedisPool.o src/xRedisLog.o 9 | EXAMPLES=xredis-example 10 | TESTS=xredis-test 11 | LIBNAME=libxredis 12 | 13 | XREDIS_MAJOR=0 14 | XREDIS_MINOR=15 15 | 16 | # Fallback to gcc when $CC is not in $PATH. 17 | CC:=g++ 18 | OPTIMIZATION?=-O3 19 | WARNINGS=-Wall -W -Wwrite-strings 20 | DEBUG?= -g -ggdb 21 | REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH) -I$(INCLUDE) 22 | REAL_LDFLAGS=$(LDFLAGS) $(ARCH) 23 | INCLUDE=/usr/local/include/hiredis 24 | 25 | DYLIBSUFFIX=so 26 | STLIBSUFFIX=a 27 | DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(XREDIS_MAJOR).$(XREDIS_MINOR) 28 | DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(XREDIS_MAJOR) 29 | DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) 30 | DYLIB_MAKE_CMD=$(CC) -shared -fPIC -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) -lhiredis 31 | STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) 32 | STLIB_MAKE_CMD=ar rcs $(STLIBNAME) 33 | 34 | # Platform-specific overrides 35 | uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 36 | ifeq ($(uname_S),SunOS) 37 | REAL_LDFLAGS+= -ldl -lnsl -lsocket 38 | DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) -lhiredis 39 | INSTALL= cp -r 40 | endif 41 | ifeq ($(uname_S),Darwin) 42 | DYLIBSUFFIX=dylib 43 | DYLIB_MINOR_NAME=$(LIBNAME).$(XREDIS_MAJOR).$(XREDIS_MINOR).$(DYLIBSUFFIX) 44 | DYLIB_MAJOR_NAME=$(LIBNAME).$(XREDIS_MAJOR).$(DYLIBSUFFIX) 45 | DYLIB_MAKE_CMD=$(CC) -shared -Wl,-install_name,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) -lhiredis 46 | endif 47 | 48 | all: $(DYLIBNAME) $(STLIBNAME) 49 | 50 | # Deps (use make dep to generate this) 51 | xRedisClient_connection.o: xRedisClient_connection.cpp 52 | xRedisClient.o: xRedisClient.cpp 53 | xRedisClient_hashs.o: xRedisClient_hashs.cpp 54 | xRedisClient_keys.o: xRedisClient_keys.cpp 55 | xRedisClient_lists.o: xRedisClient_lists.cpp 56 | xRedisClient_sets.o: xRedisClient_sets.cpp 57 | xRedisClient_sortedsets.o: xRedisClient_sortedsets.cpp 58 | xRedisClient_strings.o: xRedisClient_strings.cpp 59 | xRedisClient_pubsub.o: xRedisClient_pubsub.cpp 60 | xRedisPool.o: xRedisPool.cpp 61 | xRedisClusterClient.o: xRedisClusterClient.cpp 62 | xRedisLog.o: xRedisLog.cpp 63 | 64 | $(DYLIBNAME): $(OBJ) 65 | $(DYLIB_MAKE_CMD) $(OBJ) 66 | 67 | $(STLIBNAME): $(OBJ) 68 | $(STLIB_MAKE_CMD) $(OBJ) 69 | 70 | dynamic: $(DYLIBNAME) 71 | static: $(STLIBNAME) 72 | 73 | # Binaries: 74 | xredis-example: 75 | $(CC) examples/xredis-example.cpp -o examples/xredis-example $(REAL_CFLAGS) $(REAL_LDFLAGS) -I./src -L./ $< $(STLIBNAME) -Wl,-Bstatic -lhiredis -Wl,-Bdynamic -lpthread 76 | $(CC) examples/demo.cpp -o examples/demo $(REAL_CFLAGS) $(REAL_LDFLAGS) -I./src -L./ $< $(STLIBNAME) -Wl,-Bstatic -lhiredis -Wl,-Bdynamic -lpthread 77 | $(CC) examples/demo_slice.cpp -o examples/demo_slice $(REAL_CFLAGS) $(REAL_LDFLAGS) -I./src -L./ $< $(STLIBNAME) -Wl,-Bstatic -lhiredis -Wl,-Bdynamic -lpthread 78 | $(CC) examples/demo_multi_slice.cpp -o examples/demo_multi_slice $(REAL_CFLAGS) $(REAL_LDFLAGS) -I./src -L./ $< $(STLIBNAME) -Wl,-Bstatic -lhiredis -Wl,-Bdynamic -lpthread 79 | $(CC) examples/xRedisClusterClient_test.cpp -o examples/xRedisClusterClient_test $(REAL_CFLAGS) $(REAL_LDFLAGS) -I./src -L./ $< $(STLIBNAME) -Wl,-Bstatic -lhiredis -Wl,-Bdynamic -lpthread 80 | $(CC) examples/cluster-cli.cpp -o examples/cluster-cli $(REAL_CFLAGS) $(REAL_LDFLAGS) -I./src -L./ $< $(STLIBNAME) -Wl,-Bstatic -lhiredis -Wl,-Bdynamic -lpthread -lrt 81 | 82 | 83 | 84 | examples: $(EXAMPLES) 85 | 86 | xredis-test: test/xredis-test.cpp $(STLIBNAME) 87 | $(CC) -o test/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -D__STDC_FORMAT_MACROS -I./src -L. $< $(STLIBNAME) -lhiredis -lpthread 88 | 89 | test: xredis-test 90 | @echo ./test/xredis-test 91 | 92 | %.o: %.cpp 93 | $(CC) $(REAL_CFLAGS) -c $< -o $@ 94 | 95 | clean: 96 | rm -rf $(DYLIBNAME) $(STLIBNAME) $(TESTS) src/*.o examples/example* *.o test/*.o 97 | rm -rf examples/demo examples/demo_multi_slice examples/demo_slice 98 | rm -rf examples/xRedisClusterClient_test examples/xredis-example examples/cluster-cli 99 | rm -rf test/xredis-test 100 | 101 | dep: 102 | $(CC) -MM *.cpp 103 | 104 | # Installation related variables and target 105 | PREFIX?=/usr/local 106 | INSTALL_INCLUDE_PATH= $(PREFIX)/include/xredis 107 | INSTALL_LIBRARY_PATH= $(PREFIX)/lib 108 | 109 | ifeq ($(uname_S),SunOS) 110 | INSTALL?= cp -r 111 | endif 112 | 113 | INSTALL?= cp -a 114 | 115 | install: $(DYLIBNAME) $(STLIBNAME) 116 | mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) 117 | $(INSTALL) src/xRedisClient.h $(INSTALL_INCLUDE_PATH) 118 | $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) 119 | cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) 120 | cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MAJOR_NAME) $(DYLIBNAME) 121 | $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) 122 | 123 | 32bit: 124 | @echo "" 125 | @echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386" 126 | @echo "" 127 | $(MAKE) CFLAGS="-m32" LDFLAGS="-m32" 128 | 129 | gprof: 130 | $(MAKE) CFLAGS="-pg" LDFLAGS="-pg" 131 | 132 | 133 | .PHONY: all test check clean dep install 32bit gprof gcov noopt 134 | -------------------------------------------------------------------------------- /src/xLock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2012-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #ifndef _XLOCK_H_ 10 | #define _XLOCK_H_ 11 | 12 | #ifdef _WIN32 13 | #include 14 | #else 15 | #include 16 | #include 17 | #include 18 | #endif 19 | 20 | namespace xrc { 21 | 22 | class xLock { 23 | private: 24 | #ifdef _WIN32 25 | CRITICAL_SECTION mSection; 26 | #else 27 | pthread_mutex_t mMutex; 28 | #endif 29 | 30 | public: 31 | inline xLock() 32 | { 33 | #ifdef _WIN32 34 | InitializeCriticalSection(&mSection); 35 | #else 36 | pthread_mutexattr_t attr; 37 | pthread_mutexattr_init(&attr); 38 | pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 39 | int ret = pthread_mutex_init(&mMutex, &attr); 40 | if (ret != 0) { 41 | fprintf(stderr, "pthread_mutex_init error %d \n\r", ret); 42 | } 43 | #endif 44 | }; 45 | inline ~xLock() 46 | { 47 | #ifdef _WIN32 48 | DeleteCriticalSection(&mSection); 49 | #else 50 | pthread_mutex_destroy(&mMutex); 51 | #endif 52 | } 53 | inline void Enter() 54 | { 55 | #ifdef _WIN32 56 | EnterCriticalSection(&mSection); 57 | #else 58 | pthread_mutex_lock(&mMutex); 59 | #endif 60 | } 61 | inline void Leave() 62 | { 63 | #ifdef _WIN32 64 | LeaveCriticalSection(&mSection); 65 | #else 66 | pthread_mutex_unlock(&mMutex); 67 | #endif 68 | }; 69 | }; 70 | 71 | class CLockUser { 72 | public: 73 | inline CLockUser(xLock& lock) 74 | : mlock(lock) 75 | { 76 | mlock.Enter(); 77 | }; 78 | inline ~CLockUser() 79 | { 80 | mlock.Leave(); 81 | } 82 | 83 | private: 84 | xLock& mlock; 85 | }; 86 | 87 | #define XLOCK(T) CLockUser lock(T) 88 | 89 | } // namespace xrc 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/xRedisClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisClient.h" 10 | #include "xRedisLog.h" 11 | #include "xRedisPool.h" 12 | 13 | namespace xrc { 14 | 15 | SliceIndex::SliceIndex() 16 | { 17 | mType = 0; 18 | mIndex = 0; 19 | mStrerr = NULL; 20 | mClient = NULL; 21 | mIOtype = MASTER; 22 | mIOFlag = false; 23 | } 24 | 25 | SliceIndex::SliceIndex(xRedisClient* xredisclient, uint32_t type) 26 | { 27 | mType = type; 28 | mIndex = 0; 29 | mStrerr = NULL; 30 | mClient = xredisclient; 31 | mIOtype = MASTER; 32 | mIOFlag = false; 33 | } 34 | SliceIndex::~SliceIndex() 35 | { 36 | if (NULL != mStrerr) { 37 | delete[] mStrerr; 38 | mStrerr = NULL; 39 | } 40 | } 41 | 42 | bool SliceIndex::Create(const char* key, HASHFUN fun) 43 | { 44 | uint32_t hashbase = mClient->GetRedisPool()->GetHashBase(mType); 45 | if ((NULL != fun) && (hashbase > 0)) { 46 | mIndex = fun(key) % hashbase; 47 | return true; 48 | } 49 | return false; 50 | } 51 | 52 | bool SliceIndex::CreateByID(int64_t id) 53 | { 54 | uint32_t hashbase = mClient->GetRedisPool()->GetHashBase(mType); 55 | if (hashbase > 0) { 56 | mIndex = id % hashbase; 57 | return true; 58 | } 59 | return false; 60 | } 61 | 62 | void SliceIndex::IOtype(uint32_t iotype) { mIOtype = iotype; } 63 | 64 | void SliceIndex::SetIOMaster() 65 | { 66 | mIOtype = MASTER; 67 | mIOFlag = true; 68 | } 69 | 70 | void SliceIndex::SetIOSlave() 71 | { 72 | mIOtype = SLAVE; 73 | mIOFlag = true; 74 | } 75 | 76 | bool SliceIndex::SetErrInfo(const char* info, int32_t len) 77 | { 78 | if (NULL == info) { 79 | return false; 80 | } 81 | if (NULL == mStrerr) { 82 | mStrerr = new char[len + 1]; 83 | } 84 | if (NULL != mStrerr) { 85 | strncpy(mStrerr, info, len); 86 | mStrerr[len] = '\0'; 87 | return true; 88 | } 89 | return false; 90 | } 91 | 92 | unsigned int SliceIndex::APHash(const char* str) 93 | { 94 | unsigned int hash = 0; 95 | int i; 96 | for (i = 0; *str; i++) { 97 | if ((i & 1) == 0) { 98 | hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3)); 99 | } else { 100 | hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5))); 101 | } 102 | } 103 | return (hash & 0x7FFFFFFF); 104 | } 105 | 106 | xRedisClient::xRedisClient() 107 | { 108 | mRedisPool = NULL; 109 | } 110 | 111 | xRedisClient::~xRedisClient() { Release(); } 112 | 113 | bool xRedisClient::Init(uint32_t maxtype) 114 | { 115 | if (NULL == mRedisPool) { 116 | mRedisPool = new RedisPool; 117 | if (NULL == mRedisPool) { 118 | return false; 119 | } 120 | 121 | return mRedisPool->Init(maxtype); 122 | } 123 | return false; 124 | } 125 | 126 | void xRedisClient::Release() 127 | { 128 | if (NULL != mRedisPool) { 129 | mRedisPool->Release(); 130 | delete mRedisPool; 131 | mRedisPool = NULL; 132 | } 133 | } 134 | 135 | void xRedisClient::Keepalive() 136 | { 137 | if (NULL != mRedisPool) { 138 | mRedisPool->Keepalive(); 139 | } else { 140 | xredis_error("Keepalive mRedisPoolis NULL"); 141 | } 142 | } 143 | 144 | void xRedisClient::SetLogLevel(uint32_t level, void (*emit)(int level, const char* line)) 145 | { 146 | set_log_level(level, emit); 147 | } 148 | 149 | inline RedisPool* xRedisClient::GetRedisPool() { return mRedisPool; } 150 | 151 | void xRedisClient::FreeReply(const rReply* reply) 152 | { 153 | RedisPool::FreeReply((redisReply*)reply); 154 | } 155 | 156 | bool xRedisClient::ConnectRedisCache(const RedisNode* redisnodelist, 157 | uint32_t nodecount, uint32_t hashbase, 158 | uint32_t cachetype) 159 | { 160 | if (NULL == mRedisPool) { 161 | xredis_error("RedisPool is NULL"); 162 | return false; 163 | } 164 | 165 | if (!mRedisPool->SetHashBase(cachetype, hashbase)) { 166 | xredis_error("setHashBase error"); 167 | return false; 168 | } 169 | 170 | for (uint32_t n = 0; n < nodecount; n++) { 171 | const RedisNode* pNode = &redisnodelist[n]; 172 | if (NULL == pNode) { 173 | return false; 174 | } 175 | 176 | bool bRet = mRedisPool->ConnectRedisGroup( 177 | cachetype, pNode->dbindex, pNode->host, pNode->port, pNode->passwd, 178 | pNode->poolsize, pNode->timeout, pNode->role); 179 | if (!bRet) { 180 | return false; 181 | } 182 | } 183 | 184 | return true; 185 | } 186 | 187 | void xRedisClient::SetErrInfo(const SliceIndex& index, void* p) 188 | { 189 | if (NULL == p) { 190 | SetErrString(index, CONNECT_CLOSED_ERROR, ::strlen(CONNECT_CLOSED_ERROR)); 191 | } else { 192 | redisReply* reply = (redisReply*)p; 193 | SetErrString(index, reply->str, reply->len); 194 | } 195 | } 196 | 197 | void xRedisClient::SetErrString(const SliceIndex& index, const char* str, 198 | int32_t len) 199 | { 200 | SliceIndex& dbindex = const_cast(index); 201 | dbindex.SetErrInfo(str, len); 202 | } 203 | 204 | void xRedisClient::SetIOtype(const SliceIndex& index, uint32_t iotype, 205 | bool ioflag) 206 | { 207 | SliceIndex& dbindex = const_cast(index); 208 | dbindex.IOtype(iotype); 209 | dbindex.mIOFlag = ioflag; 210 | } 211 | 212 | void xRedisClient::SetErrMessage(const SliceIndex& index, const char* fmt, 213 | ...) 214 | { 215 | char szBuf[512] = { 0 }; 216 | va_list va; 217 | va_start(va, fmt); 218 | vsnprintf(szBuf, sizeof(szBuf), fmt, va); 219 | va_end(va); 220 | SetErrString(index, szBuf, ::strlen(szBuf)); 221 | } 222 | 223 | rReply* xRedisClient::command(const SliceIndex& index, const char* cmd) 224 | { 225 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 226 | if (NULL == pRedisConn) { 227 | SetErrMessage(index, GET_CONNECT_ERROR " %s\r\n", cmd); 228 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 229 | return NULL; 230 | } 231 | rReply* reply = static_cast(redisCommand(pRedisConn->GetCtx(), cmd)); 232 | 233 | mRedisPool->FreeConnection(pRedisConn); 234 | return reply; 235 | } 236 | 237 | bool xRedisClient::command_bool(const SliceIndex& index, const char* cmd, ...) 238 | { 239 | bool bRet = false; 240 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 241 | if (NULL == pRedisConn) { 242 | SetErrMessage(index, GET_CONNECT_ERROR " %s\r\n", cmd); 243 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 244 | return false; 245 | } 246 | 247 | va_list args; 248 | va_start(args, cmd); 249 | redisReply* reply = static_cast(redisvCommand(pRedisConn->GetCtx(), cmd, args)); 250 | va_end(args); 251 | 252 | if (RedisPool::CheckReply(reply)) { 253 | if (REDIS_REPLY_STATUS == reply->type) { 254 | bRet = true; 255 | } else { 256 | bRet = (reply->integer == 1) ? true : false; 257 | } 258 | } else { 259 | SetErrInfo(index, reply); 260 | } 261 | 262 | RedisPool::FreeReply(reply); 263 | mRedisPool->FreeConnection(pRedisConn); 264 | 265 | return bRet; 266 | } 267 | 268 | bool xRedisClient::command_status(const SliceIndex& index, const char* cmd, 269 | ...) 270 | { 271 | bool bRet = false; 272 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 273 | if (NULL == pRedisConn) { 274 | SetErrMessage(index, GET_CONNECT_ERROR " %s\r\n", cmd); 275 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 276 | return false; 277 | } 278 | 279 | va_list args; 280 | va_start(args, cmd); 281 | redisReply* reply = static_cast(redisvCommand(pRedisConn->GetCtx(), cmd, args)); 282 | va_end(args); 283 | 284 | if (RedisPool::CheckReply(reply)) { 285 | // Assume good reply until further inspection 286 | bRet = true; 287 | if (REDIS_REPLY_STRING == reply->type) { 288 | if (!reply->len || !reply->str || strcasecmp(reply->str, "OK") != 0) { 289 | bRet = false; 290 | } 291 | } 292 | } else { 293 | SetErrInfo(index, reply); 294 | } 295 | 296 | RedisPool::FreeReply(reply); 297 | mRedisPool->FreeConnection(pRedisConn); 298 | 299 | return bRet; 300 | } 301 | 302 | bool xRedisClient::command_integer(const SliceIndex& index, int64_t& retval, 303 | const char* cmd, ...) 304 | { 305 | bool bRet = false; 306 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 307 | if (NULL == pRedisConn) { 308 | SetErrMessage(index, GET_CONNECT_ERROR " %s\r\n", cmd); 309 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 310 | return false; 311 | } 312 | 313 | va_list args; 314 | va_start(args, cmd); 315 | redisReply* reply = static_cast(redisvCommand(pRedisConn->GetCtx(), cmd, args)); 316 | va_end(args); 317 | if (RedisPool::CheckReply(reply)) { 318 | retval = reply->integer; 319 | bRet = true; 320 | } else { 321 | SetErrInfo(index, reply); 322 | } 323 | 324 | RedisPool::FreeReply(reply); 325 | mRedisPool->FreeConnection(pRedisConn); 326 | 327 | return bRet; 328 | } 329 | 330 | bool xRedisClient::command_string(const SliceIndex& index, std::string& data, 331 | const char* cmd, ...) 332 | { 333 | bool bRet = false; 334 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 335 | if (NULL == pRedisConn) { 336 | SetErrMessage(index, GET_CONNECT_ERROR " %s\r\n", cmd); 337 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 338 | return false; 339 | } 340 | 341 | va_list args; 342 | va_start(args, cmd); 343 | redisReply* reply = static_cast(redisvCommand(pRedisConn->GetCtx(), cmd, args)); 344 | va_end(args); 345 | if (RedisPool::CheckReply(reply)) { 346 | data.assign(reply->str, reply->len); 347 | bRet = true; 348 | } else { 349 | SetErrInfo(index, reply); 350 | } 351 | 352 | RedisPool::FreeReply(reply); 353 | mRedisPool->FreeConnection(pRedisConn); 354 | 355 | return bRet; 356 | } 357 | 358 | bool xRedisClient::command_list(const SliceIndex& index, VALUES& vValue, 359 | const char* cmd, ...) 360 | { 361 | bool bRet = false; 362 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 363 | if (NULL == pRedisConn) { 364 | SetErrMessage(index, GET_CONNECT_ERROR " %s\r\n", cmd); 365 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 366 | return false; 367 | } 368 | 369 | va_list args; 370 | va_start(args, cmd); 371 | redisReply* reply = static_cast(redisvCommand(pRedisConn->GetCtx(), cmd, args)); 372 | va_end(args); 373 | if (RedisPool::CheckReply(reply)) { 374 | for (size_t i = 0; i < reply->elements; i++) { 375 | vValue.push_back( 376 | std::string(reply->element[i]->str, reply->element[i]->len)); 377 | } 378 | bRet = true; 379 | } else { 380 | SetErrInfo(index, reply); 381 | } 382 | 383 | RedisPool::FreeReply(reply); 384 | mRedisPool->FreeConnection(pRedisConn); 385 | 386 | return bRet; 387 | } 388 | 389 | bool xRedisClient::command_array(const SliceIndex& index, ArrayReply& array, 390 | const char* cmd, ...) 391 | { 392 | bool bRet = false; 393 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 394 | if (NULL == pRedisConn) { 395 | SetErrMessage(index, GET_CONNECT_ERROR " %s\r\n", cmd); 396 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 397 | return false; 398 | } 399 | 400 | va_list args; 401 | va_start(args, cmd); 402 | redisReply* reply = static_cast(redisvCommand(pRedisConn->GetCtx(), cmd, args)); 403 | va_end(args); 404 | if (RedisPool::CheckReply(reply)) { 405 | for (size_t i = 0; i < reply->elements; i++) { 406 | DataItem item; 407 | item.type = reply->element[i]->type; 408 | item.str.assign(reply->element[i]->str, reply->element[i]->len); 409 | array.push_back(item); 410 | } 411 | bRet = true; 412 | } else { 413 | SetErrInfo(index, reply); 414 | } 415 | 416 | RedisPool::FreeReply(reply); 417 | mRedisPool->FreeConnection(pRedisConn); 418 | return bRet; 419 | } 420 | 421 | bool xRedisClient::commandargv_array_ex(const SliceIndex& index, 422 | const VDATA& vDataIn, 423 | xRedisContext& ctx) 424 | { 425 | bool bRet = false; 426 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 427 | if (NULL == pRedisConn) { 428 | SetErrMessage(index, GET_CONNECT_ERROR " type:%u index:%u IOtype:%u \r\n", 429 | index.mType, index.mIndex, index.mIOtype); 430 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 431 | return false; 432 | } 433 | 434 | std::vector argv(vDataIn.size()); 435 | std::vector argvlen(vDataIn.size()); 436 | uint32_t j = 0; 437 | for (VDATA::const_iterator i = vDataIn.begin(); i != vDataIn.end(); 438 | ++i, ++j) { 439 | argv[j] = i->c_str(), argvlen[j] = i->size(); 440 | } 441 | 442 | redisReply* reply = static_cast(redisCommandArgv( 443 | pRedisConn->GetCtx(), argv.size(), &(argv[0]), &(argvlen[0]))); 444 | if (RedisPool::CheckReply(reply)) { 445 | bRet = true; 446 | } else { 447 | SetErrInfo(index, reply); 448 | } 449 | 450 | RedisPool::FreeReply(reply); 451 | ctx.conn = pRedisConn; 452 | return bRet; 453 | } 454 | 455 | int32_t xRedisClient::GetReply(xRedisContext* ctx, ReplyData& vData) 456 | { 457 | redisReply *reply = NULL; 458 | RedisConnection* pRedisConn = static_cast(ctx->conn); 459 | 460 | int32_t ret = redisGetReply(pRedisConn->GetCtx(), (void**)&reply); 461 | if (0 == ret) { 462 | for (size_t i = 0; i < reply->elements; i++) { 463 | DataItem item; 464 | item.type = reply->element[i]->type; 465 | item.str.assign(reply->element[i]->str, reply->element[i]->len); 466 | vData.push_back(item); 467 | } 468 | } 469 | RedisPool::FreeReply(reply); 470 | return ret; 471 | } 472 | 473 | bool xRedisClient::GetxRedisContext(const SliceIndex& index, 474 | xRedisContext* ctx) 475 | { 476 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 477 | if (NULL == pRedisConn) { 478 | return false; 479 | } 480 | ctx->conn = pRedisConn; 481 | return true; 482 | } 483 | 484 | void xRedisClient::FreexRedisContext(xRedisContext* ctx) 485 | { 486 | RedisConnection* pRedisConn = static_cast(ctx->conn); 487 | redisReply* reply = static_cast( 488 | redisCommand(pRedisConn->GetCtx(), "unsubscribe")); 489 | RedisPool::FreeReply(reply); 490 | mRedisPool->FreeConnection((RedisConnection*)ctx->conn); 491 | } 492 | 493 | bool xRedisClient::commandargv_bool(const SliceIndex& index, 494 | const VDATA& vData) 495 | { 496 | bool bRet = false; 497 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 498 | if (NULL == pRedisConn) { 499 | SetErrMessage(index, GET_CONNECT_ERROR " type:%u index:%u IOtype:%u \r\n", 500 | index.mType, index.mIndex, index.mIOtype); 501 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 502 | return bRet; 503 | } 504 | 505 | std::vector argv(vData.size()); 506 | std::vector argvlen(vData.size()); 507 | uint32_t j = 0; 508 | for (VDATA::const_iterator i = vData.begin(); i != vData.end(); ++i, ++j) { 509 | argv[j] = i->c_str(), argvlen[j] = i->size(); 510 | } 511 | 512 | redisReply* reply = static_cast(redisCommandArgv( 513 | pRedisConn->GetCtx(), argv.size(), &(argv[0]), &(argvlen[0]))); 514 | if (RedisPool::CheckReply(reply)) { 515 | bRet = (reply->integer == 1) ? true : false; 516 | } else { 517 | SetErrInfo(index, reply); 518 | } 519 | 520 | RedisPool::FreeReply(reply); 521 | mRedisPool->FreeConnection(pRedisConn); 522 | 523 | return bRet; 524 | } 525 | 526 | bool xRedisClient::commandargv_status(const SliceIndex& index, 527 | const VDATA& vData) 528 | { 529 | bool bRet = false; 530 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 531 | if (NULL == pRedisConn) { 532 | SetErrMessage(index, GET_CONNECT_ERROR " type:%u index:%u IOtype:%u \r\n", 533 | index.mType, index.mIndex, index.mIOtype); 534 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 535 | return bRet; 536 | } 537 | 538 | std::vector argv(vData.size()); 539 | std::vector argvlen(vData.size()); 540 | uint32_t j = 0; 541 | for (VDATA::const_iterator i = vData.begin(); i != vData.end(); ++i, ++j) { 542 | argv[j] = i->c_str(), argvlen[j] = i->size(); 543 | } 544 | 545 | redisReply* reply = static_cast(redisCommandArgv( 546 | pRedisConn->GetCtx(), argv.size(), &(argv[0]), &(argvlen[0]))); 547 | if (RedisPool::CheckReply(reply)) { 548 | // Assume good reply until further inspection 549 | bRet = true; 550 | 551 | if (REDIS_REPLY_STRING == reply->type) { 552 | if (!reply->len || !reply->str || strcasecmp(reply->str, "OK") != 0) { 553 | bRet = false; 554 | } 555 | } 556 | } else { 557 | SetErrInfo(index, reply); 558 | } 559 | 560 | RedisPool::FreeReply(reply); 561 | mRedisPool->FreeConnection(pRedisConn); 562 | 563 | return bRet; 564 | } 565 | 566 | bool xRedisClient::commandargv_array(const SliceIndex& index, 567 | const VDATA& vDataIn, ArrayReply& array) 568 | { 569 | bool bRet = false; 570 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 571 | if (NULL == pRedisConn) { 572 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 573 | SetErrMessage(index, GET_CONNECT_ERROR " type:%u index:%u IOtype:%u \r\n", 574 | index.mType, index.mIndex, index.mIOtype); 575 | return false; 576 | } 577 | 578 | std::vector argv(vDataIn.size()); 579 | std::vector argvlen(vDataIn.size()); 580 | uint32_t j = 0; 581 | for (VDATA::const_iterator i = vDataIn.begin(); i != vDataIn.end(); 582 | ++i, ++j) { 583 | argv[j] = i->c_str(), argvlen[j] = i->size(); 584 | } 585 | 586 | redisReply* reply = static_cast(redisCommandArgv( 587 | pRedisConn->GetCtx(), argv.size(), &(argv[0]), &(argvlen[0]))); 588 | if (RedisPool::CheckReply(reply)) { 589 | for (size_t i = 0; i < reply->elements; i++) { 590 | DataItem item; 591 | item.type = reply->element[i]->type; 592 | item.str.assign(reply->element[i]->str, reply->element[i]->len); 593 | array.push_back(item); 594 | } 595 | bRet = true; 596 | } else { 597 | SetErrInfo(index, reply); 598 | } 599 | 600 | RedisPool::FreeReply(reply); 601 | mRedisPool->FreeConnection(pRedisConn); 602 | return bRet; 603 | } 604 | 605 | bool xRedisClient::commandargv_array(const SliceIndex& index, 606 | const VDATA& vDataIn, VALUES& array) 607 | { 608 | bool bRet = false; 609 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 610 | if (NULL == pRedisConn) { 611 | SetErrMessage(index, GET_CONNECT_ERROR " type:%u index:%u IOtype:%u \r\n", 612 | index.mType, index.mIndex, index.mIOtype); 613 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 614 | return false; 615 | } 616 | 617 | std::vector argv(vDataIn.size()); 618 | std::vector argvlen(vDataIn.size()); 619 | uint32_t j = 0; 620 | for (VDATA::const_iterator i = vDataIn.begin(); i != vDataIn.end(); 621 | ++i, ++j) { 622 | argv[j] = i->c_str(), argvlen[j] = i->size(); 623 | } 624 | 625 | redisReply* reply = static_cast(redisCommandArgv( 626 | pRedisConn->GetCtx(), argv.size(), &(argv[0]), &(argvlen[0]))); 627 | if (RedisPool::CheckReply(reply)) { 628 | for (size_t i = 0; i < reply->elements; i++) { 629 | std::string str(reply->element[i]->str, reply->element[i]->len); 630 | array.push_back(str); 631 | } 632 | bRet = true; 633 | } else { 634 | SetErrInfo(index, reply); 635 | } 636 | 637 | RedisPool::FreeReply(reply); 638 | mRedisPool->FreeConnection(pRedisConn); 639 | return bRet; 640 | } 641 | 642 | bool xRedisClient::commandargv_integer(const SliceIndex& index, 643 | const VDATA& vDataIn, int64_t& retval) 644 | { 645 | bool bRet = false; 646 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex, index.mIOtype); 647 | if (NULL == pRedisConn) { 648 | SetErrMessage(index, GET_CONNECT_ERROR " type:%u index:%u IOtype:%u \r\n", 649 | index.mType, index.mIndex, index.mIOtype); 650 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 651 | return false; 652 | } 653 | 654 | std::vector argv(vDataIn.size()); 655 | std::vector argvlen(vDataIn.size()); 656 | uint32_t j = 0; 657 | for (VDATA::const_iterator iter = vDataIn.begin(); iter != vDataIn.end(); 658 | ++iter, ++j) { 659 | argv[j] = iter->c_str(), argvlen[j] = iter->size(); 660 | } 661 | 662 | redisReply* reply = static_cast(redisCommandArgv( 663 | pRedisConn->GetCtx(), argv.size(), &(argv[0]), &(argvlen[0]))); 664 | if (RedisPool::CheckReply(reply)) { 665 | retval = reply->integer; 666 | bRet = true; 667 | } else { 668 | SetErrInfo(index, reply); 669 | } 670 | 671 | RedisPool::FreeReply(reply); 672 | mRedisPool->FreeConnection(pRedisConn); 673 | return bRet; 674 | } 675 | 676 | bool xRedisClient::ScanFun(const char* cmd, const SliceIndex& index, 677 | const std::string* key, int64_t& cursor, 678 | const char* pattern, uint32_t count, 679 | ArrayReply& array, xRedisContext& ctx) 680 | { 681 | SETDEFAULTIOTYPE(MASTER); 682 | VDATA vCmdData; 683 | vCmdData.push_back(cmd); 684 | if (NULL != key) { 685 | vCmdData.push_back(*key); 686 | } 687 | 688 | vCmdData.push_back(toString(cursor)); 689 | 690 | if (NULL != pattern) { 691 | vCmdData.push_back("MATCH"); 692 | vCmdData.push_back(pattern); 693 | } 694 | 695 | if (0 != count) { 696 | vCmdData.push_back("COUNT"); 697 | vCmdData.push_back(toString(count)); 698 | } 699 | 700 | bool bRet = false; 701 | RedisConnection* pRedisConn = static_cast(ctx.conn); 702 | if (NULL == pRedisConn) { 703 | SetErrMessage(index, GET_CONNECT_ERROR " key:%s type:%u index:%u IOtype:%u \r\n", key->c_str(), 704 | index.mType, index.mIndex, index.mIOtype); 705 | //SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 706 | return false; 707 | } 708 | 709 | std::vector argv(vCmdData.size()); 710 | std::vector argvlen(vCmdData.size()); 711 | uint32_t j = 0; 712 | for (VDATA::const_iterator i = vCmdData.begin(); i != vCmdData.end(); 713 | ++i, ++j) { 714 | argv[j] = i->c_str(), argvlen[j] = i->size(); 715 | } 716 | 717 | redisReply* reply = static_cast(redisCommandArgv( 718 | pRedisConn->GetCtx(), argv.size(), &(argv[0]), &(argvlen[0]))); 719 | if (RedisPool::CheckReply(reply)) { 720 | if (0 == reply->elements) { 721 | cursor = 0; 722 | } else { 723 | cursor = atoi(reply->element[0]->str); 724 | redisReply** replyData = reply->element[1]->element; 725 | for (size_t i = 0; i < reply->element[1]->elements; i++) { 726 | DataItem item; 727 | item.type = replyData[i]->type; 728 | item.str.assign(replyData[i]->str, replyData[i]->len); 729 | array.push_back(item); 730 | } 731 | } 732 | bRet = true; 733 | } else { 734 | SetErrInfo(index, reply); 735 | } 736 | RedisPool::FreeReply(reply); 737 | return bRet; 738 | } 739 | 740 | } // namespace xrc 741 | -------------------------------------------------------------------------------- /src/xRedisClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #ifndef _XREDIS_CLIENT_H_ 10 | #define _XREDIS_CLIENT_H_ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | 22 | namespace xrc { 23 | 24 | 25 | #define LOG_LEVEL_ERROR 0 26 | #define LOG_LEVEL_WARN 1 27 | #define LOG_LEVEL_INFO 2 28 | #define LOG_LEVEL_DEBUG 3 29 | 30 | 31 | #define REDIS_REPLY_STRING 1 32 | #define REDIS_REPLY_ARRAY 2 33 | #define REDIS_REPLY_INTEGER 3 34 | #define REDIS_REPLY_NIL 4 35 | #define REDIS_REPLY_STATUS 5 36 | #define REDIS_REPLY_ERROR 6 37 | 38 | 39 | #define MAX_ERR_STR_LEN 128 40 | 41 | typedef std::string KEY; 42 | typedef std::string VALUE; 43 | typedef std::vector KEYS; 44 | typedef KEYS FILEDS; 45 | typedef std::vector VALUES; 46 | typedef std::vector VDATA; 47 | typedef std::set SETDATA; 48 | 49 | typedef struct _REDIS_NODE_{ 50 | uint32_t dbindex; // 节点编号索引,从0开始 51 | std::string host; // REDIS节点主机IP地址 52 | uint32_t port; // redis服务端口 53 | std::string passwd; // redis认证密码 54 | uint32_t poolsize; // 此节点上的连接池大小 55 | uint32_t timeout; // 连接超时时间 秒 56 | uint32_t role; // 节点角色 57 | }RedisNode; 58 | 59 | /* This is the reply object returned by redisCommand() */ 60 | typedef struct rReply { 61 | int32_t type; /* REDIS_REPLY_* */ 62 | long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ 63 | int32_t len; /* Length of string */ 64 | char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ 65 | size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ 66 | struct rReply **element; /* elements vector for REDIS_REPLY_ARRAY */ 67 | } rReply; 68 | 69 | typedef uint32_t (*HASHFUN)(const char *); 70 | 71 | class RedisPool; 72 | class xRedisClient; 73 | 74 | class SliceIndex { 75 | public: 76 | SliceIndex(); 77 | SliceIndex(xRedisClient *xredisclient, uint32_t slicetype); 78 | ~SliceIndex(); 79 | 80 | bool Create(const char *key, HASHFUN fun=APHash); 81 | bool CreateByID(int64_t id); 82 | char *GetErrInfo() {return mStrerr;} 83 | void SetIOMaster(); 84 | void SetIOSlave(); 85 | 86 | private: 87 | static unsigned int APHash(const char *str); 88 | bool SetErrInfo(const char *info, int32_t len); 89 | void IOtype(uint32_t iotype); 90 | friend class xRedisClient; 91 | 92 | private: 93 | uint32_t mType; 94 | uint32_t mIndex; 95 | bool mIOFlag; 96 | uint32_t mIOtype; 97 | char *mStrerr; 98 | xRedisClient *mClient; 99 | }; 100 | 101 | typedef struct _DATA_ITEM_{ 102 | int32_t type; 103 | std::string str; 104 | 105 | _DATA_ITEM_ & operator=(const _DATA_ITEM_ &data) { 106 | type = data.type; 107 | str = data.str; 108 | return *this; 109 | } 110 | }DataItem; 111 | typedef std::vector ReplyData; 112 | typedef ReplyData ArrayReply; 113 | typedef std::map ZSETDATA; 114 | typedef std::vector DBIArray; 115 | 116 | typedef struct xRedisContext_{ 117 | void* conn; 118 | }xRedisContext; 119 | 120 | typedef enum _SET_TYPE_{ 121 | TYPE_NONE = 0, 122 | PX = 1, 123 | EX = 2 124 | }SETPXEX; 125 | 126 | typedef enum _SET_TYPE_NXEX_{ 127 | TNXXX_NONE = 0, 128 | NX = 1, 129 | XX = 2 130 | }SETNXXX; 131 | 132 | typedef enum _BIT_OP_{ 133 | AND = 0, 134 | OR = 1, 135 | XOR = 2, 136 | NOT = 3 137 | }BITOP; 138 | 139 | typedef enum _LIST_MODEL_{ 140 | BEFORE = 0, 141 | AFTER = 1 142 | }LMODEL; 143 | 144 | 145 | typedef enum _SORT_ORDER_{ 146 | ASC = 0, 147 | DESC = 1 148 | }SORTODER; 149 | 150 | typedef struct _SORT_LIMIT_ 151 | { 152 | int32_t offset; 153 | int32_t count; 154 | }LIMIT; 155 | 156 | template 157 | std::string toString(const T &t) { 158 | std::ostringstream oss; 159 | oss << t; 160 | return oss.str(); 161 | } 162 | 163 | typedef enum _REDIS_ROLE_{ 164 | MASTER = 0, 165 | SLAVE = 1 166 | }ROLE; 167 | 168 | #define SETDEFAULTIOTYPE(type) if (!index.mIOFlag) {SetIOtype(index, type);} 169 | 170 | 171 | 172 | class xRedisClient{ 173 | public: 174 | xRedisClient(); 175 | ~xRedisClient(); 176 | 177 | bool Init(uint32_t maxtype); 178 | void Release(); 179 | void Keepalive(); 180 | inline RedisPool *GetRedisPool(); 181 | static void FreeReply(const rReply* reply); 182 | static int32_t GetReply(xRedisContext* ctx, ReplyData& vData); 183 | bool GetxRedisContext(const SliceIndex& index, xRedisContext* ctx); 184 | void FreexRedisContext(xRedisContext* ctx); 185 | bool ConnectRedisCache(const RedisNode *redisnodelist, uint32_t nodecount, 186 | uint32_t hashbase, uint32_t cachetype); 187 | 188 | static void SetLogLevel(uint32_t level, void (*emit)(int level, const char* line)); 189 | 190 | public: 191 | 192 | // Connection 193 | /* AUTH */ /* nonsupport */ 194 | /* ECHO */ bool echo(const SliceIndex& index, const std::string& str, std::string &value); 195 | /* PING */ /* nonsupport */ 196 | /* QUIT */ void quit(); 197 | /* SELECT */ /* nonsupport */ 198 | 199 | // Commands operating on std::string values 200 | /* APPEND */ bool append(const SliceIndex& index, const std::string& key, const std::string& value); 201 | /* BITCOUNT */ bool bitcount(const SliceIndex& index,const std::string& key, int32_t& count, int32_t start=0, int32_t end=0); 202 | /* BITOP */ bool bitop(const SliceIndex& index, const BITOP operation, const std::string& destkey, const KEYS& keys, int32_t& lenght); 203 | /* BITPOS */ bool bitpos(const SliceIndex& index, const std::string& key, int32_t bit, int64_t& pos, int32_t start=0, int32_t end=0); 204 | /* DECR */ bool decr(const SliceIndex& index, const std::string& key, int64_t& result); 205 | /* DECRBY */ bool decrby(const SliceIndex& index, const std::string& key, int32_t by, int64_t& result); 206 | /* GET */ bool get(const SliceIndex& index, const std::string& key, std::string& value); 207 | /* GETBIT */ bool getbit(const SliceIndex& index, const std::string& key, int32_t& offset, int32_t& bit); 208 | /* GETRANGE */ bool getrange(const SliceIndex& index,const std::string& key, int32_t start, int32_t end, std::string& out); 209 | /* GETSET */ bool getset(const SliceIndex& index, const std::string& key, const std::string& newValue, std::string& oldValue); 210 | /* INCR */ bool incr(const SliceIndex& index, const std::string& key, int64_t& result); 211 | /* INCRBY */ bool incrby(const SliceIndex& index, const std::string& key, int32_t by, int64_t& result); 212 | /* INCRBYFLOAT */ 213 | /* MGET */ bool mget(const DBIArray& index, const KEYS & keys, ReplyData& vDdata); 214 | /* MSET */ bool mset(const DBIArray& index, const VDATA& data); 215 | /* MSETNX */ 216 | /* PSETEX */ bool psetex(const SliceIndex& index, const std::string& key, int32_t milliseconds, const std::string& value); 217 | /* SET */ bool set(const SliceIndex& index, const std::string& key, const std::string& value); 218 | /* SET */ bool set(const SliceIndex& index, const std::string& key, const char *value, int32_t len, int32_t second); 219 | /* SET */ bool set(const SliceIndex& index, const std::string& key, const std::string& value, 220 | SETPXEX pxex, int32_t expiretime, SETNXXX nxxx); 221 | /* SETBIT */ bool setbit(const SliceIndex& index, const std::string& key, int32_t offset, int64_t newbitValue, int64_t oldbitValue); 222 | /* SETEX */ bool setex(const SliceIndex& index, const std::string& key, int32_t seconds, const std::string& value); 223 | /* SETNX */ bool setnx(const SliceIndex& index, const std::string& key, const std::string& value); 224 | /* SETRANGE */ bool setrange(const SliceIndex& index,const std::string& key, int32_t offset, const std::string& value, int32_t& length); 225 | /* STRLEN */ bool strlen(const SliceIndex& index, const std::string& key, int32_t& length); 226 | 227 | 228 | /* DEL */ bool del(const SliceIndex& index, const std::string& key); 229 | bool del(const DBIArray& index, const KEYS & vkey, int64_t& count); 230 | /* DUMP */ 231 | /* EXISTS */ bool exists(const SliceIndex& index, const std::string& key); 232 | /* EXPIRE */ bool expire(const SliceIndex& index, const std::string& key, uint32_t second); 233 | /* EXPIREAT */ bool expireat(const SliceIndex& index, const std::string& key, uint32_t timestamp); 234 | /* KEYS */ 235 | /* MIGRATE */ 236 | /* MOVE */ 237 | /* OBJECT */ 238 | /* PERSIST */ bool persist(const SliceIndex& index, const std::string& key); 239 | /* PEXPIRE */ bool pexpire(const SliceIndex& index, const std::string& key, uint32_t milliseconds); 240 | /* PEXPIREAT */ bool pexpireat(const SliceIndex& index, const std::string& key, uint32_t millisecondstimestamp); 241 | /* PTTL */ bool pttl(const SliceIndex& index, const std::string& key, int64_t &milliseconds); 242 | /* RANDOMKEY */ bool randomkey(const SliceIndex& index, KEY& key); 243 | /* RENAME */ 244 | /* RENAMENX */ 245 | /* RESTORE */ 246 | /* SCAN */ bool scan(const SliceIndex& index, int64_t &cursor, 247 | const char *pattern, uint32_t count, ArrayReply& array, xRedisContext& ctx); 248 | 249 | 250 | /* SORT */ bool sort(const SliceIndex& index, ArrayReply& array, const std::string& key, const char* by = NULL, 251 | LIMIT *limit = NULL, bool alpha = false, const FILEDS* get = NULL, 252 | const SORTODER order = ASC, const char* destination = NULL); 253 | 254 | /* TTL */ bool ttl(const SliceIndex& index, const std::string& key, int64_t& seconds); 255 | /* TYPE */ bool type(const SliceIndex& index, const std::string& key, std::string& value); 256 | 257 | 258 | /* HDEL */ bool hdel(const SliceIndex& index, const std::string& key, const std::string& field, int64_t& num); 259 | bool hdel(const SliceIndex& index, const std::string& key, const KEYS& vfiled, int64_t& num); 260 | /* HEXISTS */ bool hexist(const SliceIndex& index, const std::string& key, const std::string& field); 261 | /* HGET */ bool hget(const SliceIndex& index, const std::string& key, const std::string& field, std::string& value); 262 | /* HGETALL */ bool hgetall(const SliceIndex& index, const std::string& key, ArrayReply& array); 263 | /* HINCRBY */ bool hincrby(const SliceIndex& index, const std::string& key, const std::string& field, int64_t increment ,int64_t& value); 264 | /* HINCRBYFLOAT */ bool hincrbyfloat(const SliceIndex& index, const std::string& key, const std::string& field, const float increment, float& value); 265 | /* HKEYS */ bool hkeys(const SliceIndex& index, const std::string& key, KEYS& keys); 266 | /* HLEN */ bool hlen(const SliceIndex& index, const std::string& key, int64_t& count); 267 | /* HMGET */ bool hmget(const SliceIndex& index, const std::string& key, const KEYS& field, ArrayReply& array); 268 | /* HMSET */ bool hmset(const SliceIndex& index, const std::string& key, const VDATA& vData); 269 | /* HSCAN */ bool hscan(const SliceIndex& index, const std::string& key, int64_t &cursor, 270 | const char *pattern, uint32_t count, ArrayReply& array, xRedisContext& ctx); 271 | /* HSET */ bool hset(const SliceIndex& index, const std::string& key, const std::string& field, const std::string& value, int64_t& retval); 272 | /* HSETNX */ bool hsetnx(const SliceIndex& index, const std::string& key, const std::string& field, const std::string& value); 273 | /* HVALS */ bool hvals(const SliceIndex& index, const std::string& key, VALUES& values); 274 | 275 | /* BLPOP */ bool blPop(const SliceIndex& index, const std::string& key, VALUES& vValues, int64_t timeout); 276 | /* BRPOP */ bool brPop(const SliceIndex& index, const std::string& key, VALUES& vValues, int64_t timeout); 277 | /* BRPOPLPUSH */ bool brPoplpush(const SliceIndex& index, const std::string& key, std::string& targetkey, VALUE& value, int64_t timeout); 278 | /* LINDEX */ bool lindex(const SliceIndex& index, const std::string& key, int64_t idx, VALUE& value); 279 | /* LINSERT */ bool linsert(const SliceIndex& index, const std::string& key, LMODEL mod, const std::string& pivot, const std::string& value, int64_t& retval); 280 | /* LLEN */ bool llen(const SliceIndex& index, const std::string& key, int64_t& len); 281 | /* LPOP */ bool lpop(const SliceIndex& index, const std::string& key, std::string& value); 282 | /* LPUSH */ bool lpush(const SliceIndex& index, const std::string& key, const VALUES& vValue, int64_t& length); 283 | /* LPUSHX */ bool lpushx(const SliceIndex& index, const std::string& key, const std::string& value, int64_t& length); 284 | /* LRANGE */ bool lrange(const SliceIndex& index, const std::string& key, int64_t start, int64_t end, ArrayReply& array); 285 | /* LREM */ bool lrem(const SliceIndex& index, const std::string& key, int32_t count, const std::string& value, int64_t num); 286 | /* LSET */ bool lset(const SliceIndex& index, const std::string& key, int32_t idx, const std::string& value); 287 | /* LTRIM */ bool ltrim(const SliceIndex& index, const std::string& key, int32_t start, int32_t end); 288 | /* RPOP */ bool rpop(const SliceIndex& index, const std::string& key, std::string& value); 289 | /* RPOPLPUSH */ bool rpoplpush(const SliceIndex& index,const std::string& key_src, const std::string& key_dest, std::string& value); 290 | /* RPUSH */ bool rpush(const SliceIndex& index, const std::string& key, const VALUES& vValue, int64_t& length); 291 | /* RPUSHX */ bool rpushx(const SliceIndex& index, const std::string& key, const std::string& value, int64_t& length); 292 | 293 | /* SADD */ bool sadd(const SliceIndex& index, const KEY& key, const VALUES& vValue, int64_t& count); 294 | /* SCARD */ bool scard(const SliceIndex& index, const KEY& key, int64_t& count); 295 | /* SDIFF */ bool sdiff(const DBIArray& index, const KEYS& vKkey, VALUES& vValue); 296 | /* SDIFFSTORE */ bool sdiffstore(const SliceIndex& index, const KEY& destinationkey, const DBIArray& vdbi, const KEYS& vkey, int64_t& count); 297 | /* SINTER */ bool sinter(const DBIArray& index, const KEYS& vkey, VALUES& vValue); 298 | /* SINTERSTORE */ bool sinterstore(const SliceIndex& index, const KEY& destinationkey, const DBIArray& vdbi, const KEYS& vkey, int64_t& count); 299 | /* SISMEMBER */ bool sismember(const SliceIndex& index, const KEY& key, const VALUE& member); 300 | /* SMEMBERS */ bool smembers(const SliceIndex& index, const KEY& key, VALUES& vValue); 301 | /* SMOVE */ bool smove(const SliceIndex& index, const KEY& srckey, const KEY& deskey, const VALUE& member); 302 | /* SPOP */ bool spop(const SliceIndex& index, const KEY& key, VALUE& member); 303 | /* SRANDMEMBER */ bool srandmember(const SliceIndex& index, const KEY& key, VALUES& vmember, int32_t num=0); 304 | /* SREM */ bool srem(const SliceIndex& index, const KEY& key, const VALUES& vmembers, int64_t& count); 305 | /* SSCAN */ bool sscan(const SliceIndex& index, const std::string& key, int64_t &cursor, 306 | const char *pattern, uint32_t count, ArrayReply& array, xRedisContext& ctx); 307 | /* SUNION */ bool sunion(const DBIArray& index, const KEYS& vkey, VALUES& vValue); 308 | /* SUNIONSTORE */ bool sunionstore(const SliceIndex& index, const KEY& deskey, const DBIArray& vdbi, const KEYS& vkey, int64_t& count); 309 | 310 | /* ZADD */ bool zadd(const SliceIndex& index, const KEY& deskey, const VALUES& vValues, int64_t& count); 311 | /* ZCARD */ bool zscrad(const SliceIndex& index, const std::string& key, int64_t& num); 312 | /* ZCOUNT */ 313 | /* ZINCRBY */ bool zincrby(const SliceIndex& index, const std::string& key, const double &increment, const std::string& member, std::string& value ); 314 | /* ZINTERSTORE */ 315 | /* ZPOPMAX */ bool zpopmax(const SliceIndex& index, const std::string& key, VALUES& vValues); 316 | /* ZPOPMIN */ bool zpopmin(const SliceIndex& index, const std::string& key, VALUES& vValues); 317 | /* ZRANGE */ bool zrange(const SliceIndex& index, const std::string& key, int32_t start, int32_t end, VALUES& vValues, bool withscore=false); 318 | /* ZRANGEBYSCORE */ bool zrangebyscore(const SliceIndex& index, const std::string& key, const std::string& min, 319 | const std::string& max, VALUES& vValues, bool withscore=false, LIMIT *limit = NULL); 320 | /* ZRANK */ bool zrank(const SliceIndex& index, const std::string& key, const std::string& member, int64_t &rank); 321 | /* ZREM */ bool zrem(const SliceIndex& index, const KEY& key, const VALUES& vmembers, int64_t &num); 322 | /* ZREMRANGEBYRANK */ bool zremrangebyrank(const SliceIndex& index, const std::string& key, int32_t start, int32_t stop, int64_t& num); 323 | /* ZREMRANGEBYSCORE */ bool zremrangebyscore(const SliceIndex& index, const KEY& key, double min, double max, int64_t& count); 324 | /* ZREVRANGE */ bool zrevrange(const SliceIndex& index, const std::string& key, int32_t start, int32_t end, VALUES& vValues, bool withscore=false); 325 | /* ZREVRANGEBYLEX */ bool zrevrangebylex(const SliceIndex& index, const std::string& key, std::string& start, std::string& end, VALUES& vValues, int32_t offset = 0, int32_t count = 0); 326 | /* ZREVRANGEBYSCORE */ 327 | /* ZREVRANK */ bool zrevrank(const SliceIndex& index, const std::string& key, const std::string &member, int64_t& rank); 328 | /* ZSCAN */ bool zscan(const SliceIndex& index, const std::string& key, int64_t &cursor, const char *pattern, 329 | uint32_t count, ArrayReply& array, xRedisContext& ctx); 330 | /* ZSCORE */ bool zscore(const SliceIndex& index, const std::string& key, const std::string &member, std::string& score); 331 | /* ZUNIONSTORE */ 332 | 333 | /* 注意: 使用下面的 pub/sub 命令时,一定要保证数据都在同一个REDIS实例里,xredis目前的pub/sub命令实现不支持多节点数据分布的场景。 */ 334 | /* PSUBSCRIBE */ bool psubscribe(const SliceIndex& index, const KEYS& patterns, xRedisContext& ctx); 335 | /* PUBLISH */ bool publish(const SliceIndex& index, const KEY& channel, const std::string& message, int64_t& count); 336 | /* PUBSUB */ bool pubsub_channels(const SliceIndex& index, const std::string &pattern, ArrayReply &reply); 337 | bool pubsub_numsub(const SliceIndex& index, const KEYS &keys, ArrayReply &reply); 338 | bool pubsub_numpat(const SliceIndex& index, int64_t& count); 339 | /* PUNSUBSCRIBE */ bool punsubscribe(const SliceIndex& index, const KEYS& patterns, xRedisContext& ctx); 340 | /* SUBSCRIBE */ bool subscribe(const SliceIndex& index, const KEYS& channels, xRedisContext& ctx); 341 | /* UNSUBSCRIBE */ bool unsubscribe(const SliceIndex& index, const KEYS& channels, xRedisContext& ctx); 342 | 343 | 344 | /* DISCARD */ 345 | /* EXEC */ 346 | /* MULTI */ 347 | /* UNWATCH */ 348 | /* WATCH */ 349 | 350 | 351 | private: 352 | void addparam(VDATA& vDes, const VDATA& vSrc) { 353 | for (VDATA::const_iterator iter=vSrc.begin(); iter!=vSrc.end();++iter) { 354 | vDes.push_back(*iter); 355 | } 356 | } 357 | void SetErrInfo(const SliceIndex& index, void *p); 358 | void SetErrString(const SliceIndex& index, const char *str, int32_t len); 359 | void SetErrMessage(const SliceIndex& index, const char* fmt, ...); 360 | void SetIOtype(const SliceIndex& index, uint32_t iotype, bool ioflag = false); 361 | bool ScanFun(const char* cmd, const SliceIndex& index, const std::string *key, int64_t &cursor, 362 | const char* pattern, uint32_t count, ArrayReply& array, xRedisContext& ctx); 363 | 364 | public: 365 | 366 | bool command_bool(const SliceIndex& index, const char* cmd, ...); 367 | bool command_status(const SliceIndex& index, const char* cmd, ...); 368 | bool command_integer(const SliceIndex& index, int64_t &intval, const char* cmd, ...); 369 | bool command_string(const SliceIndex& index, std::string &data, const char* cmd, ...); 370 | bool command_list(const SliceIndex& index, VALUES &vValue, const char* cmd, ...); 371 | bool command_array(const SliceIndex& index, ArrayReply& array, const char* cmd, ...); 372 | rReply *command(const SliceIndex& index, const char* cmd); 373 | private: 374 | bool commandargv_bool(const SliceIndex& index, const VDATA& vData); 375 | bool commandargv_status(const SliceIndex& index, const VDATA& vData); 376 | bool commandargv_array(const SliceIndex& index, const VDATA& vDataIn, ArrayReply& array); 377 | bool commandargv_array(const SliceIndex& index, const VDATA& vDataIn, VALUES& array); 378 | bool commandargv_integer(const SliceIndex& index,const VDATA& vDataIn, int64_t& retval); 379 | bool commandargv_array_ex(const SliceIndex& index, const VDATA& vDataIn, xRedisContext& ctx); 380 | private: 381 | RedisPool *mRedisPool; 382 | }; 383 | 384 | } 385 | 386 | #endif 387 | 388 | 389 | 390 | 391 | 392 | -------------------------------------------------------------------------------- /src/xRedisClient_connection.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisClient.h" 10 | 11 | namespace xrc { 12 | 13 | void xRedisClient::quit() 14 | { 15 | Release(); 16 | } 17 | 18 | bool xRedisClient::echo(const SliceIndex& index, const std::string& str, std::string& value) 19 | { 20 | if (0 == str.length()) { 21 | return false; 22 | } 23 | SETDEFAULTIOTYPE(MASTER); 24 | return command_string(index, value, "echo %s", str.c_str()); 25 | } 26 | 27 | } // namespace xrc 28 | -------------------------------------------------------------------------------- /src/xRedisClient_hashs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisClient.h" 10 | #include "xRedisPool.h" 11 | 12 | namespace xrc { 13 | 14 | bool xRedisClient::hdel(const SliceIndex& index, const std::string& key, const std::string& field, int64_t& count) 15 | { 16 | SETDEFAULTIOTYPE(MASTER); 17 | return command_integer(index, count, "HDEL %s %s", key.c_str(), field.c_str()); 18 | } 19 | 20 | bool xRedisClient::hdel(const SliceIndex& index, const std::string& key, const KEYS& vfiled, int64_t& count) 21 | { 22 | VDATA vCmdData; 23 | vCmdData.push_back("HDEL"); 24 | vCmdData.push_back(key); 25 | addparam(vCmdData, vfiled); 26 | SETDEFAULTIOTYPE(MASTER); 27 | return commandargv_integer(index, vCmdData, count); 28 | } 29 | 30 | bool xRedisClient::hexist(const SliceIndex& index, const std::string& key, const std::string& field) 31 | { 32 | SETDEFAULTIOTYPE(SLAVE); 33 | return command_bool(index, "HEXISTS %s %s", key.c_str(), field.c_str()); 34 | } 35 | 36 | bool xRedisClient::hget(const SliceIndex& index, const std::string& key, const std::string& field, std::string& value) 37 | { 38 | SETDEFAULTIOTYPE(SLAVE); 39 | return command_string(index, value, "HGET %s %s", key.c_str(), field.c_str()); 40 | } 41 | 42 | bool xRedisClient::hgetall(const SliceIndex& index, const std::string& key, ArrayReply& array) 43 | { 44 | SETDEFAULTIOTYPE(SLAVE); 45 | return command_array(index, array, "HGETALL %s", key.c_str()); 46 | } 47 | 48 | bool xRedisClient::hincrby(const SliceIndex& index, const std::string& key, const std::string& field, int64_t increment, int64_t& num) 49 | { 50 | SETDEFAULTIOTYPE(MASTER); 51 | return command_integer(index, num, "HINCRBY %s %s %lld", key.c_str(), field.c_str(), increment); 52 | } 53 | 54 | bool xRedisClient::hincrbyfloat(const SliceIndex& index, const std::string& key, const std::string& field, float increment, float& value) 55 | { 56 | SETDEFAULTIOTYPE(MASTER); 57 | bool bRet = false; 58 | RedisConnection* pRedisConn = mRedisPool->GetConnection(index.mType, index.mIndex); 59 | if (NULL == pRedisConn) { 60 | return false; 61 | } 62 | 63 | redisReply* reply = static_cast(redisCommand(pRedisConn->GetCtx(), "HINCRBYFLOAT %s %s %f", key.c_str(), field.c_str(), increment)); 64 | if (RedisPool::CheckReply(reply)) { 65 | value = atof(reply->str); 66 | bRet = true; 67 | } 68 | 69 | RedisPool::FreeReply(reply); 70 | mRedisPool->FreeConnection(pRedisConn); 71 | return bRet; 72 | } 73 | 74 | bool xRedisClient::hkeys(const SliceIndex& index, const std::string& key, KEYS& keys) 75 | { 76 | SETDEFAULTIOTYPE(SLAVE); 77 | return command_list(index, keys, "HKEYS %s", key.c_str()); 78 | } 79 | 80 | bool xRedisClient::hlen(const SliceIndex& index, const std::string& key, int64_t& count) 81 | { 82 | SETDEFAULTIOTYPE(SLAVE); 83 | return command_integer(index, count, "HLEN %s", key.c_str()); 84 | } 85 | 86 | bool xRedisClient::hmget(const SliceIndex& index, const std::string& key, const KEYS& field, ArrayReply& array) 87 | { 88 | VDATA vCmdData; 89 | vCmdData.push_back("HMGET"); 90 | vCmdData.push_back(key); 91 | addparam(vCmdData, field); 92 | SETDEFAULTIOTYPE(SLAVE); 93 | return commandargv_array(index, vCmdData, array); 94 | } 95 | 96 | bool xRedisClient::hmset(const SliceIndex& index, const std::string& key, const VDATA& vData) 97 | { 98 | VDATA vCmdData; 99 | vCmdData.push_back("HMSET"); 100 | vCmdData.push_back(key); 101 | addparam(vCmdData, vData); 102 | SETDEFAULTIOTYPE(MASTER); 103 | return commandargv_status(index, vCmdData); 104 | } 105 | 106 | bool xRedisClient::hscan(const SliceIndex& index, const std::string& key, int64_t& cursor, const char* pattern, uint32_t count, ArrayReply& array, xRedisContext& ctx) 107 | { 108 | return ScanFun("HSCAN", index, &key, cursor, pattern, count, array, ctx); 109 | } 110 | 111 | bool xRedisClient::hset(const SliceIndex& index, const std::string& key, const std::string& field, const std::string& value, int64_t& retval) 112 | { 113 | SETDEFAULTIOTYPE(MASTER); 114 | VDATA vCmdData; 115 | vCmdData.push_back("HSET"); 116 | vCmdData.push_back(key); 117 | vCmdData.push_back(field); 118 | vCmdData.push_back(value); 119 | return commandargv_integer(index, vCmdData, retval); 120 | //return command_integer(index, retval, "HSET %s %s %s", key.c_str(), field.c_str(), value.c_str()); 121 | } 122 | 123 | bool xRedisClient::hsetnx(const SliceIndex& index, const std::string& key, const std::string& field, const std::string& value) 124 | { 125 | SETDEFAULTIOTYPE(MASTER); 126 | return command_bool(index, "HSETNX %s %s %s", key.c_str(), field.c_str(), value.c_str()); 127 | } 128 | 129 | bool xRedisClient::hvals(const SliceIndex& index, const std::string& key, VALUES& values) 130 | { 131 | SETDEFAULTIOTYPE(SLAVE); 132 | return command_list(index, values, "HVALS %s", key.c_str()); 133 | } 134 | 135 | } // namespace xrc 136 | -------------------------------------------------------------------------------- /src/xRedisClient_keys.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisClient.h" 10 | 11 | namespace xrc { 12 | 13 | bool xRedisClient::del(const SliceIndex& index, const std::string& key) 14 | { 15 | if (0 == key.length()) { 16 | return false; 17 | } 18 | 19 | SETDEFAULTIOTYPE(MASTER); 20 | return command_bool(index, "DEL %s", key.c_str()); 21 | } 22 | 23 | bool xRedisClient::del(const DBIArray& vdbi, const KEYS& vkey, int64_t& count) 24 | { 25 | count = 0; 26 | if (vdbi.size() != vkey.size()) { 27 | return false; 28 | } 29 | DBIArray::const_iterator iter_dbi = vdbi.begin(); 30 | KEYS::const_iterator iter_key = vkey.begin(); 31 | for (; iter_key != vkey.end(); ++iter_key, ++iter_dbi) { 32 | const SliceIndex& index = (*iter_dbi); 33 | const std::string& key = (*iter_key); 34 | if (del(index, key)) { 35 | count++; 36 | } 37 | } 38 | return true; 39 | } 40 | 41 | bool xRedisClient::exists(const SliceIndex& index, const std::string& key) 42 | { 43 | if (0 == key.length()) { 44 | return false; 45 | } 46 | SETDEFAULTIOTYPE(MASTER); 47 | return command_bool(index, "EXISTS %s", key.c_str()); 48 | } 49 | 50 | bool xRedisClient::expire(const SliceIndex& index, const std::string& key, uint32_t second) 51 | { 52 | if (0 == key.length()) { 53 | return false; 54 | } 55 | SETDEFAULTIOTYPE(MASTER); 56 | int64_t ret = -1; 57 | if (!command_integer(index, ret, "EXPIRE %s %u", key.c_str(), second)) { 58 | return false; 59 | } 60 | 61 | if (1 == ret) { 62 | return true; 63 | } else { 64 | SetErrMessage(index, "expire return %ld ", ret); 65 | return false; 66 | } 67 | } 68 | 69 | bool xRedisClient::expireat(const SliceIndex& index, const std::string& key, uint32_t timestamp) 70 | { 71 | if (0 == key.length()) { 72 | return false; 73 | } 74 | SETDEFAULTIOTYPE(MASTER); 75 | return command_bool(index, "EXPIREAT %s %u", key.c_str(), timestamp); 76 | } 77 | 78 | bool xRedisClient::persist(const SliceIndex& index, const std::string& key) 79 | { 80 | if (0 == key.length()) { 81 | return false; 82 | } 83 | SETDEFAULTIOTYPE(MASTER); 84 | return command_bool(index, "PERSIST %s %u", key.c_str()); 85 | } 86 | 87 | bool xRedisClient::pexpire(const SliceIndex& index, const std::string& key, uint32_t milliseconds) 88 | { 89 | if (0 == key.length()) { 90 | return false; 91 | } 92 | return command_bool(index, "PEXPIRE %s %u", key.c_str(), milliseconds); 93 | } 94 | 95 | bool xRedisClient::pexpireat(const SliceIndex& index, const std::string& key, uint32_t millisecondstimestamp) 96 | { 97 | if (0 == key.length()) { 98 | return false; 99 | } 100 | SETDEFAULTIOTYPE(MASTER); 101 | return command_bool(index, "PEXPIREAT %s %u", key.c_str(), millisecondstimestamp); 102 | } 103 | 104 | bool xRedisClient::pttl(const SliceIndex& index, const std::string& key, int64_t& milliseconds) 105 | { 106 | if (0 == key.length()) { 107 | return false; 108 | } 109 | SETDEFAULTIOTYPE(MASTER); 110 | return command_integer(index, milliseconds, "PTTL %s", key.c_str()); 111 | } 112 | 113 | bool xRedisClient::ttl(const SliceIndex& index, const std::string& key, int64_t& seconds) 114 | { 115 | if (0 == key.length()) { 116 | return false; 117 | } 118 | SETDEFAULTIOTYPE(SLAVE); 119 | return command_integer(index, seconds, "TTL %s", key.c_str()); 120 | } 121 | 122 | bool xRedisClient::type(const SliceIndex& index, const std::string& key, std::string& value) 123 | { 124 | SETDEFAULTIOTYPE(MASTER); 125 | return command_string(index, value, "TYPE %s", key.c_str()); 126 | } 127 | 128 | bool xRedisClient::randomkey(const SliceIndex& index, KEY& key) 129 | { 130 | SETDEFAULTIOTYPE(SLAVE); 131 | return command_string(index, key, "RANDOMKEY"); 132 | } 133 | 134 | bool xRedisClient::scan(const SliceIndex& index, int64_t& cursor, const char* pattern, 135 | uint32_t count, ArrayReply& array, xRedisContext& ctx) 136 | { 137 | return ScanFun("SCAN", index, NULL, cursor, pattern, count, array, ctx); 138 | } 139 | 140 | bool xRedisClient::sort(const SliceIndex& index, ArrayReply& array, const std::string& key, const char* by, 141 | LIMIT* limit /*= NULL*/, bool alpha /*= false*/, const FILEDS* get /*= NULL*/, 142 | const SORTODER order /*= ASC*/, const char* destination) 143 | { 144 | static const char* sort_order[3] = { "ASC", "DESC" }; 145 | if (0 == key.length()) { 146 | return false; 147 | } 148 | 149 | VDATA vCmdData; 150 | vCmdData.push_back("sort"); 151 | vCmdData.push_back(key); 152 | if (NULL != by) { 153 | vCmdData.push_back("by"); 154 | vCmdData.push_back(by); 155 | } 156 | 157 | if (NULL != limit) { 158 | vCmdData.push_back("LIMIT"); 159 | vCmdData.push_back(toString(limit->offset)); 160 | vCmdData.push_back(toString(limit->count)); 161 | } 162 | if (alpha) { 163 | vCmdData.push_back("ALPHA"); 164 | } 165 | 166 | if (NULL != get) { 167 | for (FILEDS::const_iterator iter = get->begin(); iter != get->end(); ++iter) { 168 | vCmdData.push_back("get"); 169 | vCmdData.push_back(*iter); 170 | } 171 | } 172 | 173 | vCmdData.push_back(sort_order[order]); 174 | if (destination) { 175 | vCmdData.push_back(destination); 176 | } 177 | SETDEFAULTIOTYPE(MASTER); 178 | return commandargv_array(index, vCmdData, array); 179 | } 180 | 181 | } // namespace xrc 182 | -------------------------------------------------------------------------------- /src/xRedisClient_lists.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisClient.h" 10 | 11 | namespace xrc { 12 | 13 | bool xRedisClient::lindex(const SliceIndex& index, const std::string& key, int64_t idx, VALUE& value) 14 | { 15 | if (0 == key.length()) { 16 | return false; 17 | } 18 | SETDEFAULTIOTYPE(SLAVE); 19 | return command_string(index, value, "LINDEX %s %lld", key.c_str(), idx); 20 | } 21 | 22 | bool xRedisClient::linsert(const SliceIndex& index, const std::string& key, const LMODEL mod, const std::string& pivot, const std::string& value, int64_t& retval) 23 | { 24 | static const char* lmodel[2] = { "BEFORE", "AFTER" }; 25 | if (0 == key.length()) { 26 | return false; 27 | } 28 | SETDEFAULTIOTYPE(MASTER); 29 | return command_integer(index, retval, "LINSERT %s %s %s %s", key.c_str(), lmodel[mod], pivot.c_str(), value.c_str()); 30 | } 31 | 32 | bool xRedisClient::llen(const SliceIndex& index, const std::string& key, int64_t& retval) 33 | { 34 | if (0 == key.length()) { 35 | return false; 36 | } 37 | SETDEFAULTIOTYPE(SLAVE); 38 | return command_integer(index, retval, "LLEN %s", key.c_str()); 39 | } 40 | 41 | bool xRedisClient::blPop(const SliceIndex& index, const std::string& key, VALUES& vValues, int64_t timeout) 42 | { 43 | if (0 == key.length()) { 44 | return false; 45 | } 46 | SETDEFAULTIOTYPE(MASTER); 47 | return command_list(index, vValues, "BLPOP %s %d", key.c_str(), (int32_t)timeout); 48 | } 49 | 50 | bool xRedisClient::brPop(const SliceIndex& index, const std::string& key, VALUES& vValues, int64_t timeout) 51 | { 52 | if (0 == key.length()) { 53 | return false; 54 | } 55 | SETDEFAULTIOTYPE(MASTER); 56 | return command_list(index, vValues, "BRPOP %s %d", key.c_str(), (int32_t)timeout); 57 | } 58 | 59 | bool xRedisClient::brPoplpush(const SliceIndex& index, const std::string& key, std::string& targetkey, VALUE& value, int64_t timeout) 60 | { 61 | if (0 == key.length()) { 62 | return false; 63 | } 64 | SETDEFAULTIOTYPE(MASTER); 65 | return command_string(index, value, "BRPOPLPUSH %s %s %d", key.c_str(), targetkey.c_str(), (int32_t)timeout); 66 | } 67 | 68 | bool xRedisClient::lpop(const SliceIndex& index, const std::string& key, std::string& value) 69 | { 70 | if (0 == key.length()) { 71 | return false; 72 | } 73 | SETDEFAULTIOTYPE(MASTER); 74 | return command_string(index, value, "LPOP %s", key.c_str()); 75 | } 76 | 77 | bool xRedisClient::lpush(const SliceIndex& index, const std::string& key, const VALUES& vValue, int64_t& length) 78 | { 79 | if (0 == key.length()) { 80 | return false; 81 | } 82 | VDATA vCmdData; 83 | vCmdData.push_back("LPUSH"); 84 | vCmdData.push_back(key); 85 | addparam(vCmdData, vValue); 86 | SETDEFAULTIOTYPE(MASTER); 87 | return commandargv_integer(index, vCmdData, length); 88 | } 89 | 90 | bool xRedisClient::lrange(const SliceIndex& index, const std::string& key, int64_t start, int64_t end, ArrayReply& array) 91 | { 92 | if (0 == key.length()) { 93 | return false; 94 | } 95 | SETDEFAULTIOTYPE(SLAVE); 96 | return command_array(index, array, "LRANGE %s %lld %lld", key.c_str(), start, end); 97 | } 98 | 99 | bool xRedisClient::lrem(const SliceIndex& index, const std::string& key, int32_t count, const std::string& value, int64_t num) 100 | { 101 | if (0 == key.length()) { 102 | return false; 103 | } 104 | SETDEFAULTIOTYPE(MASTER); 105 | return command_integer(index, num, "LREM %s %d %s", key.c_str(), count, value.c_str()); 106 | } 107 | 108 | bool xRedisClient::lset(const SliceIndex& index, const std::string& key, int32_t idx, const std::string& value) 109 | { 110 | if (0 == key.length()) { 111 | return false; 112 | } 113 | SETDEFAULTIOTYPE(MASTER); 114 | return command_status(index, "LSET %s %d %s", key.c_str(), idx, value.c_str()); 115 | } 116 | 117 | bool xRedisClient::ltrim(const SliceIndex& index, const std::string& key, int32_t start, int32_t end) 118 | { 119 | if (0 == key.length()) { 120 | return false; 121 | } 122 | SETDEFAULTIOTYPE(MASTER); 123 | return command_status(index, "LTRIM %s %d %d", key.c_str(), start, end); 124 | } 125 | 126 | bool xRedisClient::rpop(const SliceIndex& index, const std::string& key, std::string& value) 127 | { 128 | if (0 == key.length()) { 129 | return false; 130 | } 131 | SETDEFAULTIOTYPE(MASTER); 132 | return command_string(index, value, "RPOP %s", key.c_str()); 133 | } 134 | 135 | bool xRedisClient::rpoplpush(const SliceIndex& index, const std::string& key_src, const std::string& key_dest, std::string& value) 136 | { 137 | if ((0 == key_src.length()) || (0 == key_dest.length())) { 138 | return false; 139 | } 140 | SETDEFAULTIOTYPE(MASTER); 141 | return command_string(index, value, "RPOPLPUSH %s %s", key_src.c_str(), key_dest.c_str()); 142 | } 143 | 144 | bool xRedisClient::rpush(const SliceIndex& index, const std::string& key, const VALUES& vValue, int64_t& length) 145 | { 146 | if (0 == key.length()) { 147 | return false; 148 | } 149 | VDATA vCmdData; 150 | vCmdData.push_back("RPUSH"); 151 | vCmdData.push_back(key); 152 | addparam(vCmdData, vValue); 153 | SETDEFAULTIOTYPE(MASTER); 154 | return commandargv_integer(index, vCmdData, length); 155 | } 156 | 157 | bool xRedisClient::rpushx(const SliceIndex& index, const std::string& key, const std::string& value, int64_t& length) 158 | { 159 | if (0 == key.length()) { 160 | return false; 161 | } 162 | SETDEFAULTIOTYPE(MASTER); 163 | return command_integer(index, length, "RPUSHX %s %s", key.c_str(), value.c_str()); 164 | } 165 | 166 | } // namespace xrc 167 | -------------------------------------------------------------------------------- /src/xRedisClient_pubsub.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisClient.h" 10 | #include "xRedisPool.h" 11 | namespace xrc { 12 | 13 | bool xRedisClient::psubscribe(const SliceIndex& index, const KEYS& patterns, 14 | xRedisContext& ctx) 15 | { 16 | SETDEFAULTIOTYPE(MASTER); 17 | VDATA vCmdData; 18 | vCmdData.push_back("PSUBSCRIBE"); 19 | addparam(vCmdData, patterns); 20 | return commandargv_array_ex(index, vCmdData, ctx); 21 | } 22 | 23 | bool xRedisClient::publish(const SliceIndex& index, const KEY& channel, 24 | const std::string& message, int64_t& count) 25 | { 26 | // SETDEFAULTIOTYPE(MASTER); 27 | // return command_integer(index, count, "PUBLISH %s %s", channel.c_str(), 28 | // message.c_str(), count); 29 | 30 | SETDEFAULTIOTYPE(MASTER); 31 | VDATA vCmdData; 32 | vCmdData.push_back("PUBLISH"); 33 | vCmdData.push_back(channel); 34 | vCmdData.push_back(message); 35 | return commandargv_integer(index, vCmdData, count); 36 | } 37 | 38 | bool xRedisClient::pubsub_channels(const SliceIndex& index, 39 | const std::string& pattern, 40 | ArrayReply& reply) 41 | { 42 | SETDEFAULTIOTYPE(MASTER); 43 | return command_array(index, reply, "pubsub channels %s", pattern.c_str()); 44 | } 45 | 46 | bool xRedisClient::pubsub_numsub(const SliceIndex& index, const KEYS& keys, 47 | ArrayReply& reply) 48 | { 49 | SETDEFAULTIOTYPE(MASTER); 50 | VDATA vCmdData; 51 | vCmdData.push_back("pubsub"); 52 | vCmdData.push_back("numsub"); 53 | addparam(vCmdData, keys); 54 | return commandargv_array(index, vCmdData, reply); 55 | } 56 | 57 | bool xRedisClient::pubsub_numpat(const SliceIndex& index, int64_t& count) 58 | { 59 | SETDEFAULTIOTYPE(MASTER); 60 | return command_integer(index, count, "pubsub numpat"); 61 | } 62 | 63 | bool xRedisClient::punsubscribe(const SliceIndex& index, const KEYS& patterns, 64 | xRedisContext& ctx) 65 | { 66 | SETDEFAULTIOTYPE(MASTER); 67 | VDATA vCmdData; 68 | vCmdData.push_back("PUNSUBSCRIBE"); 69 | addparam(vCmdData, patterns); 70 | 71 | bool bRet = false; 72 | RedisConnection* pRedisConn = static_cast(ctx.conn); 73 | if (NULL == pRedisConn) { 74 | SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 75 | return false; 76 | } 77 | 78 | std::vector argv(vCmdData.size()); 79 | std::vector argvlen(vCmdData.size()); 80 | uint32_t j = 0; 81 | for (VDATA::const_iterator i = vCmdData.begin(); i != vCmdData.end(); 82 | ++i, ++j) { 83 | argv[j] = i->c_str(), argvlen[j] = i->size(); 84 | } 85 | 86 | redisReply* reply = static_cast(redisCommandArgv( 87 | pRedisConn->GetCtx(), argv.size(), &(argv[0]), &(argvlen[0]))); 88 | if (RedisPool::CheckReply(reply)) { 89 | bRet = true; 90 | } else { 91 | SetErrInfo(index, reply); 92 | } 93 | RedisPool::FreeReply(reply); 94 | return bRet; 95 | } 96 | 97 | bool xRedisClient::subscribe(const SliceIndex& index, const KEYS& channels, 98 | xRedisContext& ctx) 99 | { 100 | SETDEFAULTIOTYPE(MASTER); 101 | VDATA vCmdData; 102 | vCmdData.push_back("SUBSCRIBE"); 103 | addparam(vCmdData, channels); 104 | return commandargv_array_ex(index, vCmdData, ctx); 105 | } 106 | 107 | bool xRedisClient::unsubscribe(const SliceIndex& index, const KEYS& channels, 108 | xRedisContext& ctx) 109 | { 110 | SETDEFAULTIOTYPE(MASTER); 111 | VDATA vCmdData; 112 | vCmdData.push_back("UNSUBSCRIBE"); 113 | addparam(vCmdData, channels); 114 | 115 | bool bRet = false; 116 | RedisConnection* pRedisConn = static_cast(ctx.conn); 117 | if (NULL == pRedisConn) { 118 | SetErrString(index, GET_CONNECT_ERROR, ::strlen(GET_CONNECT_ERROR)); 119 | return false; 120 | } 121 | 122 | std::vector argv(vCmdData.size()); 123 | std::vector argvlen(vCmdData.size()); 124 | uint32_t j = 0; 125 | for (VDATA::const_iterator i = vCmdData.begin(); i != vCmdData.end(); 126 | ++i, ++j) { 127 | argv[j] = i->c_str(), argvlen[j] = i->size(); 128 | } 129 | 130 | redisReply* reply = static_cast(redisCommandArgv( 131 | pRedisConn->GetCtx(), argv.size(), &(argv[0]), &(argvlen[0]))); 132 | if (RedisPool::CheckReply(reply)) { 133 | bRet = true; 134 | } else { 135 | SetErrInfo(index, reply); 136 | } 137 | RedisPool::FreeReply(reply); 138 | return bRet; 139 | } 140 | 141 | } // namespace xrc 142 | -------------------------------------------------------------------------------- /src/xRedisClient_sets.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisClient.h" 10 | 11 | namespace xrc { 12 | 13 | bool xRedisClient::sadd(const SliceIndex& index, const std::string& key, 14 | const VALUES& vValue, int64_t& count) 15 | { 16 | VDATA vCmdData; 17 | vCmdData.push_back("SADD"); 18 | vCmdData.push_back(key); 19 | addparam(vCmdData, vValue); 20 | SETDEFAULTIOTYPE(MASTER); 21 | return commandargv_integer(index, vCmdData, count); 22 | } 23 | 24 | bool xRedisClient::scard(const SliceIndex& index, const std::string& key, 25 | int64_t& count) 26 | { 27 | if (0 == key.length()) { 28 | return false; 29 | } 30 | SETDEFAULTIOTYPE(SLAVE); 31 | return command_integer(index, count, "SCARD %s", key.c_str()); 32 | } 33 | 34 | bool xRedisClient::sdiff(const DBIArray& vdbi, const KEYS& vkey, 35 | VALUES& sValue) 36 | { 37 | size_t size = vkey.size(); 38 | if (0 == size) { 39 | return false; 40 | } 41 | VALUES* setData = new VALUES[size]; 42 | VALUES::iterator endpos; 43 | 44 | DBIArray::const_iterator iter_dbi = vdbi.begin(); 45 | KEYS::const_iterator iter_key = vkey.begin(); 46 | int32_t i = 0; 47 | for (; iter_key != vkey.end(); ++iter_key, ++iter_dbi, ++i) { 48 | const std::string& key = *iter_key; 49 | const SliceIndex& index = *iter_dbi; 50 | if (!smembers(index, key, setData[i])) { 51 | delete[] setData; 52 | return false; 53 | } 54 | } 55 | 56 | size_t n = 0; 57 | while (n++ < size - 1) { 58 | endpos = set_difference(setData[n].begin(), setData[n].end(), 59 | setData[n + 1].begin(), setData[n + 1].end(), 60 | sValue.begin()); 61 | sValue.resize(endpos - sValue.begin()); 62 | } 63 | delete[] setData; 64 | return true; 65 | } 66 | 67 | bool xRedisClient::sdiffstore(const SliceIndex& index, 68 | const KEY& destinationkey, const DBIArray& vdbi, 69 | const KEYS& vkey, int64_t& count) 70 | { 71 | VALUES sValue; 72 | if (!sdiff(vdbi, vkey, sValue)) { 73 | return false; 74 | } 75 | return sadd(index, destinationkey, sValue, count); 76 | } 77 | 78 | bool xRedisClient::sinter(const DBIArray& vdbi, const KEYS& vkey, 79 | VALUES& sValue) 80 | { 81 | size_t size = vkey.size(); 82 | VALUES* setData = new VALUES[size]; 83 | VALUES::iterator endpos; 84 | 85 | DBIArray::const_iterator iter_dbi = vdbi.begin(); 86 | KEYS::const_iterator iter_key = vkey.begin(); 87 | int32_t i = 0; 88 | for (; iter_key != vkey.end(); ++iter_key, ++iter_dbi, ++i) { 89 | const std::string& key = *iter_key; 90 | const SliceIndex& index = *iter_dbi; 91 | if (!smembers(index, key, setData[i])) { 92 | delete[] setData; 93 | return false; 94 | } 95 | } 96 | 97 | size_t n = 0; 98 | while (n++ < size - 1) { 99 | endpos = set_intersection(setData[n].begin(), setData[n].end(), 100 | setData[n + 1].begin(), setData[n + 1].end(), 101 | sValue.begin()); 102 | sValue.resize(endpos - sValue.begin()); 103 | } 104 | delete[] setData; 105 | 106 | return true; 107 | } 108 | 109 | bool xRedisClient::sinterstore(const SliceIndex& des_dbi, 110 | const KEY& destinationkey, const DBIArray& vdbi, 111 | const KEYS& vkey, int64_t& count) 112 | { 113 | VALUES sValue; 114 | if (!sinter(vdbi, vkey, sValue)) { 115 | return false; 116 | } 117 | return sadd(des_dbi, destinationkey, sValue, count); 118 | } 119 | 120 | bool xRedisClient::sismember(const SliceIndex& index, const KEY& key, 121 | const VALUE& member) 122 | { 123 | if (0 == key.length()) { 124 | return false; 125 | } 126 | return command_bool(index, "SISMEMBER %s %s", key.c_str(), member.c_str()); 127 | } 128 | 129 | bool xRedisClient::smembers(const SliceIndex& index, const KEY& key, 130 | VALUES& vValue) 131 | { 132 | if (0 == key.length()) { 133 | return false; 134 | } 135 | SETDEFAULTIOTYPE(SLAVE); 136 | return command_list(index, vValue, "SMEMBERS %s", key.c_str()); 137 | } 138 | 139 | bool xRedisClient::smove(const SliceIndex& index, const KEY& srckey, 140 | const KEY& deskey, const VALUE& member) 141 | { 142 | if (0 == srckey.length()) { 143 | return false; 144 | } 145 | SETDEFAULTIOTYPE(MASTER); 146 | return command_bool(index, "SMOVE %s %s %s", srckey.c_str(), deskey.c_str(), 147 | member.c_str()); 148 | } 149 | 150 | bool xRedisClient::spop(const SliceIndex& index, const KEY& key, 151 | VALUE& member) 152 | { 153 | if (0 == key.length()) { 154 | return false; 155 | } 156 | SETDEFAULTIOTYPE(MASTER); 157 | return command_string(index, member, "SPOP %s", key.c_str()); 158 | } 159 | 160 | bool xRedisClient::srandmember(const SliceIndex& index, const KEY& key, 161 | VALUES& members, int32_t count) 162 | { 163 | if (0 == key.length()) { 164 | return false; 165 | } 166 | SETDEFAULTIOTYPE(SLAVE); 167 | if (0 == count) { 168 | return command_list(index, members, "SRANDMEMBER %s", key.c_str()); 169 | } 170 | return command_list(index, members, "SRANDMEMBER %s %d", key.c_str(), count); 171 | } 172 | 173 | bool xRedisClient::srem(const SliceIndex& index, const KEY& key, 174 | const VALUES& vmembers, int64_t& count) 175 | { 176 | if (0 == key.length()) { 177 | return false; 178 | } 179 | SETDEFAULTIOTYPE(MASTER); 180 | VDATA vCmdData; 181 | vCmdData.push_back("SREM"); 182 | vCmdData.push_back(key); 183 | addparam(vCmdData, vmembers); 184 | return commandargv_integer(index, vCmdData, count); 185 | } 186 | 187 | bool xRedisClient::sscan(const SliceIndex& index, const std::string& key, 188 | int64_t& cursor, const char* pattern, uint32_t count, 189 | ArrayReply& array, xRedisContext& ctx) 190 | { 191 | return ScanFun("SSCAN", index, &key, cursor, pattern, count, array, ctx); 192 | } 193 | 194 | bool xRedisClient::sunion(const DBIArray& vdbi, const KEYS& vkey, 195 | VALUES& sValue) 196 | { 197 | size_t size = vkey.size(); 198 | VALUES* setData = new VALUES[size]; 199 | VALUES::iterator endpos; 200 | 201 | DBIArray::const_iterator iter_dbi = vdbi.begin(); 202 | KEYS::const_iterator iter_key = vkey.begin(); 203 | int32_t i = 0; 204 | for (; iter_key != vkey.end(); ++iter_key, ++iter_dbi, ++i) { 205 | const std::string& key = *iter_key; 206 | const SliceIndex& index = *iter_dbi; 207 | if (!smembers(index, key, setData[i])) { 208 | delete[] setData; 209 | return false; 210 | } 211 | } 212 | 213 | size_t n = 0; 214 | while (n++ < size - 1) { 215 | endpos = set_union(setData[n].begin(), setData[n].end(), setData[n + 1].begin(), 216 | setData[n + 1].end(), sValue.begin()); 217 | sValue.resize(endpos - sValue.begin()); 218 | } 219 | delete[] setData; 220 | return true; 221 | } 222 | 223 | bool xRedisClient::sunionstore(const SliceIndex& index, const KEY& deskey, 224 | const DBIArray& vdbi, const KEYS& vkey, 225 | int64_t& count) 226 | { 227 | VALUES sValue; 228 | if (!index.mIOFlag) { 229 | SetIOtype(index, MASTER, true); 230 | } 231 | if (!sunion(vdbi, vkey, sValue)) { 232 | return false; 233 | } 234 | return sadd(index, deskey, sValue, count); 235 | } 236 | 237 | } // namespace xrc 238 | -------------------------------------------------------------------------------- /src/xRedisClient_sortedsets.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisClient.h" 10 | namespace xrc { 11 | 12 | bool xRedisClient::zadd(const SliceIndex& index, const KEY& key, 13 | const VALUES& vValues, int64_t& count) 14 | { 15 | VDATA vCmdData; 16 | vCmdData.push_back("ZADD"); 17 | vCmdData.push_back(key); 18 | addparam(vCmdData, vValues); 19 | SETDEFAULTIOTYPE(MASTER); 20 | return commandargv_integer(index, vCmdData, count); 21 | } 22 | 23 | bool xRedisClient::zscrad(const SliceIndex& index, const std::string& key, 24 | int64_t& count) 25 | { 26 | if (0 == key.length()) { 27 | return false; 28 | } 29 | SETDEFAULTIOTYPE(SLAVE); 30 | return command_integer(index, count, "ZSCRAD %s", key.c_str()); 31 | } 32 | 33 | bool xRedisClient::zincrby(const SliceIndex& index, const std::string& key, 34 | const double& increment, const std::string& member, 35 | std::string& value) 36 | { 37 | if (0 == key.length()) { 38 | return false; 39 | } 40 | SETDEFAULTIOTYPE(MASTER); 41 | return command_string(index, value, "ZINCRBY %s %f %s", key.c_str(), 42 | increment, member.c_str()); 43 | } 44 | 45 | bool xRedisClient::zpopmax(const SliceIndex& index, const std::string& key, 46 | VALUES& vValues) 47 | { 48 | if (0 == key.length()) { 49 | return false; 50 | } 51 | SETDEFAULTIOTYPE(MASTER); 52 | return command_list(index, vValues, "ZPOPMAX %s", key.c_str()); 53 | } 54 | 55 | bool xRedisClient::zpopmin(const SliceIndex& index, const std::string& key, 56 | VALUES& vValues) 57 | { 58 | if (0 == key.length()) { 59 | return false; 60 | } 61 | SETDEFAULTIOTYPE(MASTER); 62 | return command_list(index, vValues, "ZPOPMIN %s", key.c_str()); 63 | } 64 | 65 | bool xRedisClient::zrange(const SliceIndex& index, const std::string& key, 66 | int32_t start, int32_t end, VALUES& vValues, 67 | bool withscore) 68 | { 69 | if (0 == key.length()) { 70 | return false; 71 | } 72 | SETDEFAULTIOTYPE(SLAVE); 73 | if (withscore) { 74 | return command_list(index, vValues, "ZRANGE %s %d %d %s", key.c_str(), 75 | start, end, "WITHSCORES"); 76 | } 77 | return command_list(index, vValues, "ZRANGE %s %d %d", key.c_str(), start, 78 | end); 79 | } 80 | 81 | bool xRedisClient::zrangebyscore(const SliceIndex& index, 82 | const std::string& key, const std::string& min, 83 | const std::string& max, VALUES& vValues, 84 | bool withscore, LIMIT* limit /*= NULL*/) 85 | { 86 | if (0 == key.length()) { 87 | return false; 88 | } 89 | 90 | VDATA vCmdData; 91 | vCmdData.push_back("ZRANGEBYSCORE"); 92 | vCmdData.push_back(key); 93 | vCmdData.push_back(min); 94 | vCmdData.push_back(max); 95 | 96 | if (withscore) { 97 | vCmdData.push_back("WITHSCORES"); 98 | } 99 | 100 | if (NULL != limit) { 101 | vCmdData.push_back("LIMIT"); 102 | vCmdData.push_back(toString(limit->offset)); 103 | vCmdData.push_back(toString(limit->count)); 104 | } 105 | 106 | SETDEFAULTIOTYPE(SLAVE); 107 | return commandargv_array(index, vCmdData, vValues); 108 | } 109 | 110 | bool xRedisClient::zrank(const SliceIndex& index, const std::string& key, 111 | const std::string& member, int64_t& rank) 112 | { 113 | if (0 == key.length()) { 114 | return false; 115 | } 116 | SETDEFAULTIOTYPE(MASTER); 117 | return command_integer(index, rank, "ZRANK %s %s", key.c_str(), 118 | member.c_str()); 119 | } 120 | 121 | bool xRedisClient::zrem(const SliceIndex& index, const KEY& key, 122 | const VALUES& vmembers, int64_t& count) 123 | { 124 | VDATA vCmdData; 125 | vCmdData.push_back("ZREM"); 126 | vCmdData.push_back(key); 127 | addparam(vCmdData, vmembers); 128 | SETDEFAULTIOTYPE(MASTER); 129 | return commandargv_integer(index, vCmdData, count); 130 | } 131 | 132 | bool xRedisClient::zremrangebyrank(const SliceIndex& index, 133 | const std::string& key, int32_t start, 134 | int32_t stop, int64_t& count) 135 | { 136 | if (0 == key.length()) { 137 | return false; 138 | } 139 | SETDEFAULTIOTYPE(MASTER); 140 | return command_integer(index, count, "ZREMRANGEBYRANK %s %d %d", key.c_str(), 141 | start, stop); 142 | } 143 | 144 | bool xRedisClient::zremrangebyscore(const SliceIndex& index, const KEY& key, 145 | double min, double max, int64_t& count) 146 | { 147 | if (0 == key.length()) { 148 | return false; 149 | } 150 | SETDEFAULTIOTYPE(SLAVE); 151 | return command_integer(index, count, "ZREMRANGEBYSCORE %s %f %f", key.c_str(), 152 | min, max); 153 | } 154 | 155 | bool xRedisClient::zrevrange(const SliceIndex& index, const std::string& key, 156 | int32_t start, int32_t end, VALUES& vValues, 157 | bool withscore) 158 | { 159 | if (0 == key.length()) { 160 | return false; 161 | } 162 | if (withscore) { 163 | return command_list(index, vValues, "ZREVRANGE %s %d %d %s", key.c_str(), 164 | start, end, "WITHSCORES"); 165 | } 166 | return command_list(index, vValues, "ZREVRANGE %s %d %d", key.c_str(), start, 167 | end); 168 | } 169 | 170 | bool xRedisClient::zrevrank(const SliceIndex& index, const std::string& key, 171 | const std::string& member, int64_t& rank) 172 | { 173 | if (0 == key.length()) { 174 | return false; 175 | } 176 | SETDEFAULTIOTYPE(SLAVE); 177 | return command_integer(index, rank, "ZREVRANK %s %s", key.c_str(), 178 | member.c_str()); 179 | } 180 | 181 | bool xRedisClient::zscan(const SliceIndex& index, const std::string& key, 182 | int64_t& cursor, const char* pattern, uint32_t count, 183 | ArrayReply& array, xRedisContext& ctx) 184 | { 185 | return ScanFun("ZSCAN", index, &key, cursor, pattern, count, array, ctx); 186 | } 187 | 188 | bool xRedisClient::zscore(const SliceIndex& index, const std::string& key, 189 | const std::string& member, std::string& score) 190 | { 191 | if (0 == key.length()) { 192 | return false; 193 | } 194 | SETDEFAULTIOTYPE(SLAVE); 195 | return command_string(index, score, "ZSCORE %s %s", key.c_str(), 196 | member.c_str()); 197 | } 198 | 199 | } // namespace xrc 200 | -------------------------------------------------------------------------------- /src/xRedisClient_strings.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisClient.h" 10 | 11 | namespace xrc { 12 | 13 | bool xRedisClient::psetex(const SliceIndex& index, const std::string& key, 14 | int32_t milliseconds, const std::string& value) 15 | { 16 | SETDEFAULTIOTYPE(MASTER); 17 | return command_bool(index, "PSETEX %s %d %s", key.c_str(), milliseconds, 18 | value.c_str()); 19 | } 20 | 21 | bool xRedisClient::append(const SliceIndex& index, const std::string& key, 22 | const std::string& value) 23 | { 24 | VDATA vCmdData; 25 | vCmdData.push_back("APPEND"); 26 | vCmdData.push_back(key); 27 | vCmdData.push_back(value); 28 | SETDEFAULTIOTYPE(MASTER); 29 | return commandargv_status(index, vCmdData); 30 | } 31 | 32 | bool xRedisClient::set(const SliceIndex& index, const std::string& key, 33 | const std::string& value) 34 | { 35 | VDATA vCmdData; 36 | vCmdData.push_back("SET"); 37 | vCmdData.push_back(key); 38 | vCmdData.push_back(value); 39 | SETDEFAULTIOTYPE(MASTER); 40 | return commandargv_status(index, vCmdData); 41 | } 42 | 43 | bool xRedisClient::set(const SliceIndex& index, const std::string& key, 44 | const std::string& value, SETPXEX pxex, 45 | int32_t expiretime, SETNXXX nxxx) 46 | { 47 | static const char* pXflag[] = { "px", "ex", "nx", "xx" }; 48 | SETDEFAULTIOTYPE(MASTER); 49 | 50 | VDATA vCmdData; 51 | vCmdData.push_back("SET"); 52 | vCmdData.push_back(key); 53 | vCmdData.push_back(value); 54 | 55 | if (pxex > 0) { 56 | vCmdData.push_back((pxex == PX) ? pXflag[0] : pXflag[1]); 57 | vCmdData.push_back(toString(expiretime)); 58 | } 59 | 60 | if (nxxx > 0) { 61 | vCmdData.push_back((nxxx == NX) ? pXflag[2] : pXflag[3]); 62 | } 63 | 64 | return commandargv_status(index, vCmdData); 65 | } 66 | 67 | bool xRedisClient::set(const SliceIndex& index, const std::string& key, 68 | const char* value, int32_t len, int32_t second) 69 | { 70 | SETDEFAULTIOTYPE(MASTER); 71 | if (0 == second) { 72 | return command_bool(index, "set %s %b", key.c_str(), value, len); 73 | } else { 74 | return command_bool(index, "set %s %b EX %d", key.c_str(), value, len, 75 | second); 76 | } 77 | } 78 | 79 | bool xRedisClient::setbit(const SliceIndex& index, const std::string& key, 80 | int32_t offset, int64_t newbitValue, 81 | int64_t oldbitValue) 82 | { 83 | SETDEFAULTIOTYPE(MASTER); 84 | return command_integer(index, oldbitValue, "SETBIT %s %d %lld", key.c_str(), 85 | offset, newbitValue); 86 | } 87 | 88 | bool xRedisClient::get(const SliceIndex& index, const std::string& key, 89 | std::string& value) 90 | { 91 | SETDEFAULTIOTYPE(SLAVE); 92 | return command_string(index, value, "GET %s", key.c_str()); 93 | } 94 | 95 | bool xRedisClient::getbit(const SliceIndex& index, const std::string& key, 96 | int32_t& offset, int32_t& bit) 97 | { 98 | SETDEFAULTIOTYPE(SLAVE); 99 | int64_t intval = 0; 100 | bool bRet = command_integer(index, intval, "GETBIT %s %d", key.c_str(), offset); 101 | bit = (int32_t)intval; 102 | return bRet; 103 | } 104 | 105 | bool xRedisClient::getrange(const SliceIndex& index, const std::string& key, 106 | int32_t start, int32_t end, std::string& out) 107 | { 108 | SETDEFAULTIOTYPE(SLAVE); 109 | return command_string(index, out, "GETRANGE %s %d %d", key.c_str(), start, 110 | end); 111 | } 112 | 113 | bool xRedisClient::getset(const SliceIndex& index, const std::string& key, 114 | const std::string& newValue, std::string& oldValue) 115 | { 116 | SETDEFAULTIOTYPE(MASTER); 117 | return command_string(index, oldValue, "GETSET %s %s", key.c_str(), 118 | newValue.c_str()); 119 | } 120 | 121 | bool xRedisClient::mget(const DBIArray& vdbi, const KEYS& keys, 122 | ReplyData& vDdata) 123 | { 124 | bool bRet = false; 125 | size_t n = vdbi.size(); 126 | if (n != keys.size()) { 127 | return bRet; 128 | } 129 | 130 | DataItem item; 131 | DBIArray::const_iterator iter_dbi = vdbi.begin(); 132 | KEYS::const_iterator iter_key = keys.begin(); 133 | for (; iter_key != keys.end(); ++iter_key, ++iter_dbi) { 134 | const SliceIndex& index = *iter_dbi; 135 | SETDEFAULTIOTYPE(SLAVE); 136 | const std::string& key = *iter_key; 137 | if (key.length() > 0) { 138 | bool ret = command_string(*iter_dbi, item.str, "GET %s", key.c_str()); 139 | if (!ret) { 140 | item.type = REDIS_REPLY_NIL; 141 | item.str = ""; 142 | } else { 143 | item.type = REDIS_REPLY_STRING; 144 | bRet = true; 145 | } 146 | vDdata.push_back(item); 147 | } 148 | } 149 | return bRet; 150 | } 151 | 152 | bool xRedisClient::mset(const DBIArray& vdbi, const VDATA& vData) 153 | { 154 | DBIArray::const_iterator iter_dbi = vdbi.begin(); 155 | VDATA::const_iterator iter_data = vData.begin(); 156 | for (; iter_data != vData.end(); iter_dbi++) { 157 | const std::string& key = (*iter_data++); 158 | const std::string& value = (*iter_data++); 159 | const SliceIndex& index = *iter_dbi; 160 | SETDEFAULTIOTYPE(SLAVE); 161 | command_status(index, "SET %s %s", key.c_str(), value.c_str()); 162 | } 163 | return true; 164 | } 165 | 166 | bool xRedisClient::setex(const SliceIndex& index, const std::string& key, 167 | int32_t seconds, const std::string& value) 168 | { 169 | VDATA vCmdData; 170 | 171 | vCmdData.push_back("SETEX"); 172 | vCmdData.push_back(key); 173 | vCmdData.push_back(toString(seconds)); 174 | vCmdData.push_back(value); 175 | SETDEFAULTIOTYPE(MASTER); 176 | return commandargv_status(index, vCmdData); 177 | } 178 | 179 | bool xRedisClient::setnx(const SliceIndex& index, const std::string& key, 180 | const std::string& value) 181 | { 182 | VDATA vCmdData; 183 | vCmdData.push_back("SETNX"); 184 | vCmdData.push_back(key); 185 | vCmdData.push_back(value); 186 | SETDEFAULTIOTYPE(MASTER); 187 | return commandargv_bool(index, vCmdData); 188 | } 189 | 190 | bool xRedisClient::setrange(const SliceIndex& index, const std::string& key, 191 | int32_t offset, const std::string& value, 192 | int32_t& length) 193 | { 194 | int64_t intval = 0; 195 | SETDEFAULTIOTYPE(MASTER); 196 | bool bRet = command_integer(index, intval, "setrange %s %d %s", key.c_str(), 197 | offset, value.c_str()); 198 | length = (int32_t)intval; 199 | return bRet; 200 | } 201 | 202 | bool xRedisClient::strlen(const SliceIndex& index, const std::string& key, 203 | int32_t& length) 204 | { 205 | int64_t intval = 0; 206 | SETDEFAULTIOTYPE(SLAVE); 207 | bool bRet = command_integer(index, intval, "STRLEN %s", key.c_str()); 208 | length = (int32_t)intval; 209 | return bRet; 210 | } 211 | 212 | bool xRedisClient::incr(const SliceIndex& index, const std::string& key, 213 | int64_t& result) 214 | { 215 | SETDEFAULTIOTYPE(MASTER); 216 | return command_integer(index, result, "INCR %s", key.c_str()); 217 | } 218 | 219 | bool xRedisClient::incrby(const SliceIndex& index, const std::string& key, 220 | int32_t by, int64_t& result) 221 | { 222 | SETDEFAULTIOTYPE(MASTER); 223 | return command_integer(index, result, "INCRBY %s %d", key.c_str(), by); 224 | } 225 | 226 | bool xRedisClient::bitcount(const SliceIndex& index, const std::string& key, 227 | int32_t& count, int32_t start, int32_t end) 228 | { 229 | int64_t intval = 0; 230 | bool bRet = false; 231 | SETDEFAULTIOTYPE(SLAVE); 232 | if ((start != 0) || (end != 0)) { 233 | bRet = command_integer(index, intval, "bitcount %s %d %d", key.c_str(), 234 | start, end); 235 | } else { 236 | bRet = command_integer(index, intval, "bitcount %s", key.c_str()); 237 | } 238 | count = (int32_t)intval; 239 | return bRet; 240 | } 241 | 242 | //// 这个实现有问题 243 | // bool xRedisClient::bitop(const SliceIndex& index, const BITOP operation, 244 | // const string& destkey, const KEYS& keys, int32_t& lenght) { 245 | // static const char *op_cmd[4]= {"AND","OR","XOR","NOT"}; 246 | // VDATA vCmdData; 247 | // int64_t intval = 0; 248 | // vCmdData.push_back("bitop"); 249 | // vCmdData.push_back(op_cmd[operation]); 250 | // vCmdData.push_back(destkey); 251 | // addparam(vCmdData, keys); 252 | // SETDEFAULTIOTYPE(MASTER); 253 | // bool bRet = commandargv_integer(index, vCmdData, intval); 254 | // lenght = (int32_t)intval; 255 | // return bRet; 256 | //} 257 | 258 | bool xRedisClient::bitpos(const SliceIndex& index, const std::string& key, 259 | int32_t bit, int64_t& pos, int32_t start, 260 | int32_t end) 261 | { 262 | SETDEFAULTIOTYPE(SLAVE); 263 | if ((start != 0) || (end != 0)) { 264 | return command_integer(index, pos, "BITPOS %s %d %d %d", key.c_str(), bit, 265 | start, end); 266 | } 267 | return command_integer(index, pos, "BITPOS %s %d", key.c_str(), bit); 268 | } 269 | 270 | bool xRedisClient::decr(const SliceIndex& index, const std::string& key, 271 | int64_t& result) 272 | { 273 | SETDEFAULTIOTYPE(MASTER); 274 | return command_integer(index, result, "decr %s", key.c_str()); 275 | } 276 | 277 | bool xRedisClient::decrby(const SliceIndex& index, const std::string& key, 278 | int32_t by, int64_t& result) 279 | { 280 | SETDEFAULTIOTYPE(MASTER); 281 | return command_integer(index, result, "decrby %s %d", key.c_str(), by); 282 | } 283 | } // namespace xrc 284 | -------------------------------------------------------------------------------- /src/xRedisClusterClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #ifndef _XREDIS_CLUSTER_CLIENT_H_ 10 | #define _XREDIS_CLUSTER_CLIENT_H_ 11 | 12 | #include "hiredis.h" 13 | #include "xLock.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | namespace xrc { 22 | 23 | #define LOG_LEVEL_ERROR 0 24 | #define LOG_LEVEL_WARN 1 25 | #define LOG_LEVEL_INFO 2 26 | #define LOG_LEVEL_DEBUG 3 27 | 28 | class xRedisClusterManager; 29 | class RedisResult; 30 | typedef std::vector VString; 31 | class ClusterInfo; 32 | 33 | class RedisResult { 34 | public: 35 | RedisResult() { } 36 | ~RedisResult() 37 | { 38 | if (Reply.reply) { 39 | freeReplyObject((void*)Reply.reply); 40 | } 41 | } 42 | 43 | public: 44 | class RedisReply { 45 | public: 46 | RedisReply(redisReply* r) { reply = r; } 47 | RedisReply(const RedisReply& r) { reply = r.reply; } 48 | RedisReply() { reply = NULL; } 49 | ~RedisReply() { } 50 | 51 | inline int32_t type() const { return reply->type; } 52 | inline long long integer() const { return reply->integer; } 53 | inline int32_t len() const { return reply->len; } 54 | inline char* str() const { return reply->str; } 55 | inline size_t elements() const { return reply->elements; } 56 | inline struct RedisReply element(uint32_t index) const 57 | { 58 | return RedisReply(reply->element[index]); 59 | } 60 | 61 | private: 62 | friend class RedisResult; 63 | redisReply* reply; 64 | }; 65 | 66 | inline void Init(redisReply* r) 67 | { 68 | if (Reply.reply) { 69 | freeReplyObject((void*)Reply.reply); 70 | } 71 | Reply.reply = r; 72 | } 73 | inline int32_t type() const { return Reply.type(); } 74 | inline long long integer() const { return Reply.integer(); } 75 | inline int32_t len() const { return Reply.len(); } 76 | inline char* str() const { return Reply.str(); } 77 | inline size_t elements() const { return Reply.elements(); } 78 | inline RedisReply element(uint32_t index) const { return Reply.element(index); } 79 | 80 | private: 81 | RedisReply Reply; 82 | }; 83 | 84 | class xRedisClusterClient { 85 | public: 86 | xRedisClusterClient(); 87 | ~xRedisClusterClient(); 88 | 89 | public: 90 | bool connect(const std::string& host, uint32_t port, 91 | const std::string& pass, uint32_t poolsize); 92 | void keepalive(); 93 | bool commandArgv(const VString& vDataIn, RedisResult& result); 94 | bool command(RedisResult& result, const char* format, ...); 95 | void setLogLevel(uint32_t level, void (*emit)(int level, const char* line)); 96 | 97 | private: 98 | xRedisClusterManager* mClusterManager_free; 99 | xRedisClusterManager* mClusterManager; 100 | ClusterInfo* mRedisInfo; 101 | }; 102 | 103 | } // namespace xrc 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /src/xRedisClusterManager.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #ifndef _XREDIS_CLUSTER_MANAGER_H_ 10 | #define _XREDIS_CLUSTER_MANAGER_H_ 11 | 12 | #include "hiredis.h" 13 | #include "xLock.h" 14 | #include "xRedisLog.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #ifdef _WIN32 25 | #define strcasecmp stricmp 26 | #define strncasecmp strnicmp 27 | #define usleep(us) Sleep((us)/1000) 28 | #define pthread_self() GetCurrentThreadId() 29 | #endif 30 | 31 | namespace xrc { 32 | 33 | #define MAX_REDIS_POOLSIZE 128 34 | #define MAX_TIME_OUT 5 35 | 36 | typedef std::vector VSTRING; 37 | 38 | class RedisResult; 39 | typedef struct _REDISCONN_ { 40 | _REDISCONN_() 41 | { 42 | mCtx = NULL; 43 | mPort = 0; 44 | mPoolSize = 0; 45 | } 46 | ~_REDISCONN_() { } 47 | 48 | redisContext* connectWithTimeout() 49 | { 50 | struct timeval timeoutVal; 51 | timeoutVal.tv_sec = MAX_TIME_OUT; 52 | timeoutVal.tv_usec = 0; 53 | 54 | redisContext* ctx = NULL; 55 | ctx = redisConnectWithTimeout(mHost.c_str(), mPort, timeoutVal); 56 | if (NULL == ctx || ctx->err) { 57 | if (NULL != ctx) { 58 | redisFree(ctx); 59 | ctx = NULL; 60 | } else { 61 | } 62 | } 63 | 64 | return ctx; 65 | } 66 | bool ping() 67 | { 68 | redisReply* reply = static_cast(redisCommand(mCtx, "PING")); 69 | bool bRet = (NULL != reply) && (reply->str) && (strcasecmp(reply->str, "PONG") == 0); 70 | if (bRet) { 71 | freeReplyObject(reply); 72 | } 73 | return bRet; 74 | } 75 | bool redisReConnect() 76 | { 77 | bool bRet = false; 78 | redisContext* tmp_ctx = connectWithTimeout(); 79 | if (NULL == tmp_ctx) { 80 | bRet = false; 81 | } else { 82 | if (NULL != mCtx) { 83 | redisFree(mCtx); 84 | } 85 | mCtx = tmp_ctx; 86 | bRet = auth(); 87 | } 88 | return bRet; 89 | } 90 | 91 | bool auth() 92 | { 93 | bool bRet = false; 94 | if (0 == mPass.length()) { 95 | bRet = true; 96 | } else { 97 | redisReply* reply = static_cast( 98 | redisCommand(mCtx, "AUTH %s", mPass.c_str())); 99 | if ((NULL == reply) || (strcasecmp(reply->str, "OK") != 0)) { 100 | bRet = false; 101 | } else { 102 | bRet = true; 103 | } 104 | freeReplyObject(reply); 105 | } 106 | xredis_debug("auth %s:%u %s %d", mHost.c_str(), mPort, mPass.c_str(), bRet); 107 | return bRet; 108 | } 109 | 110 | redisContext* mCtx; 111 | std::string mHost; 112 | std::string mPass; 113 | uint32_t mPort; 114 | uint32_t mPoolSize; 115 | uint32_t mIndex; 116 | } RedisConnection; 117 | 118 | typedef std::list RedisConnectionList; 119 | typedef std::list::iterator RedisConnectionIter; 120 | 121 | struct NodeInfo { 122 | std::string strinfo; 123 | std::string id; 124 | std::string ip; // The node IP 125 | uint16_t port; // The node port 126 | std::string flags; // A list of comma separated flags: myself, master, slave, fail?, fail, handshake, noaddr, noflags 127 | bool is_fail; 128 | bool is_master; // true if node is master, false if node is salve 129 | bool is_slave; 130 | std::string master_id; // The replication master 131 | int32_t ping_sent; // Milliseconds unix time at which the currently active ping was sent, or zero if there are no pending pings 132 | int32_t pong_recv; // Milliseconds unix time the last pong was received 133 | int32_t epoch; // 134 | bool connected; // The state of the link used for the node-to-node cluster 135 | std::vector > mSlots; 136 | 137 | bool checkSlot(uint32_t slotindex) 138 | { 139 | std::vector >::const_iterator citer = mSlots.begin(); 140 | for (; citer != mSlots.end(); ++citer) { 141 | //xredis_debug("check %u [%u, %u]\n", slotindex, citer->first, citer->second); 142 | if ((slotindex >= citer->first) && (slotindex <= citer->second)) { 143 | return true; 144 | } 145 | } 146 | return false; 147 | } 148 | 149 | void parse_role(const std::string& nodeString) 150 | { 151 | const char* p = strstr(nodeString.c_str(), "master"); 152 | if (NULL != p) { 153 | is_master = true; 154 | is_slave = false; 155 | } 156 | 157 | p = strstr(nodeString.c_str(), "slave"); 158 | if (NULL != p) { 159 | is_master = false; 160 | is_slave = true; 161 | } 162 | 163 | p = strstr(nodeString.c_str(), "fail"); 164 | if (NULL != p) { 165 | is_fail = true; 166 | } else { 167 | is_fail = false; 168 | } 169 | } 170 | 171 | bool parse_host(const std::string& nodeString) 172 | { 173 | std::string::size_type ColonPos = nodeString.find(':'); 174 | if (ColonPos == std::string::npos) { 175 | return false; 176 | } else { 177 | const std::string port_str = nodeString.substr(ColonPos + 1); 178 | port = atoi(port_str.c_str()); 179 | ip = nodeString.substr(0, ColonPos); 180 | return true; 181 | } 182 | } 183 | 184 | void parse_slot(const std::string& SlotString) 185 | { 186 | if (0 == SlotString.length()) { 187 | xredis_warn("SlotString is NULL "); 188 | return; 189 | } 190 | 191 | uint32_t StartSlot = 0; 192 | uint32_t EndSlot = 0; 193 | std::string::size_type BarPos = SlotString.find('-'); 194 | if (BarPos == std::string::npos) { 195 | StartSlot = atoi(SlotString.c_str()); 196 | EndSlot = StartSlot; 197 | } else { 198 | const std::string EndSlotStr = SlotString.substr(BarPos + 1); 199 | EndSlot = atoi(EndSlotStr.c_str()); 200 | StartSlot = atoi(SlotString.substr(0, BarPos).c_str()); 201 | } 202 | mSlots.push_back(std::make_pair(StartSlot, EndSlot)); 203 | 204 | xredis_debug("%s mSlots:%u", SlotString.c_str(), mSlots.size()); 205 | } 206 | }; 207 | 208 | typedef std::vector NODELIST; 209 | 210 | class ClusterInfo { 211 | public: 212 | ClusterInfo() { } 213 | ~ClusterInfo() { } 214 | NODELIST nodes; 215 | std::string pass; 216 | uint32_t poolsize; 217 | bool clusterEnabled; 218 | }; 219 | 220 | class xRedisClusterManager { 221 | public: 222 | xRedisClusterManager(); 223 | ~xRedisClusterManager(); 224 | 225 | private: 226 | public: 227 | static bool auth(redisContext* c, const std::string& pass); 228 | bool connectCluster(const ClusterInfo* cluster_info); 229 | void keepalive(); 230 | bool commandArgv(const VSTRING& vDataIn, RedisResult& result); 231 | bool command(RedisResult& result, const char* format, const char* key, va_list args); 232 | 233 | RedisConnection* get_cluster_info(ClusterInfo& ClusterInfo); 234 | bool check_cluster_info(ClusterInfo& cinfo); 235 | 236 | static bool Sort_asc(const NodeInfo& a, const NodeInfo& b) 237 | { 238 | return (a.id < b.id); 239 | } 240 | 241 | void bfree() 242 | { 243 | bFree = true; 244 | } 245 | 246 | private: 247 | static uint16_t crc16(const char* buf, int32_t len); 248 | static bool checkReply(const redisReply* reply); 249 | static void freeReply(const redisReply* reply); 250 | static int32_t str2Vect(const char* pSrc, std::vector& vDest, 251 | const char* pSep = ","); 252 | 253 | public: 254 | static bool clusterEnabled(redisContext* ctx); 255 | static bool clusterState(redisContext* ctx); 256 | static bool clusterNodes(redisContext* ctx, ClusterInfo* info); 257 | void freeConnection(RedisConnection* pRedis); 258 | bool release(); 259 | 260 | static xRedisClusterManager* connectRedis(const std::string& host, uint32_t port, 261 | const std::string& pass, uint32_t poolsize, ClusterInfo*& info); 262 | 263 | private: 264 | bool connectRedisNode(int idx, const std::string& host, uint32_t port, 265 | const std::string& pass, uint32_t poolsize); 266 | bool checkReply(redisReply* reply); 267 | uint32_t keyHashSlot(const char* key, size_t keylen); 268 | 269 | RedisConnection* getConnection(uint32_t idx); 270 | 271 | uint32_t findNodeIndex(uint32_t slot); 272 | uint32_t getKeySlotIndex(const char* key); 273 | RedisConnection* findNodeConnection(const char* key); 274 | 275 | private: 276 | RedisConnectionList* mRedisConnList; 277 | xLock* mLock; 278 | ClusterInfo mClusterInfo; 279 | bool bFree; 280 | }; 281 | 282 | } 283 | #endif 284 | -------------------------------------------------------------------------------- /src/xRedisLog.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisLog.h" 10 | #include 11 | #include 12 | 13 | namespace xrc { 14 | 15 | const char* const _errstr[] = { "\033[01;31mERROR\033[0m", "\033[01;33mWARN \033[0m", "\033[01;37mINFO \033[0m", "\033[22;34mDEBUG\033[0m" }; 16 | static void (*log_fn)(int level, const char* line) = NULL; 17 | uint32_t _level = LOG_LEVEL_INFO; 18 | 19 | void set_log_level(uint32_t level, void (*call_fn)(int level, const char* line)) 20 | { 21 | _level = level; 22 | log_fn = call_fn; 23 | } 24 | 25 | void log_message(uint32_t level, const char* function, int line, const char* fmt, ...) 26 | { 27 | if (level > _level) { 28 | return; 29 | } 30 | 31 | time_t t; 32 | time(&t); 33 | struct tm tm; 34 | 35 | #ifdef _WIN32 36 | ::localtime_s(&tm, (const time_t*)&t); 37 | #else 38 | ::localtime_r((const time_t*)&t, &tm); 39 | #endif 40 | 41 | char data1[DATA_BUF + 4]; 42 | int i = 0; 43 | va_list args; 44 | va_start(args, fmt); 45 | i = vsnprintf(data1, DATA_BUF, fmt, args); 46 | va_end(args); 47 | 48 | if (i > (int)DATA_BUF - 1) { 49 | i = DATA_BUF - 5; 50 | data1[i++] = '.'; 51 | data1[i++] = '.'; 52 | data1[i++] = '.'; 53 | data1[i++] = '\n'; 54 | data1[i] = '\0'; 55 | } else { 56 | if (i > 0) { 57 | if (data1[i - 1] != '\n') { 58 | data1[i++] = '\n'; 59 | data1[i] = '\0'; 60 | } 61 | } 62 | } 63 | 64 | while (data1[i - 2] == '\n') 65 | i--; 66 | data1[i] = '\0'; 67 | 68 | if (log_fn) { 69 | log_fn(level, data1); 70 | } else { 71 | printf("[%04d-%02d-%02d %02d:%02d:%02d] %-5s %s:%d %s", 72 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 73 | tm.tm_hour, tm.tm_min, tm.tm_sec, 74 | _errstr[level], function, line, data1); 75 | } 76 | } 77 | 78 | } // namespace xrc 79 | 80 | -------------------------------------------------------------------------------- /src/xRedisLog.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ---------------------------------------------------------------------------- 4 | * Copyright (c) 2013-2021, xSky 5 | * All rights reserved. 6 | * Distributed under GPL license. 7 | * ---------------------------------------------------------------------------- 8 | */ 9 | 10 | #ifndef _XREDIS_LOG_H_ 11 | #define _XREDIS_LOG_H_ 12 | 13 | #include "xRedisClient.h" 14 | #include 15 | #include 16 | 17 | namespace xrc { 18 | 19 | #define xredis_error(...) log_message(LOG_LEVEL_ERROR, __FUNCTION__, __LINE__, __VA_ARGS__) 20 | #define xredis_warn(...) log_message(LOG_LEVEL_WARN, __FUNCTION__, __LINE__, __VA_ARGS__) 21 | #define xredis_info(...) log_message(LOG_LEVEL_INFO, __FUNCTION__, __LINE__, __VA_ARGS__) 22 | #define xredis_debug(...) log_message(LOG_LEVEL_DEBUG, __FUNCTION__, __LINE__, __VA_ARGS__) 23 | 24 | #define DATA_BUF 4096 25 | 26 | void log_message(uint32_t level, const char* function, int line, const char* fmt, ...); 27 | void set_log_level(uint32_t level, void (*emit)(int level, const char* line)); 28 | 29 | } // namespace xrc 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/xRedisPool.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #include "xRedisPool.h" 10 | #include "hiredis.h" 11 | #include "xRedisLog.h" 12 | #include 13 | 14 | namespace xrc { 15 | 16 | RedisPool::RedisPool() 17 | { 18 | mRedisGroupList = NULL; 19 | mTypeSize = 0; 20 | srand((unsigned)time(NULL)); 21 | } 22 | 23 | RedisPool::~RedisPool() { } 24 | 25 | bool RedisPool::Init(uint32_t typesize) 26 | { 27 | mTypeSize = typesize; 28 | if (mTypeSize > MAX_REDIS_CACHE_TYPE) { 29 | return false; 30 | } 31 | 32 | mRedisGroupList = new RedisGroup[mTypeSize]; 33 | return mRedisGroupList != NULL; 34 | } 35 | 36 | bool RedisPool::SetHashBase(uint32_t cachetype, uint32_t hashbase) 37 | { 38 | if ((hashbase > MAX_REDIS_DB_HASHBASE) || (cachetype > mTypeSize - 1)) { 39 | return false; 40 | } 41 | bool bRet = mRedisGroupList[cachetype].InitDB(cachetype, hashbase); 42 | return bRet; 43 | } 44 | 45 | uint32_t RedisPool::GetHashBase(uint32_t cachetype) 46 | { 47 | if ((cachetype > mTypeSize) || (cachetype > MAX_REDIS_CACHE_TYPE)) { 48 | return 0; 49 | } 50 | return mRedisGroupList[cachetype].GetHashBase(); 51 | } 52 | 53 | void RedisPool::Keepalive() 54 | { 55 | for (uint32_t i = 0; i < mTypeSize; i++) { 56 | if (mRedisGroupList[i].GetHashBase() > 0) { 57 | mRedisGroupList[i].KeepAlive(); 58 | } 59 | } 60 | } 61 | 62 | bool RedisPool::CheckReply(const redisReply* reply) 63 | { 64 | if (NULL == reply) { 65 | return false; 66 | } 67 | 68 | switch (reply->type) { 69 | case REDIS_REPLY_STRING: { 70 | return true; 71 | } 72 | case REDIS_REPLY_ARRAY: { 73 | return true; 74 | } 75 | case REDIS_REPLY_INTEGER: { 76 | return true; 77 | } 78 | case REDIS_REPLY_NIL: { 79 | return false; 80 | } 81 | case REDIS_REPLY_STATUS: { 82 | return true; 83 | } 84 | case REDIS_REPLY_ERROR: { 85 | return false; 86 | } 87 | default: { 88 | return false; 89 | } 90 | } 91 | 92 | return false; 93 | } 94 | 95 | void RedisPool::FreeReply(const redisReply* reply) 96 | { 97 | if (NULL != reply) { 98 | freeReplyObject((void*)reply); 99 | } 100 | } 101 | 102 | bool RedisPool::ConnectRedisGroup(uint32_t cachetype, uint32_t dbindex, 103 | const std::string& host, uint32_t port, 104 | const std::string& passwd, uint32_t poolsize, 105 | uint32_t timeout, uint32_t role) 106 | { 107 | if ((0 == host.length()) || (cachetype > MAX_REDIS_CACHE_TYPE) || (dbindex > MAX_REDIS_DB_HASHBASE) 108 | || (cachetype > mTypeSize - 1) || (role > SLAVE) || (poolsize > MAX_REDIS_CONN_POOLSIZE)) { 109 | xredis_error("ConnectRedisDB cachetype:%u dbindex:%u host:%s port:%u passwd:%s poolsize:%u timeout:%u role:%u", 110 | cachetype, dbindex, host.c_str(), port, passwd.c_str(), poolsize, timeout, role); 111 | return false; 112 | } 113 | 114 | return mRedisGroupList[cachetype].ConnectRedisGroup( 115 | cachetype, dbindex, host, port, passwd, poolsize, timeout, role); 116 | } 117 | 118 | void RedisPool::Release() 119 | { 120 | for (uint32_t i = 0; i < mTypeSize; i++) { 121 | if (mRedisGroupList[i].GetHashBase() > 0) { 122 | mRedisGroupList[i].ClosePool(); 123 | } 124 | } 125 | delete[] mRedisGroupList; 126 | } 127 | 128 | RedisConnection* RedisPool::GetConnection(uint32_t cachetype, uint32_t dbindex, 129 | uint32_t ioType) 130 | { 131 | RedisConnection* pRedisConn = NULL; 132 | 133 | if ((cachetype > mTypeSize) || (dbindex > mRedisGroupList[cachetype].GetHashBase()) || (ioType > SLAVE)) { 134 | return NULL; 135 | } 136 | 137 | RedisGroup* pRedisCache = &mRedisGroupList[cachetype]; 138 | pRedisConn = pRedisCache->GetConn(dbindex, ioType); 139 | 140 | return pRedisConn; 141 | } 142 | 143 | void RedisPool::FreeConnection(RedisConnection* redisconn) 144 | { 145 | if (NULL != redisconn) { 146 | mRedisGroupList[redisconn->GetType()].FreeConn(redisconn); 147 | } 148 | } 149 | 150 | RedisConnection::RedisConnection() 151 | { 152 | mCtx = NULL; 153 | mPort = 0; 154 | mTimeout = 0; 155 | mPoolsize = 0; 156 | mType = 0; 157 | mSliceIndex = 0; 158 | mConnStatus = false; 159 | } 160 | 161 | RedisConnection::~RedisConnection() { } 162 | 163 | redisContext* RedisConnection::ConnectWithTimeout() 164 | { 165 | struct timeval timeoutVal; 166 | timeoutVal.tv_sec = mTimeout; 167 | timeoutVal.tv_usec = 0; 168 | 169 | redisContext* ctx = NULL; 170 | ctx = redisConnectWithTimeout(mHost.c_str(), mPort, timeoutVal); 171 | if (NULL == ctx || ctx->err) { 172 | xredis_info("ConnectWithTimeout auth failed dbindex:%u host:%s port:%u passwd:%s poolsize:%u timeout:%u role:%u", 173 | mSliceIndex, mHost.c_str(), mPort, mPass.c_str(), mPoolsize, mTimeout, mRole); 174 | if (NULL != ctx) { 175 | redisFree(ctx); 176 | ctx = NULL; 177 | } else { 178 | } 179 | } 180 | 181 | return ctx; 182 | } 183 | 184 | bool RedisConnection::Auth() 185 | { 186 | bool bRet = false; 187 | if (0 == mPass.length()) { 188 | bRet = true; 189 | } else { 190 | redisReply* reply = static_cast(redisCommand(mCtx, "AUTH %s", mPass.c_str())); 191 | if ((NULL == reply) || (strcasecmp(reply->str, "OK") != 0)) { 192 | xredis_error("auth failed dbindex:%u host:%s port:%u passwd:%s poolsize:%u timeout:%u role:%u", 193 | mSliceIndex, mHost.c_str(), mPort, mPass.c_str(), mPoolsize, mTimeout, mRole); 194 | bRet = false; 195 | } else { 196 | xredis_info("auth success dbindex:%u host:%s port:%u passwd:%s poolsize:%u timeout:%u role:%u", 197 | mSliceIndex, mHost.c_str(), mPort, mPass.c_str(), mPoolsize, mTimeout, mRole); 198 | bRet = true; 199 | } 200 | freeReplyObject(reply); 201 | } 202 | 203 | return bRet; 204 | } 205 | 206 | bool RedisConnection::RedisConnect() 207 | { 208 | bool bRet = false; 209 | if (NULL != mCtx) { 210 | redisFree(mCtx); 211 | mCtx = NULL; 212 | } 213 | 214 | mCtx = ConnectWithTimeout(); 215 | if (NULL == mCtx) { 216 | bRet = false; 217 | } else { 218 | bRet = Auth(); 219 | mConnStatus = bRet; 220 | } 221 | 222 | return bRet; 223 | } 224 | 225 | bool RedisConnection::RedisReConnect() 226 | { 227 | if (NULL == mCtx) { 228 | return false; 229 | } 230 | 231 | bool bRet = false; 232 | redisContext* tmp_ctx = ConnectWithTimeout(); 233 | if (NULL == tmp_ctx) { 234 | xredis_warn("RedisReConnect failed dbindex:%u host:%s port:%u passwd:%s poolsize:%u timeout:%u role:%u", 235 | mSliceIndex, mHost.c_str(), mPort, mPass.c_str(), mPoolsize, mTimeout, mRole); 236 | bRet = false; 237 | } else { 238 | redisFree(mCtx); 239 | mCtx = tmp_ctx; 240 | bRet = Auth(); 241 | } 242 | 243 | mConnStatus = bRet; 244 | return bRet; 245 | } 246 | 247 | bool RedisConnection::Ping() 248 | { 249 | redisReply* reply = static_cast(redisCommand(mCtx, "PING")); 250 | bool bRet = (NULL != reply) && (reply->str) && (strcasecmp(reply->str, "PONG") == 0); 251 | mConnStatus = bRet; 252 | if (bRet) { 253 | freeReplyObject(reply); 254 | } 255 | if (bRet) { 256 | xredis_warn("Ping failed dbindex:%u host:%s port:%u passwd:%s poolsize:%u timeout:%u role:%u", 257 | mSliceIndex, mHost.c_str(), mPort, mPass.c_str(), mPoolsize, mTimeout, mRole); 258 | } 259 | return bRet; 260 | } 261 | 262 | void RedisConnection::Init(uint32_t cahcetype, uint32_t dbindex, 263 | const std::string& host, uint32_t port, 264 | const std::string& pass, uint32_t poolsize, 265 | uint32_t timeout, uint32_t role, uint32_t slaveidx) 266 | { 267 | mType = cahcetype; 268 | mSliceIndex = dbindex; 269 | mHost = host; 270 | mPort = port; 271 | mPass = pass; 272 | mPoolsize = poolsize; 273 | mTimeout = timeout; 274 | mRole = role; 275 | mSlaveIdx = slaveidx; 276 | } 277 | 278 | RedisSlice::RedisSlice() 279 | { 280 | mType = 0; 281 | mSliceindex = 0; 282 | mStatus = 0; 283 | mHaveSlave = false; 284 | } 285 | 286 | RedisSlice::~RedisSlice() { } 287 | 288 | void RedisSlice::Init(uint32_t cahcetype, uint32_t dbindex) 289 | { 290 | mType = cahcetype; 291 | mSliceindex = dbindex; 292 | } 293 | 294 | bool RedisSlice::ConnectRedisSlice(uint32_t cahcetype, uint32_t dbindex, 295 | const std::string& host, uint32_t port, 296 | const std::string& passwd, 297 | uint32_t poolsize, uint32_t timeout, 298 | int32_t role) 299 | { 300 | bool bRet = false; 301 | if ((host.empty()) || (cahcetype > MAX_REDIS_CACHE_TYPE) || (dbindex > MAX_REDIS_DB_HASHBASE) || (poolsize > MAX_REDIS_CONN_POOLSIZE)) { 302 | return false; 303 | } 304 | 305 | try { 306 | if (MASTER == role) { 307 | XLOCK(mSliceConn.MasterLock); 308 | for (uint32_t i = 0; i < poolsize; ++i) { 309 | RedisConnection* pRedisconn = new RedisConnection; 310 | if (NULL == pRedisconn) { 311 | continue; 312 | } 313 | 314 | pRedisconn->Init(cahcetype, dbindex, host, port, passwd, poolsize, 315 | timeout, role, 0); 316 | if (pRedisconn->RedisConnect()) { 317 | mSliceConn.RedisMasterConnection.push_back(pRedisconn); 318 | mStatus = REDISDB_WORKING; 319 | bRet = true; 320 | } else { 321 | delete pRedisconn; 322 | } 323 | } 324 | 325 | } else if (SLAVE == role) { 326 | XLOCK(mSliceConn.SlaveLock); 327 | RedisConnectionPool* pSlaveNode = new RedisConnectionPool; 328 | int32_t slave_idx = mSliceConn.RedisSlaveConnection.size(); 329 | for (uint32_t i = 0; i < poolsize; ++i) { 330 | RedisConnection* pRedisconn = new RedisConnection; 331 | if (NULL == pRedisconn) { 332 | continue; 333 | } 334 | 335 | pRedisconn->Init(cahcetype, dbindex, host, port, passwd, poolsize, 336 | timeout, role, slave_idx); 337 | if (pRedisconn->RedisConnect()) { 338 | pSlaveNode->push_back(pRedisconn); 339 | bRet = true; 340 | } else { 341 | delete pRedisconn; 342 | } 343 | } 344 | mSliceConn.RedisSlaveConnection.push_back(pSlaveNode); 345 | mHaveSlave = true; 346 | } else { 347 | bRet = false; 348 | } 349 | 350 | } catch (...) { 351 | return false; 352 | } 353 | 354 | return bRet; 355 | } 356 | 357 | RedisConnection* RedisSlice::GetMasterConn() 358 | { 359 | RedisConnection* pRedisConn = NULL; 360 | XLOCK(mSliceConn.MasterLock); 361 | if (!mSliceConn.RedisMasterConnection.empty()) { 362 | pRedisConn = mSliceConn.RedisMasterConnection.front(); 363 | mSliceConn.RedisMasterConnection.pop_front(); 364 | } else { 365 | mStatus = REDISDB_DEAD; 366 | } 367 | return pRedisConn; 368 | } 369 | 370 | RedisConnection* RedisSlice::GetSlaveConn() 371 | { 372 | RedisConnection* pRedisConn = NULL; 373 | XLOCK(mSliceConn.SlaveLock); 374 | if (!mSliceConn.RedisSlaveConnection.empty()) { 375 | size_t slave_cnt = mSliceConn.RedisSlaveConnection.size(); 376 | uint32_t idx = rand() % slave_cnt; 377 | RedisConnectionPool* pSlave = mSliceConn.RedisSlaveConnection[idx]; 378 | pRedisConn = pSlave->front(); 379 | pSlave->pop_front(); 380 | // if (idx != pRedisConn->GetSlaveIdx()) { 381 | //} 382 | } 383 | return pRedisConn; 384 | } 385 | 386 | RedisConnection* RedisSlice::GetConn(int32_t ioRole) 387 | { 388 | RedisConnection* pRedisConn = NULL; 389 | if (!mHaveSlave) { 390 | ioRole = MASTER; 391 | } 392 | if (MASTER == ioRole) { 393 | pRedisConn = GetMasterConn(); 394 | } else if (SLAVE == ioRole) { 395 | pRedisConn = GetSlaveConn(); 396 | } else { 397 | pRedisConn = NULL; 398 | } 399 | 400 | return pRedisConn; 401 | } 402 | 403 | void RedisSlice::FreeConn(RedisConnection* redisconn) 404 | { 405 | if (NULL != redisconn) { 406 | uint32_t role = redisconn->GetRole(); 407 | if (MASTER == role) { 408 | XLOCK(mSliceConn.MasterLock); 409 | mSliceConn.RedisMasterConnection.push_back(redisconn); 410 | } else if (SLAVE == role) { 411 | XLOCK(mSliceConn.SlaveLock); 412 | RedisConnectionPool* pSlave = mSliceConn.RedisSlaveConnection[redisconn->GetSlaveIdx()]; 413 | pSlave->push_back(redisconn); 414 | } else { 415 | } 416 | } 417 | } 418 | 419 | void RedisSlice::CloseConnPool() 420 | { 421 | { 422 | XLOCK(mSliceConn.MasterLock); 423 | RedisConnectionIter master_iter = mSliceConn.RedisMasterConnection.begin(); 424 | for (; master_iter != mSliceConn.RedisMasterConnection.end(); ++master_iter) { 425 | redisFree((*master_iter)->GetCtx()); 426 | delete *master_iter; 427 | } 428 | } 429 | 430 | { 431 | XLOCK(mSliceConn.SlaveLock); 432 | RedisSlaveGroupIter slave_iter = mSliceConn.RedisSlaveConnection.begin(); 433 | for (; slave_iter != mSliceConn.RedisSlaveConnection.end(); ++slave_iter) { 434 | RedisConnectionPool* pConnPool = (*slave_iter); 435 | RedisConnectionIter iter = pConnPool->begin(); 436 | for (; iter != pConnPool->end(); ++iter) { 437 | redisFree((*iter)->GetCtx()); 438 | delete *iter; 439 | } 440 | delete pConnPool; 441 | } 442 | } 443 | 444 | mStatus = REDISDB_DEAD; 445 | } 446 | 447 | void RedisSlice::ConnPoolPing() 448 | { 449 | { 450 | XLOCK(mSliceConn.MasterLock); 451 | RedisConnectionIter master_iter = mSliceConn.RedisMasterConnection.begin(); 452 | for (; master_iter != mSliceConn.RedisMasterConnection.end(); ++master_iter) { 453 | bool bRet = (*master_iter)->Ping(); 454 | if (!bRet) { 455 | (*master_iter)->RedisReConnect(); 456 | } else { 457 | } 458 | } 459 | } 460 | 461 | { 462 | XLOCK(mSliceConn.SlaveLock); 463 | RedisSlaveGroupIter slave_iter = mSliceConn.RedisSlaveConnection.begin(); 464 | for (; slave_iter != mSliceConn.RedisSlaveConnection.end(); ++slave_iter) { 465 | RedisConnectionPool* pConnPool = (*slave_iter); 466 | RedisConnectionIter iter = pConnPool->begin(); 467 | for (; iter != pConnPool->end(); ++iter) { 468 | bool bRet = (*iter)->Ping(); 469 | if (!bRet) { 470 | (*iter)->RedisReConnect(); 471 | } else { 472 | } 473 | } 474 | } 475 | } 476 | } 477 | 478 | uint32_t RedisSlice::GetStatus() const { return mStatus; } 479 | 480 | RedisGroup::RedisGroup() 481 | { 482 | mCachetype = 0; 483 | mHashbase = 0; 484 | mSliceList = NULL; 485 | } 486 | 487 | RedisGroup::~RedisGroup() { } 488 | 489 | bool RedisGroup::InitDB(uint32_t cachetype, uint32_t hashbase) 490 | { 491 | mCachetype = cachetype; 492 | mHashbase = hashbase; 493 | if (NULL == mSliceList) { 494 | mSliceList = new RedisSlice[hashbase]; 495 | } 496 | 497 | return true; 498 | } 499 | 500 | bool RedisGroup::ConnectRedisGroup(uint32_t cahcetype, uint32_t dbindex, 501 | const std::string& host, uint32_t port, 502 | const std::string& passwd, uint32_t poolsize, 503 | uint32_t timeout, uint32_t role) 504 | { 505 | mSliceList[dbindex].Init(cahcetype, dbindex); 506 | return mSliceList[dbindex].ConnectRedisSlice(cahcetype, dbindex, host, port, 507 | passwd, poolsize, timeout, role); 508 | } 509 | 510 | void RedisGroup::ClosePool() 511 | { 512 | for (uint32_t i = 0; i < mHashbase; i++) { 513 | mSliceList[i].CloseConnPool(); 514 | } 515 | delete[] mSliceList; 516 | mSliceList = NULL; 517 | } 518 | 519 | void RedisGroup::KeepAlive() 520 | { 521 | for (uint32_t i = 0; i < mHashbase; i++) { 522 | mSliceList[i].ConnPoolPing(); 523 | } 524 | } 525 | 526 | uint32_t RedisGroup::GetDBStatus(uint32_t dbindex) 527 | { 528 | RedisSlice* pdbSclice = &mSliceList[dbindex]; 529 | if (NULL == pdbSclice) { 530 | return REDISDB_UNCONN; 531 | } 532 | return pdbSclice->GetStatus(); 533 | } 534 | 535 | void RedisGroup::FreeConn(RedisConnection* redisconn) 536 | { 537 | return mSliceList[redisconn->GetdbIndex()].FreeConn(redisconn); 538 | } 539 | 540 | RedisConnection* RedisGroup::GetConn(uint32_t dbindex, uint32_t ioRole) 541 | { 542 | return mSliceList[dbindex].GetConn(ioRole); 543 | } 544 | 545 | uint32_t RedisGroup::GetHashBase() const { return mHashbase; } 546 | } // namespace xrc 547 | -------------------------------------------------------------------------------- /src/xRedisPool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * Copyright (c) 2013-2021, xSky 4 | * All rights reserved. 5 | * Distributed under GPL license. 6 | * ---------------------------------------------------------------------------- 7 | */ 8 | 9 | #ifndef _XREDIS_POOL_H_ 10 | #define _XREDIS_POOL_H_ 11 | 12 | #include "hiredis.h" 13 | #include "xLock.h" 14 | #include "xRedisClient.h" 15 | #include 16 | #include 17 | #include 18 | 19 | namespace xrc { 20 | 21 | #define MAX_REDIS_CONN_POOLSIZE 128 // 每个DB最大连接数 22 | #define MAX_REDIS_CACHE_TYPE 128 // 最大支持的CACHE种类数 23 | #define MAX_REDIS_DB_HASHBASE 128 // 最大HASH分库基数 24 | 25 | #define GET_CONNECT_ERROR "get connection error" 26 | #define CONNECT_CLOSED_ERROR "redis connection be closed" 27 | 28 | #ifdef WIN32 29 | #define strcasecmp stricmp 30 | #define strncasecmp strnicmp 31 | #define usleep(us) Sleep((us)/1000) 32 | #define pthread_self() GetCurrentThreadId() 33 | #endif 34 | 35 | enum { REDISDB_UNCONN, 36 | REDISDB_WORKING, 37 | REDISDB_DEAD }; 38 | 39 | class RedisConnection { 40 | public: 41 | RedisConnection(); 42 | ~RedisConnection(); 43 | 44 | void Init(uint32_t cahcetype, uint32_t sliceindex, const std::string& host, 45 | uint32_t port, const std::string& pass, uint32_t poolsize, 46 | uint32_t timeout, uint32_t role, uint32_t slaveidx); 47 | 48 | bool RedisConnect(); 49 | bool RedisReConnect(); 50 | bool Ping(); 51 | 52 | redisContext* GetCtx() const { return mCtx; } 53 | uint32_t GetdbIndex() const { return mSliceIndex; } 54 | uint32_t GetType() const { return mType; } 55 | uint32_t GetRole() const { return mRole; } 56 | uint32_t GetSlaveIdx() const { return mSlaveIdx; } 57 | bool GetConnstatus() const { return mConnStatus; } 58 | 59 | private: 60 | bool Auth(); 61 | redisContext* ConnectWithTimeout(); 62 | 63 | private: 64 | // redis connector context 65 | redisContext* mCtx; 66 | std::string mHost; // redis host 67 | uint32_t mPort; // redis sever port 68 | std::string mPass; // redis server password 69 | uint32_t mTimeout; // connect timeout second 70 | uint32_t mPoolsize; // connect pool size for each redis DB 71 | uint32_t mType; // redis cache pool type 72 | uint32_t mSliceIndex; // redis DB index 73 | uint32_t mRole; // redis role 74 | uint32_t mSlaveIdx; // the index in the slave group 75 | bool mConnStatus; // redis connection status 76 | }; 77 | 78 | typedef std::list RedisConnectionPool; 79 | typedef std::list::iterator RedisConnectionIter; 80 | 81 | typedef std::vector RedisSlaveGroup; 82 | typedef std::vector::iterator RedisSlaveGroupIter; 83 | 84 | typedef struct _RedisSliceConn_ { 85 | RedisConnectionPool RedisMasterConnection; 86 | RedisSlaveGroup RedisSlaveConnection; 87 | xLock MasterLock; 88 | xLock SlaveLock; 89 | } RedisSliceConn; 90 | 91 | class RedisSlice { 92 | public: 93 | RedisSlice(); 94 | ~RedisSlice(); 95 | 96 | void Init(uint32_t cahcetype, uint32_t dbindex); 97 | // 连到到一个REDIS服务节点 98 | bool ConnectRedisSlice(uint32_t cahcetype, uint32_t dbindex, 99 | const std::string& host, uint32_t port, 100 | const std::string& passwd, uint32_t poolsize, 101 | uint32_t timeout, int32_t role); 102 | 103 | RedisConnection* GetMasterConn(); 104 | RedisConnection* GetSlaveConn(); 105 | RedisConnection* GetConn(int32_t ioRole); 106 | void FreeConn(RedisConnection* redisconn); 107 | void CloseConnPool(); 108 | void ConnPoolPing(); 109 | uint32_t GetStatus() const; 110 | 111 | private: 112 | RedisSliceConn mSliceConn; 113 | bool mHaveSlave; 114 | uint32_t mType; // redis cache pool type 115 | uint32_t mSliceindex; // redis slice index 116 | uint32_t mStatus; // redis slice status 117 | }; 118 | 119 | class RedisGroup { 120 | public: 121 | RedisGroup(); 122 | virtual ~RedisGroup(); 123 | 124 | bool InitDB(uint32_t cachetype, uint32_t hashbase); 125 | bool ConnectRedisGroup(uint32_t cahcetype, uint32_t dbindex, 126 | const std::string& host, uint32_t port, 127 | const std::string& passwd, uint32_t poolsize, 128 | uint32_t timeout, uint32_t role); 129 | 130 | RedisConnection* GetConn(uint32_t dbindex, uint32_t ioRole); 131 | void FreeConn(RedisConnection* redisconn); 132 | void ClosePool(); 133 | void KeepAlive(); 134 | uint32_t GetDBStatus(uint32_t dbindex); 135 | uint32_t GetHashBase() const; 136 | 137 | private: 138 | RedisSlice* mSliceList; 139 | uint32_t mCachetype; 140 | uint32_t mHashbase; 141 | }; 142 | 143 | class RedisPool { 144 | public: 145 | RedisPool(); 146 | ~RedisPool(); 147 | 148 | bool Init(uint32_t typesize); 149 | bool SetHashBase(uint32_t cachetype, uint32_t hashbase); 150 | uint32_t GetHashBase(uint32_t cachetype); 151 | bool ConnectRedisGroup(uint32_t cachetype, uint32_t sliceindex, 152 | const std::string& host, uint32_t port, 153 | const std::string& passwd, uint32_t poolsize, 154 | uint32_t timeout, uint32_t role); 155 | static bool CheckReply(const redisReply* reply); 156 | static void FreeReply(const redisReply* reply); 157 | 158 | RedisConnection* GetConnection(uint32_t cachetype, uint32_t index, 159 | uint32_t ioType = MASTER); 160 | void FreeConnection(RedisConnection* redisconn); 161 | 162 | void Keepalive(); 163 | void Release(); 164 | 165 | private: 166 | RedisGroup* mRedisGroupList; 167 | uint32_t mTypeSize; 168 | }; 169 | 170 | } // namespace xrc 171 | 172 | #endif 173 | -------------------------------------------------------------------------------- /test/xredis-test.cpp: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ---------------------------------------------------------------------------- 4 | * Copyright (c) 2013-2021, xSky 5 | * All rights reserved. 6 | * Distributed under GPL license. 7 | * ---------------------------------------------------------------------------- 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "xRedisClient.h" 16 | 17 | using namespace xrc; 18 | 19 | #define CACHE_TYPE_1 1 20 | xRedisClient xClient; 21 | 22 | // AP Hash Function 23 | unsigned int APHash(const char* str) 24 | { 25 | unsigned int hash = 0; 26 | int i; 27 | 28 | for (i = 0; *str; i++) { 29 | if ((i & 1) == 0) { 30 | hash ^= ((hash << 7) ^ (*str++) ^ (hash >> 3)); 31 | } else { 32 | hash ^= (~((hash << 11) ^ (*str++) ^ (hash >> 5))); 33 | } 34 | } 35 | 36 | return (hash & 0x7FFFFFFF); 37 | } 38 | 39 | void test_zadd(const char* key, const std::string& strValue) 40 | { 41 | std::string strkey = key; 42 | VALUES vVal; 43 | int64_t retVal = 0; 44 | int64_t scores = 168; 45 | vVal.push_back(toString(scores)); 46 | vVal.push_back(strValue); 47 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 48 | bool bRet = dbi.Create(key); 49 | if (bRet) { 50 | if (xClient.zadd(dbi, strkey, vVal, retVal)) { 51 | printf("%s success \r\n", __PRETTY_FUNCTION__); 52 | } else { 53 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 54 | } 55 | } 56 | } 57 | 58 | void test_set(const char* key, const char* strValue) 59 | { 60 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 61 | bool bRet = dbi.Create(key); 62 | if (bRet) { 63 | if (xClient.set(dbi, key, strValue)) { 64 | printf("%s success \r\n", __PRETTY_FUNCTION__); 65 | } else { 66 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 67 | } 68 | } 69 | } 70 | 71 | void test_append() 72 | { 73 | test_set("test", "hello"); 74 | char szKey[256] = { 0 }; 75 | strcpy(szKey, "test"); 76 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 77 | bool bRet = dbi.Create(szKey); 78 | if (bRet) { 79 | if (xClient.append(dbi, szKey, " xsky")) { 80 | printf("%s success \r\n", __PRETTY_FUNCTION__); 81 | } else { 82 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 83 | } 84 | } 85 | } 86 | 87 | void test_decr() 88 | { 89 | test_set("test", "100"); 90 | char szKey[256] = { 0 }; 91 | strcpy(szKey, "test"); 92 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 93 | bool bRet = dbi.Create(szKey); 94 | if (bRet) { 95 | int64_t res = 0; 96 | if (xClient.decr(dbi, szKey, res)) { 97 | if (res == 99) { 98 | printf("%s success %ld \r\n", __PRETTY_FUNCTION__, res); 99 | } else { 100 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 101 | } 102 | } else { 103 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 104 | } 105 | } 106 | } 107 | 108 | void test_decrby() 109 | { 110 | test_set("test", "100"); 111 | char szKey[256] = { 0 }; 112 | strcpy(szKey, "test"); 113 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 114 | bool bRet = dbi.Create(szKey); 115 | if (bRet) { 116 | int64_t res = 0; 117 | if (xClient.decrby(dbi, szKey, 11, res)) { 118 | if (res == 89) { 119 | printf("%s success %ld \r\n", __PRETTY_FUNCTION__, res); 120 | } else { 121 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 122 | } 123 | } else { 124 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 125 | } 126 | } 127 | } 128 | 129 | void test_incr() 130 | { 131 | test_set("test", "100"); 132 | char szKey[256] = { 0 }; 133 | strcpy(szKey, "test"); 134 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 135 | bool bRet = dbi.Create(szKey); 136 | if (bRet) { 137 | int64_t res = 0; 138 | if (xClient.incr(dbi, szKey, res)) { 139 | if (res == 101) { 140 | printf("%s success %ld \r\n", __PRETTY_FUNCTION__, res); 141 | } else { 142 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 143 | } 144 | } else { 145 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 146 | } 147 | } 148 | } 149 | 150 | void test_incrby() 151 | { 152 | test_set("test", "100"); 153 | char szKey[256] = { 0 }; 154 | strcpy(szKey, "test"); 155 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 156 | bool bRet = dbi.Create(szKey); 157 | if (bRet) { 158 | int64_t res = 0; 159 | if (xClient.incrby(dbi, szKey, 11, res)) { 160 | if (res == 111) { 161 | printf("%s success %ld \r\n", __PRETTY_FUNCTION__, res); 162 | } else { 163 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 164 | } 165 | } else { 166 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 167 | } 168 | } 169 | } 170 | 171 | void test_get() 172 | { 173 | 174 | char szKey[256] = { 0 }; 175 | { 176 | strcpy(szKey, "test"); 177 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 178 | bool bRet = dbi.Create(szKey); 179 | if (bRet) { 180 | std::string strData; 181 | if (xClient.get(dbi, szKey, strData)) { 182 | printf("%s success data:%s \r\n", __PRETTY_FUNCTION__, strData.c_str()); 183 | } else { 184 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 185 | } 186 | } 187 | } 188 | 189 | { 190 | sprintf(szKey, "test_%u", (unsigned int)time(NULL)); 191 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 192 | bool bRet = dbi.Create(szKey); 193 | if (bRet) { 194 | std::string strData; 195 | if (xClient.get(dbi, szKey, strData)) { 196 | printf("%s error data:%s \r\n", __PRETTY_FUNCTION__, strData.c_str()); 197 | } else { 198 | printf("%s success [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 199 | } 200 | } 201 | } 202 | } 203 | 204 | void test_type() 205 | { 206 | char szKey[256] = { 0 }; 207 | 208 | strcpy(szKey, "test"); 209 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 210 | dbi.Create(szKey); 211 | 212 | const std::string str = "wwwwwwwwwwwwwwwwwwwwwwwww"; 213 | xClient.set(dbi, szKey, str); 214 | std::string strData; 215 | if (xClient.type(dbi, szKey, strData)) { 216 | printf("%s success data:%s \r\n", __PRETTY_FUNCTION__, strData.c_str()); 217 | } else { 218 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 219 | } 220 | } 221 | 222 | void test_getrange() 223 | { 224 | test_set("test", "01234567890123456789"); 225 | char szKey[256] = { 0 }; 226 | 227 | strcpy(szKey, "test"); 228 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 229 | bool bRet = dbi.Create(szKey); 230 | if (bRet) { 231 | std::string strData; 232 | if (xClient.getrange(dbi, szKey, 2, 6, strData)) { 233 | printf("%s success data:%s \r\n", __PRETTY_FUNCTION__, strData.c_str()); 234 | } else { 235 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 236 | } 237 | } 238 | } 239 | 240 | void test_exists() 241 | { 242 | char szKey[256] = { 0 }; 243 | strcpy(szKey, "test"); 244 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 245 | bool bRet = dbi.Create(szKey); 246 | if (bRet) { 247 | if (xClient.exists(dbi, szKey)) { 248 | printf("%s success \r\n", __PRETTY_FUNCTION__); 249 | } else { 250 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 251 | } 252 | } 253 | } 254 | 255 | void test_del() 256 | { 257 | char szKey[256] = { 0 }; 258 | strcpy(szKey, "test"); 259 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 260 | bool bRet = dbi.Create(szKey); 261 | if (bRet) { 262 | if (xClient.del(dbi, szKey)) { 263 | printf("%s success \r\n", __PRETTY_FUNCTION__); 264 | } else { 265 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 266 | } 267 | } 268 | } 269 | 270 | void test_mset() 271 | { 272 | char szKey[256] = { 0 }; 273 | DBIArray vdbi; 274 | VDATA kvData; 275 | 276 | for (int i = 0; i < 10; i++) { 277 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 278 | sprintf(szKey, "mset_key_%d", i); 279 | dbi.Create(szKey); 280 | vdbi.push_back(dbi); 281 | kvData.push_back(szKey); 282 | sprintf(szKey, "mset_value_%d", i); 283 | kvData.push_back(szKey); 284 | } 285 | 286 | if (xClient.mset(vdbi, kvData)) { 287 | printf("%s success \r\n", __PRETTY_FUNCTION__); 288 | } else { 289 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, "mset error"); 290 | } 291 | } 292 | 293 | void test_mget() 294 | { 295 | char szKey[256] = { 0 }; 296 | DBIArray vdbi; 297 | KEYS kData; 298 | ReplyData Reply; 299 | for (int i = 0; i < 15; i++) { 300 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 301 | sprintf(szKey, "mset_key_%d", i); 302 | dbi.Create(szKey); 303 | vdbi.push_back(dbi); 304 | kData.push_back(szKey); 305 | } 306 | 307 | if (xClient.mget(vdbi, kData, Reply)) { 308 | printf("%s success %zu \r\n", __PRETTY_FUNCTION__, Reply.size()); 309 | ReplyData::iterator iter = Reply.begin(); 310 | for (; iter != Reply.end(); iter++) { 311 | printf("%d\t%s\r\n", (*iter).type, (*iter).str.c_str()); 312 | } 313 | } else { 314 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, "mset error"); 315 | } 316 | } 317 | 318 | void test_hset() 319 | { 320 | char szHKey[256] = { 0 }; 321 | strcpy(szHKey, "hashtest"); 322 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 323 | bool bRet = dbi.Create(szHKey); 324 | if (bRet) { 325 | int64_t count = 0; 326 | if (xClient.hset(dbi, szHKey, "filed1", "filed1_values", count)) { 327 | printf("%s success \r\n", __PRETTY_FUNCTION__); 328 | } else { 329 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 330 | } 331 | } 332 | } 333 | 334 | void test_lpush() 335 | { 336 | char szHKey[256] = { 0 }; 337 | strcpy(szHKey, "list_test"); 338 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 339 | 340 | VALUES vVal; 341 | vVal.push_back(toString(time(NULL))); 342 | bool bRet = dbi.Create(szHKey); 343 | 344 | if (bRet) { 345 | int64_t count = 0; 346 | if (xClient.lpush(dbi, szHKey, vVal, count)) { 347 | printf("%s success %ld \r\n", __PRETTY_FUNCTION__, count); 348 | } else { 349 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 350 | } 351 | } 352 | } 353 | 354 | void test_llen() 355 | { 356 | char szHKey[256] = { 0 }; 357 | strcpy(szHKey, "list_test"); 358 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 359 | 360 | bool bRet = dbi.Create(szHKey); 361 | if (bRet) { 362 | int64_t count = 0; 363 | if (xClient.llen(dbi, szHKey, count)) { 364 | printf("%s success len: %ld \r\n", __PRETTY_FUNCTION__, count); 365 | } else { 366 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 367 | } 368 | } 369 | } 370 | 371 | void test_lrange() 372 | { 373 | char szHKey[256] = { 0 }; 374 | strcpy(szHKey, "list_test"); 375 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 376 | 377 | VALUES vVal; 378 | 379 | bool bRet = dbi.Create(szHKey); 380 | if (bRet) { 381 | ArrayReply Reply; 382 | if (xClient.lrange(dbi, szHKey, 0, -1, Reply)) { 383 | printf("%s success \r\n", __PRETTY_FUNCTION__); 384 | ReplyData::iterator iter = Reply.begin(); 385 | for (; iter != Reply.end(); iter++) { 386 | printf("%d\t%s\r\n", (*iter).type, (*iter).str.c_str()); 387 | } 388 | } else { 389 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 390 | } 391 | } 392 | } 393 | 394 | void test_lpop() 395 | { 396 | char szHKey[256] = { 0 }; 397 | strcpy(szHKey, "list_test"); 398 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 399 | 400 | bool bRet = dbi.Create(szHKey); 401 | if (bRet) { 402 | std::string strVal; 403 | if (xClient.lpop(dbi, szHKey, strVal)) { 404 | printf("%s success val: %s \r\n", __PRETTY_FUNCTION__, strVal.c_str()); 405 | } else { 406 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 407 | } 408 | } 409 | } 410 | 411 | void test_rpop() 412 | { 413 | char szHKey[256] = { 0 }; 414 | strcpy(szHKey, "list_test"); 415 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 416 | 417 | bool bRet = dbi.Create(szHKey); 418 | if (bRet) { 419 | std::string strVal; 420 | if (xClient.rpop(dbi, szHKey, strVal)) { 421 | printf("%s success val: %s \r\n", __PRETTY_FUNCTION__, strVal.c_str()); 422 | } else { 423 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 424 | } 425 | } 426 | } 427 | 428 | void test_publish() 429 | { 430 | char szHKey[256] = { 0 }; 431 | strcpy(szHKey, "pubsub_test"); 432 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 433 | 434 | bool bRet = dbi.Create(szHKey); 435 | if (bRet) { 436 | int64_t count; 437 | if (xClient.publish(dbi, szHKey, "test message", count)) { 438 | printf("%s success \r\n", __PRETTY_FUNCTION__); 439 | } else { 440 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 441 | } 442 | } 443 | } 444 | 445 | void test_subscribe() 446 | { 447 | char szHKey[256] = { 0 }; 448 | strcpy(szHKey, "pubsub_test"); 449 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 450 | bool bRet = dbi.Create(szHKey); 451 | if (!bRet) { 452 | return; 453 | } 454 | 455 | VDATA channels; 456 | channels.push_back(szHKey); 457 | xRedisContext ctx; 458 | if (xClient.subscribe(dbi, channels, ctx)) { 459 | printf("%s success \r\n", __PRETTY_FUNCTION__); 460 | ReplyData vReply; 461 | while (0 == xRedisClient::GetReply(&ctx, vReply)) { 462 | ReplyData::iterator iter = vReply.begin(); 463 | for (; iter != vReply.end(); iter++) { 464 | printf("%d\t%s\r\n", (*iter).type, (*iter).str.c_str()); 465 | } 466 | } 467 | 468 | } else { 469 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 470 | } 471 | xClient.unsubscribe(dbi, channels, ctx); 472 | xClient.FreexRedisContext(&ctx); 473 | } 474 | 475 | void test_scan() 476 | { 477 | const char* pattern = "a*"; 478 | SliceIndex dbi(&xClient, CACHE_TYPE_1); 479 | bool bRet = dbi.CreateByID(0); 480 | if (!bRet) { 481 | return; 482 | } 483 | 484 | ArrayReply arrayReply; 485 | int64_t cursor = 0; 486 | xRedisContext ctx; 487 | xClient.GetxRedisContext(dbi, &ctx); 488 | 489 | do { 490 | arrayReply.clear(); 491 | if (xClient.scan(dbi, cursor, pattern, 0, arrayReply, ctx)) { 492 | printf("%" PRId64 "\t\r\n", cursor); 493 | ReplyData::iterator iter = arrayReply.begin(); 494 | for (; iter != arrayReply.end(); iter++) { 495 | printf("\t\t%s\r\n", (*iter).str.c_str()); 496 | } 497 | } else { 498 | printf("%s error [%s] \r\n", __PRETTY_FUNCTION__, dbi.GetErrInfo()); 499 | break; 500 | } 501 | } while (cursor != 0); 502 | 503 | xClient.FreexRedisContext(&ctx); 504 | } 505 | 506 | int main(int argc, char** argv) 507 | { 508 | printf("%d %s\r\n", argc, argv[0]); 509 | 510 | xClient.Init(3); 511 | 512 | /* 配置一个3分片存储xRedis集群 CACHE_TYPE_1:共3个存储主节点 */ 513 | RedisNode RedisList1[3] = { 514 | { .dbindex = 0, .host = "127.0.0.1", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 515 | { .dbindex = 1, .host = "127.0.0.2", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER }, 516 | { .dbindex = 2, .host = "127.0.0.3", .port = 6379, .passwd = "", .poolsize = 4, .timeout = 5, .role = MASTER } 517 | }; 518 | 519 | xClient.ConnectRedisCache(RedisList1, sizeof(RedisList1) / sizeof(RedisNode), 3, CACHE_TYPE_1); 520 | 521 | test_zadd("test:sorted:key", "sorted value hello xredis"); 522 | test_set("test", "wwww"); 523 | test_get(); 524 | test_getrange(); 525 | test_exists(); 526 | test_del(); 527 | test_hset(); 528 | test_mset(); 529 | test_mget(); 530 | test_append(); 531 | 532 | test_decr(); 533 | test_decrby(); 534 | test_incr(); 535 | test_incrby(); 536 | 537 | test_lpush(); 538 | test_llen(); 539 | test_lrange(); 540 | test_lpop(); 541 | test_rpop(); 542 | 543 | test_type(); 544 | test_scan(); 545 | //int n = 10; 546 | //while (n--) { 547 | // xClient.KeepAlive(); 548 | // usleep(1000*1000*10); 549 | //} 550 | 551 | xClient.Release(); 552 | 553 | return 0; 554 | } 555 | --------------------------------------------------------------------------------