From d699116795b5e1db30798b8abb59b4fa3e70ea13 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Mon, 11 May 2020 16:02:49 -0700 Subject: [PATCH] mac deps --- controller/PostgreSQL.cpp | 22 +- controller/PostgreSQL.hpp | 4 + controller/Redis.hpp | 15 + ext/hiredis-0.14.1/.gitignore | 1 - ext/hiredis-0.14.1/include/hiredis/alloc.h | 53 + .../include/hiredis}/async.h | 2 +- .../include/hiredis}/dict.h | 0 ext/hiredis-0.14.1/include/hiredis/fmacros.h | 12 + .../include/hiredis}/hiredis.h | 35 +- .../include/hiredis}/net.h | 4 - .../include/hiredis}/read.h | 26 +- ext/hiredis-0.14.1/include/hiredis/sds.h | 273 + ext/hiredis-0.14.1/include/hiredis/sdsalloc.h | 42 + .../include/hiredis}/win32.h | 0 ext/hiredis-vip-0.3.0/.gitignore | 7 - ext/hiredis-vip-0.3.0/.travis.yml | 16 - ext/hiredis-vip-0.3.0/CHANGELOG.md | 16 - ext/hiredis-vip-0.3.0/COPYING | 29 - ext/hiredis-vip-0.3.0/Makefile | 205 - ext/hiredis-vip-0.3.0/README.md | 255 - ext/hiredis-vip-0.3.0/adapters/ae.h | 154 - ext/hiredis-vip-0.3.0/adapters/glib.h | 153 - ext/hiredis-vip-0.3.0/adapters/libev.h | 147 - ext/hiredis-vip-0.3.0/adapters/libevent.h | 135 - ext/hiredis-vip-0.3.0/adapters/libuv.h | 122 - ext/hiredis-vip-0.3.0/adlist.c | 341 -- ext/hiredis-vip-0.3.0/adlist.h | 93 - ext/hiredis-vip-0.3.0/async.c | 691 --- ext/hiredis-vip-0.3.0/command.c | 1700 ------ ext/hiredis-vip-0.3.0/command.h | 179 - ext/hiredis-vip-0.3.0/crc16.c | 87 - ext/hiredis-vip-0.3.0/dict.c | 338 -- ext/hiredis-vip-0.3.0/examples/example-ae.c | 62 - ext/hiredis-vip-0.3.0/examples/example-glib.c | 73 - .../examples/example-libev.c | 52 - .../examples/example-libevent.c | 53 - .../examples/example-libuv.c | 53 - ext/hiredis-vip-0.3.0/examples/example.c | 78 - ext/hiredis-vip-0.3.0/fmacros.h | 23 - ext/hiredis-vip-0.3.0/hiarray.c | 188 - ext/hiredis-vip-0.3.0/hiarray.h | 56 - ext/hiredis-vip-0.3.0/hircluster.c | 4747 ----------------- ext/hiredis-vip-0.3.0/hircluster.h | 178 - ext/hiredis-vip-0.3.0/hiredis.c | 1021 ---- ext/hiredis-vip-0.3.0/hiutil.c | 554 -- ext/hiredis-vip-0.3.0/hiutil.h | 265 - ext/hiredis-vip-0.3.0/net.c | 458 -- ext/hiredis-vip-0.3.0/read.c | 525 -- ext/hiredis-vip-0.3.0/sds.c | 1095 ---- ext/hiredis-vip-0.3.0/sds.h | 105 - ext/hiredis-vip-0.3.0/test.c | 806 --- make-mac.mk | 5 +- objects.mk | 1 - 53 files changed, 434 insertions(+), 15121 deletions(-) create mode 100644 controller/Redis.hpp create mode 100644 ext/hiredis-0.14.1/include/hiredis/alloc.h rename ext/{hiredis-vip-0.3.0 => hiredis-0.14.1/include/hiredis}/async.h (98%) rename ext/{hiredis-vip-0.3.0 => hiredis-0.14.1/include/hiredis}/dict.h (100%) create mode 100644 ext/hiredis-0.14.1/include/hiredis/fmacros.h rename ext/{hiredis-vip-0.3.0 => hiredis-0.14.1/include/hiredis}/hiredis.h (83%) rename ext/{hiredis-vip-0.3.0 => hiredis-0.14.1/include/hiredis}/net.h (97%) rename ext/{hiredis-vip-0.3.0 => hiredis-0.14.1/include/hiredis}/read.h (80%) create mode 100644 ext/hiredis-0.14.1/include/hiredis/sds.h create mode 100644 ext/hiredis-0.14.1/include/hiredis/sdsalloc.h rename ext/{hiredis-vip-0.3.0 => hiredis-0.14.1/include/hiredis}/win32.h (100%) delete mode 100644 ext/hiredis-vip-0.3.0/.gitignore delete mode 100644 ext/hiredis-vip-0.3.0/.travis.yml delete mode 100644 ext/hiredis-vip-0.3.0/CHANGELOG.md delete mode 100644 ext/hiredis-vip-0.3.0/COPYING delete mode 100644 ext/hiredis-vip-0.3.0/Makefile delete mode 100644 ext/hiredis-vip-0.3.0/README.md delete mode 100644 ext/hiredis-vip-0.3.0/adapters/ae.h delete mode 100644 ext/hiredis-vip-0.3.0/adapters/glib.h delete mode 100644 ext/hiredis-vip-0.3.0/adapters/libev.h delete mode 100644 ext/hiredis-vip-0.3.0/adapters/libevent.h delete mode 100644 ext/hiredis-vip-0.3.0/adapters/libuv.h delete mode 100644 ext/hiredis-vip-0.3.0/adlist.c delete mode 100644 ext/hiredis-vip-0.3.0/adlist.h delete mode 100644 ext/hiredis-vip-0.3.0/async.c delete mode 100644 ext/hiredis-vip-0.3.0/command.c delete mode 100644 ext/hiredis-vip-0.3.0/command.h delete mode 100644 ext/hiredis-vip-0.3.0/crc16.c delete mode 100644 ext/hiredis-vip-0.3.0/dict.c delete mode 100644 ext/hiredis-vip-0.3.0/examples/example-ae.c delete mode 100644 ext/hiredis-vip-0.3.0/examples/example-glib.c delete mode 100644 ext/hiredis-vip-0.3.0/examples/example-libev.c delete mode 100644 ext/hiredis-vip-0.3.0/examples/example-libevent.c delete mode 100644 ext/hiredis-vip-0.3.0/examples/example-libuv.c delete mode 100644 ext/hiredis-vip-0.3.0/examples/example.c delete mode 100644 ext/hiredis-vip-0.3.0/fmacros.h delete mode 100644 ext/hiredis-vip-0.3.0/hiarray.c delete mode 100644 ext/hiredis-vip-0.3.0/hiarray.h delete mode 100644 ext/hiredis-vip-0.3.0/hircluster.c delete mode 100644 ext/hiredis-vip-0.3.0/hircluster.h delete mode 100644 ext/hiredis-vip-0.3.0/hiredis.c delete mode 100644 ext/hiredis-vip-0.3.0/hiutil.c delete mode 100644 ext/hiredis-vip-0.3.0/hiutil.h delete mode 100644 ext/hiredis-vip-0.3.0/net.c delete mode 100644 ext/hiredis-vip-0.3.0/read.c delete mode 100644 ext/hiredis-vip-0.3.0/sds.c delete mode 100644 ext/hiredis-vip-0.3.0/sds.h delete mode 100644 ext/hiredis-vip-0.3.0/test.c diff --git a/controller/PostgreSQL.cpp b/controller/PostgreSQL.cpp index 91cbdb789..0640cb8ee 100644 --- a/controller/PostgreSQL.cpp +++ b/controller/PostgreSQL.cpp @@ -78,6 +78,8 @@ PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, R , _waitNoticePrinted(false) , _listenPort(listenPort) , _rc(rc) + , _redis(NULL) + , _cluster(NULL) { char myAddress[64]; _myAddressStr = myId.address().toString(myAddress); @@ -113,6 +115,21 @@ PostgreSQL::PostgreSQL(const Identity &myId, const char *path, int listenPort, R PQfinish(conn); conn = NULL; + if (_rc != NULL) { + sw::redis::ConnectionOptions opts; + sw::redis::ConnectionPoolOptions poolOpts; + opts.host = _rc->hostname; + opts.port = _rc->port; + opts.password = _rc->password; + opts.db = 0; + poolOpts.size = 10; + if (_rc->clusterMode) { + _cluster = new sw::redis::RedisCluster(opts, poolOpts); + } else { + _redis = new sw::redis::Redis(opts, poolOpts); + } + } + _readyLock.lock(); _heartbeatThread = std::thread(&PostgreSQL::heartbeat, this); _membersDbWatcher = std::thread(&PostgreSQL::membersDbWatcher, this); @@ -128,6 +145,8 @@ PostgreSQL::~PostgreSQL() _run = 0; std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + _heartbeatThread.join(); _membersDbWatcher.join(); _networksDbWatcher.join(); @@ -135,7 +154,8 @@ PostgreSQL::~PostgreSQL() _commitThread[i].join(); } _onlineNotificationThread.join(); - + delete _redis; + delete _cluster; } diff --git a/controller/PostgreSQL.hpp b/controller/PostgreSQL.hpp index 5d14e2ff6..986559acf 100644 --- a/controller/PostgreSQL.hpp +++ b/controller/PostgreSQL.hpp @@ -20,6 +20,8 @@ #define ZT_CENTRAL_CONTROLLER_COMMIT_THREADS 4 +#include + extern "C" { typedef struct pg_conn PGconn; } @@ -98,6 +100,8 @@ private: int _listenPort; RedisConfig *_rc; + sw::redis::Redis *_redis; + sw::redis::RedisCluster *_cluster; }; } // namespace ZeroTier diff --git a/controller/Redis.hpp b/controller/Redis.hpp new file mode 100644 index 000000000..095419b01 --- /dev/null +++ b/controller/Redis.hpp @@ -0,0 +1,15 @@ +#ifndef ZT_CONTROLLER_REDIS_HPP +#define ZT_CONTROLLER_REDIS_HPP + +#include + +namespace ZeroTier { +struct RedisConfig { + std::string hostname; + int port; + std::string password; + bool clusterMode; +}; +} + +#endif \ No newline at end of file diff --git a/ext/hiredis-0.14.1/.gitignore b/ext/hiredis-0.14.1/.gitignore index c44b5c537..db2ad032a 100644 --- a/ext/hiredis-0.14.1/.gitignore +++ b/ext/hiredis-0.14.1/.gitignore @@ -3,5 +3,4 @@ /*.o /*.so /*.dylib -/*.a /*.pc diff --git a/ext/hiredis-0.14.1/include/hiredis/alloc.h b/ext/hiredis-0.14.1/include/hiredis/alloc.h new file mode 100644 index 000000000..2c9b04e35 --- /dev/null +++ b/ext/hiredis-0.14.1/include/hiredis/alloc.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020, Michael Grunder + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef HIREDIS_ALLOC_H +#define HIREDIS_ALLOC_H + +#include /* for size_t */ + +#ifndef HIREDIS_OOM_HANDLER +#define HIREDIS_OOM_HANDLER abort() +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +void *hi_malloc(size_t size); +void *hi_calloc(size_t nmemb, size_t size); +void *hi_realloc(void *ptr, size_t size); +char *hi_strdup(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif /* HIREDIS_ALLOC_H */ diff --git a/ext/hiredis-vip-0.3.0/async.h b/ext/hiredis-0.14.1/include/hiredis/async.h similarity index 98% rename from ext/hiredis-vip-0.3.0/async.h rename to ext/hiredis-0.14.1/include/hiredis/async.h index 2ba7142b8..e69d84090 100644 --- a/ext/hiredis-vip-0.3.0/async.h +++ b/ext/hiredis-0.14.1/include/hiredis/async.h @@ -45,6 +45,7 @@ typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*); typedef struct redisCallback { struct redisCallback *next; /* simple singly linked list */ redisCallbackFn *fn; + int pending_subs; void *privdata; } redisCallback; @@ -68,7 +69,6 @@ typedef struct redisAsyncContext { /* Not used by hiredis */ void *data; - void (*dataHandler)(struct redisAsyncContext* ac); /* Event library data and hooks */ struct { diff --git a/ext/hiredis-vip-0.3.0/dict.h b/ext/hiredis-0.14.1/include/hiredis/dict.h similarity index 100% rename from ext/hiredis-vip-0.3.0/dict.h rename to ext/hiredis-0.14.1/include/hiredis/dict.h diff --git a/ext/hiredis-0.14.1/include/hiredis/fmacros.h b/ext/hiredis-0.14.1/include/hiredis/fmacros.h new file mode 100644 index 000000000..3227faafd --- /dev/null +++ b/ext/hiredis-0.14.1/include/hiredis/fmacros.h @@ -0,0 +1,12 @@ +#ifndef __HIREDIS_FMACRO_H +#define __HIREDIS_FMACRO_H + +#define _XOPEN_SOURCE 600 +#define _POSIX_C_SOURCE 200112L + +#if defined(__APPLE__) && defined(__MACH__) +/* Enable TCP_KEEPALIVE */ +#define _DARWIN_C_SOURCE +#endif + +#endif diff --git a/ext/hiredis-vip-0.3.0/hiredis.h b/ext/hiredis-0.14.1/include/hiredis/hiredis.h similarity index 83% rename from ext/hiredis-vip-0.3.0/hiredis.h rename to ext/hiredis-0.14.1/include/hiredis/hiredis.h index 87f7366f8..d945bf204 100644 --- a/ext/hiredis-vip-0.3.0/hiredis.h +++ b/ext/hiredis-0.14.1/include/hiredis/hiredis.h @@ -38,10 +38,12 @@ #include /* for struct timeval */ #include /* uintXX_t, etc */ #include "sds.h" /* for sds */ +#include "alloc.h" /* for allocation wrappers */ #define HIREDIS_MAJOR 0 -#define HIREDIS_MINOR 13 +#define HIREDIS_MINOR 14 #define HIREDIS_PATCH 1 +#define HIREDIS_SONAME 0.14 /* Connection type can be blocking or non-blocking and is set in the * least significant bit of the flags field in redisContext. */ @@ -79,30 +81,6 @@ * SO_REUSEADDR is being used. */ #define REDIS_CONNECT_RETRIES 10 -/* strerror_r has two completely different prototypes and behaviors - * depending on system issues, so we need to operate on the error buffer - * differently depending on which strerror_r we're using. */ -#ifndef _GNU_SOURCE -/* "regular" POSIX strerror_r that does the right thing. */ -#define __redis_strerror_r(errno, buf, len) \ - do { \ - strerror_r((errno), (buf), (len)); \ - } while (0) -#else -/* "bad" GNU strerror_r we need to clean up after. */ -#define __redis_strerror_r(errno, buf, len) \ - do { \ - char *err_str = strerror_r((errno), (buf), (len)); \ - /* If return value _isn't_ the start of the buffer we passed in, \ - * then GNU strerror_r returned an internal static buffer and we \ - * need to copy the result into our private buffer. */ \ - if (err_str != (buf)) { \ - buf[(len)] = '\0'; \ - strncat((buf), err_str, ((len) - 1)); \ - } \ - } while (0) -#endif - #ifdef __cplusplus extern "C" { #endif @@ -111,7 +89,7 @@ extern "C" { typedef struct redisReply { int type; /* REDIS_REPLY_* */ long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ - int len; /* Length of string */ + size_t len; /* Length of string */ char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ @@ -132,7 +110,7 @@ void redisFreeSdsCommand(sds cmd); enum redisConnectionType { REDIS_CONN_TCP, - REDIS_CONN_UNIX, + REDIS_CONN_UNIX }; /* Context for a connection to Redis */ @@ -156,6 +134,7 @@ typedef struct redisContext { struct { char *path; } unix_sock; + } redisContext; redisContext *redisConnect(const char *ip, int port); @@ -177,7 +156,7 @@ redisContext *redisConnectFd(int fd); * host, ip (or path), timeout and bind address are reused, * flags are used unmodified from the existing context. * - * Returns REDIS_OK on successfull connect or REDIS_ERR otherwise. + * Returns REDIS_OK on successful connect or REDIS_ERR otherwise. */ int redisReconnect(redisContext *c); diff --git a/ext/hiredis-vip-0.3.0/net.h b/ext/hiredis-0.14.1/include/hiredis/net.h similarity index 97% rename from ext/hiredis-vip-0.3.0/net.h rename to ext/hiredis-0.14.1/include/hiredis/net.h index 2f1a0bf85..d9dc36257 100644 --- a/ext/hiredis-vip-0.3.0/net.h +++ b/ext/hiredis-0.14.1/include/hiredis/net.h @@ -37,10 +37,6 @@ #include "hiredis.h" -#if defined(__sun) -#define AF_LOCAL AF_UNIX -#endif - int redisCheckSocketError(redisContext *c); int redisContextSetTimeout(redisContext *c, const struct timeval tv); int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout); diff --git a/ext/hiredis-vip-0.3.0/read.h b/ext/hiredis-0.14.1/include/hiredis/read.h similarity index 80% rename from ext/hiredis-vip-0.3.0/read.h rename to ext/hiredis-0.14.1/include/hiredis/read.h index 088c97903..2988aa453 100644 --- a/ext/hiredis-vip-0.3.0/read.h +++ b/ext/hiredis-0.14.1/include/hiredis/read.h @@ -38,7 +38,7 @@ #define REDIS_OK 0 /* When an error occurs, the err flag in a context is set to hold the type of - * error that occured. REDIS_ERR_IO means there was an I/O error and you + * error that occurred. REDIS_ERR_IO means there was an I/O error and you * should use the "errno" variable to find out what is wrong. * For other values, the "errstr" field will hold a description. */ #define REDIS_ERR_IO 1 /* Error in read or write */ @@ -46,9 +46,6 @@ #define REDIS_ERR_PROTOCOL 4 /* Protocol error */ #define REDIS_ERR_OOM 5 /* Out of memory */ #define REDIS_ERR_OTHER 2 /* Everything else... */ -#if 1 //shenzheng 2015-8-10 redis cluster -#define REDIS_ERR_CLUSTER_TOO_MANY_REDIRECT 6 -#endif //shenzheng 2015-8-10 redis cluster #define REDIS_REPLY_STRING 1 #define REDIS_REPLY_ARRAY 2 @@ -59,16 +56,6 @@ #define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */ -#if 1 //shenzheng 2015-8-22 redis cluster -#define REDIS_ERROR_MOVED "MOVED" -#define REDIS_ERROR_ASK "ASK" -#define REDIS_ERROR_TRYAGAIN "TRYAGAIN" -#define REDIS_ERROR_CROSSSLOT "CROSSSLOT" -#define REDIS_ERROR_CLUSTERDOWN "CLUSTERDOWN" - -#define REDIS_STATUS_OK "OK" -#endif //shenzheng 2015-9-24 redis cluster - #ifdef __cplusplus extern "C" { #endif @@ -113,14 +100,9 @@ void redisReaderFree(redisReader *r); int redisReaderFeed(redisReader *r, const char *buf, size_t len); int redisReaderGetReply(redisReader *r, void **reply); -/* Backwards compatibility, can be removed on big version bump. */ -#define redisReplyReaderCreate redisReaderCreate -#define redisReplyReaderFree redisReaderFree -#define redisReplyReaderFeed redisReaderFeed -#define redisReplyReaderGetReply redisReaderGetReply -#define redisReplyReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) -#define redisReplyReaderGetObject(_r) (((redisReader*)(_r))->reply) -#define redisReplyReaderGetError(_r) (((redisReader*)(_r))->errstr) +#define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) +#define redisReaderGetObject(_r) (((redisReader*)(_r))->reply) +#define redisReaderGetError(_r) (((redisReader*)(_r))->errstr) #ifdef __cplusplus } diff --git a/ext/hiredis-0.14.1/include/hiredis/sds.h b/ext/hiredis-0.14.1/include/hiredis/sds.h new file mode 100644 index 000000000..13be75a9f --- /dev/null +++ b/ext/hiredis-0.14.1/include/hiredis/sds.h @@ -0,0 +1,273 @@ +/* SDSLib 2.0 -- A C dynamic strings library + * + * Copyright (c) 2006-2015, Salvatore Sanfilippo + * Copyright (c) 2015, Oran Agra + * Copyright (c) 2015, Redis Labs, Inc + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __SDS_H +#define __SDS_H + +#define SDS_MAX_PREALLOC (1024*1024) + +#include +#include +#include + +typedef char *sds; + +/* Note: sdshdr5 is never used, we just access the flags byte directly. + * However is here to document the layout of type 5 SDS strings. */ +struct __attribute__ ((__packed__)) sdshdr5 { + unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ + char buf[]; +}; +struct __attribute__ ((__packed__)) sdshdr8 { + uint8_t len; /* used */ + uint8_t alloc; /* excluding the header and null terminator */ + unsigned char flags; /* 3 lsb of type, 5 unused bits */ + char buf[]; +}; +struct __attribute__ ((__packed__)) sdshdr16 { + uint16_t len; /* used */ + uint16_t alloc; /* excluding the header and null terminator */ + unsigned char flags; /* 3 lsb of type, 5 unused bits */ + char buf[]; +}; +struct __attribute__ ((__packed__)) sdshdr32 { + uint32_t len; /* used */ + uint32_t alloc; /* excluding the header and null terminator */ + unsigned char flags; /* 3 lsb of type, 5 unused bits */ + char buf[]; +}; +struct __attribute__ ((__packed__)) sdshdr64 { + uint64_t len; /* used */ + uint64_t alloc; /* excluding the header and null terminator */ + unsigned char flags; /* 3 lsb of type, 5 unused bits */ + char buf[]; +}; + +#define SDS_TYPE_5 0 +#define SDS_TYPE_8 1 +#define SDS_TYPE_16 2 +#define SDS_TYPE_32 3 +#define SDS_TYPE_64 4 +#define SDS_TYPE_MASK 7 +#define SDS_TYPE_BITS 3 +#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))); +#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) +#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS) + +static inline size_t sdslen(const sds s) { + unsigned char flags = s[-1]; + switch(flags&SDS_TYPE_MASK) { + case SDS_TYPE_5: + return SDS_TYPE_5_LEN(flags); + case SDS_TYPE_8: + return SDS_HDR(8,s)->len; + case SDS_TYPE_16: + return SDS_HDR(16,s)->len; + case SDS_TYPE_32: + return SDS_HDR(32,s)->len; + case SDS_TYPE_64: + return SDS_HDR(64,s)->len; + } + return 0; +} + +static inline size_t sdsavail(const sds s) { + unsigned char flags = s[-1]; + switch(flags&SDS_TYPE_MASK) { + case SDS_TYPE_5: { + return 0; + } + case SDS_TYPE_8: { + SDS_HDR_VAR(8,s); + return sh->alloc - sh->len; + } + case SDS_TYPE_16: { + SDS_HDR_VAR(16,s); + return sh->alloc - sh->len; + } + case SDS_TYPE_32: { + SDS_HDR_VAR(32,s); + return sh->alloc - sh->len; + } + case SDS_TYPE_64: { + SDS_HDR_VAR(64,s); + return sh->alloc - sh->len; + } + } + return 0; +} + +static inline void sdssetlen(sds s, size_t newlen) { + unsigned char flags = s[-1]; + switch(flags&SDS_TYPE_MASK) { + case SDS_TYPE_5: + { + unsigned char *fp = ((unsigned char*)s)-1; + *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); + } + break; + case SDS_TYPE_8: + SDS_HDR(8,s)->len = newlen; + break; + case SDS_TYPE_16: + SDS_HDR(16,s)->len = newlen; + break; + case SDS_TYPE_32: + SDS_HDR(32,s)->len = newlen; + break; + case SDS_TYPE_64: + SDS_HDR(64,s)->len = newlen; + break; + } +} + +static inline void sdsinclen(sds s, size_t inc) { + unsigned char flags = s[-1]; + switch(flags&SDS_TYPE_MASK) { + case SDS_TYPE_5: + { + unsigned char *fp = ((unsigned char*)s)-1; + unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc; + *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); + } + break; + case SDS_TYPE_8: + SDS_HDR(8,s)->len += inc; + break; + case SDS_TYPE_16: + SDS_HDR(16,s)->len += inc; + break; + case SDS_TYPE_32: + SDS_HDR(32,s)->len += inc; + break; + case SDS_TYPE_64: + SDS_HDR(64,s)->len += inc; + break; + } +} + +/* sdsalloc() = sdsavail() + sdslen() */ +static inline size_t sdsalloc(const sds s) { + unsigned char flags = s[-1]; + switch(flags&SDS_TYPE_MASK) { + case SDS_TYPE_5: + return SDS_TYPE_5_LEN(flags); + case SDS_TYPE_8: + return SDS_HDR(8,s)->alloc; + case SDS_TYPE_16: + return SDS_HDR(16,s)->alloc; + case SDS_TYPE_32: + return SDS_HDR(32,s)->alloc; + case SDS_TYPE_64: + return SDS_HDR(64,s)->alloc; + } + return 0; +} + +static inline void sdssetalloc(sds s, size_t newlen) { + unsigned char flags = s[-1]; + switch(flags&SDS_TYPE_MASK) { + case SDS_TYPE_5: + /* Nothing to do, this type has no total allocation info. */ + break; + case SDS_TYPE_8: + SDS_HDR(8,s)->alloc = newlen; + break; + case SDS_TYPE_16: + SDS_HDR(16,s)->alloc = newlen; + break; + case SDS_TYPE_32: + SDS_HDR(32,s)->alloc = newlen; + break; + case SDS_TYPE_64: + SDS_HDR(64,s)->alloc = newlen; + break; + } +} + +sds sdsnewlen(const void *init, size_t initlen); +sds sdsnew(const char *init); +sds sdsempty(void); +sds sdsdup(const sds s); +void sdsfree(sds s); +sds sdsgrowzero(sds s, size_t len); +sds sdscatlen(sds s, const void *t, size_t len); +sds sdscat(sds s, const char *t); +sds sdscatsds(sds s, const sds t); +sds sdscpylen(sds s, const char *t, size_t len); +sds sdscpy(sds s, const char *t); + +sds sdscatvprintf(sds s, const char *fmt, va_list ap); +#ifdef __GNUC__ +sds sdscatprintf(sds s, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +#else +sds sdscatprintf(sds s, const char *fmt, ...); +#endif + +sds sdscatfmt(sds s, char const *fmt, ...); +sds sdstrim(sds s, const char *cset); +void sdsrange(sds s, int start, int end); +void sdsupdatelen(sds s); +void sdsclear(sds s); +int sdscmp(const sds s1, const sds s2); +sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); +void sdsfreesplitres(sds *tokens, int count); +void sdstolower(sds s); +void sdstoupper(sds s); +sds sdsfromlonglong(long long value); +sds sdscatrepr(sds s, const char *p, size_t len); +sds *sdssplitargs(const char *line, int *argc); +sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); +sds sdsjoin(char **argv, int argc, char *sep); +sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); + +/* Low level functions exposed to the user API */ +sds sdsMakeRoomFor(sds s, size_t addlen); +void sdsIncrLen(sds s, int incr); +sds sdsRemoveFreeSpace(sds s); +size_t sdsAllocSize(sds s); +void *sdsAllocPtr(sds s); + +/* Export the allocator used by SDS to the program using SDS. + * Sometimes the program SDS is linked to, may use a different set of + * allocators, but may want to allocate or free things that SDS will + * respectively free or allocate. */ +void *sds_malloc(size_t size); +void *sds_realloc(void *ptr, size_t size); +void sds_free(void *ptr); + +#ifdef REDIS_TEST +int sdsTest(int argc, char *argv[]); +#endif + +#endif diff --git a/ext/hiredis-0.14.1/include/hiredis/sdsalloc.h b/ext/hiredis-0.14.1/include/hiredis/sdsalloc.h new file mode 100644 index 000000000..f43023c48 --- /dev/null +++ b/ext/hiredis-0.14.1/include/hiredis/sdsalloc.h @@ -0,0 +1,42 @@ +/* SDSLib 2.0 -- A C dynamic strings library + * + * Copyright (c) 2006-2015, Salvatore Sanfilippo + * Copyright (c) 2015, Oran Agra + * Copyright (c) 2015, Redis Labs, Inc + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* SDS allocator selection. + * + * This file is used in order to change the SDS allocator at compile time. + * Just define the following defines to what you want to use. Also add + * the include of your alternate allocator if needed (not needed in order + * to use the default libc allocator). */ + +#define s_malloc malloc +#define s_realloc realloc +#define s_free free diff --git a/ext/hiredis-vip-0.3.0/win32.h b/ext/hiredis-0.14.1/include/hiredis/win32.h similarity index 100% rename from ext/hiredis-vip-0.3.0/win32.h rename to ext/hiredis-0.14.1/include/hiredis/win32.h diff --git a/ext/hiredis-vip-0.3.0/.gitignore b/ext/hiredis-vip-0.3.0/.gitignore deleted file mode 100644 index c44b5c537..000000000 --- a/ext/hiredis-vip-0.3.0/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -/hiredis-test -/examples/hiredis-example* -/*.o -/*.so -/*.dylib -/*.a -/*.pc diff --git a/ext/hiredis-vip-0.3.0/.travis.yml b/ext/hiredis-vip-0.3.0/.travis.yml deleted file mode 100644 index 1df63b0b5..000000000 --- a/ext/hiredis-vip-0.3.0/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: c -compiler: - - gcc - - clang - -env: - - CFLAGS="-Werror" - - PRE="valgrind --track-origins=yes --leak-check=full" - - TARGET="32bit" TARGET_VARS="32bit-vars" CFLAGS="-Werror" - - TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full" - -install: - - sudo apt-get update -qq - - sudo apt-get install libc6-dbg libc6-dev libc6-i686:i386 libc6-dev-i386 libc6-dbg:i386 valgrind -y - -script: make $TARGET CFLAGS="$CFLAGS" && make check PRE="$PRE" && make $TARGET_VARS hiredis-example diff --git a/ext/hiredis-vip-0.3.0/CHANGELOG.md b/ext/hiredis-vip-0.3.0/CHANGELOG.md deleted file mode 100644 index db304b6a7..000000000 --- a/ext/hiredis-vip-0.3.0/CHANGELOG.md +++ /dev/null @@ -1,16 +0,0 @@ -### 0.3.0 - Dec 07, 2016 - -* Support redisClustervCommand, redisClustervAppendCommand and redisClustervAsyncCommand api. (deep011) -* Add flags HIRCLUSTER_FLAG_ADD_OPENSLOT and HIRCLUSTER_FLAG_ROUTE_USE_SLOTS. (deep011) -* Support redisClusterCommandArgv related api. (deep011) -* Fix some serious bugs. (deep011) - -### 0.2.1 - Nov 24, 2015 - -This release support redis cluster api. - -* Add hiredis 0.3.1. (deep011) -* Support cluster synchronous API. (deep011) -* Support multi-key command(mget/mset/del) for redis cluster. (deep011) -* Support cluster pipelining. (deep011) -* Support cluster asynchronous API. (deep011) diff --git a/ext/hiredis-vip-0.3.0/COPYING b/ext/hiredis-vip-0.3.0/COPYING deleted file mode 100644 index a5fc97395..000000000 --- a/ext/hiredis-vip-0.3.0/COPYING +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (c) 2009-2011, Salvatore Sanfilippo -Copyright (c) 2010-2011, Pieter Noordhuis - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of Redis nor the names of its contributors may be used - to endorse or promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ext/hiredis-vip-0.3.0/Makefile b/ext/hiredis-vip-0.3.0/Makefile deleted file mode 100644 index 58494bfc3..000000000 --- a/ext/hiredis-vip-0.3.0/Makefile +++ /dev/null @@ -1,205 +0,0 @@ -# Hiredis Makefile -# Copyright (C) 2010-2011 Salvatore Sanfilippo -# Copyright (C) 2010-2011 Pieter Noordhuis -# This file is released under the BSD license, see the COPYING file - -OBJ=net.o hiredis.o sds.o async.o read.o hiarray.o hiutil.o command.o crc16.o adlist.o hircluster.o -EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib -TESTS=hiredis-test -LIBNAME=libhiredis_vip -PKGCONFNAME=hiredis.pc - -HIREDIS_VIP_MAJOR=$(shell grep HIREDIS_VIP_MAJOR hircluster.h | awk '{print $$3}') -HIREDIS_VIP_MINOR=$(shell grep HIREDIS_VIP_MINOR hircluster.h | awk '{print $$3}') -HIREDIS_VIP_PATCH=$(shell grep HIREDIS_VIP_PATCH hircluster.h | awk '{print $$3}') - -# Installation related variables and target -PREFIX?=/usr/local -INCLUDE_PATH?=include/hiredis-vip -LIBRARY_PATH?=lib -PKGCONF_PATH?=pkgconfig -INSTALL_INCLUDE_PATH= $(DESTDIR)$(PREFIX)/$(INCLUDE_PATH) -INSTALL_LIBRARY_PATH= $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH) -INSTALL_PKGCONF_PATH= $(INSTALL_LIBRARY_PATH)/$(PKGCONF_PATH) - -# redis-server configuration used for testing -REDIS_PORT=56379 -REDIS_SERVER=redis-server -define REDIS_TEST_CONFIG - daemonize yes - pidfile /tmp/hiredis-test-redis.pid - port $(REDIS_PORT) - bind 127.0.0.1 - unixsocket /tmp/hiredis-test-redis.sock -endef -export REDIS_TEST_CONFIG - -# Fallback to gcc when $CC is not in $PATH. -CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc') -OPTIMIZATION?=-O3 -WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings -DEBUG?= -g -ggdb -REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH) -REAL_LDFLAGS=$(LDFLAGS) $(ARCH) - -DYLIBSUFFIX=so -STLIBSUFFIX=a -DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_VIP_MAJOR).$(HIREDIS_VIP_MINOR) -DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_VIP_MAJOR) -DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) -DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) -STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) -STLIB_MAKE_CMD=ar rcs $(STLIBNAME) - -# Platform-specific overrides -uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') -ifeq ($(uname_S),SunOS) - REAL_LDFLAGS+= -ldl -lnsl -lsocket - DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) - INSTALL= cp -r -endif -ifeq ($(uname_S),Darwin) - DYLIBSUFFIX=dylib - DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_VIP_MAJOR).$(HIREDIS_VIP_MINOR).$(DYLIBSUFFIX) - DYLIB_MAJOR_NAME=$(LIBNAME).$(HIREDIS_VIP_MAJOR).$(DYLIBSUFFIX) - DYLIB_MAKE_CMD=$(CC) -shared -Wl,-install_name,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) -endif - -all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME) - -# Deps (use make dep to generate this) - -adlist.o: adlist.c adlist.h hiutil.h -async.o: async.c fmacros.h async.h hiredis.h read.h sds.h net.h dict.c dict.h -command.o: command.c command.h hiredis.h read.h sds.h adlist.h hiutil.h hiarray.h -crc16.o: crc16.c hiutil.h -dict.o: dict.c fmacros.h dict.h -hiarray.o: hiarray.c hiarray.h hiutil.h -hircluster.o: hircluster.c fmacros.h hircluster.h hiredis.h read.h sds.h adlist.h hiarray.h hiutil.h async.h command.h dict.c dict.h -hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h -hiutil.o: hiutil.c hiutil.h -net.o: net.c fmacros.h net.h hiredis.h read.h sds.h -read.o: read.c fmacros.h read.h sds.h -sds.o: sds.c sds.h -test.o: test.c fmacros.h hiredis.h read.h sds.h net.h - -$(DYLIBNAME): $(OBJ) - $(DYLIB_MAKE_CMD) $(OBJ) - -$(STLIBNAME): $(OBJ) - $(STLIB_MAKE_CMD) $(OBJ) - -dynamic: $(DYLIBNAME) -static: $(STLIBNAME) - -# Binaries: -hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME) - -hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME) - -hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) $(shell pkg-config --cflags --libs glib-2.0) -I. $< $(STLIBNAME) - -ifndef AE_DIR -hiredis-example-ae: - @echo "Please specify AE_DIR (e.g. /src)" - @false -else -hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(AE_DIR) $< $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o $(AE_DIR)/../deps/jemalloc/lib/libjemalloc.a -pthread $(STLIBNAME) -endif - -ifndef LIBUV_DIR -hiredis-example-libuv: - @echo "Please specify LIBUV_DIR (e.g. ../libuv/)" - @false -else -hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread $(STLIBNAME) -endif - -hiredis-example: examples/example.c $(STLIBNAME) - $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(STLIBNAME) - -examples: $(EXAMPLES) - -hiredis-test: test.o $(STLIBNAME) - -hiredis-%: %.o $(STLIBNAME) - $(CC) $(REAL_CFLAGS) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME) - -test: hiredis-test - ./hiredis-test - -check: hiredis-test - @echo "$$REDIS_TEST_CONFIG" | $(REDIS_SERVER) - - $(PRE) ./hiredis-test -h 127.0.0.1 -p $(REDIS_PORT) -s /tmp/hiredis-test-redis.sock || \ - ( kill `cat /tmp/hiredis-test-redis.pid` && false ) - kill `cat /tmp/hiredis-test-redis.pid` - -.c.o: - $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $< - -clean: - rm -rf $(DYLIBNAME) $(STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov - -dep: - $(CC) -MM *.c - -ifeq ($(uname_S),SunOS) - INSTALL?= cp -r -endif - -INSTALL?= cp -a - -$(PKGCONFNAME): hiredis.h - @echo "Generating $@ for pkgconfig..." - @echo prefix=$(PREFIX) > $@ - @echo exec_prefix=\$${prefix} >> $@ - @echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@ - @echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@ - @echo >> $@ - @echo Name: hiredis >> $@ - @echo Description: Minimalistic C client library for Redis. >> $@ - @echo Version: $(HIREDIS_VIP_MAJOR).$(HIREDIS_VIP_MINOR).$(HIREDIS_VIP_PATCH) >> $@ - @echo Libs: -L\$${libdir} -lhiredis >> $@ - @echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@ - -install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) - mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) - $(INSTALL) hiredis.h async.h read.h sds.h hiutil.h hiarray.h dict.h dict.c adlist.h fmacros.h hircluster.h adapters $(INSTALL_INCLUDE_PATH) - $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) - cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME) - cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MAJOR_NAME) $(DYLIBNAME) - $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) - mkdir -p $(INSTALL_PKGCONF_PATH) - $(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH) - -32bit: - @echo "" - @echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386" - @echo "" - $(MAKE) CFLAGS="-m32" LDFLAGS="-m32" - -32bit-vars: - $(eval CFLAGS=-m32) - $(eval LDFLAGS=-m32) - -gprof: - $(MAKE) CFLAGS="-pg" LDFLAGS="-pg" - -gcov: - $(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs" - -coverage: gcov - make check - mkdir -p tmp/lcov - lcov -d . -c -o tmp/lcov/hiredis.info - genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info - -noopt: - $(MAKE) OPTIMIZATION="" - -.PHONY: all test check clean dep install 32bit gprof gcov noopt diff --git a/ext/hiredis-vip-0.3.0/README.md b/ext/hiredis-vip-0.3.0/README.md deleted file mode 100644 index 897419390..000000000 --- a/ext/hiredis-vip-0.3.0/README.md +++ /dev/null @@ -1,255 +0,0 @@ - -# HIREDIS-VIP - -Hiredis-vip is a C client library for the [Redis](http://redis.io/) database. - -Hiredis-vip supported redis cluster. - -Hiredis-vip fully contained and based on [Hiredis](https://github.com/redis/hiredis) . - -## CLUSTER SUPPORT - -### FEATURES: - -* **`SUPPORT REDIS CLUSTER`**: - * Connect to redis cluster and run commands. - -* **`SUPPORT MULTI-KEY COMMAND`**: - * Support `MSET`, `MGET` and `DEL`. - -* **`SUPPORT PIPELING`**: - * Support redis pipeline and can contain multi-key command like above. - -* **`SUPPORT Asynchronous API`**: - * User can run commands with asynchronous mode. - -### CLUSTER API: - -```c -redisClusterContext *redisClusterConnect(const char *addrs, int flags); -redisClusterContext *redisClusterConnectWithTimeout(const char *addrs, const struct timeval tv, int flags); -redisClusterContext *redisClusterConnectNonBlock(const char *addrs, int flags); -void redisClusterFree(redisClusterContext *cc); -void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count); -void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, int len); -void *redisClustervCommand(redisClusterContext *cc, const char *format, va_list ap); -void *redisClusterCommand(redisClusterContext *cc, const char *format, ...); -void *redisClusterCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); -redisContext *ctx_get_by_node(struct cluster_node *node, const struct timeval *timeout, int flags); -int redisClusterAppendFormattedCommand(redisClusterContext *cc, char *cmd, int len); -int redisClustervAppendCommand(redisClusterContext *cc, const char *format, va_list ap); -int redisClusterAppendCommand(redisClusterContext *cc, const char *format, ...); -int redisClusterAppendCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); -int redisClusterGetReply(redisClusterContext *cc, void **reply); -void redisClusterReset(redisClusterContext *cc); - -redisClusterAsyncContext *redisClusterAsyncConnect(const char *addrs, int flags); -int redisClusterAsyncSetConnectCallback(redisClusterAsyncContext *acc, redisConnectCallback *fn); -int redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn); -int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, char *cmd, int len); -int redisClustervAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, va_list ap); -int redisClusterAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, ...); -int redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); - -void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc); -void redisClusterAsyncFree(redisClusterAsyncContext *acc); -``` - -## Quick usage - -If you want used but not read the follow, please reference the examples: -https://github.com/vipshop/hiredis-vip/wiki - -## Cluster synchronous API - -To consume the synchronous API, there are only a few function calls that need to be introduced: - -```c -redisClusterContext *redisClusterConnect(const char *addrs, int flags); -void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count); -void *redisClusterCommand(redisClusterContext *cc, const char *format, ...); -void redisClusterFree(redisClusterContext *cc); -``` - -### Cluster connecting - -The function `redisClusterConnect` is used to create a so-called `redisClusterContext`. The -context is where Hiredis-vip Cluster holds state for connections. The `redisClusterContext` -struct has an integer `err` field that is non-zero when the connection is in -an error state. The field `errstr` will contain a string with a description of -the error. -After trying to connect to Redis using `redisClusterContext` you should -check the `err` field to see if establishing the connection was successful: -```c -redisClusterContext *cc = redisClusterConnect("127.0.0.1:6379", HIRCLUSTER_FLAG_NULL); -if (cc != NULL && cc->err) { - printf("Error: %s\n", cc->errstr); - // handle error -} -``` - -### Cluster sending commands - -The next that will be introduced is `redisClusterCommand`. -This function takes a format similar to printf. In the simplest form, -it is used like this: -```c -reply = redisClusterCommand(clustercontext, "SET foo bar"); -``` - -The specifier `%s` interpolates a string in the command, and uses `strlen` to -determine the length of the string: -```c -reply = redisClusterCommand(clustercontext, "SET foo %s", value); -``` -Internally, Hiredis-vip splits the command in different arguments and will -convert it to the protocol used to communicate with Redis. -One or more spaces separates arguments, so you can use the specifiers -anywhere in an argument: -```c -reply = redisClusterCommand(clustercontext, "SET key:%s %s", myid, value); -``` - -### Cluster multi-key commands - -Hiredis-vip supports mget/mset/del multi-key commands. -Those multi-key commands is highly effective. -Millions of keys in one mget command just used several seconds. - -Example: -```c -reply = redisClusterCommand(clustercontext, "mget %s %s %s %s", key1, key2, key3, key4); -``` - -### Cluster cleaning up - -To disconnect and free the context the following function can be used: -```c -void redisClusterFree(redisClusterContext *cc); -``` -This function immediately closes the socket and then frees the allocations done in -creating the context. - -### Cluster pipelining - -The function `redisClusterGetReply` is exported as part of the Hiredis API and can be used -when a reply is expected on the socket. To pipeline commands, the only things that needs -to be done is filling up the output buffer. For this cause, two commands can be used that -are identical to the `redisClusterCommand` family, apart from not returning a reply: -```c -int redisClusterAppendCommand(redisClusterContext *cc, const char *format, ...); -int redisClusterAppendCommandArgv(redisClusterContext *cc, int argc, const char **argv); -``` -After calling either function one or more times, `redisClusterGetReply` can be used to receive the -subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where -the latter means an error occurred while reading a reply. Just as with the other commands, -the `err` field in the context can be used to find out what the cause of this error is. -```c -void redisClusterReset(redisClusterContext *cc); -``` -Warning: You must call `redisClusterReset` function after one pipelining anyway. - -The following examples shows a simple cluster pipeline: -```c -redisReply *reply; -redisClusterAppendCommand(clusterContext,"SET foo bar"); -redisClusterAppendCommand(clusterContext,"GET foo"); -redisClusterGetReply(clusterContext,&reply); // reply for SET -freeReplyObject(reply); -redisClusterGetReply(clusterContext,&reply); // reply for GET -freeReplyObject(reply); -redisClusterReset(clusterContext); -``` - -## Cluster asynchronous API - -Hiredis-vip comes with an cluster asynchronous API that works easily with any event library. -Now we just support and test for libevent and redis ae, if you need for other event libraries, -please contact with us, and we will support it quickly. - -### Connecting - -The function `redisAsyncConnect` can be used to establish a non-blocking connection to -Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field -should be checked after creation to see if there were errors creating the connection. -Because the connection that will be created is non-blocking, the kernel is not able to -instantly return if the specified host and port is able to accept a connection. -```c -redisClusterAsyncContext *acc = redisClusterAsyncConnect("127.0.0.1:6379", HIRCLUSTER_FLAG_NULL); -if (acc->err) { - printf("Error: %s\n", acc->errstr); - // handle error -} -``` - -The cluster asynchronous context can hold a disconnect callback function that is called when the -connection is disconnected (either because of an error or per user request). This function should -have the following prototype: -```c -void(const redisAsyncContext *c, int status); -``` -On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the -user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err` -field in the context can be accessed to find out the cause of the error. - -You not need to reconnect in the disconnect callback, hiredis-vip will reconnect this connection itself -when commands come to this redis node. - -Setting the disconnect callback can only be done once per context. For subsequent calls it will -return `REDIS_ERR`. The function to set the disconnect callback has the following prototype: -```c -int redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn); -``` -### Sending commands and their callbacks - -In an cluster asynchronous context, commands are automatically pipelined due to the nature of an event loop. -Therefore, unlike the cluster synchronous API, there is only a single way to send commands. -Because commands are sent to Redis cluster asynchronously, issuing a command requires a callback function -that is called when the reply is received. Reply callbacks should have the following prototype: -```c -void(redisClusterAsyncContext *acc, void *reply, void *privdata); -``` -The `privdata` argument can be used to curry arbitrary data to the callback from the point where -the command is initially queued for execution. - -The functions that can be used to issue commands in an asynchronous context are: -```c -int redisClusterAsyncCommand( - redisClusterAsyncContext *acc, - redisClusterCallbackFn *fn, - void *privdata, const char *format, ...); -``` -This function work like their blocking counterparts. The return value is `REDIS_OK` when the command -was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection -is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is -returned on calls to the `redisClusterAsyncCommand` family. - -If the reply for a command with a `NULL` callback is read, it is immediately freed. When the callback -for a command is non-`NULL`, the memory is freed immediately following the callback: the reply is only -valid for the duration of the callback. - -All pending callbacks are called with a `NULL` reply when the context encountered an error. - -### Disconnecting - -An cluster asynchronous connection can be terminated using: -```c -void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc); -``` -When this function is called, the connection is **not** immediately terminated. Instead, new -commands are no longer accepted and the connection is only terminated when all pending commands -have been written to the socket, their respective replies have been read and their respective -callbacks have been executed. After this, the disconnection callback is executed with the -`REDIS_OK` status and the context object is freed. - -### Hooking it up to event library *X* - -There are a few hooks that need to be set on the cluster context object after it is created. -See the `adapters/` directory for bindings to *ae* and *libevent*. - -## AUTHORS - -Hiredis-vip was maintained and used at vipshop(https://github.com/vipshop). -The redis client library part in hiredis-vip is same as hiredis(https://github.com/redis/hiredis). -The redis cluster client library part in hiredis-vip is written by deep(https://github.com/deep011). -Hiredis-vip is released under the BSD license. diff --git a/ext/hiredis-vip-0.3.0/adapters/ae.h b/ext/hiredis-vip-0.3.0/adapters/ae.h deleted file mode 100644 index f861cf287..000000000 --- a/ext/hiredis-vip-0.3.0/adapters/ae.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_AE_H__ -#define __HIREDIS_AE_H__ -#include -#include -#include "../hiredis.h" -#include "../async.h" - -#if 1 //shenzheng 2015-11-5 redis cluster -#include "../hircluster.h" -#endif //shenzheng 2015-11-5 redis cluster - -typedef struct redisAeEvents { - redisAsyncContext *context; - aeEventLoop *loop; - int fd; - int reading, writing; -} redisAeEvents; - -static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) { - ((void)el); ((void)fd); ((void)mask); - - redisAeEvents *e = (redisAeEvents*)privdata; - redisAsyncHandleRead(e->context); -} - -static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) { - ((void)el); ((void)fd); ((void)mask); - - redisAeEvents *e = (redisAeEvents*)privdata; - redisAsyncHandleWrite(e->context); -} - -static void redisAeAddRead(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - aeEventLoop *loop = e->loop; - if (!e->reading) { - e->reading = 1; - aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); - } -} - -static void redisAeDelRead(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - aeEventLoop *loop = e->loop; - if (e->reading) { - e->reading = 0; - aeDeleteFileEvent(loop,e->fd,AE_READABLE); - } -} - -static void redisAeAddWrite(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - aeEventLoop *loop = e->loop; - if (!e->writing) { - e->writing = 1; - aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e); - } -} - -static void redisAeDelWrite(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - aeEventLoop *loop = e->loop; - if (e->writing) { - e->writing = 0; - aeDeleteFileEvent(loop,e->fd,AE_WRITABLE); - } -} - -static void redisAeCleanup(void *privdata) { - redisAeEvents *e = (redisAeEvents*)privdata; - redisAeDelRead(privdata); - redisAeDelWrite(privdata); - free(e); -} - -static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisAeEvents *e; - - /* Nothing should be attached when something is already attached */ - if (ac->ev.data != NULL) - return REDIS_ERR; - - /* Create container for context and r/w events */ - e = (redisAeEvents*)malloc(sizeof(*e)); - e->context = ac; - e->loop = loop; - e->fd = c->fd; - e->reading = e->writing = 0; - - /* Register functions to start/stop listening for events */ - ac->ev.addRead = redisAeAddRead; - ac->ev.delRead = redisAeDelRead; - ac->ev.addWrite = redisAeAddWrite; - ac->ev.delWrite = redisAeDelWrite; - ac->ev.cleanup = redisAeCleanup; - ac->ev.data = e; - - return REDIS_OK; -} - -#if 1 //shenzheng 2015-11-5 redis cluster - -static int redisAeAttach_link(redisAsyncContext *ac, void *base) -{ - redisAeAttach((aeEventLoop *)base, ac); -} - -static int redisClusterAeAttach(aeEventLoop *loop, redisClusterAsyncContext *acc) { - - if(acc == NULL || loop == NULL) - { - return REDIS_ERR; - } - - acc->adapter = loop; - acc->attach_fn = redisAeAttach_link; - - return REDIS_OK; -} - -#endif //shenzheng 2015-11-5 redis cluster - -#endif diff --git a/ext/hiredis-vip-0.3.0/adapters/glib.h b/ext/hiredis-vip-0.3.0/adapters/glib.h deleted file mode 100644 index e13eee73b..000000000 --- a/ext/hiredis-vip-0.3.0/adapters/glib.h +++ /dev/null @@ -1,153 +0,0 @@ -#ifndef __HIREDIS_GLIB_H__ -#define __HIREDIS_GLIB_H__ - -#include - -#include "../hiredis.h" -#include "../async.h" - -typedef struct -{ - GSource source; - redisAsyncContext *ac; - GPollFD poll_fd; -} RedisSource; - -static void -redis_source_add_read (gpointer data) -{ - RedisSource *source = data; - g_return_if_fail(source); - source->poll_fd.events |= G_IO_IN; - g_main_context_wakeup(g_source_get_context(data)); -} - -static void -redis_source_del_read (gpointer data) -{ - RedisSource *source = data; - g_return_if_fail(source); - source->poll_fd.events &= ~G_IO_IN; - g_main_context_wakeup(g_source_get_context(data)); -} - -static void -redis_source_add_write (gpointer data) -{ - RedisSource *source = data; - g_return_if_fail(source); - source->poll_fd.events |= G_IO_OUT; - g_main_context_wakeup(g_source_get_context(data)); -} - -static void -redis_source_del_write (gpointer data) -{ - RedisSource *source = data; - g_return_if_fail(source); - source->poll_fd.events &= ~G_IO_OUT; - g_main_context_wakeup(g_source_get_context(data)); -} - -static void -redis_source_cleanup (gpointer data) -{ - RedisSource *source = data; - - g_return_if_fail(source); - - redis_source_del_read(source); - redis_source_del_write(source); - /* - * It is not our responsibility to remove ourself from the - * current main loop. However, we will remove the GPollFD. - */ - if (source->poll_fd.fd >= 0) { - g_source_remove_poll(data, &source->poll_fd); - source->poll_fd.fd = -1; - } -} - -static gboolean -redis_source_prepare (GSource *source, - gint *timeout_) -{ - RedisSource *redis = (RedisSource *)source; - *timeout_ = -1; - return !!(redis->poll_fd.events & redis->poll_fd.revents); -} - -static gboolean -redis_source_check (GSource *source) -{ - RedisSource *redis = (RedisSource *)source; - return !!(redis->poll_fd.events & redis->poll_fd.revents); -} - -static gboolean -redis_source_dispatch (GSource *source, - GSourceFunc callback, - gpointer user_data) -{ - RedisSource *redis = (RedisSource *)source; - - if ((redis->poll_fd.revents & G_IO_OUT)) { - redisAsyncHandleWrite(redis->ac); - redis->poll_fd.revents &= ~G_IO_OUT; - } - - if ((redis->poll_fd.revents & G_IO_IN)) { - redisAsyncHandleRead(redis->ac); - redis->poll_fd.revents &= ~G_IO_IN; - } - - if (callback) { - return callback(user_data); - } - - return TRUE; -} - -static void -redis_source_finalize (GSource *source) -{ - RedisSource *redis = (RedisSource *)source; - - if (redis->poll_fd.fd >= 0) { - g_source_remove_poll(source, &redis->poll_fd); - redis->poll_fd.fd = -1; - } -} - -static GSource * -redis_source_new (redisAsyncContext *ac) -{ - static GSourceFuncs source_funcs = { - .prepare = redis_source_prepare, - .check = redis_source_check, - .dispatch = redis_source_dispatch, - .finalize = redis_source_finalize, - }; - redisContext *c = &ac->c; - RedisSource *source; - - g_return_val_if_fail(ac != NULL, NULL); - - source = (RedisSource *)g_source_new(&source_funcs, sizeof *source); - source->ac = ac; - source->poll_fd.fd = c->fd; - source->poll_fd.events = 0; - source->poll_fd.revents = 0; - g_source_add_poll((GSource *)source, &source->poll_fd); - - ac->ev.addRead = redis_source_add_read; - ac->ev.delRead = redis_source_del_read; - ac->ev.addWrite = redis_source_add_write; - ac->ev.delWrite = redis_source_del_write; - ac->ev.cleanup = redis_source_cleanup; - ac->ev.data = source; - - return (GSource *)source; -} - -#endif /* __HIREDIS_GLIB_H__ */ diff --git a/ext/hiredis-vip-0.3.0/adapters/libev.h b/ext/hiredis-vip-0.3.0/adapters/libev.h deleted file mode 100644 index 2bf8d521f..000000000 --- a/ext/hiredis-vip-0.3.0/adapters/libev.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_LIBEV_H__ -#define __HIREDIS_LIBEV_H__ -#include -#include -#include -#include "../hiredis.h" -#include "../async.h" - -typedef struct redisLibevEvents { - redisAsyncContext *context; - struct ev_loop *loop; - int reading, writing; - ev_io rev, wev; -} redisLibevEvents; - -static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) { -#if EV_MULTIPLICITY - ((void)loop); -#endif - ((void)revents); - - redisLibevEvents *e = (redisLibevEvents*)watcher->data; - redisAsyncHandleRead(e->context); -} - -static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) { -#if EV_MULTIPLICITY - ((void)loop); -#endif - ((void)revents); - - redisLibevEvents *e = (redisLibevEvents*)watcher->data; - redisAsyncHandleWrite(e->context); -} - -static void redisLibevAddRead(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - if (!e->reading) { - e->reading = 1; - ev_io_start(EV_A_ &e->rev); - } -} - -static void redisLibevDelRead(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - if (e->reading) { - e->reading = 0; - ev_io_stop(EV_A_ &e->rev); - } -} - -static void redisLibevAddWrite(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - if (!e->writing) { - e->writing = 1; - ev_io_start(EV_A_ &e->wev); - } -} - -static void redisLibevDelWrite(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - struct ev_loop *loop = e->loop; - ((void)loop); - if (e->writing) { - e->writing = 0; - ev_io_stop(EV_A_ &e->wev); - } -} - -static void redisLibevCleanup(void *privdata) { - redisLibevEvents *e = (redisLibevEvents*)privdata; - redisLibevDelRead(privdata); - redisLibevDelWrite(privdata); - free(e); -} - -static int redisLibevAttach(EV_P_ redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisLibevEvents *e; - - /* Nothing should be attached when something is already attached */ - if (ac->ev.data != NULL) - return REDIS_ERR; - - /* Create container for context and r/w events */ - e = (redisLibevEvents*)malloc(sizeof(*e)); - e->context = ac; -#if EV_MULTIPLICITY - e->loop = loop; -#else - e->loop = NULL; -#endif - e->reading = e->writing = 0; - e->rev.data = e; - e->wev.data = e; - - /* Register functions to start/stop listening for events */ - ac->ev.addRead = redisLibevAddRead; - ac->ev.delRead = redisLibevDelRead; - ac->ev.addWrite = redisLibevAddWrite; - ac->ev.delWrite = redisLibevDelWrite; - ac->ev.cleanup = redisLibevCleanup; - ac->ev.data = e; - - /* Initialize read/write events */ - ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ); - ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE); - return REDIS_OK; -} - -#endif diff --git a/ext/hiredis-vip-0.3.0/adapters/libevent.h b/ext/hiredis-vip-0.3.0/adapters/libevent.h deleted file mode 100644 index 6bc911c77..000000000 --- a/ext/hiredis-vip-0.3.0/adapters/libevent.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __HIREDIS_LIBEVENT_H__ -#define __HIREDIS_LIBEVENT_H__ -#include -#include "../hiredis.h" -#include "../async.h" - -#if 1 //shenzheng 2015-9-21 redis cluster -#include "../hircluster.h" -#endif //shenzheng 2015-9-21 redis cluster - -typedef struct redisLibeventEvents { - redisAsyncContext *context; - struct event rev, wev; -} redisLibeventEvents; - -static void redisLibeventReadEvent(int fd, short event, void *arg) { - ((void)fd); ((void)event); - redisLibeventEvents *e = (redisLibeventEvents*)arg; - redisAsyncHandleRead(e->context); -} - -static void redisLibeventWriteEvent(int fd, short event, void *arg) { - ((void)fd); ((void)event); - redisLibeventEvents *e = (redisLibeventEvents*)arg; - redisAsyncHandleWrite(e->context); -} - -static void redisLibeventAddRead(void *privdata) { - redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_add(&e->rev,NULL); -} - -static void redisLibeventDelRead(void *privdata) { - redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_del(&e->rev); -} - -static void redisLibeventAddWrite(void *privdata) { - redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_add(&e->wev,NULL); -} - -static void redisLibeventDelWrite(void *privdata) { - redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_del(&e->wev); -} - -static void redisLibeventCleanup(void *privdata) { - redisLibeventEvents *e = (redisLibeventEvents*)privdata; - event_del(&e->rev); - event_del(&e->wev); - free(e); -} - -static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { - redisContext *c = &(ac->c); - redisLibeventEvents *e; - - /* Nothing should be attached when something is already attached */ - if (ac->ev.data != NULL) - return REDIS_ERR; - - /* Create container for context and r/w events */ - e = (redisLibeventEvents*)malloc(sizeof(*e)); - e->context = ac; - - /* Register functions to start/stop listening for events */ - ac->ev.addRead = redisLibeventAddRead; - ac->ev.delRead = redisLibeventDelRead; - ac->ev.addWrite = redisLibeventAddWrite; - ac->ev.delWrite = redisLibeventDelWrite; - ac->ev.cleanup = redisLibeventCleanup; - ac->ev.data = e; - - /* Initialize and install read/write events */ - event_set(&e->rev,c->fd,EV_READ,redisLibeventReadEvent,e); - event_set(&e->wev,c->fd,EV_WRITE,redisLibeventWriteEvent,e); - event_base_set(base,&e->rev); - event_base_set(base,&e->wev); - return REDIS_OK; -} - -#if 1 //shenzheng 2015-9-21 redis cluster - -static int redisLibeventAttach_link(redisAsyncContext *ac, void *base) -{ - redisLibeventAttach(ac, (struct event_base *)base); -} - -static int redisClusterLibeventAttach(redisClusterAsyncContext *acc, struct event_base *base) { - - if(acc == NULL || base == NULL) - { - return REDIS_ERR; - } - - acc->adapter = base; - acc->attach_fn = redisLibeventAttach_link; - - return REDIS_OK; -} - -#endif //shenzheng 2015-9-21 redis cluster - -#endif diff --git a/ext/hiredis-vip-0.3.0/adapters/libuv.h b/ext/hiredis-vip-0.3.0/adapters/libuv.h deleted file mode 100644 index 3c9a49f53..000000000 --- a/ext/hiredis-vip-0.3.0/adapters/libuv.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef __HIREDIS_LIBUV_H__ -#define __HIREDIS_LIBUV_H__ -#include -#include -#include "../hiredis.h" -#include "../async.h" -#include - -typedef struct redisLibuvEvents { - redisAsyncContext* context; - uv_poll_t handle; - int events; -} redisLibuvEvents; - - -static void redisLibuvPoll(uv_poll_t* handle, int status, int events) { - redisLibuvEvents* p = (redisLibuvEvents*)handle->data; - - if (status != 0) { - return; - } - - if (events & UV_READABLE) { - redisAsyncHandleRead(p->context); - } - if (events & UV_WRITABLE) { - redisAsyncHandleWrite(p->context); - } -} - - -static void redisLibuvAddRead(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->events |= UV_READABLE; - - uv_poll_start(&p->handle, p->events, redisLibuvPoll); -} - - -static void redisLibuvDelRead(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->events &= ~UV_READABLE; - - if (p->events) { - uv_poll_start(&p->handle, p->events, redisLibuvPoll); - } else { - uv_poll_stop(&p->handle); - } -} - - -static void redisLibuvAddWrite(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->events |= UV_WRITABLE; - - uv_poll_start(&p->handle, p->events, redisLibuvPoll); -} - - -static void redisLibuvDelWrite(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - p->events &= ~UV_WRITABLE; - - if (p->events) { - uv_poll_start(&p->handle, p->events, redisLibuvPoll); - } else { - uv_poll_stop(&p->handle); - } -} - - -static void on_close(uv_handle_t* handle) { - redisLibuvEvents* p = (redisLibuvEvents*)handle->data; - - free(p); -} - - -static void redisLibuvCleanup(void *privdata) { - redisLibuvEvents* p = (redisLibuvEvents*)privdata; - - uv_close((uv_handle_t*)&p->handle, on_close); -} - - -static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) { - redisContext *c = &(ac->c); - - if (ac->ev.data != NULL) { - return REDIS_ERR; - } - - ac->ev.addRead = redisLibuvAddRead; - ac->ev.delRead = redisLibuvDelRead; - ac->ev.addWrite = redisLibuvAddWrite; - ac->ev.delWrite = redisLibuvDelWrite; - ac->ev.cleanup = redisLibuvCleanup; - - redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p)); - - if (!p) { - return REDIS_ERR; - } - - memset(p, 0, sizeof(*p)); - - if (uv_poll_init(loop, &p->handle, c->fd) != 0) { - return REDIS_ERR; - } - - ac->ev.data = p; - p->handle.data = p; - p->context = ac; - - return REDIS_OK; -} - -#endif diff --git a/ext/hiredis-vip-0.3.0/adlist.c b/ext/hiredis-vip-0.3.0/adlist.c deleted file mode 100644 index b490a6bd1..000000000 --- a/ext/hiredis-vip-0.3.0/adlist.c +++ /dev/null @@ -1,341 +0,0 @@ -/* adlist.c - A generic doubly linked list implementation - * - * Copyright (c) 2006-2010, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -#include -#include "adlist.h" -#include "hiutil.h" - -/* Create a new list. The created list can be freed with - * AlFreeList(), but private value of every node need to be freed - * by the user before to call AlFreeList(). - * - * On error, NULL is returned. Otherwise the pointer to the new list. */ -hilist *listCreate(void) -{ - struct hilist *list; - - if ((list = hi_alloc(sizeof(*list))) == NULL) - return NULL; - list->head = list->tail = NULL; - list->len = 0; - list->dup = NULL; - list->free = NULL; - list->match = NULL; - return list; -} - -/* Free the whole list. - * - * This function can't fail. */ -void listRelease(hilist *list) -{ - unsigned long len; - listNode *current, *next; - - current = list->head; - len = list->len; - while(len--) { - next = current->next; - if (list->free) list->free(current->value); - hi_free(current); - current = next; - } - hi_free(list); -} - -/* Add a new node to the list, to head, containing the specified 'value' - * pointer as value. - * - * On error, NULL is returned and no operation is performed (i.e. the - * list remains unaltered). - * On success the 'list' pointer you pass to the function is returned. */ -hilist *listAddNodeHead(hilist *list, void *value) -{ - listNode *node; - - if ((node = hi_alloc(sizeof(*node))) == NULL) - return NULL; - node->value = value; - if (list->len == 0) { - list->head = list->tail = node; - node->prev = node->next = NULL; - } else { - node->prev = NULL; - node->next = list->head; - list->head->prev = node; - list->head = node; - } - list->len++; - return list; -} - -/* Add a new node to the list, to tail, containing the specified 'value' - * pointer as value. - * - * On error, NULL is returned and no operation is performed (i.e. the - * list remains unaltered). - * On success the 'list' pointer you pass to the function is returned. */ -hilist *listAddNodeTail(hilist *list, void *value) -{ - listNode *node; - - if ((node = hi_alloc(sizeof(*node))) == NULL) - return NULL; - node->value = value; - if (list->len == 0) { - list->head = list->tail = node; - node->prev = node->next = NULL; - } else { - node->prev = list->tail; - node->next = NULL; - list->tail->next = node; - list->tail = node; - } - list->len++; - return list; -} - -hilist *listInsertNode(hilist *list, listNode *old_node, void *value, int after) { - listNode *node; - - if ((node = hi_alloc(sizeof(*node))) == NULL) - return NULL; - node->value = value; - if (after) { - node->prev = old_node; - node->next = old_node->next; - if (list->tail == old_node) { - list->tail = node; - } - } else { - node->next = old_node; - node->prev = old_node->prev; - if (list->head == old_node) { - list->head = node; - } - } - if (node->prev != NULL) { - node->prev->next = node; - } - if (node->next != NULL) { - node->next->prev = node; - } - list->len++; - return list; -} - -/* Remove the specified node from the specified list. - * It's up to the caller to free the private value of the node. - * - * This function can't fail. */ -void listDelNode(hilist *list, listNode *node) -{ - if (node->prev) - node->prev->next = node->next; - else - list->head = node->next; - if (node->next) - node->next->prev = node->prev; - else - list->tail = node->prev; - if (list->free) list->free(node->value); - hi_free(node); - list->len--; -} - -/* Returns a list iterator 'iter'. After the initialization every - * call to listNext() will return the next element of the list. - * - * This function can't fail. */ -listIter *listGetIterator(hilist *list, int direction) -{ - listIter *iter; - - if ((iter = hi_alloc(sizeof(*iter))) == NULL) return NULL; - if (direction == AL_START_HEAD) - iter->next = list->head; - else - iter->next = list->tail; - iter->direction = direction; - return iter; -} - -/* Release the iterator memory */ -void listReleaseIterator(listIter *iter) { - hi_free(iter); -} - -/* Create an iterator in the list private iterator structure */ -void listRewind(hilist *list, listIter *li) { - li->next = list->head; - li->direction = AL_START_HEAD; -} - -void listRewindTail(hilist *list, listIter *li) { - li->next = list->tail; - li->direction = AL_START_TAIL; -} - -/* Return the next element of an iterator. - * It's valid to remove the currently returned element using - * listDelNode(), but not to remove other elements. - * - * The function returns a pointer to the next element of the list, - * or NULL if there are no more elements, so the classical usage patter - * is: - * - * iter = listGetIterator(list,); - * while ((node = listNext(iter)) != NULL) { - * doSomethingWith(listNodeValue(node)); - * } - * - * */ -listNode *listNext(listIter *iter) -{ - listNode *current = iter->next; - - if (current != NULL) { - if (iter->direction == AL_START_HEAD) - iter->next = current->next; - else - iter->next = current->prev; - } - return current; -} - -/* Duplicate the whole list. On out of memory NULL is returned. - * On success a copy of the original list is returned. - * - * The 'Dup' method set with listSetDupMethod() function is used - * to copy the node value. Otherwise the same pointer value of - * the original node is used as value of the copied node. - * - * The original list both on success or error is never modified. */ -hilist *listDup(hilist *orig) -{ - hilist *copy; - listIter *iter; - listNode *node; - - if ((copy = listCreate()) == NULL) - return NULL; - copy->dup = orig->dup; - copy->free = orig->free; - copy->match = orig->match; - iter = listGetIterator(orig, AL_START_HEAD); - while((node = listNext(iter)) != NULL) { - void *value; - - if (copy->dup) { - value = copy->dup(node->value); - if (value == NULL) { - listRelease(copy); - listReleaseIterator(iter); - return NULL; - } - } else - value = node->value; - if (listAddNodeTail(copy, value) == NULL) { - listRelease(copy); - listReleaseIterator(iter); - return NULL; - } - } - listReleaseIterator(iter); - return copy; -} - -/* Search the list for a node matching a given key. - * The match is performed using the 'match' method - * set with listSetMatchMethod(). If no 'match' method - * is set, the 'value' pointer of every node is directly - * compared with the 'key' pointer. - * - * On success the first matching node pointer is returned - * (search starts from head). If no matching node exists - * NULL is returned. */ -listNode *listSearchKey(hilist *list, void *key) -{ - listIter *iter; - listNode *node; - - iter = listGetIterator(list, AL_START_HEAD); - while((node = listNext(iter)) != NULL) { - if (list->match) { - if (list->match(node->value, key)) { - listReleaseIterator(iter); - return node; - } - } else { - if (key == node->value) { - listReleaseIterator(iter); - return node; - } - } - } - listReleaseIterator(iter); - return NULL; -} - -/* Return the element at the specified zero-based index - * where 0 is the head, 1 is the element next to head - * and so on. Negative integers are used in order to count - * from the tail, -1 is the last element, -2 the penultimate - * and so on. If the index is out of range NULL is returned. */ -listNode *listIndex(hilist *list, long index) { - listNode *n; - - if (index < 0) { - index = (-index)-1; - n = list->tail; - while(index-- && n) n = n->prev; - } else { - n = list->head; - while(index-- && n) n = n->next; - } - return n; -} - -/* Rotate the list removing the tail node and inserting it to the head. */ -void listRotate(hilist *list) { - listNode *tail = list->tail; - - if (listLength(list) <= 1) return; - - /* Detach current tail */ - list->tail = tail->prev; - list->tail->next = NULL; - /* Move it as head */ - list->head->prev = tail; - tail->prev = NULL; - tail->next = list->head; - list->head = tail; -} diff --git a/ext/hiredis-vip-0.3.0/adlist.h b/ext/hiredis-vip-0.3.0/adlist.h deleted file mode 100644 index 5b9a53ea5..000000000 --- a/ext/hiredis-vip-0.3.0/adlist.h +++ /dev/null @@ -1,93 +0,0 @@ -/* adlist.h - A generic doubly linked list implementation - * - * Copyright (c) 2006-2012, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ADLIST_H__ -#define __ADLIST_H__ - -/* Node, List, and Iterator are the only data structures used currently. */ - -typedef struct listNode { - struct listNode *prev; - struct listNode *next; - void *value; -} listNode; - -typedef struct listIter { - listNode *next; - int direction; -} listIter; - -typedef struct hilist { - listNode *head; - listNode *tail; - void *(*dup)(void *ptr); - void (*free)(void *ptr); - int (*match)(void *ptr, void *key); - unsigned long len; -} hilist; - -/* Functions implemented as macros */ -#define listLength(l) ((l)->len) -#define listFirst(l) ((l)->head) -#define listLast(l) ((l)->tail) -#define listPrevNode(n) ((n)->prev) -#define listNextNode(n) ((n)->next) -#define listNodeValue(n) ((n)->value) - -#define listSetDupMethod(l,m) ((l)->dup = (m)) -#define listSetFreeMethod(l,m) ((l)->free = (m)) -#define listSetMatchMethod(l,m) ((l)->match = (m)) - -#define listGetDupMethod(l) ((l)->dup) -#define listGetFree(l) ((l)->free) -#define listGetMatchMethod(l) ((l)->match) - -/* Prototypes */ -hilist *listCreate(void); -void listRelease(hilist *list); -hilist *listAddNodeHead(hilist *list, void *value); -hilist *listAddNodeTail(hilist *list, void *value); -hilist *listInsertNode(hilist *list, listNode *old_node, void *value, int after); -void listDelNode(hilist *list, listNode *node); -listIter *listGetIterator(hilist *list, int direction); -listNode *listNext(listIter *iter); -void listReleaseIterator(listIter *iter); -hilist *listDup(hilist *orig); -listNode *listSearchKey(hilist *list, void *key); -listNode *listIndex(hilist *list, long index); -void listRewind(hilist *list, listIter *li); -void listRewindTail(hilist *list, listIter *li); -void listRotate(hilist *list); - -/* Directions for iterators */ -#define AL_START_HEAD 0 -#define AL_START_TAIL 1 - -#endif /* __ADLIST_H__ */ diff --git a/ext/hiredis-vip-0.3.0/async.c b/ext/hiredis-vip-0.3.0/async.c deleted file mode 100644 index 75a3575de..000000000 --- a/ext/hiredis-vip-0.3.0/async.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include -#include -#include -#include -#include -#include -#include "async.h" -#include "net.h" -#include "dict.c" -#include "sds.h" - -#define _EL_ADD_READ(ctx) do { \ - if ((ctx)->ev.addRead) (ctx)->ev.addRead((ctx)->ev.data); \ - } while(0) -#define _EL_DEL_READ(ctx) do { \ - if ((ctx)->ev.delRead) (ctx)->ev.delRead((ctx)->ev.data); \ - } while(0) -#define _EL_ADD_WRITE(ctx) do { \ - if ((ctx)->ev.addWrite) (ctx)->ev.addWrite((ctx)->ev.data); \ - } while(0) -#define _EL_DEL_WRITE(ctx) do { \ - if ((ctx)->ev.delWrite) (ctx)->ev.delWrite((ctx)->ev.data); \ - } while(0) -#define _EL_CLEANUP(ctx) do { \ - if ((ctx)->ev.cleanup) (ctx)->ev.cleanup((ctx)->ev.data); \ - } while(0); - -/* Forward declaration of function in hiredis.c */ -int __redisAppendCommand(redisContext *c, const char *cmd, size_t len); - -/* Functions managing dictionary of callbacks for pub/sub. */ -static unsigned int callbackHash(const void *key) { - return dictGenHashFunction((const unsigned char *)key, - sdslen((const sds)key)); -} - -static void *callbackValDup(void *privdata, const void *src) { - ((void) privdata); - redisCallback *dup = malloc(sizeof(*dup)); - memcpy(dup,src,sizeof(*dup)); - return dup; -} - -static int callbackKeyCompare(void *privdata, const void *key1, const void *key2) { - int l1, l2; - ((void) privdata); - - l1 = sdslen((const sds)key1); - l2 = sdslen((const sds)key2); - if (l1 != l2) return 0; - return memcmp(key1,key2,l1) == 0; -} - -static void callbackKeyDestructor(void *privdata, void *key) { - ((void) privdata); - sdsfree((sds)key); -} - -static void callbackValDestructor(void *privdata, void *val) { - ((void) privdata); - free(val); -} - -static dictType callbackDict = { - callbackHash, - NULL, - callbackValDup, - callbackKeyCompare, - callbackKeyDestructor, - callbackValDestructor -}; - -static redisAsyncContext *redisAsyncInitialize(redisContext *c) { - redisAsyncContext *ac; - - ac = realloc(c,sizeof(redisAsyncContext)); - if (ac == NULL) - return NULL; - - c = &(ac->c); - - /* The regular connect functions will always set the flag REDIS_CONNECTED. - * For the async API, we want to wait until the first write event is - * received up before setting this flag, so reset it here. */ - c->flags &= ~REDIS_CONNECTED; - - ac->err = 0; - ac->errstr = NULL; - ac->data = NULL; - ac->dataHandler = NULL; - - ac->ev.data = NULL; - ac->ev.addRead = NULL; - ac->ev.delRead = NULL; - ac->ev.addWrite = NULL; - ac->ev.delWrite = NULL; - ac->ev.cleanup = NULL; - - ac->onConnect = NULL; - ac->onDisconnect = NULL; - - ac->replies.head = NULL; - ac->replies.tail = NULL; - ac->sub.invalid.head = NULL; - ac->sub.invalid.tail = NULL; - ac->sub.channels = dictCreate(&callbackDict,NULL); - ac->sub.patterns = dictCreate(&callbackDict,NULL); - return ac; -} - -/* We want the error field to be accessible directly instead of requiring - * an indirection to the redisContext struct. */ -static void __redisAsyncCopyError(redisAsyncContext *ac) { - if (!ac) - return; - - redisContext *c = &(ac->c); - ac->err = c->err; - ac->errstr = c->errstr; -} - -redisAsyncContext *redisAsyncConnect(const char *ip, int port) { - redisContext *c; - redisAsyncContext *ac; - - c = redisConnectNonBlock(ip,port); - if (c == NULL) - return NULL; - - ac = redisAsyncInitialize(c); - if (ac == NULL) { - redisFree(c); - return NULL; - } - - __redisAsyncCopyError(ac); - return ac; -} - -redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, - const char *source_addr) { - redisContext *c = redisConnectBindNonBlock(ip,port,source_addr); - redisAsyncContext *ac = redisAsyncInitialize(c); - __redisAsyncCopyError(ac); - return ac; -} - -redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, - const char *source_addr) { - redisContext *c = redisConnectBindNonBlockWithReuse(ip,port,source_addr); - redisAsyncContext *ac = redisAsyncInitialize(c); - __redisAsyncCopyError(ac); - return ac; -} - -redisAsyncContext *redisAsyncConnectUnix(const char *path) { - redisContext *c; - redisAsyncContext *ac; - - c = redisConnectUnixNonBlock(path); - if (c == NULL) - return NULL; - - ac = redisAsyncInitialize(c); - if (ac == NULL) { - redisFree(c); - return NULL; - } - - __redisAsyncCopyError(ac); - return ac; -} - -int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) { - if (ac->onConnect == NULL) { - ac->onConnect = fn; - - /* The common way to detect an established connection is to wait for - * the first write event to be fired. This assumes the related event - * library functions are already set. */ - _EL_ADD_WRITE(ac); - return REDIS_OK; - } - return REDIS_ERR; -} - -int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) { - if (ac->onDisconnect == NULL) { - ac->onDisconnect = fn; - return REDIS_OK; - } - return REDIS_ERR; -} - -/* Helper functions to push/shift callbacks */ -static int __redisPushCallback(redisCallbackList *list, redisCallback *source) { - redisCallback *cb; - - /* Copy callback from stack to heap */ - cb = malloc(sizeof(*cb)); - if (cb == NULL) - return REDIS_ERR_OOM; - - if (source != NULL) { - memcpy(cb,source,sizeof(*cb)); - cb->next = NULL; - } - - /* Store callback in list */ - if (list->head == NULL) - list->head = cb; - if (list->tail != NULL) - list->tail->next = cb; - list->tail = cb; - return REDIS_OK; -} - -static int __redisShiftCallback(redisCallbackList *list, redisCallback *target) { - redisCallback *cb = list->head; - if (cb != NULL) { - list->head = cb->next; - if (cb == list->tail) - list->tail = NULL; - - /* Copy callback from heap to stack */ - if (target != NULL) - memcpy(target,cb,sizeof(*cb)); - free(cb); - return REDIS_OK; - } - return REDIS_ERR; -} - -static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisReply *reply) { - redisContext *c = &(ac->c); - if (cb->fn != NULL) { - c->flags |= REDIS_IN_CALLBACK; - cb->fn(ac,reply,cb->privdata); - c->flags &= ~REDIS_IN_CALLBACK; - } -} - -/* Helper function to free the context. */ -static void __redisAsyncFree(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisCallback cb; - dictIterator *it; - dictEntry *de; - - /* Execute pending callbacks with NULL reply. */ - while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK) - __redisRunCallback(ac,&cb,NULL); - - /* Execute callbacks for invalid commands */ - while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK) - __redisRunCallback(ac,&cb,NULL); - - /* Run subscription callbacks callbacks with NULL reply */ - it = dictGetIterator(ac->sub.channels); - while ((de = dictNext(it)) != NULL) - __redisRunCallback(ac,dictGetEntryVal(de),NULL); - dictReleaseIterator(it); - dictRelease(ac->sub.channels); - - it = dictGetIterator(ac->sub.patterns); - while ((de = dictNext(it)) != NULL) - __redisRunCallback(ac,dictGetEntryVal(de),NULL); - dictReleaseIterator(it); - dictRelease(ac->sub.patterns); - - /* Signal event lib to clean up */ - _EL_CLEANUP(ac); - - /* Execute disconnect callback. When redisAsyncFree() initiated destroying - * this context, the status will always be REDIS_OK. */ - if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) { - if (c->flags & REDIS_FREEING) { - ac->onDisconnect(ac,REDIS_OK); - } else { - ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR); - } - } - - if (ac->dataHandler) { - ac->dataHandler(ac); - } - - /* Cleanup self */ - redisFree(c); -} - -/* Free the async context. When this function is called from a callback, - * control needs to be returned to redisProcessCallbacks() before actual - * free'ing. To do so, a flag is set on the context which is picked up by - * redisProcessCallbacks(). Otherwise, the context is immediately free'd. */ -void redisAsyncFree(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - c->flags |= REDIS_FREEING; - if (!(c->flags & REDIS_IN_CALLBACK)) - __redisAsyncFree(ac); -} - -/* Helper function to make the disconnect happen and clean up. */ -static void __redisAsyncDisconnect(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - - /* Make sure error is accessible if there is any */ - __redisAsyncCopyError(ac); - - if (ac->err == 0) { - /* For clean disconnects, there should be no pending callbacks. */ - assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR); - } else { - /* Disconnection is caused by an error, make sure that pending - * callbacks cannot call new commands. */ - c->flags |= REDIS_DISCONNECTING; - } - - /* For non-clean disconnects, __redisAsyncFree() will execute pending - * callbacks with a NULL-reply. */ - __redisAsyncFree(ac); -} - -/* Tries to do a clean disconnect from Redis, meaning it stops new commands - * from being issued, but tries to flush the output buffer and execute - * callbacks for all remaining replies. When this function is called from a - * callback, there might be more replies and we can safely defer disconnecting - * to redisProcessCallbacks(). Otherwise, we can only disconnect immediately - * when there are no pending callbacks. */ -void redisAsyncDisconnect(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - c->flags |= REDIS_DISCONNECTING; - if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL) - __redisAsyncDisconnect(ac); -} - -static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) { - redisContext *c = &(ac->c); - dict *callbacks; - dictEntry *de; - int pvariant; - char *stype; - sds sname; - - /* Custom reply functions are not supported for pub/sub. This will fail - * very hard when they are used... */ - if (reply->type == REDIS_REPLY_ARRAY) { - assert(reply->elements >= 2); - assert(reply->element[0]->type == REDIS_REPLY_STRING); - stype = reply->element[0]->str; - pvariant = (tolower(stype[0]) == 'p') ? 1 : 0; - - if (pvariant) - callbacks = ac->sub.patterns; - else - callbacks = ac->sub.channels; - - /* Locate the right callback */ - assert(reply->element[1]->type == REDIS_REPLY_STRING); - sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len); - de = dictFind(callbacks,sname); - if (de != NULL) { - memcpy(dstcb,dictGetEntryVal(de),sizeof(*dstcb)); - - /* If this is an unsubscribe message, remove it. */ - if (strcasecmp(stype+pvariant,"unsubscribe") == 0) { - dictDelete(callbacks,sname); - - /* If this was the last unsubscribe message, revert to - * non-subscribe mode. */ - assert(reply->element[2]->type == REDIS_REPLY_INTEGER); - if (reply->element[2]->integer == 0) - c->flags &= ~REDIS_SUBSCRIBED; - } - } - sdsfree(sname); - } else { - /* Shift callback for invalid commands. */ - __redisShiftCallback(&ac->sub.invalid,dstcb); - } - return REDIS_OK; -} - -void redisProcessCallbacks(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - redisCallback cb = {NULL, NULL, NULL}; - void *reply = NULL; - int status; - - while((status = redisGetReply(c,&reply)) == REDIS_OK) { - if (reply == NULL) { - /* When the connection is being disconnected and there are - * no more replies, this is the cue to really disconnect. */ - if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0) { - __redisAsyncDisconnect(ac); - return; - } - - /* If monitor mode, repush callback */ - if(c->flags & REDIS_MONITORING) { - __redisPushCallback(&ac->replies,&cb); - } - - /* When the connection is not being disconnected, simply stop - * trying to get replies and wait for the next loop tick. */ - break; - } - - /* Even if the context is subscribed, pending regular callbacks will - * get a reply before pub/sub messages arrive. */ - if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) { - /* - * A spontaneous reply in a not-subscribed context can be the error - * reply that is sent when a new connection exceeds the maximum - * number of allowed connections on the server side. - * - * This is seen as an error instead of a regular reply because the - * server closes the connection after sending it. - * - * To prevent the error from being overwritten by an EOF error the - * connection is closed here. See issue #43. - * - * Another possibility is that the server is loading its dataset. - * In this case we also want to close the connection, and have the - * user wait until the server is ready to take our request. - */ - if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) { - c->err = REDIS_ERR_OTHER; - snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str); - c->reader->fn->freeObject(reply); - __redisAsyncDisconnect(ac); - return; - } - /* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */ - assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING)); - if(c->flags & REDIS_SUBSCRIBED) - __redisGetSubscribeCallback(ac,reply,&cb); - } - - if (cb.fn != NULL) { - __redisRunCallback(ac,&cb,reply); - c->reader->fn->freeObject(reply); - - /* Proceed with free'ing when redisAsyncFree() was called. */ - if (c->flags & REDIS_FREEING) { - __redisAsyncFree(ac); - return; - } - } else { - /* No callback for this reply. This can either be a NULL callback, - * or there were no callbacks to begin with. Either way, don't - * abort with an error, but simply ignore it because the client - * doesn't know what the server will spit out over the wire. */ - c->reader->fn->freeObject(reply); - } - } - - /* Disconnect when there was an error reading the reply */ - if (status != REDIS_OK) - __redisAsyncDisconnect(ac); -} - -/* Internal helper function to detect socket status the first time a read or - * write event fires. When connecting was not succesful, the connect callback - * is called with a REDIS_ERR status and the context is free'd. */ -static int __redisAsyncHandleConnect(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - - if (redisCheckSocketError(c) == REDIS_ERR) { - /* Try again later when connect(2) is still in progress. */ - if (errno == EINPROGRESS) - return REDIS_OK; - - if (ac->onConnect) ac->onConnect(ac,REDIS_ERR); - __redisAsyncDisconnect(ac); - return REDIS_ERR; - } - - /* Mark context as connected. */ - c->flags |= REDIS_CONNECTED; - if (ac->onConnect) ac->onConnect(ac,REDIS_OK); - return REDIS_OK; -} - -/* This function should be called when the socket is readable. - * It processes all replies that can be read and executes their callbacks. - */ -void redisAsyncHandleRead(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - - if (!(c->flags & REDIS_CONNECTED)) { - /* Abort connect was not successful. */ - if (__redisAsyncHandleConnect(ac) != REDIS_OK) - return; - /* Try again later when the context is still not connected. */ - if (!(c->flags & REDIS_CONNECTED)) - return; - } - - if (redisBufferRead(c) == REDIS_ERR) { - __redisAsyncDisconnect(ac); - } else { - /* Always re-schedule reads */ - _EL_ADD_READ(ac); - redisProcessCallbacks(ac); - } -} - -void redisAsyncHandleWrite(redisAsyncContext *ac) { - redisContext *c = &(ac->c); - int done = 0; - - if (!(c->flags & REDIS_CONNECTED)) { - /* Abort connect was not successful. */ - if (__redisAsyncHandleConnect(ac) != REDIS_OK) - return; - /* Try again later when the context is still not connected. */ - if (!(c->flags & REDIS_CONNECTED)) - return; - } - - if (redisBufferWrite(c,&done) == REDIS_ERR) { - __redisAsyncDisconnect(ac); - } else { - /* Continue writing when not done, stop writing otherwise */ - if (!done) - _EL_ADD_WRITE(ac); - else - _EL_DEL_WRITE(ac); - - /* Always schedule reads after writes */ - _EL_ADD_READ(ac); - } -} - -/* Sets a pointer to the first argument and its length starting at p. Returns - * the number of bytes to skip to get to the following argument. */ -static const char *nextArgument(const char *start, const char **str, size_t *len) { - const char *p = start; - if (p[0] != '$') { - p = strchr(p,'$'); - if (p == NULL) return NULL; - } - - *len = (int)strtol(p+1,NULL,10); - p = strchr(p,'\r'); - assert(p); - *str = p+2; - return p+2+(*len)+2; -} - -/* Helper function for the redisAsyncCommand* family of functions. Writes a - * formatted command to the output buffer and registers the provided callback - * function with the context. */ -static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { - redisContext *c = &(ac->c); - redisCallback cb; - int pvariant, hasnext; - const char *cstr, *astr; - size_t clen, alen; - const char *p; - sds sname; - int ret; - - /* Don't accept new commands when the connection is about to be closed. */ - if (c->flags & (REDIS_DISCONNECTING | REDIS_FREEING)) return REDIS_ERR; - - /* Setup callback */ - cb.fn = fn; - cb.privdata = privdata; - - /* Find out which command will be appended. */ - p = nextArgument(cmd,&cstr,&clen); - assert(p != NULL); - hasnext = (p[0] == '$'); - pvariant = (tolower(cstr[0]) == 'p') ? 1 : 0; - cstr += pvariant; - clen -= pvariant; - - if (hasnext && strncasecmp(cstr,"subscribe\r\n",11) == 0) { - c->flags |= REDIS_SUBSCRIBED; - - /* Add every channel/pattern to the list of subscription callbacks. */ - while ((p = nextArgument(p,&astr,&alen)) != NULL) { - sname = sdsnewlen(astr,alen); - if (pvariant) - ret = dictReplace(ac->sub.patterns,sname,&cb); - else - ret = dictReplace(ac->sub.channels,sname,&cb); - - if (ret == 0) sdsfree(sname); - } - } else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) { - /* It is only useful to call (P)UNSUBSCRIBE when the context is - * subscribed to one or more channels or patterns. */ - if (!(c->flags & REDIS_SUBSCRIBED)) return REDIS_ERR; - - /* (P)UNSUBSCRIBE does not have its own response: every channel or - * pattern that is unsubscribed will receive a message. This means we - * should not append a callback function for this command. */ - } else if(strncasecmp(cstr,"monitor\r\n",9) == 0) { - /* Set monitor flag and push callback */ - c->flags |= REDIS_MONITORING; - __redisPushCallback(&ac->replies,&cb); - } else { - if (c->flags & REDIS_SUBSCRIBED) - /* This will likely result in an error reply, but it needs to be - * received and passed to the callback. */ - __redisPushCallback(&ac->sub.invalid,&cb); - else - __redisPushCallback(&ac->replies,&cb); - } - - __redisAppendCommand(c,cmd,len); - - /* Always schedule a write when the write buffer is non-empty */ - _EL_ADD_WRITE(ac); - - return REDIS_OK; -} - -int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) { - char *cmd; - int len; - int status; - len = redisvFormatCommand(&cmd,format,ap); - - /* We don't want to pass -1 or -2 to future functions as a length. */ - if (len < 0) - return REDIS_ERR; - - status = __redisAsyncCommand(ac,fn,privdata,cmd,len); - free(cmd); - return status; -} - -int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...) { - va_list ap; - int status; - va_start(ap,format); - status = redisvAsyncCommand(ac,fn,privdata,format,ap); - va_end(ap); - return status; -} - -int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) { - sds cmd; - int len; - int status; - len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); - status = __redisAsyncCommand(ac,fn,privdata,cmd,len); - sdsfree(cmd); - return status; -} - -int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { - int status = __redisAsyncCommand(ac,fn,privdata,cmd,len); - return status; -} diff --git a/ext/hiredis-vip-0.3.0/command.c b/ext/hiredis-vip-0.3.0/command.c deleted file mode 100644 index e32091b40..000000000 --- a/ext/hiredis-vip-0.3.0/command.c +++ /dev/null @@ -1,1700 +0,0 @@ -#include -#include - -#include "command.h" -#include "hiutil.h" -#include "hiarray.h" - - -static uint64_t cmd_id = 0; /* command id counter */ - - -/* - * Return true, if the redis command take no key, otherwise - * return false - */ -static int -redis_argz(struct cmd *r) -{ - switch (r->type) { - case CMD_REQ_REDIS_PING: - case CMD_REQ_REDIS_QUIT: - return 1; - - default: - break; - } - - return 0; -} - -/* - * Return true, if the redis command accepts no arguments, otherwise - * return false - */ -static int -redis_arg0(struct cmd *r) -{ - switch (r->type) { - case CMD_REQ_REDIS_EXISTS: - case CMD_REQ_REDIS_PERSIST: - case CMD_REQ_REDIS_PTTL: - case CMD_REQ_REDIS_SORT: - case CMD_REQ_REDIS_TTL: - case CMD_REQ_REDIS_TYPE: - case CMD_REQ_REDIS_DUMP: - - case CMD_REQ_REDIS_DECR: - case CMD_REQ_REDIS_GET: - case CMD_REQ_REDIS_INCR: - case CMD_REQ_REDIS_STRLEN: - - case CMD_REQ_REDIS_HGETALL: - case CMD_REQ_REDIS_HKEYS: - case CMD_REQ_REDIS_HLEN: - case CMD_REQ_REDIS_HVALS: - - case CMD_REQ_REDIS_LLEN: - case CMD_REQ_REDIS_LPOP: - case CMD_REQ_REDIS_RPOP: - - case CMD_REQ_REDIS_SCARD: - case CMD_REQ_REDIS_SMEMBERS: - case CMD_REQ_REDIS_SPOP: - - case CMD_REQ_REDIS_ZCARD: - case CMD_REQ_REDIS_PFCOUNT: - case CMD_REQ_REDIS_AUTH: - return 1; - - default: - break; - } - - return 0; -} - -/* - * Return true, if the redis command accepts exactly 1 argument, otherwise - * return false - */ -static int -redis_arg1(struct cmd *r) -{ - switch (r->type) { - case CMD_REQ_REDIS_EXPIRE: - case CMD_REQ_REDIS_EXPIREAT: - case CMD_REQ_REDIS_PEXPIRE: - case CMD_REQ_REDIS_PEXPIREAT: - - case CMD_REQ_REDIS_APPEND: - case CMD_REQ_REDIS_DECRBY: - case CMD_REQ_REDIS_GETBIT: - case CMD_REQ_REDIS_GETSET: - case CMD_REQ_REDIS_INCRBY: - case CMD_REQ_REDIS_INCRBYFLOAT: - case CMD_REQ_REDIS_SETNX: - - case CMD_REQ_REDIS_HEXISTS: - case CMD_REQ_REDIS_HGET: - - case CMD_REQ_REDIS_LINDEX: - case CMD_REQ_REDIS_LPUSHX: - case CMD_REQ_REDIS_RPOPLPUSH: - case CMD_REQ_REDIS_RPUSHX: - - case CMD_REQ_REDIS_SISMEMBER: - - case CMD_REQ_REDIS_ZRANK: - case CMD_REQ_REDIS_ZREVRANK: - case CMD_REQ_REDIS_ZSCORE: - return 1; - - default: - break; - } - - return 0; -} - -/* - * Return true, if the redis command accepts exactly 2 arguments, otherwise - * return false - */ -static int -redis_arg2(struct cmd *r) -{ - switch (r->type) { - case CMD_REQ_REDIS_GETRANGE: - case CMD_REQ_REDIS_PSETEX: - case CMD_REQ_REDIS_SETBIT: - case CMD_REQ_REDIS_SETEX: - case CMD_REQ_REDIS_SETRANGE: - - case CMD_REQ_REDIS_HINCRBY: - case CMD_REQ_REDIS_HINCRBYFLOAT: - case CMD_REQ_REDIS_HSET: - case CMD_REQ_REDIS_HSETNX: - - case CMD_REQ_REDIS_LRANGE: - case CMD_REQ_REDIS_LREM: - case CMD_REQ_REDIS_LSET: - case CMD_REQ_REDIS_LTRIM: - - case CMD_REQ_REDIS_SMOVE: - - case CMD_REQ_REDIS_ZCOUNT: - case CMD_REQ_REDIS_ZLEXCOUNT: - case CMD_REQ_REDIS_ZINCRBY: - case CMD_REQ_REDIS_ZREMRANGEBYLEX: - case CMD_REQ_REDIS_ZREMRANGEBYRANK: - case CMD_REQ_REDIS_ZREMRANGEBYSCORE: - - case CMD_REQ_REDIS_RESTORE: - return 1; - - default: - break; - } - - return 0; -} - -/* - * Return true, if the redis command accepts exactly 3 arguments, otherwise - * return false - */ -static int -redis_arg3(struct cmd *r) -{ - switch (r->type) { - case CMD_REQ_REDIS_LINSERT: - return 1; - - default: - break; - } - - return 0; -} - -/* - * Return true, if the redis command accepts 0 or more arguments, otherwise - * return false - */ -static int -redis_argn(struct cmd *r) -{ - switch (r->type) { - case CMD_REQ_REDIS_BITCOUNT: - - case CMD_REQ_REDIS_SET: - case CMD_REQ_REDIS_HDEL: - case CMD_REQ_REDIS_HMGET: - case CMD_REQ_REDIS_HMSET: - case CMD_REQ_REDIS_HSCAN: - - case CMD_REQ_REDIS_LPUSH: - case CMD_REQ_REDIS_RPUSH: - - case CMD_REQ_REDIS_SADD: - case CMD_REQ_REDIS_SDIFF: - case CMD_REQ_REDIS_SDIFFSTORE: - case CMD_REQ_REDIS_SINTER: - case CMD_REQ_REDIS_SINTERSTORE: - case CMD_REQ_REDIS_SREM: - case CMD_REQ_REDIS_SUNION: - case CMD_REQ_REDIS_SUNIONSTORE: - case CMD_REQ_REDIS_SRANDMEMBER: - case CMD_REQ_REDIS_SSCAN: - - case CMD_REQ_REDIS_PFADD: - case CMD_REQ_REDIS_PFMERGE: - - case CMD_REQ_REDIS_ZADD: - case CMD_REQ_REDIS_ZINTERSTORE: - case CMD_REQ_REDIS_ZRANGE: - case CMD_REQ_REDIS_ZRANGEBYSCORE: - case CMD_REQ_REDIS_ZREM: - case CMD_REQ_REDIS_ZREVRANGE: - case CMD_REQ_REDIS_ZRANGEBYLEX: - case CMD_REQ_REDIS_ZREVRANGEBYSCORE: - case CMD_REQ_REDIS_ZUNIONSTORE: - case CMD_REQ_REDIS_ZSCAN: - return 1; - - default: - break; - } - - return 0; -} - -/* - * Return true, if the redis command is a vector command accepting one or - * more keys, otherwise return false - */ -static int -redis_argx(struct cmd *r) -{ - switch (r->type) { - case CMD_REQ_REDIS_MGET: - case CMD_REQ_REDIS_DEL: - return 1; - - default: - break; - } - - return 0; -} - -/* - * Return true, if the redis command is a vector command accepting one or - * more key-value pairs, otherwise return false - */ -static int -redis_argkvx(struct cmd *r) -{ - switch (r->type) { - case CMD_REQ_REDIS_MSET: - return 1; - - default: - break; - } - - return 0; -} - -/* - * Return true, if the redis command is either EVAL or EVALSHA. These commands - * have a special format with exactly 2 arguments, followed by one or more keys, - * followed by zero or more arguments (the documentation online seems to suggest - * that at least one argument is required, but that shouldn't be the case). - */ -static int -redis_argeval(struct cmd *r) -{ - switch (r->type) { - case CMD_REQ_REDIS_EVAL: - case CMD_REQ_REDIS_EVALSHA: - return 1; - - default: - break; - } - - return 0; -} - -/* - * Reference: http://redis.io/topics/protocol - * - * Redis >= 1.2 uses the unified protocol to send requests to the Redis - * server. In the unified protocol all the arguments sent to the server - * are binary safe and every request has the following general form: - * - * * CR LF - * $ CR LF - * CR LF - * ... - * $ CR LF - * CR LF - * - * Before the unified request protocol, redis protocol for requests supported - * the following commands - * 1). Inline commands: simple commands where arguments are just space - * separated strings. No binary safeness is possible. - * 2). Bulk commands: bulk commands are exactly like inline commands, but - * the last argument is handled in a special way in order to allow for - * a binary-safe last argument. - * - * only supports the Redis unified protocol for requests. - */ -void -redis_parse_cmd(struct cmd *r) -{ - int len; - char *p, *m, *token = NULL; - char *cmd_end; - char ch; - uint32_t rlen = 0; /* running length in parsing fsa */ - uint32_t rnarg = 0; /* running # arg used by parsing fsa */ - enum { - SW_START, - SW_NARG, - SW_NARG_LF, - SW_REQ_TYPE_LEN, - SW_REQ_TYPE_LEN_LF, - SW_REQ_TYPE, - SW_REQ_TYPE_LF, - SW_KEY_LEN, - SW_KEY_LEN_LF, - SW_KEY, - SW_KEY_LF, - SW_ARG1_LEN, - SW_ARG1_LEN_LF, - SW_ARG1, - SW_ARG1_LF, - SW_ARG2_LEN, - SW_ARG2_LEN_LF, - SW_ARG2, - SW_ARG2_LF, - SW_ARG3_LEN, - SW_ARG3_LEN_LF, - SW_ARG3, - SW_ARG3_LF, - SW_ARGN_LEN, - SW_ARGN_LEN_LF, - SW_ARGN, - SW_ARGN_LF, - SW_SENTINEL - } state; - - state = SW_START; - cmd_end = r->cmd + r->clen; - - ASSERT(state >= SW_START && state < SW_SENTINEL); - ASSERT(r->cmd != NULL && r->clen > 0); - - for (p = r->cmd; p < cmd_end; p++) { - ch = *p; - - switch (state) { - - case SW_START: - case SW_NARG: - if (token == NULL) { - if (ch != '*') { - goto error; - } - token = p; - /* req_start <- p */ - r->narg_start = p; - rnarg = 0; - state = SW_NARG; - } else if (isdigit(ch)) { - rnarg = rnarg * 10 + (uint32_t)(ch - '0'); - } else if (ch == CR) { - if (rnarg == 0) { - goto error; - } - r->narg = rnarg; - r->narg_end = p; - token = NULL; - state = SW_NARG_LF; - } else { - goto error; - } - - break; - - case SW_NARG_LF: - switch (ch) { - case LF: - state = SW_REQ_TYPE_LEN; - break; - - default: - goto error; - } - - break; - - case SW_REQ_TYPE_LEN: - if (token == NULL) { - if (ch != '$') { - goto error; - } - token = p; - rlen = 0; - } else if (isdigit(ch)) { - rlen = rlen * 10 + (uint32_t)(ch - '0'); - } else if (ch == CR) { - if (rlen == 0 || rnarg == 0) { - goto error; - } - rnarg--; - token = NULL; - state = SW_REQ_TYPE_LEN_LF; - } else { - goto error; - } - - break; - - case SW_REQ_TYPE_LEN_LF: - switch (ch) { - case LF: - state = SW_REQ_TYPE; - break; - - default: - goto error; - } - - break; - - case SW_REQ_TYPE: - if (token == NULL) { - token = p; - } - - m = token + rlen; - if (m >= cmd_end) { - //m = cmd_end - 1; - //p = m; - //break; - goto error; - } - - if (*m != CR) { - goto error; - } - - p = m; /* move forward by rlen bytes */ - rlen = 0; - m = token; - token = NULL; - r->type = CMD_UNKNOWN; - - switch (p - m) { - - case 3: - if (str3icmp(m, 'g', 'e', 't')) { - r->type = CMD_REQ_REDIS_GET; - break; - } - - if (str3icmp(m, 's', 'e', 't')) { - r->type = CMD_REQ_REDIS_SET; - break; - } - - if (str3icmp(m, 't', 't', 'l')) { - r->type = CMD_REQ_REDIS_TTL; - break; - } - - if (str3icmp(m, 'd', 'e', 'l')) { - r->type = CMD_REQ_REDIS_DEL; - break; - } - - break; - - case 4: - if (str4icmp(m, 'p', 't', 't', 'l')) { - r->type = CMD_REQ_REDIS_PTTL; - break; - } - - if (str4icmp(m, 'd', 'e', 'c', 'r')) { - r->type = CMD_REQ_REDIS_DECR; - break; - } - - if (str4icmp(m, 'd', 'u', 'm', 'p')) { - r->type = CMD_REQ_REDIS_DUMP; - break; - } - - if (str4icmp(m, 'h', 'd', 'e', 'l')) { - r->type = CMD_REQ_REDIS_HDEL; - break; - } - - if (str4icmp(m, 'h', 'g', 'e', 't')) { - r->type = CMD_REQ_REDIS_HGET; - break; - } - - if (str4icmp(m, 'h', 'l', 'e', 'n')) { - r->type = CMD_REQ_REDIS_HLEN; - break; - } - - if (str4icmp(m, 'h', 's', 'e', 't')) { - r->type = CMD_REQ_REDIS_HSET; - break; - } - - if (str4icmp(m, 'i', 'n', 'c', 'r')) { - r->type = CMD_REQ_REDIS_INCR; - break; - } - - if (str4icmp(m, 'l', 'l', 'e', 'n')) { - r->type = CMD_REQ_REDIS_LLEN; - break; - } - - if (str4icmp(m, 'l', 'p', 'o', 'p')) { - r->type = CMD_REQ_REDIS_LPOP; - break; - } - - if (str4icmp(m, 'l', 'r', 'e', 'm')) { - r->type = CMD_REQ_REDIS_LREM; - break; - } - - if (str4icmp(m, 'l', 's', 'e', 't')) { - r->type = CMD_REQ_REDIS_LSET; - break; - } - - if (str4icmp(m, 'r', 'p', 'o', 'p')) { - r->type = CMD_REQ_REDIS_RPOP; - break; - } - - if (str4icmp(m, 's', 'a', 'd', 'd')) { - r->type = CMD_REQ_REDIS_SADD; - break; - } - - if (str4icmp(m, 's', 'p', 'o', 'p')) { - r->type = CMD_REQ_REDIS_SPOP; - break; - } - - if (str4icmp(m, 's', 'r', 'e', 'm')) { - r->type = CMD_REQ_REDIS_SREM; - break; - } - - if (str4icmp(m, 't', 'y', 'p', 'e')) { - r->type = CMD_REQ_REDIS_TYPE; - break; - } - - if (str4icmp(m, 'm', 'g', 'e', 't')) { - r->type = CMD_REQ_REDIS_MGET; - break; - } - if (str4icmp(m, 'm', 's', 'e', 't')) { - r->type = CMD_REQ_REDIS_MSET; - break; - } - - if (str4icmp(m, 'z', 'a', 'd', 'd')) { - r->type = CMD_REQ_REDIS_ZADD; - break; - } - - if (str4icmp(m, 'z', 'r', 'e', 'm')) { - r->type = CMD_REQ_REDIS_ZREM; - break; - } - - if (str4icmp(m, 'e', 'v', 'a', 'l')) { - r->type = CMD_REQ_REDIS_EVAL; - break; - } - - if (str4icmp(m, 's', 'o', 'r', 't')) { - r->type = CMD_REQ_REDIS_SORT; - break; - } - - if (str4icmp(m, 'p', 'i', 'n', 'g')) { - r->type = CMD_REQ_REDIS_PING; - r->noforward = 1; - break; - } - - if (str4icmp(m, 'q', 'u', 'i', 't')) { - r->type = CMD_REQ_REDIS_QUIT; - r->quit = 1; - break; - } - - if (str4icmp(m, 'a', 'u', 't', 'h')) { - r->type = CMD_REQ_REDIS_AUTH; - r->noforward = 1; - break; - } - - break; - - case 5: - if (str5icmp(m, 'h', 'k', 'e', 'y', 's')) { - r->type = CMD_REQ_REDIS_HKEYS; - break; - } - - if (str5icmp(m, 'h', 'm', 'g', 'e', 't')) { - r->type = CMD_REQ_REDIS_HMGET; - break; - } - - if (str5icmp(m, 'h', 'm', 's', 'e', 't')) { - r->type = CMD_REQ_REDIS_HMSET; - break; - } - - if (str5icmp(m, 'h', 'v', 'a', 'l', 's')) { - r->type = CMD_REQ_REDIS_HVALS; - break; - } - - if (str5icmp(m, 'h', 's', 'c', 'a', 'n')) { - r->type = CMD_REQ_REDIS_HSCAN; - break; - } - - if (str5icmp(m, 'l', 'p', 'u', 's', 'h')) { - r->type = CMD_REQ_REDIS_LPUSH; - break; - } - - if (str5icmp(m, 'l', 't', 'r', 'i', 'm')) { - r->type = CMD_REQ_REDIS_LTRIM; - break; - } - - if (str5icmp(m, 'r', 'p', 'u', 's', 'h')) { - r->type = CMD_REQ_REDIS_RPUSH; - break; - } - - if (str5icmp(m, 's', 'c', 'a', 'r', 'd')) { - r->type = CMD_REQ_REDIS_SCARD; - break; - } - - if (str5icmp(m, 's', 'd', 'i', 'f', 'f')) { - r->type = CMD_REQ_REDIS_SDIFF; - break; - } - - if (str5icmp(m, 's', 'e', 't', 'e', 'x')) { - r->type = CMD_REQ_REDIS_SETEX; - break; - } - - if (str5icmp(m, 's', 'e', 't', 'n', 'x')) { - r->type = CMD_REQ_REDIS_SETNX; - break; - } - - if (str5icmp(m, 's', 'm', 'o', 'v', 'e')) { - r->type = CMD_REQ_REDIS_SMOVE; - break; - } - - if (str5icmp(m, 's', 's', 'c', 'a', 'n')) { - r->type = CMD_REQ_REDIS_SSCAN; - break; - } - - if (str5icmp(m, 'z', 'c', 'a', 'r', 'd')) { - r->type = CMD_REQ_REDIS_ZCARD; - break; - } - - if (str5icmp(m, 'z', 'r', 'a', 'n', 'k')) { - r->type = CMD_REQ_REDIS_ZRANK; - break; - } - - if (str5icmp(m, 'z', 's', 'c', 'a', 'n')) { - r->type = CMD_REQ_REDIS_ZSCAN; - break; - } - - if (str5icmp(m, 'p', 'f', 'a', 'd', 'd')) { - r->type = CMD_REQ_REDIS_PFADD; - break; - } - - break; - - case 6: - if (str6icmp(m, 'a', 'p', 'p', 'e', 'n', 'd')) { - r->type = CMD_REQ_REDIS_APPEND; - break; - } - - if (str6icmp(m, 'd', 'e', 'c', 'r', 'b', 'y')) { - r->type = CMD_REQ_REDIS_DECRBY; - break; - } - - if (str6icmp(m, 'e', 'x', 'i', 's', 't', 's')) { - r->type = CMD_REQ_REDIS_EXISTS; - break; - } - - if (str6icmp(m, 'e', 'x', 'p', 'i', 'r', 'e')) { - r->type = CMD_REQ_REDIS_EXPIRE; - break; - } - - if (str6icmp(m, 'g', 'e', 't', 'b', 'i', 't')) { - r->type = CMD_REQ_REDIS_GETBIT; - break; - } - - if (str6icmp(m, 'g', 'e', 't', 's', 'e', 't')) { - r->type = CMD_REQ_REDIS_GETSET; - break; - } - - if (str6icmp(m, 'p', 's', 'e', 't', 'e', 'x')) { - r->type = CMD_REQ_REDIS_PSETEX; - break; - } - - if (str6icmp(m, 'h', 's', 'e', 't', 'n', 'x')) { - r->type = CMD_REQ_REDIS_HSETNX; - break; - } - - if (str6icmp(m, 'i', 'n', 'c', 'r', 'b', 'y')) { - r->type = CMD_REQ_REDIS_INCRBY; - break; - } - - if (str6icmp(m, 'l', 'i', 'n', 'd', 'e', 'x')) { - r->type = CMD_REQ_REDIS_LINDEX; - break; - } - - if (str6icmp(m, 'l', 'p', 'u', 's', 'h', 'x')) { - r->type = CMD_REQ_REDIS_LPUSHX; - break; - } - - if (str6icmp(m, 'l', 'r', 'a', 'n', 'g', 'e')) { - r->type = CMD_REQ_REDIS_LRANGE; - break; - } - - if (str6icmp(m, 'r', 'p', 'u', 's', 'h', 'x')) { - r->type = CMD_REQ_REDIS_RPUSHX; - break; - } - - if (str6icmp(m, 's', 'e', 't', 'b', 'i', 't')) { - r->type = CMD_REQ_REDIS_SETBIT; - break; - } - - if (str6icmp(m, 's', 'i', 'n', 't', 'e', 'r')) { - r->type = CMD_REQ_REDIS_SINTER; - break; - } - - if (str6icmp(m, 's', 't', 'r', 'l', 'e', 'n')) { - r->type = CMD_REQ_REDIS_STRLEN; - break; - } - - if (str6icmp(m, 's', 'u', 'n', 'i', 'o', 'n')) { - r->type = CMD_REQ_REDIS_SUNION; - break; - } - - if (str6icmp(m, 'z', 'c', 'o', 'u', 'n', 't')) { - r->type = CMD_REQ_REDIS_ZCOUNT; - break; - } - - if (str6icmp(m, 'z', 'r', 'a', 'n', 'g', 'e')) { - r->type = CMD_REQ_REDIS_ZRANGE; - break; - } - - if (str6icmp(m, 'z', 's', 'c', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_ZSCORE; - break; - } - - break; - - case 7: - if (str7icmp(m, 'p', 'e', 'r', 's', 'i', 's', 't')) { - r->type = CMD_REQ_REDIS_PERSIST; - break; - } - - if (str7icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e')) { - r->type = CMD_REQ_REDIS_PEXPIRE; - break; - } - - if (str7icmp(m, 'h', 'e', 'x', 'i', 's', 't', 's')) { - r->type = CMD_REQ_REDIS_HEXISTS; - break; - } - - if (str7icmp(m, 'h', 'g', 'e', 't', 'a', 'l', 'l')) { - r->type = CMD_REQ_REDIS_HGETALL; - break; - } - - if (str7icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y')) { - r->type = CMD_REQ_REDIS_HINCRBY; - break; - } - - if (str7icmp(m, 'l', 'i', 'n', 's', 'e', 'r', 't')) { - r->type = CMD_REQ_REDIS_LINSERT; - break; - } - - if (str7icmp(m, 'z', 'i', 'n', 'c', 'r', 'b', 'y')) { - r->type = CMD_REQ_REDIS_ZINCRBY; - break; - } - - if (str7icmp(m, 'e', 'v', 'a', 'l', 's', 'h', 'a')) { - r->type = CMD_REQ_REDIS_EVALSHA; - break; - } - - if (str7icmp(m, 'r', 'e', 's', 't', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_RESTORE; - break; - } - - if (str7icmp(m, 'p', 'f', 'c', 'o', 'u', 'n', 't')) { - r->type = CMD_REQ_REDIS_PFCOUNT; - break; - } - - if (str7icmp(m, 'p', 'f', 'm', 'e', 'r', 'g', 'e')) { - r->type = CMD_REQ_REDIS_PFMERGE; - break; - } - - break; - - case 8: - if (str8icmp(m, 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) { - r->type = CMD_REQ_REDIS_EXPIREAT; - break; - } - - if (str8icmp(m, 'b', 'i', 't', 'c', 'o', 'u', 'n', 't')) { - r->type = CMD_REQ_REDIS_BITCOUNT; - break; - } - - if (str8icmp(m, 'g', 'e', 't', 'r', 'a', 'n', 'g', 'e')) { - r->type = CMD_REQ_REDIS_GETRANGE; - break; - } - - if (str8icmp(m, 's', 'e', 't', 'r', 'a', 'n', 'g', 'e')) { - r->type = CMD_REQ_REDIS_SETRANGE; - break; - } - - if (str8icmp(m, 's', 'm', 'e', 'm', 'b', 'e', 'r', 's')) { - r->type = CMD_REQ_REDIS_SMEMBERS; - break; - } - - if (str8icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'k')) { - r->type = CMD_REQ_REDIS_ZREVRANK; - break; - } - - break; - - case 9: - if (str9icmp(m, 'p', 'e', 'x', 'p', 'i', 'r', 'e', 'a', 't')) { - r->type = CMD_REQ_REDIS_PEXPIREAT; - break; - } - - if (str9icmp(m, 'r', 'p', 'o', 'p', 'l', 'p', 'u', 's', 'h')) { - r->type = CMD_REQ_REDIS_RPOPLPUSH; - break; - } - - if (str9icmp(m, 's', 'i', 's', 'm', 'e', 'm', 'b', 'e', 'r')) { - r->type = CMD_REQ_REDIS_SISMEMBER; - break; - } - - if (str9icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e')) { - r->type = CMD_REQ_REDIS_ZREVRANGE; - break; - } - - if (str9icmp(m, 'z', 'l', 'e', 'x', 'c', 'o', 'u', 'n', 't')) { - r->type = CMD_REQ_REDIS_ZLEXCOUNT; - break; - } - - break; - - case 10: - if (str10icmp(m, 's', 'd', 'i', 'f', 'f', 's', 't', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_SDIFFSTORE; - break; - } - - case 11: - if (str11icmp(m, 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) { - r->type = CMD_REQ_REDIS_INCRBYFLOAT; - break; - } - - if (str11icmp(m, 's', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_SINTERSTORE; - break; - } - - if (str11icmp(m, 's', 'r', 'a', 'n', 'd', 'm', 'e', 'm', 'b', 'e', 'r')) { - r->type = CMD_REQ_REDIS_SRANDMEMBER; - break; - } - - if (str11icmp(m, 's', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_SUNIONSTORE; - break; - } - - if (str11icmp(m, 'z', 'i', 'n', 't', 'e', 'r', 's', 't', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_ZINTERSTORE; - break; - } - - if (str11icmp(m, 'z', 'u', 'n', 'i', 'o', 'n', 's', 't', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_ZUNIONSTORE; - break; - } - - if (str11icmp(m, 'z', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'l', 'e', 'x')) { - r->type = CMD_REQ_REDIS_ZRANGEBYLEX; - break; - } - - break; - - case 12: - if (str12icmp(m, 'h', 'i', 'n', 'c', 'r', 'b', 'y', 'f', 'l', 'o', 'a', 't')) { - r->type = CMD_REQ_REDIS_HINCRBYFLOAT; - break; - } - - - break; - - case 13: - if (str13icmp(m, 'z', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_ZRANGEBYSCORE; - break; - } - - break; - - case 14: - if (str14icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'l', 'e', 'x')) { - r->type = CMD_REQ_REDIS_ZREMRANGEBYLEX; - break; - } - - break; - - case 15: - if (str15icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 'r', 'a', 'n', 'k')) { - r->type = CMD_REQ_REDIS_ZREMRANGEBYRANK; - break; - } - - break; - - case 16: - if (str16icmp(m, 'z', 'r', 'e', 'm', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_ZREMRANGEBYSCORE; - break; - } - - if (str16icmp(m, 'z', 'r', 'e', 'v', 'r', 'a', 'n', 'g', 'e', 'b', 'y', 's', 'c', 'o', 'r', 'e')) { - r->type = CMD_REQ_REDIS_ZREVRANGEBYSCORE; - break; - } - - break; - - default: - break; - } - - if (r->type == CMD_UNKNOWN) { - goto error; - } - - state = SW_REQ_TYPE_LF; - break; - - case SW_REQ_TYPE_LF: - switch (ch) { - case LF: - if (redis_argz(r)) { - goto done; - } else if (redis_argeval(r)) { - state = SW_ARG1_LEN; - } else { - state = SW_KEY_LEN; - } - break; - - default: - goto error; - } - - break; - - case SW_KEY_LEN: - if (token == NULL) { - if (ch != '$') { - goto error; - } - token = p; - rlen = 0; - } else if (isdigit(ch)) { - rlen = rlen * 10 + (uint32_t)(ch - '0'); - } else if (ch == CR) { - - if (rnarg == 0) { - goto error; - } - rnarg--; - token = NULL; - state = SW_KEY_LEN_LF; - } else { - goto error; - } - - break; - - case SW_KEY_LEN_LF: - switch (ch) { - case LF: - state = SW_KEY; - break; - - default: - goto error; - } - - break; - - case SW_KEY: - if (token == NULL) { - token = p; - } - - m = token + rlen; - if (m >= cmd_end) { - //m = b->last - 1; - //p = m; - //break; - goto error; - } - - if (*m != CR) { - goto error; - } else { /* got a key */ - struct keypos *kpos; - - p = m; /* move forward by rlen bytes */ - rlen = 0; - m = token; - token = NULL; - - kpos = hiarray_push(r->keys); - if (kpos == NULL) { - goto enomem; - } - kpos->start = m; - kpos->end = p; - //kpos->v_len = 0; - - state = SW_KEY_LF; - } - - break; - - case SW_KEY_LF: - switch (ch) { - case LF: - if (redis_arg0(r)) { - if (rnarg != 0) { - goto error; - } - goto done; - } else if (redis_arg1(r)) { - if (rnarg != 1) { - goto error; - } - state = SW_ARG1_LEN; - } else if (redis_arg2(r)) { - if (rnarg != 2) { - goto error; - } - state = SW_ARG1_LEN; - } else if (redis_arg3(r)) { - if (rnarg != 3) { - goto error; - } - state = SW_ARG1_LEN; - } else if (redis_argn(r)) { - if (rnarg == 0) { - goto done; - } - state = SW_ARG1_LEN; - } else if (redis_argx(r)) { - if (rnarg == 0) { - goto done; - } - state = SW_KEY_LEN; - } else if (redis_argkvx(r)) { - if (rnarg == 0) { - goto done; - } - if (r->narg % 2 == 0) { - goto error; - } - state = SW_ARG1_LEN; - } else if (redis_argeval(r)) { - if (rnarg == 0) { - goto done; - } - state = SW_ARGN_LEN; - } else { - goto error; - } - - break; - - default: - goto error; - } - - break; - - case SW_ARG1_LEN: - if (token == NULL) { - if (ch != '$') { - goto error; - } - rlen = 0; - token = p; - } else if (isdigit(ch)) { - rlen = rlen * 10 + (uint32_t)(ch - '0'); - } else if (ch == CR) { - if ((p - token) <= 1 || rnarg == 0) { - goto error; - } - rnarg--; - token = NULL; - - /* - //for mset value length - if(redis_argkvx(r)) - { - struct keypos *kpos; - uint32_t array_len = array_n(r->keys); - if(array_len == 0) - { - goto error; - } - - kpos = array_n(r->keys, array_len-1); - if (kpos == NULL || kpos->v_len != 0) { - goto error; - } - - kpos->v_len = rlen; - } - */ - state = SW_ARG1_LEN_LF; - } else { - goto error; - } - - break; - - case SW_ARG1_LEN_LF: - switch (ch) { - case LF: - state = SW_ARG1; - break; - - default: - goto error; - } - - break; - - case SW_ARG1: - m = p + rlen; - if (m >= cmd_end) { - //rlen -= (uint32_t)(b->last - p); - //m = b->last - 1; - //p = m; - //break; - goto error; - } - - if (*m != CR) { - goto error; - } - - p = m; /* move forward by rlen bytes */ - rlen = 0; - - state = SW_ARG1_LF; - - break; - - case SW_ARG1_LF: - switch (ch) { - case LF: - if (redis_arg1(r)) { - if (rnarg != 0) { - goto error; - } - goto done; - } else if (redis_arg2(r)) { - if (rnarg != 1) { - goto error; - } - state = SW_ARG2_LEN; - } else if (redis_arg3(r)) { - if (rnarg != 2) { - goto error; - } - state = SW_ARG2_LEN; - } else if (redis_argn(r)) { - if (rnarg == 0) { - goto done; - } - state = SW_ARGN_LEN; - } else if (redis_argeval(r)) { - if (rnarg < 2) { - goto error; - } - state = SW_ARG2_LEN; - } else if (redis_argkvx(r)) { - if (rnarg == 0) { - goto done; - } - state = SW_KEY_LEN; - } else { - goto error; - } - - break; - - default: - goto error; - } - - break; - - case SW_ARG2_LEN: - if (token == NULL) { - if (ch != '$') { - goto error; - } - rlen = 0; - token = p; - } else if (isdigit(ch)) { - rlen = rlen * 10 + (uint32_t)(ch - '0'); - } else if (ch == CR) { - if ((p - token) <= 1 || rnarg == 0) { - goto error; - } - rnarg--; - token = NULL; - state = SW_ARG2_LEN_LF; - } else { - goto error; - } - - break; - - case SW_ARG2_LEN_LF: - switch (ch) { - case LF: - state = SW_ARG2; - break; - - default: - goto error; - } - - break; - - case SW_ARG2: - if (token == NULL && redis_argeval(r)) { - /* - * For EVAL/EVALSHA, ARG2 represents the # key/arg pairs which must - * be tokenized and stored in contiguous memory. - */ - token = p; - } - - m = p + rlen; - if (m >= cmd_end) { - //rlen -= (uint32_t)(b->last - p); - //m = b->last - 1; - //p = m; - //break; - goto error; - } - - if (*m != CR) { - goto error; - } - - p = m; /* move forward by rlen bytes */ - rlen = 0; - - if (redis_argeval(r)) { - uint32_t nkey; - char *chp; - - /* - * For EVAL/EVALSHA, we need to find the integer value of this - * argument. It tells us the number of keys in the script, and - * we need to error out if number of keys is 0. At this point, - * both p and m point to the end of the argument and r->token - * points to the start. - */ - if (p - token < 1) { - goto error; - } - - for (nkey = 0, chp = token; chp < p; chp++) { - if (isdigit(*chp)) { - nkey = nkey * 10 + (uint32_t)(*chp - '0'); - } else { - goto error; - } - } - if (nkey == 0) { - goto error; - } - - token = NULL; - } - - state = SW_ARG2_LF; - - break; - - case SW_ARG2_LF: - switch (ch) { - case LF: - if (redis_arg2(r)) { - if (rnarg != 0) { - goto error; - } - goto done; - } else if (redis_arg3(r)) { - if (rnarg != 1) { - goto error; - } - state = SW_ARG3_LEN; - } else if (redis_argn(r)) { - if (rnarg == 0) { - goto done; - } - state = SW_ARGN_LEN; - } else if (redis_argeval(r)) { - if (rnarg < 1) { - goto error; - } - state = SW_KEY_LEN; - } else { - goto error; - } - - break; - - default: - goto error; - } - - break; - - case SW_ARG3_LEN: - if (token == NULL) { - if (ch != '$') { - goto error; - } - rlen = 0; - token = p; - } else if (isdigit(ch)) { - rlen = rlen * 10 + (uint32_t)(ch - '0'); - } else if (ch == CR) { - if ((p - token) <= 1 || rnarg == 0) { - goto error; - } - rnarg--; - token = NULL; - state = SW_ARG3_LEN_LF; - } else { - goto error; - } - - break; - - case SW_ARG3_LEN_LF: - switch (ch) { - case LF: - state = SW_ARG3; - break; - - default: - goto error; - } - - break; - - case SW_ARG3: - m = p + rlen; - if (m >= cmd_end) { - //rlen -= (uint32_t)(b->last - p); - //m = b->last - 1; - //p = m; - //break; - goto error; - } - - if (*m != CR) { - goto error; - } - - p = m; /* move forward by rlen bytes */ - rlen = 0; - state = SW_ARG3_LF; - - break; - - case SW_ARG3_LF: - switch (ch) { - case LF: - if (redis_arg3(r)) { - if (rnarg != 0) { - goto error; - } - goto done; - } else if (redis_argn(r)) { - if (rnarg == 0) { - goto done; - } - state = SW_ARGN_LEN; - } else { - goto error; - } - - break; - - default: - goto error; - } - - break; - - case SW_ARGN_LEN: - if (token == NULL) { - if (ch != '$') { - goto error; - } - rlen = 0; - token = p; - } else if (isdigit(ch)) { - rlen = rlen * 10 + (uint32_t)(ch - '0'); - } else if (ch == CR) { - if ((p - token) <= 1 || rnarg == 0) { - goto error; - } - rnarg--; - token = NULL; - state = SW_ARGN_LEN_LF; - } else { - goto error; - } - - break; - - case SW_ARGN_LEN_LF: - switch (ch) { - case LF: - state = SW_ARGN; - break; - - default: - goto error; - } - - break; - - case SW_ARGN: - m = p + rlen; - if (m >= cmd_end) { - //rlen -= (uint32_t)(b->last - p); - //m = b->last - 1; - //p = m; - //break; - goto error; - } - - if (*m != CR) { - goto error; - } - - p = m; /* move forward by rlen bytes */ - rlen = 0; - state = SW_ARGN_LF; - - break; - - case SW_ARGN_LF: - switch (ch) { - case LF: - if (redis_argn(r) || redis_argeval(r)) { - if (rnarg == 0) { - goto done; - } - state = SW_ARGN_LEN; - } else { - goto error; - } - - break; - - default: - goto error; - } - - break; - - case SW_SENTINEL: - default: - NOT_REACHED(); - break; - } - } - - ASSERT(p == cmd_end); - - return; - -done: - - ASSERT(r->type > CMD_UNKNOWN && r->type < CMD_SENTINEL); - - r->result = CMD_PARSE_OK; - - return; - -enomem: - - r->result = CMD_PARSE_ENOMEM; - - return; - -error: - - r->result = CMD_PARSE_ERROR; - errno = EINVAL; - if(r->errstr == NULL){ - r->errstr = hi_alloc(100*sizeof(*r->errstr)); - } - - len = _scnprintf(r->errstr, 100, "Parse command error. Cmd type: %d, state: %d, break position: %d.", - r->type, state, (int)(p - r->cmd)); - r->errstr[len] = '\0'; -} - -struct cmd *command_get() -{ - struct cmd *command; - command = hi_alloc(sizeof(struct cmd)); - if(command == NULL) - { - return NULL; - } - - command->id = ++cmd_id; - command->result = CMD_PARSE_OK; - command->errstr = NULL; - command->type = CMD_UNKNOWN; - command->cmd = NULL; - command->clen = 0; - command->keys = NULL; - command->narg_start = NULL; - command->narg_end = NULL; - command->narg = 0; - command->quit = 0; - command->noforward = 0; - command->slot_num = -1; - command->frag_seq = NULL; - command->reply = NULL; - command->sub_commands = NULL; - - command->keys = hiarray_create(1, sizeof(struct keypos)); - if (command->keys == NULL) - { - hi_free(command); - return NULL; - } - - return command; -} - -void command_destroy(struct cmd *command) -{ - if(command == NULL) - { - return; - } - - if(command->cmd != NULL) - { - free(command->cmd); - } - - if(command->errstr != NULL){ - hi_free(command->errstr); - } - - if(command->keys != NULL) - { - command->keys->nelem = 0; - hiarray_destroy(command->keys); - } - - if(command->frag_seq != NULL) - { - hi_free(command->frag_seq); - command->frag_seq = NULL; - } - - if(command->reply != NULL) - { - freeReplyObject(command->reply); - } - - if(command->sub_commands != NULL) - { - listRelease(command->sub_commands); - } - - hi_free(command); -} - - diff --git a/ext/hiredis-vip-0.3.0/command.h b/ext/hiredis-vip-0.3.0/command.h deleted file mode 100644 index b7c388a69..000000000 --- a/ext/hiredis-vip-0.3.0/command.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef __COMMAND_H_ -#define __COMMAND_H_ - -#include - -#include "hiredis.h" -#include "adlist.h" - -typedef enum cmd_parse_result { - CMD_PARSE_OK, /* parsing ok */ - CMD_PARSE_ENOMEM, /* out of memory */ - CMD_PARSE_ERROR, /* parsing error */ - CMD_PARSE_REPAIR, /* more to parse -> repair parsed & unparsed data */ - CMD_PARSE_AGAIN, /* incomplete -> parse again */ -} cmd_parse_result_t; - -#define CMD_TYPE_CODEC(ACTION) \ - ACTION( UNKNOWN ) \ - ACTION( REQ_REDIS_DEL ) /* redis commands - keys */ \ - ACTION( REQ_REDIS_EXISTS ) \ - ACTION( REQ_REDIS_EXPIRE ) \ - ACTION( REQ_REDIS_EXPIREAT ) \ - ACTION( REQ_REDIS_PEXPIRE ) \ - ACTION( REQ_REDIS_PEXPIREAT ) \ - ACTION( REQ_REDIS_PERSIST ) \ - ACTION( REQ_REDIS_PTTL ) \ - ACTION( REQ_REDIS_SORT ) \ - ACTION( REQ_REDIS_TTL ) \ - ACTION( REQ_REDIS_TYPE ) \ - ACTION( REQ_REDIS_APPEND ) /* redis requests - string */ \ - ACTION( REQ_REDIS_BITCOUNT ) \ - ACTION( REQ_REDIS_DECR ) \ - ACTION( REQ_REDIS_DECRBY ) \ - ACTION( REQ_REDIS_DUMP ) \ - ACTION( REQ_REDIS_GET ) \ - ACTION( REQ_REDIS_GETBIT ) \ - ACTION( REQ_REDIS_GETRANGE ) \ - ACTION( REQ_REDIS_GETSET ) \ - ACTION( REQ_REDIS_INCR ) \ - ACTION( REQ_REDIS_INCRBY ) \ - ACTION( REQ_REDIS_INCRBYFLOAT ) \ - ACTION( REQ_REDIS_MGET ) \ - ACTION( REQ_REDIS_MSET ) \ - ACTION( REQ_REDIS_PSETEX ) \ - ACTION( REQ_REDIS_RESTORE ) \ - ACTION( REQ_REDIS_SET ) \ - ACTION( REQ_REDIS_SETBIT ) \ - ACTION( REQ_REDIS_SETEX ) \ - ACTION( REQ_REDIS_SETNX ) \ - ACTION( REQ_REDIS_SETRANGE ) \ - ACTION( REQ_REDIS_STRLEN ) \ - ACTION( REQ_REDIS_HDEL ) /* redis requests - hashes */ \ - ACTION( REQ_REDIS_HEXISTS ) \ - ACTION( REQ_REDIS_HGET ) \ - ACTION( REQ_REDIS_HGETALL ) \ - ACTION( REQ_REDIS_HINCRBY ) \ - ACTION( REQ_REDIS_HINCRBYFLOAT ) \ - ACTION( REQ_REDIS_HKEYS ) \ - ACTION( REQ_REDIS_HLEN ) \ - ACTION( REQ_REDIS_HMGET ) \ - ACTION( REQ_REDIS_HMSET ) \ - ACTION( REQ_REDIS_HSET ) \ - ACTION( REQ_REDIS_HSETNX ) \ - ACTION( REQ_REDIS_HSCAN) \ - ACTION( REQ_REDIS_HVALS ) \ - ACTION( REQ_REDIS_LINDEX ) /* redis requests - lists */ \ - ACTION( REQ_REDIS_LINSERT ) \ - ACTION( REQ_REDIS_LLEN ) \ - ACTION( REQ_REDIS_LPOP ) \ - ACTION( REQ_REDIS_LPUSH ) \ - ACTION( REQ_REDIS_LPUSHX ) \ - ACTION( REQ_REDIS_LRANGE ) \ - ACTION( REQ_REDIS_LREM ) \ - ACTION( REQ_REDIS_LSET ) \ - ACTION( REQ_REDIS_LTRIM ) \ - ACTION( REQ_REDIS_PFADD ) /* redis requests - hyperloglog */ \ - ACTION( REQ_REDIS_PFCOUNT ) \ - ACTION( REQ_REDIS_PFMERGE ) \ - ACTION( REQ_REDIS_RPOP ) \ - ACTION( REQ_REDIS_RPOPLPUSH ) \ - ACTION( REQ_REDIS_RPUSH ) \ - ACTION( REQ_REDIS_RPUSHX ) \ - ACTION( REQ_REDIS_SADD ) /* redis requests - sets */ \ - ACTION( REQ_REDIS_SCARD ) \ - ACTION( REQ_REDIS_SDIFF ) \ - ACTION( REQ_REDIS_SDIFFSTORE ) \ - ACTION( REQ_REDIS_SINTER ) \ - ACTION( REQ_REDIS_SINTERSTORE ) \ - ACTION( REQ_REDIS_SISMEMBER ) \ - ACTION( REQ_REDIS_SMEMBERS ) \ - ACTION( REQ_REDIS_SMOVE ) \ - ACTION( REQ_REDIS_SPOP ) \ - ACTION( REQ_REDIS_SRANDMEMBER ) \ - ACTION( REQ_REDIS_SREM ) \ - ACTION( REQ_REDIS_SUNION ) \ - ACTION( REQ_REDIS_SUNIONSTORE ) \ - ACTION( REQ_REDIS_SSCAN) \ - ACTION( REQ_REDIS_ZADD ) /* redis requests - sorted sets */ \ - ACTION( REQ_REDIS_ZCARD ) \ - ACTION( REQ_REDIS_ZCOUNT ) \ - ACTION( REQ_REDIS_ZINCRBY ) \ - ACTION( REQ_REDIS_ZINTERSTORE ) \ - ACTION( REQ_REDIS_ZLEXCOUNT ) \ - ACTION( REQ_REDIS_ZRANGE ) \ - ACTION( REQ_REDIS_ZRANGEBYLEX ) \ - ACTION( REQ_REDIS_ZRANGEBYSCORE ) \ - ACTION( REQ_REDIS_ZRANK ) \ - ACTION( REQ_REDIS_ZREM ) \ - ACTION( REQ_REDIS_ZREMRANGEBYRANK ) \ - ACTION( REQ_REDIS_ZREMRANGEBYLEX ) \ - ACTION( REQ_REDIS_ZREMRANGEBYSCORE ) \ - ACTION( REQ_REDIS_ZREVRANGE ) \ - ACTION( REQ_REDIS_ZREVRANGEBYSCORE ) \ - ACTION( REQ_REDIS_ZREVRANK ) \ - ACTION( REQ_REDIS_ZSCORE ) \ - ACTION( REQ_REDIS_ZUNIONSTORE ) \ - ACTION( REQ_REDIS_ZSCAN) \ - ACTION( REQ_REDIS_EVAL ) /* redis requests - eval */ \ - ACTION( REQ_REDIS_EVALSHA ) \ - ACTION( REQ_REDIS_PING ) /* redis requests - ping/quit */ \ - ACTION( REQ_REDIS_QUIT) \ - ACTION( REQ_REDIS_AUTH) \ - ACTION( RSP_REDIS_STATUS ) /* redis response */ \ - ACTION( RSP_REDIS_ERROR ) \ - ACTION( RSP_REDIS_INTEGER ) \ - ACTION( RSP_REDIS_BULK ) \ - ACTION( RSP_REDIS_MULTIBULK ) \ - ACTION( SENTINEL ) \ - - -#define DEFINE_ACTION(_name) CMD_##_name, -typedef enum cmd_type { - CMD_TYPE_CODEC(DEFINE_ACTION) -} cmd_type_t; -#undef DEFINE_ACTION - - -struct keypos { - char *start; /* key start pos */ - char *end; /* key end pos */ - uint32_t remain_len; /* remain length after keypos->end for more key-value pairs in command, like mset */ -}; - -struct cmd { - - uint64_t id; /* command id */ - - cmd_parse_result_t result; /* command parsing result */ - char *errstr; /* error info when the command parse failed */ - - cmd_type_t type; /* command type */ - - char *cmd; - uint32_t clen; /* command length */ - - struct hiarray *keys; /* array of keypos, for req */ - - char *narg_start; /* narg start (redis) */ - char *narg_end; /* narg end (redis) */ - uint32_t narg; /* # arguments (redis) */ - - unsigned quit:1; /* quit request? */ - unsigned noforward:1; /* not need forward (example: ping) */ - - int slot_num; /* this command should send to witch slot? - * -1:the keys in this command cross different slots*/ - struct cmd **frag_seq; /* sequence of fragment command, map from keys to fragments*/ - - redisReply *reply; - - hilist *sub_commands; /* just for pipeline and multi-key commands */ -}; - -void redis_parse_cmd(struct cmd *r); - -struct cmd *command_get(void); -void command_destroy(struct cmd *command); - -#endif diff --git a/ext/hiredis-vip-0.3.0/crc16.c b/ext/hiredis-vip-0.3.0/crc16.c deleted file mode 100644 index 0f304f6e4..000000000 --- a/ext/hiredis-vip-0.3.0/crc16.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2001-2010 Georges Menie (www.menie.org) - * Copyright 2010-2012 Salvatore Sanfilippo (adapted to Redis coding style) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the University of California, Berkeley nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* CRC16 implementation according to CCITT standards. - * - * Note by @antirez: this is actually the XMODEM CRC 16 algorithm, using the - * following parameters: - * - * Name : "XMODEM", also known as "ZMODEM", "CRC-16/ACORN" - * Width : 16 bit - * Poly : 1021 (That is actually x^16 + x^12 + x^5 + 1) - * Initialization : 0000 - * Reflect Input byte : False - * Reflect Output CRC : False - * Xor constant to output CRC : 0000 - * Output for "123456789" : 31C3 - */ -#include "hiutil.h" - -static const uint16_t crc16tab[256]= { - 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, - 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, - 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, - 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, - 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, - 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, - 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, - 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, - 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, - 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, - 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, - 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, - 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, - 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, - 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, - 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, - 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, - 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, - 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, - 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, - 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, - 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, - 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, - 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, - 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, - 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, - 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, - 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, - 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, - 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, - 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, - 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 -}; - -uint16_t crc16(const char *buf, int len) { - int counter; - uint16_t crc = 0; - for (counter = 0; counter < len; counter++) - crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF]; - return crc; -} diff --git a/ext/hiredis-vip-0.3.0/dict.c b/ext/hiredis-vip-0.3.0/dict.c deleted file mode 100644 index 79b1041ca..000000000 --- a/ext/hiredis-vip-0.3.0/dict.c +++ /dev/null @@ -1,338 +0,0 @@ -/* Hash table implementation. - * - * This file implements in memory hash tables with insert/del/replace/find/ - * get-random-element operations. Hash tables will auto resize if needed - * tables of power of two in size are used, collisions are handled by - * chaining. See the source code for more information... :) - * - * Copyright (c) 2006-2010, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include -#include -#include -#include "dict.h" - -/* -------------------------- private prototypes ---------------------------- */ - -static int _dictExpandIfNeeded(dict *ht); -static unsigned long _dictNextPower(unsigned long size); -static int _dictKeyIndex(dict *ht, const void *key); -static int _dictInit(dict *ht, dictType *type, void *privDataPtr); - -/* -------------------------- hash functions -------------------------------- */ - -/* Generic hash function (a popular one from Bernstein). - * I tested a few and this was the best. */ -static unsigned int dictGenHashFunction(const unsigned char *buf, int len) { - unsigned int hash = 5381; - - while (len--) - hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */ - return hash; -} - -/* ----------------------------- API implementation ------------------------- */ - -/* Reset an hashtable already initialized with ht_init(). - * NOTE: This function should only called by ht_destroy(). */ -static void _dictReset(dict *ht) { - ht->table = NULL; - ht->size = 0; - ht->sizemask = 0; - ht->used = 0; -} - -/* Create a new hash table */ -static dict *dictCreate(dictType *type, void *privDataPtr) { - dict *ht = malloc(sizeof(*ht)); - _dictInit(ht,type,privDataPtr); - return ht; -} - -/* Initialize the hash table */ -static int _dictInit(dict *ht, dictType *type, void *privDataPtr) { - _dictReset(ht); - ht->type = type; - ht->privdata = privDataPtr; - return DICT_OK; -} - -/* Expand or create the hashtable */ -static int dictExpand(dict *ht, unsigned long size) { - dict n; /* the new hashtable */ - unsigned long realsize = _dictNextPower(size), i; - - /* the size is invalid if it is smaller than the number of - * elements already inside the hashtable */ - if (ht->used > size) - return DICT_ERR; - - _dictInit(&n, ht->type, ht->privdata); - n.size = realsize; - n.sizemask = realsize-1; - n.table = calloc(realsize,sizeof(dictEntry*)); - - /* Copy all the elements from the old to the new table: - * note that if the old hash table is empty ht->size is zero, - * so dictExpand just creates an hash table. */ - n.used = ht->used; - for (i = 0; i < ht->size && ht->used > 0; i++) { - dictEntry *he, *nextHe; - - if (ht->table[i] == NULL) continue; - - /* For each hash entry on this slot... */ - he = ht->table[i]; - while(he) { - unsigned int h; - - nextHe = he->next; - /* Get the new element index */ - h = dictHashKey(ht, he->key) & n.sizemask; - he->next = n.table[h]; - n.table[h] = he; - ht->used--; - /* Pass to the next element */ - he = nextHe; - } - } - assert(ht->used == 0); - free(ht->table); - - /* Remap the new hashtable in the old */ - *ht = n; - return DICT_OK; -} - -/* Add an element to the target hash table */ -static int dictAdd(dict *ht, void *key, void *val) { - int index; - dictEntry *entry; - - /* Get the index of the new element, or -1 if - * the element already exists. */ - if ((index = _dictKeyIndex(ht, key)) == -1) - return DICT_ERR; - - /* Allocates the memory and stores key */ - entry = malloc(sizeof(*entry)); - entry->next = ht->table[index]; - ht->table[index] = entry; - - /* Set the hash entry fields. */ - dictSetHashKey(ht, entry, key); - dictSetHashVal(ht, entry, val); - ht->used++; - return DICT_OK; -} - -/* Add an element, discarding the old if the key already exists. - * Return 1 if the key was added from scratch, 0 if there was already an - * element with such key and dictReplace() just performed a value update - * operation. */ -static int dictReplace(dict *ht, void *key, void *val) { - dictEntry *entry, auxentry; - - /* Try to add the element. If the key - * does not exists dictAdd will suceed. */ - if (dictAdd(ht, key, val) == DICT_OK) - return 1; - /* It already exists, get the entry */ - entry = dictFind(ht, key); - /* Free the old value and set the new one */ - /* Set the new value and free the old one. Note that it is important - * to do that in this order, as the value may just be exactly the same - * as the previous one. In this context, think to reference counting, - * you want to increment (set), and then decrement (free), and not the - * reverse. */ - auxentry = *entry; - dictSetHashVal(ht, entry, val); - dictFreeEntryVal(ht, &auxentry); - return 0; -} - -/* Search and remove an element */ -static int dictDelete(dict *ht, const void *key) { - unsigned int h; - dictEntry *de, *prevde; - - if (ht->size == 0) - return DICT_ERR; - h = dictHashKey(ht, key) & ht->sizemask; - de = ht->table[h]; - - prevde = NULL; - while(de) { - if (dictCompareHashKeys(ht,key,de->key)) { - /* Unlink the element from the list */ - if (prevde) - prevde->next = de->next; - else - ht->table[h] = de->next; - - dictFreeEntryKey(ht,de); - dictFreeEntryVal(ht,de); - free(de); - ht->used--; - return DICT_OK; - } - prevde = de; - de = de->next; - } - return DICT_ERR; /* not found */ -} - -/* Destroy an entire hash table */ -static int _dictClear(dict *ht) { - unsigned long i; - - /* Free all the elements */ - for (i = 0; i < ht->size && ht->used > 0; i++) { - dictEntry *he, *nextHe; - - if ((he = ht->table[i]) == NULL) continue; - while(he) { - nextHe = he->next; - dictFreeEntryKey(ht, he); - dictFreeEntryVal(ht, he); - free(he); - ht->used--; - he = nextHe; - } - } - /* Free the table and the allocated cache structure */ - free(ht->table); - /* Re-initialize the table */ - _dictReset(ht); - return DICT_OK; /* never fails */ -} - -/* Clear & Release the hash table */ -static void dictRelease(dict *ht) { - _dictClear(ht); - free(ht); -} - -static dictEntry *dictFind(dict *ht, const void *key) { - dictEntry *he; - unsigned int h; - - if (ht->size == 0) return NULL; - h = dictHashKey(ht, key) & ht->sizemask; - he = ht->table[h]; - while(he) { - if (dictCompareHashKeys(ht, key, he->key)) - return he; - he = he->next; - } - return NULL; -} - -static dictIterator *dictGetIterator(dict *ht) { - dictIterator *iter = malloc(sizeof(*iter)); - - iter->ht = ht; - iter->index = -1; - iter->entry = NULL; - iter->nextEntry = NULL; - return iter; -} - -static dictEntry *dictNext(dictIterator *iter) { - while (1) { - if (iter->entry == NULL) { - iter->index++; - if (iter->index >= - (signed)iter->ht->size) break; - iter->entry = iter->ht->table[iter->index]; - } else { - iter->entry = iter->nextEntry; - } - if (iter->entry) { - /* We need to save the 'next' here, the iterator user - * may delete the entry we are returning. */ - iter->nextEntry = iter->entry->next; - return iter->entry; - } - } - return NULL; -} - -static void dictReleaseIterator(dictIterator *iter) { - free(iter); -} - -/* ------------------------- private functions ------------------------------ */ - -/* Expand the hash table if needed */ -static int _dictExpandIfNeeded(dict *ht) { - /* If the hash table is empty expand it to the intial size, - * if the table is "full" dobule its size. */ - if (ht->size == 0) - return dictExpand(ht, DICT_HT_INITIAL_SIZE); - if (ht->used == ht->size) - return dictExpand(ht, ht->size*2); - return DICT_OK; -} - -/* Our hash table capability is a power of two */ -static unsigned long _dictNextPower(unsigned long size) { - unsigned long i = DICT_HT_INITIAL_SIZE; - - if (size >= LONG_MAX) return LONG_MAX; - while(1) { - if (i >= size) - return i; - i *= 2; - } -} - -/* Returns the index of a free slot that can be populated with - * an hash entry for the given 'key'. - * If the key already exists, -1 is returned. */ -static int _dictKeyIndex(dict *ht, const void *key) { - unsigned int h; - dictEntry *he; - - /* Expand the hashtable if needed */ - if (_dictExpandIfNeeded(ht) == DICT_ERR) - return -1; - /* Compute the key hash value */ - h = dictHashKey(ht, key) & ht->sizemask; - /* Search if this slot does not already contain the given key */ - he = ht->table[h]; - while(he) { - if (dictCompareHashKeys(ht, key, he->key)) - return -1; - he = he->next; - } - return h; -} - diff --git a/ext/hiredis-vip-0.3.0/examples/example-ae.c b/ext/hiredis-vip-0.3.0/examples/example-ae.c deleted file mode 100644 index 8efa7306a..000000000 --- a/ext/hiredis-vip-0.3.0/examples/example-ae.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -/* Put event loop in the global scope, so it can be explicitly stopped */ -static aeEventLoop *loop; - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - aeStop(loop); - return; - } - - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - aeStop(loop); - return; - } - - printf("Disconnected...\n"); - aeStop(loop); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - loop = aeCreateEventLoop(64); - redisAeAttach(loop, c); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - aeMain(loop); - return 0; -} - diff --git a/ext/hiredis-vip-0.3.0/examples/example-glib.c b/ext/hiredis-vip-0.3.0/examples/example-glib.c deleted file mode 100644 index d6e10f8e8..000000000 --- a/ext/hiredis-vip-0.3.0/examples/example-glib.c +++ /dev/null @@ -1,73 +0,0 @@ -#include - -#include -#include -#include - -static GMainLoop *mainloop; - -static void -connect_cb (const redisAsyncContext *ac G_GNUC_UNUSED, - int status) -{ - if (status != REDIS_OK) { - g_printerr("Failed to connect: %s\n", ac->errstr); - g_main_loop_quit(mainloop); - } else { - g_printerr("Connected...\n"); - } -} - -static void -disconnect_cb (const redisAsyncContext *ac G_GNUC_UNUSED, - int status) -{ - if (status != REDIS_OK) { - g_error("Failed to disconnect: %s", ac->errstr); - } else { - g_printerr("Disconnected...\n"); - g_main_loop_quit(mainloop); - } -} - -static void -command_cb(redisAsyncContext *ac, - gpointer r, - gpointer user_data G_GNUC_UNUSED) -{ - redisReply *reply = r; - - if (reply) { - g_print("REPLY: %s\n", reply->str); - } - - redisAsyncDisconnect(ac); -} - -gint -main (gint argc G_GNUC_UNUSED, - gchar *argv[] G_GNUC_UNUSED) -{ - redisAsyncContext *ac; - GMainContext *context = NULL; - GSource *source; - - ac = redisAsyncConnect("127.0.0.1", 6379); - if (ac->err) { - g_printerr("%s\n", ac->errstr); - exit(EXIT_FAILURE); - } - - source = redis_source_new(ac); - mainloop = g_main_loop_new(context, FALSE); - g_source_attach(source, context); - - redisAsyncSetConnectCallback(ac, connect_cb); - redisAsyncSetDisconnectCallback(ac, disconnect_cb); - redisAsyncCommand(ac, command_cb, NULL, "SET key 1234"); - redisAsyncCommand(ac, command_cb, NULL, "GET key"); - - g_main_loop_run(mainloop); - - return EXIT_SUCCESS; -} diff --git a/ext/hiredis-vip-0.3.0/examples/example-libev.c b/ext/hiredis-vip-0.3.0/examples/example-libev.c deleted file mode 100644 index cc8b166ec..000000000 --- a/ext/hiredis-vip-0.3.0/examples/example-libev.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisLibevAttach(EV_DEFAULT_ c); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - ev_loop(EV_DEFAULT_ 0); - return 0; -} diff --git a/ext/hiredis-vip-0.3.0/examples/example-libevent.c b/ext/hiredis-vip-0.3.0/examples/example-libevent.c deleted file mode 100644 index d333c22b7..000000000 --- a/ext/hiredis-vip-0.3.0/examples/example-libevent.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - struct event_base *base = event_base_new(); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisLibeventAttach(c,base); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - event_base_dispatch(base); - return 0; -} diff --git a/ext/hiredis-vip-0.3.0/examples/example-libuv.c b/ext/hiredis-vip-0.3.0/examples/example-libuv.c deleted file mode 100644 index a5462d410..000000000 --- a/ext/hiredis-vip-0.3.0/examples/example-libuv.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include - -void getCallback(redisAsyncContext *c, void *r, void *privdata) { - redisReply *reply = r; - if (reply == NULL) return; - printf("argv[%s]: %s\n", (char*)privdata, reply->str); - - /* Disconnect after receiving the reply to GET */ - redisAsyncDisconnect(c); -} - -void connectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Connected...\n"); -} - -void disconnectCallback(const redisAsyncContext *c, int status) { - if (status != REDIS_OK) { - printf("Error: %s\n", c->errstr); - return; - } - printf("Disconnected...\n"); -} - -int main (int argc, char **argv) { - signal(SIGPIPE, SIG_IGN); - uv_loop_t* loop = uv_default_loop(); - - redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); - if (c->err) { - /* Let *c leak for now... */ - printf("Error: %s\n", c->errstr); - return 1; - } - - redisLibuvAttach(c,loop); - redisAsyncSetConnectCallback(c,connectCallback); - redisAsyncSetDisconnectCallback(c,disconnectCallback); - redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); - redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); - uv_run(loop, UV_RUN_DEFAULT); - return 0; -} diff --git a/ext/hiredis-vip-0.3.0/examples/example.c b/ext/hiredis-vip-0.3.0/examples/example.c deleted file mode 100644 index 25226a807..000000000 --- a/ext/hiredis-vip-0.3.0/examples/example.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include - -#include - -int main(int argc, char **argv) { - unsigned int j; - redisContext *c; - redisReply *reply; - const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; - int port = (argc > 2) ? atoi(argv[2]) : 6379; - - struct timeval timeout = { 1, 500000 }; // 1.5 seconds - c = redisConnectWithTimeout(hostname, port, timeout); - if (c == NULL || c->err) { - if (c) { - printf("Connection error: %s\n", c->errstr); - redisFree(c); - } else { - printf("Connection error: can't allocate redis context\n"); - } - exit(1); - } - - /* PING server */ - reply = redisCommand(c,"PING"); - printf("PING: %s\n", reply->str); - freeReplyObject(reply); - - /* Set a key */ - reply = redisCommand(c,"SET %s %s", "foo", "hello world"); - printf("SET: %s\n", reply->str); - freeReplyObject(reply); - - /* Set a key using binary safe API */ - reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5); - printf("SET (binary API): %s\n", reply->str); - freeReplyObject(reply); - - /* Try a GET and two INCR */ - reply = redisCommand(c,"GET foo"); - printf("GET foo: %s\n", reply->str); - freeReplyObject(reply); - - reply = redisCommand(c,"INCR counter"); - printf("INCR counter: %lld\n", reply->integer); - freeReplyObject(reply); - /* again ... */ - reply = redisCommand(c,"INCR counter"); - printf("INCR counter: %lld\n", reply->integer); - freeReplyObject(reply); - - /* Create a list of numbers, from 0 to 9 */ - reply = redisCommand(c,"DEL mylist"); - freeReplyObject(reply); - for (j = 0; j < 10; j++) { - char buf[64]; - - snprintf(buf,64,"%d",j); - reply = redisCommand(c,"LPUSH mylist element-%s", buf); - freeReplyObject(reply); - } - - /* Let's check what we have inside the list */ - reply = redisCommand(c,"LRANGE mylist 0 -1"); - if (reply->type == REDIS_REPLY_ARRAY) { - for (j = 0; j < reply->elements; j++) { - printf("%u) %s\n", j, reply->element[j]->str); - } - } - freeReplyObject(reply); - - /* Disconnects and frees the context */ - redisFree(c); - - return 0; -} diff --git a/ext/hiredis-vip-0.3.0/fmacros.h b/ext/hiredis-vip-0.3.0/fmacros.h deleted file mode 100644 index a3b1df034..000000000 --- a/ext/hiredis-vip-0.3.0/fmacros.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __HIREDIS_FMACRO_H -#define __HIREDIS_FMACRO_H - -#if defined(__linux__) -#ifndef _BSD_SOURCE -#define _BSD_SOURCE -#endif -#define _DEFAULT_SOURCE -#endif - -#if defined(__sun__) -#define _POSIX_C_SOURCE 200112L -#elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__) -#define _XOPEN_SOURCE 600 -#else -#define _XOPEN_SOURCE -#endif - -#if __APPLE__ && __MACH__ -#define _OSX -#endif - -#endif diff --git a/ext/hiredis-vip-0.3.0/hiarray.c b/ext/hiredis-vip-0.3.0/hiarray.c deleted file mode 100644 index cf742ecf6..000000000 --- a/ext/hiredis-vip-0.3.0/hiarray.c +++ /dev/null @@ -1,188 +0,0 @@ -#include - -#include "hiutil.h" -#include "hiarray.h" - -struct hiarray * -hiarray_create(uint32_t n, size_t size) -{ - struct hiarray *a; - - ASSERT(n != 0 && size != 0); - - a = hi_alloc(sizeof(*a)); - if (a == NULL) { - return NULL; - } - - a->elem = hi_alloc(n * size); - if (a->elem == NULL) { - hi_free(a); - return NULL; - } - - a->nelem = 0; - a->size = size; - a->nalloc = n; - - return a; -} - -void -hiarray_destroy(struct hiarray *a) -{ - hiarray_deinit(a); - hi_free(a); -} - -int -hiarray_init(struct hiarray *a, uint32_t n, size_t size) -{ - ASSERT(n != 0 && size != 0); - - a->elem = hi_alloc(n * size); - if (a->elem == NULL) { - return HI_ENOMEM; - } - - a->nelem = 0; - a->size = size; - a->nalloc = n; - - return HI_OK; -} - -void -hiarray_deinit(struct hiarray *a) -{ - ASSERT(a->nelem == 0); - - if (a->elem != NULL) { - hi_free(a->elem); - } -} - -uint32_t -hiarray_idx(struct hiarray *a, void *elem) -{ - uint8_t *p, *q; - uint32_t off, idx; - - ASSERT(elem >= a->elem); - - p = a->elem; - q = elem; - off = (uint32_t)(q - p); - - ASSERT(off % (uint32_t)a->size == 0); - - idx = off / (uint32_t)a->size; - - return idx; -} - -void * -hiarray_push(struct hiarray *a) -{ - void *elem, *new; - size_t size; - - if (a->nelem == a->nalloc) { - - /* the array is full; allocate new array */ - size = a->size * a->nalloc; - new = hi_realloc(a->elem, 2 * size); - if (new == NULL) { - return NULL; - } - - a->elem = new; - a->nalloc *= 2; - } - - elem = (uint8_t *)a->elem + a->size * a->nelem; - a->nelem++; - - return elem; -} - -void * -hiarray_pop(struct hiarray *a) -{ - void *elem; - - ASSERT(a->nelem != 0); - - a->nelem--; - elem = (uint8_t *)a->elem + a->size * a->nelem; - - return elem; -} - -void * -hiarray_get(struct hiarray *a, uint32_t idx) -{ - void *elem; - - ASSERT(a->nelem != 0); - ASSERT(idx < a->nelem); - - elem = (uint8_t *)a->elem + (a->size * idx); - - return elem; -} - -void * -hiarray_top(struct hiarray *a) -{ - ASSERT(a->nelem != 0); - - return hiarray_get(a, a->nelem - 1); -} - -void -hiarray_swap(struct hiarray *a, struct hiarray *b) -{ - struct hiarray tmp; - - tmp = *a; - *a = *b; - *b = tmp; -} - -/* - * Sort nelem elements of the array in ascending order based on the - * compare comparator. - */ -void -hiarray_sort(struct hiarray *a, hiarray_compare_t compare) -{ - ASSERT(a->nelem != 0); - - qsort(a->elem, a->nelem, a->size, compare); -} - -/* - * Calls the func once for each element in the array as long as func returns - * success. On failure short-circuits and returns the error status. - */ -int -hiarray_each(struct hiarray *a, hiarray_each_t func, void *data) -{ - uint32_t i, nelem; - - ASSERT(array_n(a) != 0); - ASSERT(func != NULL); - - for (i = 0, nelem = hiarray_n(a); i < nelem; i++) { - void *elem = hiarray_get(a, i); - rstatus_t status; - - status = func(elem, data); - if (status != HI_OK) { - return status; - } - } - - return HI_OK; -} diff --git a/ext/hiredis-vip-0.3.0/hiarray.h b/ext/hiredis-vip-0.3.0/hiarray.h deleted file mode 100644 index fda3a4b8b..000000000 --- a/ext/hiredis-vip-0.3.0/hiarray.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __HIARRAY_H_ -#define __HIARRAY_H_ - -#include - -typedef int (*hiarray_compare_t)(const void *, const void *); -typedef int (*hiarray_each_t)(void *, void *); - -struct hiarray { - uint32_t nelem; /* # element */ - void *elem; /* element */ - size_t size; /* element size */ - uint32_t nalloc; /* # allocated element */ -}; - -#define null_hiarray { 0, NULL, 0, 0 } - -static inline void -hiarray_null(struct hiarray *a) -{ - a->nelem = 0; - a->elem = NULL; - a->size = 0; - a->nalloc = 0; -} - -static inline void -hiarray_set(struct hiarray *a, void *elem, size_t size, uint32_t nalloc) -{ - a->nelem = 0; - a->elem = elem; - a->size = size; - a->nalloc = nalloc; -} - -static inline uint32_t -hiarray_n(const struct hiarray *a) -{ - return a->nelem; -} - -struct hiarray *hiarray_create(uint32_t n, size_t size); -void hiarray_destroy(struct hiarray *a); -int hiarray_init(struct hiarray *a, uint32_t n, size_t size); -void hiarray_deinit(struct hiarray *a); - -uint32_t hiarray_idx(struct hiarray *a, void *elem); -void *hiarray_push(struct hiarray *a); -void *hiarray_pop(struct hiarray *a); -void *hiarray_get(struct hiarray *a, uint32_t idx); -void *hiarray_top(struct hiarray *a); -void hiarray_swap(struct hiarray *a, struct hiarray *b); -void hiarray_sort(struct hiarray *a, hiarray_compare_t compare); -int hiarray_each(struct hiarray *a, hiarray_each_t func, void *data); - -#endif diff --git a/ext/hiredis-vip-0.3.0/hircluster.c b/ext/hiredis-vip-0.3.0/hircluster.c deleted file mode 100644 index edf9cb2f9..000000000 --- a/ext/hiredis-vip-0.3.0/hircluster.c +++ /dev/null @@ -1,4747 +0,0 @@ - -#include "fmacros.h" -#include -#include -#include -#include -#include - -#include "hircluster.h" -#include "hiutil.h" -#include "adlist.h" -#include "hiarray.h" -#include "command.h" -#include "dict.c" - -#define REDIS_COMMAND_CLUSTER_NODES "CLUSTER NODES" -#define REDIS_COMMAND_CLUSTER_SLOTS "CLUSTER SLOTS" - -#define REDIS_COMMAND_ASKING "ASKING" -#define REDIS_COMMAND_PING "PING" - -#define REDIS_PROTOCOL_ASKING "*1\r\n$6\r\nASKING\r\n" - -#define IP_PORT_SEPARATOR ":" - -#define CLUSTER_ADDRESS_SEPARATOR "," - -#define CLUSTER_DEFAULT_MAX_REDIRECT_COUNT 5 - -typedef struct cluster_async_data -{ - redisClusterAsyncContext *acc; - struct cmd *command; - redisClusterCallbackFn *callback; - int retry_count; - void *privdata; -}cluster_async_data; - -typedef enum CLUSTER_ERR_TYPE{ - CLUSTER_NOT_ERR = 0, - CLUSTER_ERR_MOVED, - CLUSTER_ERR_ASK, - CLUSTER_ERR_TRYAGAIN, - CLUSTER_ERR_CROSSSLOT, - CLUSTER_ERR_CLUSTERDOWN, - CLUSTER_ERR_SENTINEL -}CLUSTER_ERR_TYPE; - -static void cluster_node_deinit(cluster_node *node); -static void cluster_slot_destroy(cluster_slot *slot); -static void cluster_open_slot_destroy(copen_slot *oslot); - -void listClusterNodeDestructor(void *val) -{ - cluster_node_deinit(val); - - hi_free(val); -} - -void listClusterSlotDestructor(void *val) -{ - cluster_slot_destroy(val); -} - -unsigned int dictSdsHash(const void *key) { - return dictGenHashFunction((unsigned char*)key, sdslen((char*)key)); -} - -int dictSdsKeyCompare(void *privdata, const void *key1, - const void *key2) -{ - int l1,l2; - DICT_NOTUSED(privdata); - - l1 = sdslen((sds)key1); - l2 = sdslen((sds)key2); - if (l1 != l2) return 0; - return memcmp(key1, key2, l1) == 0; -} - -void dictSdsDestructor(void *privdata, void *val) -{ - DICT_NOTUSED(privdata); - - sdsfree(val); -} - -void dictClusterNodeDestructor(void *privdata, void *val) -{ - DICT_NOTUSED(privdata); - - cluster_node_deinit(val); - - hi_free(val); -} - -/* Cluster nodes hash table, mapping nodes - * name(437c719f50dc9d0745032f3b280ce7ecc40792ac) - * or addresses(1.2.3.4:6379) to clusterNode structures. - * Those nodes need destroy. - */ -dictType clusterNodesDictType = { - dictSdsHash, /* hash function */ - NULL, /* key dup */ - NULL, /* val dup */ - dictSdsKeyCompare, /* key compare */ - dictSdsDestructor, /* key destructor */ - dictClusterNodeDestructor /* val destructor */ -}; - -/* Cluster nodes hash table, mapping nodes - * name(437c719f50dc9d0745032f3b280ce7ecc40792ac) - * or addresses(1.2.3.4:6379) to clusterNode structures. - * Those nodes do not need destroy. - */ -dictType clusterNodesRefDictType = { - dictSdsHash, /* hash function */ - NULL, /* key dup */ - NULL, /* val dup */ - dictSdsKeyCompare, /* key compare */ - dictSdsDestructor, /* key destructor */ - NULL /* val destructor */ -}; - - -void listCommandFree(void *command) -{ - struct cmd *cmd = command; - command_destroy(cmd); -} - -/* Defined in hiredis.c */ -void __redisSetError(redisContext *c, int type, const char *str); - -/* Forward declaration of function in hiredis.c */ -int __redisAppendCommand(redisContext *c, const char *cmd, size_t len); - -/* Helper function for the redisClusterCommand* family of functions. - * - * Write a formatted command to the output buffer. If the given context is - * blocking, immediately read the reply into the "reply" pointer. When the - * context is non-blocking, the "reply" pointer will not be used and the - * command is simply appended to the write buffer. - * - * Returns the reply when a reply was succesfully retrieved. Returns NULL - * otherwise. When NULL is returned in a blocking context, the error field - * in the context will be set. - */ -static void *__redisBlockForReply(redisContext *c) { - void *reply; - - if (c->flags & REDIS_BLOCK) { - if (redisGetReply(c,&reply) != REDIS_OK) - return NULL; - return reply; - } - return NULL; -} - - -/* ----------------------------------------------------------------------------- - * Key space handling - * -------------------------------------------------------------------------- */ - -/* We have 16384 hash slots. The hash slot of a given key is obtained - * as the least significant 14 bits of the crc16 of the key. - * - * However if the key contains the {...} pattern, only the part between - * { and } is hashed. This may be useful in the future to force certain - * keys to be in the same node (assuming no resharding is in progress). */ -static unsigned int keyHashSlot(char *key, int keylen) { - int s, e; /* start-end indexes of { and } */ - - for (s = 0; s < keylen; s++) - if (key[s] == '{') break; - - /* No '{' ? Hash the whole key. This is the base case. */ - if (s == keylen) return crc16(key,keylen) & 0x3FFF; - - /* '{' found? Check if we have the corresponding '}'. */ - for (e = s+1; e < keylen; e++) - if (key[e] == '}') break; - - /* No '}' or nothing betweeen {} ? Hash the whole key. */ - if (e == keylen || e == s+1) return crc16(key,keylen) & 0x3FFF; - - /* If we are here there is both a { and a } on its right. Hash - * what is in the middle between { and }. */ - return crc16(key+s+1,e-s-1) & 0x3FFF; -} - -static void __redisClusterSetError(redisClusterContext *cc, int type, const char *str) { - size_t len; - - if(cc == NULL){ - return; - } - - cc->err = type; - if (str != NULL) { - len = strlen(str); - len = len < (sizeof(cc->errstr)-1) ? len : (sizeof(cc->errstr)-1); - memcpy(cc->errstr,str,len); - cc->errstr[len] = '\0'; - } else { - /* Only REDIS_ERR_IO may lack a description! */ - assert(type == REDIS_ERR_IO); - __redis_strerror_r(errno, cc->errstr, sizeof(cc->errstr)); - } -} - -static int cluster_reply_error_type(redisReply *reply) -{ - - if(reply == NULL) - { - return REDIS_ERR; - } - - if(reply->type == REDIS_REPLY_ERROR) - { - if((int)strlen(REDIS_ERROR_MOVED) < reply->len && - strncmp(reply->str, REDIS_ERROR_MOVED, strlen(REDIS_ERROR_MOVED)) == 0) - { - return CLUSTER_ERR_MOVED; - } - else if((int)strlen(REDIS_ERROR_ASK) < reply->len && - strncmp(reply->str, REDIS_ERROR_ASK, strlen(REDIS_ERROR_ASK)) == 0) - { - return CLUSTER_ERR_ASK; - } - else if((int)strlen(REDIS_ERROR_TRYAGAIN) < reply->len && - strncmp(reply->str, REDIS_ERROR_TRYAGAIN, strlen(REDIS_ERROR_TRYAGAIN)) == 0) - { - return CLUSTER_ERR_TRYAGAIN; - } - else if((int)strlen(REDIS_ERROR_CROSSSLOT) < reply->len && - strncmp(reply->str, REDIS_ERROR_CROSSSLOT, strlen(REDIS_ERROR_CROSSSLOT)) == 0) - { - return CLUSTER_ERR_CROSSSLOT; - } - else if((int)strlen(REDIS_ERROR_CLUSTERDOWN) < reply->len && - strncmp(reply->str, REDIS_ERROR_CLUSTERDOWN, strlen(REDIS_ERROR_CLUSTERDOWN)) == 0) - { - return CLUSTER_ERR_CLUSTERDOWN; - } - else - { - return CLUSTER_ERR_SENTINEL; - } - } - - return CLUSTER_NOT_ERR; -} - -static int cluster_node_init(cluster_node *node) -{ - if(node == NULL){ - return REDIS_ERR; - } - - node->name = NULL; - node->addr = NULL; - node->host = NULL; - node->port = 0; - node->role = REDIS_ROLE_NULL; - node->myself = 0; - node->slaves = NULL; - node->con = NULL; - node->acon = NULL; - node->slots = NULL; - node->failure_count = 0; - node->data = NULL; - node->migrating = NULL; - node->importing = NULL; - - return REDIS_OK; -} - -static void cluster_node_deinit(cluster_node *node) -{ - copen_slot **oslot; - - if(node == NULL) - { - return; - } - - sdsfree(node->name); - sdsfree(node->addr); - sdsfree(node->host); - node->port = 0; - node->role = REDIS_ROLE_NULL; - node->myself = 0; - - if(node->con != NULL) - { - redisFree(node->con); - } - - if(node->acon != NULL) - { - redisAsyncFree(node->acon); - } - - if(node->slots != NULL) - { - listRelease(node->slots); - } - - if(node->slaves != NULL) - { - listRelease(node->slaves); - } - - if(node->migrating) - { - while(hiarray_n(node->migrating)) - { - oslot = hiarray_pop(node->migrating); - cluster_open_slot_destroy(*oslot); - } - - hiarray_destroy(node->migrating); - node->migrating = NULL; - } - - if(node->importing) - { - while(hiarray_n(node->importing)) - { - oslot = hiarray_pop(node->importing); - cluster_open_slot_destroy(*oslot); - } - - hiarray_destroy(node->importing); - node->importing = NULL; - } -} - -static int cluster_slot_init(cluster_slot *slot, cluster_node *node) -{ - slot->start = 0; - slot->end = 0; - slot->node = node; - - return REDIS_OK; -} - -static cluster_slot *cluster_slot_create(cluster_node *node) -{ - cluster_slot *slot; - - slot = hi_alloc(sizeof(*slot)); - if(slot == NULL){ - return NULL; - } - - cluster_slot_init(slot, node); - - if(node != NULL){ - ASSERT(node->role == REDIS_ROLE_MASTER); - if(node->slots == NULL){ - node->slots = listCreate(); - if(node->slots == NULL) - { - cluster_slot_destroy(slot); - return NULL; - } - - node->slots->free = listClusterSlotDestructor; - } - - listAddNodeTail(node->slots, slot); - } - - return slot; -} - -static int cluster_slot_ref_node(cluster_slot * slot, cluster_node *node) -{ - if(slot == NULL || node == NULL){ - return REDIS_ERR; - } - - - if(node->role != REDIS_ROLE_MASTER){ - return REDIS_ERR; - } - - if(node->slots == NULL){ - node->slots = listCreate(); - if(node->slots == NULL) - { - return REDIS_ERR; - } - - node->slots->free = listClusterSlotDestructor; - } - - listAddNodeTail(node->slots, slot); - slot->node = node; - - return REDIS_OK; -} - -static void cluster_slot_destroy(cluster_slot *slot) -{ - slot->start = 0; - slot->end = 0; - slot->node = NULL; - - hi_free(slot); -} - -static copen_slot *cluster_open_slot_create(uint32_t slot_num, int migrate, - sds remote_name, cluster_node *node) -{ - copen_slot *oslot; - - oslot = hi_alloc(sizeof(*oslot)); - if(oslot == NULL){ - return NULL; - } - - oslot->slot_num = 0; - oslot->migrate = 0; - oslot->node = NULL; - oslot->remote_name = NULL; - - oslot->slot_num = slot_num; - oslot->migrate = migrate; - oslot->node = node; - oslot->remote_name = sdsdup(remote_name); - - return oslot; -} - -static void cluster_open_slot_destroy(copen_slot *oslot) -{ - oslot->slot_num = 0; - oslot->migrate = 0; - oslot->node = NULL; - - if(oslot->remote_name != NULL){ - sdsfree(oslot->remote_name); - oslot->remote_name = NULL; - } - - hi_free(oslot); -} - -/** - * Return a new node with the "cluster slots" command reply. - */ -static cluster_node *node_get_with_slots( - redisClusterContext *cc, redisReply *host_elem, - redisReply *port_elem, uint8_t role) -{ - cluster_node *node = NULL; - - if(host_elem == NULL || port_elem == NULL){ - return NULL; - } - - if(host_elem->type != REDIS_REPLY_STRING || - host_elem->len <= 0){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "node ip is not string."); - goto error; - } - - if(port_elem->type != REDIS_REPLY_INTEGER || - port_elem->integer <= 0){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "node port is not integer."); - goto error; - } - - if(!hi_valid_port((int)port_elem->integer)){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "node port is not valid."); - goto error; - } - - node = hi_alloc(sizeof(cluster_node)); - if(node == NULL){ - __redisClusterSetError(cc, - REDIS_ERR_OOM,"Out of memory"); - goto error; - } - - cluster_node_init(node); - - if(role == REDIS_ROLE_MASTER){ - node->slots = listCreate(); - if(node->slots == NULL){ - hi_free(node); - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "slots for node listCreate error"); - goto error; - } - - node->slots->free = listClusterSlotDestructor; - } - - node->name = NULL; - node->addr = sdsnewlen(host_elem->str, host_elem->len); - node->addr = sdscatfmt(node->addr, ":%i", port_elem->integer); - - node->host = sdsnewlen(host_elem->str, host_elem->len); - node->port = (int)port_elem->integer; - node->role = role; - - return node; - -error: - - if(node != NULL){ - hi_free(node); - } - - return NULL; -} - -/** - * Return a new node with the "cluster nodes" command reply. - */ -static cluster_node *node_get_with_nodes( - redisClusterContext *cc, - sds *node_infos, int info_count, uint8_t role) -{ - sds *ip_port = NULL; - int count_ip_port = 0; - cluster_node *node; - - if(info_count < 8) - { - return NULL; - } - - node = hi_alloc(sizeof(cluster_node)); - if(node == NULL) - { - __redisClusterSetError(cc, - REDIS_ERR_OOM,"Out of memory"); - goto error; - } - - cluster_node_init(node); - - if(role == REDIS_ROLE_MASTER) - { - node->slots = listCreate(); - if(node->slots == NULL) - { - hi_free(node); - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "slots for node listCreate error"); - goto error; - } - - node->slots->free = listClusterSlotDestructor; - } - - node->name = node_infos[0]; - node->addr = node_infos[1]; - - ip_port = sdssplitlen(node_infos[1], sdslen(node_infos[1]), - IP_PORT_SEPARATOR, strlen(IP_PORT_SEPARATOR), &count_ip_port); - if(ip_port == NULL || count_ip_port != 2) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "split ip port error"); - goto error; - } - node->host = ip_port[0]; - node->port = hi_atoi(ip_port[1], sdslen(ip_port[1])); - node->role = role; - - sdsfree(ip_port[1]); - free(ip_port); - - node_infos[0] = NULL; - node_infos[1] = NULL; - - return node; - -error: - if(ip_port != NULL) - { - sdsfreesplitres(ip_port, count_ip_port); - } - - if(node != NULL) - { - hi_free(node); - } - - return NULL; -} - -static void cluster_nodes_swap_ctx(dict *nodes_f, dict *nodes_t) -{ - dictIterator *di; - dictEntry *de_f, *de_t; - cluster_node *node_f, *node_t; - redisContext *c; - redisAsyncContext *ac; - - if(nodes_f == NULL || nodes_t == NULL){ - return; - } - - di = dictGetIterator(nodes_t); - while((de_t = dictNext(di)) != NULL){ - node_t = dictGetEntryVal(de_t); - if(node_t == NULL){ - continue; - } - - de_f = dictFind(nodes_f, node_t->addr); - if(de_f == NULL){ - continue; - } - - node_f = dictGetEntryVal(de_f); - if(node_f->con != NULL){ - c = node_f->con; - node_f->con = node_t->con; - node_t->con = c; - } - - if(node_f->acon != NULL){ - ac = node_f->acon; - node_f->acon = node_t->acon; - node_t->acon = ac; - - node_t->acon->data = node_t; - if (node_f->acon) - node_f->acon->data = node_f; - } - } - - dictReleaseIterator(di); - -} - -static int -cluster_slot_start_cmp(const void *t1, const void *t2) -{ - const cluster_slot **s1 = t1, **s2 = t2; - - return (*s1)->start > (*s2)->start?1:-1; -} - -static int -cluster_master_slave_mapping_with_name(redisClusterContext *cc, - dict **nodes, cluster_node *node, sds master_name) -{ - int ret; - dictEntry *di; - cluster_node *node_old; - listNode *lnode; - - if(node == NULL || master_name == NULL) - { - return REDIS_ERR; - } - - if(*nodes == NULL) - { - *nodes = dictCreate( - &clusterNodesRefDictType, NULL); - } - - di = dictFind(*nodes, master_name); - if(di == NULL) - { - ret = dictAdd(*nodes, - sdsnewlen(master_name, sdslen(master_name)), node); - if(ret != DICT_OK) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "the address already exists in the nodes"); - return REDIS_ERR; - } - - } - else - { - node_old = dictGetEntryVal(di); - if(node_old == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "dict get value null"); - return REDIS_ERR; - } - - if(node->role == REDIS_ROLE_MASTER && - node_old->role == REDIS_ROLE_MASTER) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "two masters have the same name"); - return REDIS_ERR; - } - else if(node->role == REDIS_ROLE_MASTER - && node_old->role == REDIS_ROLE_SLAVE) - { - if(node->slaves == NULL) - { - node->slaves = listCreate(); - if(node->slaves == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM, - "Out of memory"); - return REDIS_ERR; - } - - node->slaves->free = - listClusterNodeDestructor; - } - - if(node_old->slaves != NULL) - { - node_old->slaves->free = NULL; - while(listLength(node_old->slaves) > 0) - { - lnode = listFirst(node_old->slaves); - listAddNodeHead(node->slaves, lnode->value); - listDelNode(node_old->slaves, lnode); - } - listRelease(node_old->slaves); - node_old->slaves = NULL; - } - - listAddNodeHead(node->slaves, node_old); - - dictSetHashVal(*nodes, di, node); - } - else if(node->role == REDIS_ROLE_SLAVE) - { - if(node_old->slaves == NULL) - { - node_old->slaves = listCreate(); - if(node_old->slaves == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM, - "Out of memory"); - return REDIS_ERR; - } - - node_old->slaves->free = - listClusterNodeDestructor; - } - - listAddNodeTail(node_old->slaves, node); - } - else - { - NOT_REACHED(); - } - } - - return REDIS_OK; -} - -/** - * Parse the "cluster slots" command reply to nodes dict. - */ -dict * -parse_cluster_slots(redisClusterContext *cc, - redisReply *reply, int flags) -{ - int ret; - cluster_slot *slot = NULL; - dict *nodes = NULL; - dictEntry *den; - redisReply *elem_slots; - redisReply *elem_slots_begin, *elem_slots_end; - redisReply *elem_nodes; - redisReply *elem_ip, *elem_port; - cluster_node *master = NULL, *slave; - sds address; - uint32_t i, idx; - - if(reply == NULL){ - return NULL; - } - - nodes = dictCreate(&clusterNodesDictType, NULL); - if(nodes == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OOM, - "out of memory"); - goto error; - } - - if(reply->type != REDIS_REPLY_ARRAY || reply->elements <= 0){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "reply is not an array."); - goto error; - } - - for(i = 0; i < reply->elements; i ++){ - elem_slots = reply->element[i]; - if(elem_slots->type != REDIS_REPLY_ARRAY || - elem_slots->elements < 3){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "first sub_reply is not an array."); - goto error; - } - - slot = cluster_slot_create(NULL); - if(slot == NULL){ - __redisClusterSetError(cc, REDIS_ERR_OOM, - "Slot create failed: out of memory."); - goto error; - } - - //one slots region - for(idx = 0; idx < elem_slots->elements; idx ++){ - if(idx == 0){ - elem_slots_begin = elem_slots->element[idx]; - if(elem_slots_begin->type != REDIS_REPLY_INTEGER){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "slot begin is not an integer."); - goto error; - } - slot->start = (int)(elem_slots_begin->integer); - }else if(idx == 1){ - elem_slots_end = elem_slots->element[idx]; - if(elem_slots_end->type != REDIS_REPLY_INTEGER){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "slot end is not an integer."); - goto error; - } - - slot->end = (int)(elem_slots_end->integer); - - if(slot->start > slot->end){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "slot begin is bigger than slot end."); - goto error; - } - }else{ - elem_nodes = elem_slots->element[idx]; - if(elem_nodes->type != REDIS_REPLY_ARRAY || - elem_nodes->elements != 3){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "nodes sub_reply is not an correct array."); - goto error; - } - - elem_ip = elem_nodes->element[0]; - elem_port = elem_nodes->element[1]; - - if(elem_ip == NULL || elem_port == NULL || - elem_ip->type != REDIS_REPLY_STRING || - elem_port->type != REDIS_REPLY_INTEGER){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Command(cluster slots) reply error: " - "master ip or port is not correct."); - goto error; - } - - //this is master. - if(idx == 2){ - address = sdsnewlen(elem_ip->str, elem_ip->len); - address = sdscatfmt(address, ":%i", elem_port->integer); - - den = dictFind(nodes, address); - //master already exits, break to the next slots region. - if(den != NULL){ - sdsfree(address); - - master = dictGetEntryVal(den); - ret = cluster_slot_ref_node(slot, master); - if(ret != REDIS_OK){ - __redisClusterSetError(cc, REDIS_ERR_OOM, - "Slot ref node failed: out of memory."); - goto error; - } - - slot = NULL; - break; - } - - sdsfree(address); - master = node_get_with_slots(cc, elem_ip, - elem_port, REDIS_ROLE_MASTER); - if(master == NULL){ - goto error; - } - - ret = dictAdd(nodes, - sdsnewlen(master->addr, sdslen(master->addr)), master); - if(ret != DICT_OK){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "The address already exists in the nodes"); - cluster_node_deinit(master); - hi_free(master); - goto error; - } - - ret = cluster_slot_ref_node(slot, master); - if(ret != REDIS_OK){ - __redisClusterSetError(cc, REDIS_ERR_OOM, - "Slot ref node failed: out of memory."); - goto error; - } - - slot = NULL; - }else if(flags & HIRCLUSTER_FLAG_ADD_SLAVE){ - slave = node_get_with_slots(cc, elem_ip, - elem_port, REDIS_ROLE_SLAVE); - if(slave == NULL){ - goto error; - } - - if(master->slaves == NULL){ - master->slaves = listCreate(); - if(master->slaves == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OOM, - "Out of memory"); - cluster_node_deinit(slave); - goto error; - } - - master->slaves->free = - listClusterNodeDestructor; - } - - listAddNodeTail(master->slaves, slave); - } - } - } - } - - return nodes; - -error: - - if(nodes != NULL){ - dictRelease(nodes); - } - - if(slot != NULL){ - cluster_slot_destroy(slot); - } - - return NULL; -} - -/** - * Parse the "cluster nodes" command reply to nodes dict. - */ -dict * -parse_cluster_nodes(redisClusterContext *cc, - char *str, int str_len, int flags) -{ - int ret; - dict *nodes = NULL; - dict *nodes_name = NULL; - cluster_node *master, *slave; - cluster_slot *slot; - char *pos, *start, *end, *line_start, *line_end; - char *role; - int role_len; - uint8_t myself = 0; - int slot_start, slot_end; - sds *part = NULL, *slot_start_end = NULL; - int count_part = 0, count_slot_start_end = 0; - int k; - int len; - - nodes = dictCreate(&clusterNodesDictType, NULL); - if(nodes == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OOM, - "out of memory"); - goto error; - } - - start = str; - end = start + str_len; - - line_start = start; - - for(pos = start; pos < end; pos ++){ - if(*pos == '\n'){ - line_end = pos - 1; - len = line_end - line_start; - - part = sdssplitlen(line_start, len + 1, " ", 1, &count_part); - - if(part == NULL || count_part < 8){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "split cluster nodes error"); - goto error; - } - - //the address string is ":0", skip this node. - if(sdslen(part[1]) == 2 && strcmp(part[1], ":0") == 0){ - sdsfreesplitres(part, count_part); - count_part = 0; - part = NULL; - - start = pos + 1; - line_start = start; - pos = start; - - continue; - } - - if(sdslen(part[2]) >= 7 && memcmp(part[2], "myself,", 7) == 0){ - role_len = sdslen(part[2]) - 7; - role = part[2] + 7; - myself = 1; - }else{ - role_len = sdslen(part[2]); - role = part[2]; - } - - //add master node - if(role_len >= 6 && memcmp(role, "master", 6) == 0){ - if(count_part < 8){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "Master node parts number error: less than 8."); - goto error; - } - - master = node_get_with_nodes(cc, - part, count_part, REDIS_ROLE_MASTER); - if(master == NULL){ - goto error; - } - - ret = dictAdd(nodes, - sdsnewlen(master->addr, sdslen(master->addr)), master); - if(ret != DICT_OK){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "The address already exists in the nodes"); - cluster_node_deinit(master); - hi_free(master); - goto error; - } - - if(flags & HIRCLUSTER_FLAG_ADD_SLAVE){ - ret = cluster_master_slave_mapping_with_name(cc, - &nodes_name, master, master->name); - if(ret != REDIS_OK){ - cluster_node_deinit(master); - hi_free(master); - goto error; - } - } - - if(myself) master->myself = 1; - - for(k = 8; k < count_part; k ++){ - slot_start_end = sdssplitlen(part[k], - sdslen(part[k]), "-", 1, &count_slot_start_end); - - if(slot_start_end == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "split slot start end error(NULL)"); - goto error; - }else if(count_slot_start_end == 1){ - slot_start = - hi_atoi(slot_start_end[0], sdslen(slot_start_end[0])); - slot_end = slot_start; - }else if(count_slot_start_end == 2){ - slot_start = - hi_atoi(slot_start_end[0], sdslen(slot_start_end[0]));; - slot_end = - hi_atoi(slot_start_end[1], sdslen(slot_start_end[1]));; - }else{ - //add open slot for master - if(flags & HIRCLUSTER_FLAG_ADD_OPENSLOT && - count_slot_start_end == 3 && - sdslen(slot_start_end[0]) > 1 && - sdslen(slot_start_end[1]) == 1 && - sdslen(slot_start_end[2]) > 1 && - slot_start_end[0][0] == '[' && - slot_start_end[2][sdslen(slot_start_end[2])-1] == ']'){ - - copen_slot *oslot, **oslot_elem; - - sdsrange(slot_start_end[0], 1, -1); - sdsrange(slot_start_end[2], 0, -2); - - if(slot_start_end[1][0] == '>'){ - oslot = cluster_open_slot_create( - hi_atoi(slot_start_end[0], - sdslen(slot_start_end[0])), - 1, slot_start_end[2], master); - if(oslot == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "create open slot error"); - goto error; - } - - if(master->migrating == NULL){ - master->migrating = hiarray_create(1, sizeof(oslot)); - if(master->migrating == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "create migrating array error"); - cluster_open_slot_destroy(oslot); - goto error; - } - } - - oslot_elem = hiarray_push(master->migrating); - if(oslot_elem == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "Push migrating array error: out of memory"); - cluster_open_slot_destroy(oslot); - goto error; - } - - *oslot_elem = oslot; - }else if(slot_start_end[1][0] == '<'){ - oslot = cluster_open_slot_create(hi_atoi(slot_start_end[0], - sdslen(slot_start_end[0])), 0, slot_start_end[2], - master); - if(oslot == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "create open slot error"); - goto error; - } - - if(master->importing == NULL){ - master->importing = hiarray_create(1, sizeof(oslot)); - if(master->importing == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "create migrating array error"); - cluster_open_slot_destroy(oslot); - goto error; - } - } - - oslot_elem = hiarray_push(master->importing); - if(oslot_elem == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "push migrating array error: out of memory"); - cluster_open_slot_destroy(oslot); - goto error; - } - - *oslot_elem = oslot; - } - } - - slot_start = -1; - slot_end = -1; - } - - sdsfreesplitres(slot_start_end, count_slot_start_end); - count_slot_start_end = 0; - slot_start_end = NULL; - - if(slot_start < 0 || slot_end < 0 || - slot_start > slot_end || slot_end >= REDIS_CLUSTER_SLOTS){ - continue; - } - - slot = cluster_slot_create(master); - if(slot == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OOM, - "Out of memory"); - goto error; - } - - slot->start = (uint32_t)slot_start; - slot->end = (uint32_t)slot_end; - } - - } - //add slave node - else if((flags & HIRCLUSTER_FLAG_ADD_SLAVE) && - (role_len >= 5 && memcmp(role, "slave", 5) == 0)){ - slave = node_get_with_nodes(cc, part, - count_part, REDIS_ROLE_SLAVE); - if(slave == NULL){ - goto error; - } - - ret = cluster_master_slave_mapping_with_name(cc, - &nodes_name, slave, part[3]); - if(ret != REDIS_OK){ - cluster_node_deinit(slave); - hi_free(slave); - goto error; - } - - if(myself) slave->myself = 1; - } - - if(myself == 1){ - myself = 0; - } - - sdsfreesplitres(part, count_part); - count_part = 0; - part = NULL; - - start = pos + 1; - line_start = start; - pos = start; - } - } - - if(nodes_name != NULL){ - dictRelease(nodes_name); - } - - return nodes; - -error: - - if(part != NULL){ - sdsfreesplitres(part, count_part); - count_part = 0; - part = NULL; - } - - if(slot_start_end != NULL){ - sdsfreesplitres(slot_start_end, count_slot_start_end); - count_slot_start_end = 0; - slot_start_end = NULL; - } - - if(nodes != NULL){ - dictRelease(nodes); - } - - if(nodes_name != NULL){ - dictRelease(nodes_name); - } - - return NULL; -} - -/** - * Update route with the "cluster nodes" or "cluster slots" command reply. - */ -static int -cluster_update_route_by_addr(redisClusterContext *cc, - const char *ip, int port) -{ - redisContext *c = NULL; - redisReply *reply = NULL; - dict *nodes = NULL; - struct hiarray *slots = NULL; - cluster_node *master; - cluster_slot *slot, **slot_elem; - dictIterator *dit = NULL; - dictEntry *den; - listIter *lit = NULL; - listNode *lnode; - cluster_node *table[REDIS_CLUSTER_SLOTS]; - uint32_t j, k; - - if(cc == NULL){ - return REDIS_ERR; - } - - if(ip == NULL || port <= 0){ - __redisClusterSetError(cc, - REDIS_ERR_OTHER,"Ip or port error!"); - goto error; - } - - if(cc->timeout){ - c = redisConnectWithTimeout(ip, port, *cc->timeout); - }else{ - c = redisConnect(ip, port); - } - - if (c == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "Init redis context error(return NULL)"); - goto error; - }else if(c->err){ - __redisClusterSetError(cc,c->err,c->errstr); - goto error; - } - - if(cc->flags & HIRCLUSTER_FLAG_ROUTE_USE_SLOTS){ - reply = redisCommand(c, REDIS_COMMAND_CLUSTER_SLOTS); - if(reply == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "Command(cluster slots) reply error(NULL)."); - goto error; - }else if(reply->type != REDIS_REPLY_ARRAY){ - if(reply->type == REDIS_REPLY_ERROR){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - reply->str); - }else{ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "Command(cluster slots) reply error: type is not array."); - } - - goto error; - } - - nodes = parse_cluster_slots(cc, reply, cc->flags); - }else{ - reply = redisCommand(c, REDIS_COMMAND_CLUSTER_NODES); - if(reply == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "Command(cluster nodes) reply error(NULL)."); - goto error; - }else if(reply->type != REDIS_REPLY_STRING){ - if(reply->type == REDIS_REPLY_ERROR){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - reply->str); - }else{ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "Command(cluster nodes) reply error: type is not string."); - } - - goto error; - } - - nodes = parse_cluster_nodes(cc, reply->str, reply->len, cc->flags); - } - - if(nodes == NULL){ - goto error; - } - - memset(table, 0, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); - - slots = hiarray_create(dictSize(nodes), sizeof(cluster_slot*)); - if(slots == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "Slots array create failed: out of memory"); - goto error; - } - - dit = dictGetIterator(nodes); - if(dit == NULL){ - __redisClusterSetError(cc,REDIS_ERR_OOM, - "Dict get iterator failed: out of memory"); - goto error; - } - - while((den = dictNext(dit))){ - master = dictGetEntryVal(den); - if(master->role != REDIS_ROLE_MASTER){ - __redisClusterSetError(cc,REDIS_ERR_OOM, - "Node role must be master"); - goto error; - } - - if(master->slots == NULL){ - continue; - } - - lit = listGetIterator(master->slots, AL_START_HEAD); - if(lit == NULL){ - __redisClusterSetError(cc, REDIS_ERR_OOM, - "List get iterator failed: out of memory"); - goto error; - } - - while((lnode = listNext(lit))){ - slot = listNodeValue(lnode); - if(slot->start > slot->end || - slot->end >= REDIS_CLUSTER_SLOTS){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Slot region for node is error"); - goto error; - } - - slot_elem = hiarray_push(slots); - *slot_elem = slot; - } - - listReleaseIterator(lit); - } - - dictReleaseIterator(dit); - - hiarray_sort(slots, cluster_slot_start_cmp); - for(j = 0; j < hiarray_n(slots); j ++){ - slot_elem = hiarray_get(slots, j); - - for(k = (*slot_elem)->start; k <= (*slot_elem)->end; k ++){ - if(table[k] != NULL){ - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "Diffent node hold a same slot"); - goto error; - } - - table[k] = (*slot_elem)->node; - } - } - - cluster_nodes_swap_ctx(cc->nodes, nodes); - if(cc->nodes != NULL){ - dictRelease(cc->nodes); - cc->nodes = NULL; - } - cc->nodes = nodes; - - if(cc->slots != NULL) - { - cc->slots->nelem = 0; - hiarray_destroy(cc->slots); - cc->slots = NULL; - } - cc->slots = slots; - - memcpy(cc->table, table, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); - cc->route_version ++; - - freeReplyObject(reply); - - if(c != NULL){ - redisFree(c); - } - - return REDIS_OK; - -error: - - if(dit != NULL){ - dictReleaseIterator(dit); - } - - if(lit != NULL){ - listReleaseIterator(lit); - } - - if(slots != NULL) - { - if(slots == cc->slots) - { - cc->slots = NULL; - } - - slots->nelem = 0; - hiarray_destroy(slots); - } - - if(nodes != NULL){ - if(nodes == cc->nodes){ - cc->nodes = NULL; - } - - dictRelease(nodes); - } - - if(reply != NULL){ - freeReplyObject(reply); - reply = NULL; - } - - if(c != NULL){ - redisFree(c); - } - - return REDIS_ERR; -} - - -/** - * Update route with the "cluster nodes" command reply. - */ -static int -cluster_update_route_with_nodes_old(redisClusterContext *cc, - const char *ip, int port) -{ - int ret; - redisContext *c = NULL; - redisReply *reply = NULL; - struct hiarray *slots = NULL; - dict *nodes = NULL; - dict *nodes_name = NULL; - cluster_node *master, *slave; - cluster_slot **slot; - char *pos, *start, *end, *line_start, *line_end; - char *role; - int role_len; - uint8_t myself = 0; - int slot_start, slot_end; - sds *part = NULL, *slot_start_end = NULL; - int count_part = 0, count_slot_start_end = 0; - int j, k; - int len; - cluster_node *table[REDIS_CLUSTER_SLOTS] = {NULL}; - - if(cc == NULL) - { - return REDIS_ERR; - } - - if(ip == NULL || port <= 0) - { - __redisClusterSetError(cc, - REDIS_ERR_OTHER,"ip or port error!"); - goto error; - } - - if(cc->timeout) - { - c = redisConnectWithTimeout(ip, port, *cc->timeout); - } - else - { - c = redisConnect(ip, port); - } - - if (c == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "init redis context error(return NULL)"); - goto error; - } - else if(c->err) - { - __redisClusterSetError(cc,c->err,c->errstr); - goto error; - } - - reply = redisCommand(c, REDIS_COMMAND_CLUSTER_NODES); - - if(reply == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "command(cluster nodes) reply error(NULL)"); - goto error; - } - else if(reply->type != REDIS_REPLY_STRING) - { - if(reply->type == REDIS_REPLY_ERROR) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - reply->str); - } - else - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "command(cluster nodes) reply error(type is not string)"); - } - - goto error; - } - - nodes = dictCreate(&clusterNodesDictType, NULL); - - slots = hiarray_create(10, sizeof(cluster_slot*)); - if(slots == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "array create error"); - goto error; - } - - start = reply->str; - end = start + reply->len; - - line_start = start; - - for(pos = start; pos < end; pos ++) - { - if(*pos == '\n') - { - line_end = pos - 1; - len = line_end - line_start; - - part = sdssplitlen(line_start, len + 1, " ", 1, &count_part); - - if(part == NULL || count_part < 8) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "split cluster nodes error"); - goto error; - } - - //the address string is ":0", skip this node. - if(sdslen(part[1]) == 2 && strcmp(part[1], ":0") == 0) - { - sdsfreesplitres(part, count_part); - count_part = 0; - part = NULL; - - start = pos + 1; - line_start = start; - pos = start; - - continue; - } - - if(sdslen(part[2]) >= 7 && memcmp(part[2], "myself,", 7) == 0) - { - role_len = sdslen(part[2]) - 7; - role = part[2] + 7; - myself = 1; - } - else - { - role_len = sdslen(part[2]); - role = part[2]; - } - - //add master node - if(role_len >= 6 && memcmp(role, "master", 6) == 0) - { - if(count_part < 8) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "master node part number error"); - goto error; - } - - master = node_get_with_nodes(cc, - part, count_part, REDIS_ROLE_MASTER); - if(master == NULL) - { - goto error; - } - - ret = dictAdd(nodes, - sdsnewlen(master->addr, sdslen(master->addr)), master); - if(ret != DICT_OK) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "the address already exists in the nodes"); - cluster_node_deinit(master); - hi_free(master); - goto error; - } - - if(cc->flags & HIRCLUSTER_FLAG_ADD_SLAVE) - { - ret = cluster_master_slave_mapping_with_name(cc, - &nodes_name, master, master->name); - if(ret != REDIS_OK) - { - cluster_node_deinit(master); - hi_free(master); - goto error; - } - } - - if(myself == 1) - { - master->con = c; - c = NULL; - } - - for(k = 8; k < count_part; k ++) - { - slot_start_end = sdssplitlen(part[k], - sdslen(part[k]), "-", 1, &count_slot_start_end); - - if(slot_start_end == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "split slot start end error(NULL)"); - goto error; - } - else if(count_slot_start_end == 1) - { - slot_start = - hi_atoi(slot_start_end[0], sdslen(slot_start_end[0])); - slot_end = slot_start; - } - else if(count_slot_start_end == 2) - { - slot_start = - hi_atoi(slot_start_end[0], sdslen(slot_start_end[0]));; - slot_end = - hi_atoi(slot_start_end[1], sdslen(slot_start_end[1]));; - } - else - { - slot_start = -1; - slot_end = -1; - } - - sdsfreesplitres(slot_start_end, count_slot_start_end); - count_slot_start_end = 0; - slot_start_end = NULL; - - if(slot_start < 0 || slot_end < 0 || - slot_start > slot_end || slot_end >= REDIS_CLUSTER_SLOTS) - { - continue; - } - - for(j = slot_start; j <= slot_end; j ++) - { - if(table[j] != NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "diffent node hold a same slot"); - goto error; - } - table[j] = master; - } - - slot = hiarray_push(slots); - if(slot == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "slot push in array error"); - goto error; - } - - *slot = cluster_slot_create(master); - if(*slot == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM, - "Out of memory"); - goto error; - } - - (*slot)->start = (uint32_t)slot_start; - (*slot)->end = (uint32_t)slot_end; - } - - } - //add slave node - else if((cc->flags & HIRCLUSTER_FLAG_ADD_SLAVE) && - (role_len >= 5 && memcmp(role, "slave", 5) == 0)) - { - slave = node_get_with_nodes(cc, part, - count_part, REDIS_ROLE_SLAVE); - if(slave == NULL) - { - goto error; - } - - ret = cluster_master_slave_mapping_with_name(cc, - &nodes_name, slave, part[3]); - if(ret != REDIS_OK) - { - cluster_node_deinit(slave); - hi_free(slave); - goto error; - } - - if(myself == 1) - { - slave->con = c; - c = NULL; - } - } - - if(myself == 1) - { - myself = 0; - } - - sdsfreesplitres(part, count_part); - count_part = 0; - part = NULL; - - start = pos + 1; - line_start = start; - pos = start; - } - } - - if(cc->slots != NULL) - { - cc->slots->nelem = 0; - hiarray_destroy(cc->slots); - cc->slots = NULL; - } - cc->slots = slots; - - cluster_nodes_swap_ctx(cc->nodes, nodes); - - if(cc->nodes != NULL) - { - dictRelease(cc->nodes); - cc->nodes = NULL; - } - cc->nodes = nodes; - - hiarray_sort(cc->slots, cluster_slot_start_cmp); - - memcpy(cc->table, table, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); - cc->route_version ++; - - freeReplyObject(reply); - - if(c != NULL) - { - redisFree(c); - } - - if(nodes_name != NULL) - { - dictRelease(nodes_name); - } - - return REDIS_OK; - -error: - - if(part != NULL) - { - sdsfreesplitres(part, count_part); - count_part = 0; - part = NULL; - } - - if(slot_start_end != NULL) - { - sdsfreesplitres(slot_start_end, count_slot_start_end); - count_slot_start_end = 0; - slot_start_end = NULL; - } - - if(slots != NULL) - { - if(slots == cc->slots) - { - cc->slots = NULL; - } - - slots->nelem = 0; - hiarray_destroy(slots); - } - - if(nodes != NULL) - { - if(nodes == cc->nodes) - { - cc->nodes = NULL; - } - - dictRelease(nodes); - } - - if(nodes_name != NULL) - { - dictRelease(nodes_name); - } - - if(reply != NULL) - { - freeReplyObject(reply); - reply = NULL; - } - - if(c != NULL) - { - redisFree(c); - } - - return REDIS_ERR; -} - -int -cluster_update_route(redisClusterContext *cc) -{ - int ret; - int flag_err_not_set = 1; - cluster_node *node; - dictIterator *it; - dictEntry *de; - - if(cc == NULL) - { - return REDIS_ERR; - } - - if(cc->ip != NULL && cc->port > 0) - { - ret = cluster_update_route_by_addr(cc, cc->ip, cc->port); - if(ret == REDIS_OK) - { - return REDIS_OK; - } - - flag_err_not_set = 0; - } - - if(cc->nodes == NULL) - { - if(flag_err_not_set) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "no server address"); - } - - return REDIS_ERR; - } - - it = dictGetIterator(cc->nodes); - while ((de = dictNext(it)) != NULL) - { - node = dictGetEntryVal(de); - if(node == NULL || node->host == NULL || node->port < 0) - { - continue; - } - - ret = cluster_update_route_by_addr(cc, node->host, node->port); - if(ret == REDIS_OK) - { - if(cc->err) - { - cc->err = 0; - memset(cc->errstr, '\0', strlen(cc->errstr)); - } - - dictReleaseIterator(it); - return REDIS_OK; - } - - flag_err_not_set = 0; - } - - dictReleaseIterator(it); - - if(flag_err_not_set) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "no valid server address"); - } - - return REDIS_ERR; -} - -static void print_cluster_node_list(redisClusterContext *cc) -{ - dictIterator *di = NULL; - dictEntry *de; - listIter *it; - listNode *ln; - cluster_node *master, *slave; - hilist *slaves; - - if(cc == NULL) - { - return; - } - - di = dictGetIterator(cc->nodes); - - printf("name\taddress\trole\tslaves\n"); - - while((de = dictNext(di)) != NULL) { - master = dictGetEntryVal(de); - - printf("%s\t%s\t%d\t%s\n",master->name, master->addr, - master->role, master->slaves?"hava":"null"); - - slaves = master->slaves; - if(slaves == NULL) - { - continue; - } - - it = listGetIterator(slaves, AL_START_HEAD); - while((ln = listNext(it)) != NULL) - { - slave = listNodeValue(ln); - printf("%s\t%s\t%d\t%s\n",slave->name, slave->addr, - slave->role, slave->slaves?"hava":"null"); - } - - listReleaseIterator(it); - - printf("\n"); - } -} - - -int test_cluster_update_route(redisClusterContext *cc) -{ - int ret; - - ret = cluster_update_route(cc); - - //print_cluster_node_list(cc); - - return ret; -} - -static redisClusterContext *redisClusterContextInit(void) { - redisClusterContext *cc; - - cc = calloc(1,sizeof(redisClusterContext)); - if (cc == NULL) - return NULL; - - cc->err = 0; - cc->errstr[0] = '\0'; - cc->ip = NULL; - cc->port = 0; - cc->flags = 0; - cc->timeout = NULL; - cc->nodes = NULL; - cc->slots = NULL; - cc->max_redirect_count = CLUSTER_DEFAULT_MAX_REDIRECT_COUNT; - cc->retry_count = 0; - cc->requests = NULL; - cc->need_update_route = 0; - cc->update_route_time = 0LL; - - cc->route_version = 0LL; - - memset(cc->table, 0, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); - - return cc; -} - -void redisClusterFree(redisClusterContext *cc) { - - if (cc == NULL) - return; - - if(cc->ip) - { - sdsfree(cc->ip); - cc->ip = NULL; - } - - if (cc->timeout) - { - free(cc->timeout); - } - - memset(cc->table, 0, REDIS_CLUSTER_SLOTS*sizeof(cluster_node *)); - - if(cc->slots != NULL) - { - cc->slots->nelem = 0; - hiarray_destroy(cc->slots); - cc->slots = NULL; - } - - if(cc->nodes != NULL) - { - dictRelease(cc->nodes); - } - - if(cc->requests != NULL) - { - listRelease(cc->requests); - } - - free(cc); -} - -static int redisClusterAddNode(redisClusterContext *cc, const char *addr) -{ - dictEntry *node_entry; - cluster_node *node; - sds *ip_port = NULL; - int ip_port_count = 0; - sds ip; - int port; - - if(cc == NULL) - { - return REDIS_ERR; - } - - if(cc->nodes == NULL) - { - cc->nodes = dictCreate(&clusterNodesDictType, NULL); - if(cc->nodes == NULL) - { - return REDIS_ERR; - } - } - - node_entry = dictFind(cc->nodes, addr); - if(node_entry == NULL) - { - ip_port = sdssplitlen(addr, strlen(addr), - IP_PORT_SEPARATOR, strlen(IP_PORT_SEPARATOR), &ip_port_count); - if(ip_port == NULL || ip_port_count != 2 || - sdslen(ip_port[0]) <= 0 || sdslen(ip_port[1]) <= 0) - { - if(ip_port != NULL) - { - sdsfreesplitres(ip_port, ip_port_count); - } - __redisClusterSetError(cc,REDIS_ERR_OTHER,"server address is error(correct is like: 127.0.0.1:1234)"); - return REDIS_ERR; - } - - ip = ip_port[0]; - port = hi_atoi(ip_port[1], sdslen(ip_port[1])); - - if(port <= 0) - { - sdsfreesplitres(ip_port, ip_port_count); - __redisClusterSetError(cc,REDIS_ERR_OTHER,"server port is error"); - return REDIS_ERR; - } - - sdsfree(ip_port[1]); - free(ip_port); - ip_port = NULL; - - node = hi_alloc(sizeof(cluster_node)); - if(node == NULL) - { - sdsfree(ip); - __redisClusterSetError(cc,REDIS_ERR_OTHER,"alloc cluster node error"); - return REDIS_ERR; - } - - cluster_node_init(node); - - node->addr = sdsnew(addr); - if(node->addr == NULL) - { - sdsfree(ip); - hi_free(node); - __redisClusterSetError(cc,REDIS_ERR_OTHER,"new node address error"); - return REDIS_ERR; - } - - node->host = ip; - node->port = port; - - dictAdd(cc->nodes, sdsnewlen(node->addr, sdslen(node->addr)), node); - } - - return REDIS_OK; -} - - -/* Connect to a Redis cluster. On error the field error in the returned - * context will be set to the return value of the error function. - * When no set of reply functions is given, the default set will be used. */ -static redisClusterContext *_redisClusterConnect(redisClusterContext *cc, const char *addrs) { - - int ret; - sds *address = NULL; - int address_count = 0; - int i; - - if(cc == NULL) - { - return NULL; - } - - - address = sdssplitlen(addrs, strlen(addrs), CLUSTER_ADDRESS_SEPARATOR, - strlen(CLUSTER_ADDRESS_SEPARATOR), &address_count); - if(address == NULL || address_count <= 0) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER,"servers address is error(correct is like: 127.0.0.1:1234,127.0.0.2:5678)"); - return cc; - } - - for(i = 0; i < address_count; i ++) - { - ret = redisClusterAddNode(cc, address[i]); - if(ret != REDIS_OK) - { - sdsfreesplitres(address, address_count); - return cc; - } - } - - sdsfreesplitres(address, address_count); - - cluster_update_route(cc); - - return cc; -} - -redisClusterContext *redisClusterConnect(const char *addrs, int flags) -{ - redisClusterContext *cc; - - cc = redisClusterContextInit(); - - if(cc == NULL) - { - return NULL; - } - - cc->flags |= REDIS_BLOCK; - if(flags) - { - cc->flags |= flags; - } - - return _redisClusterConnect(cc, addrs); -} - -redisClusterContext *redisClusterConnectWithTimeout( - const char *addrs, const struct timeval tv, int flags) -{ - redisClusterContext *cc; - - cc = redisClusterContextInit(); - - if(cc == NULL) - { - return NULL; - } - - cc->flags |= REDIS_BLOCK; - if(flags) - { - cc->flags |= flags; - } - - if (cc->timeout == NULL) - { - cc->timeout = malloc(sizeof(struct timeval)); - } - - memcpy(cc->timeout, &tv, sizeof(struct timeval)); - - return _redisClusterConnect(cc, addrs); -} - -redisClusterContext *redisClusterConnectNonBlock(const char *addrs, int flags) { - - redisClusterContext *cc; - - cc = redisClusterContextInit(); - - if(cc == NULL) - { - return NULL; - } - - cc->flags &= ~REDIS_BLOCK; - if(flags) - { - cc->flags |= flags; - } - - return _redisClusterConnect(cc, addrs); -} - -redisContext *ctx_get_by_node(cluster_node *node, - const struct timeval *timeout, int flags) -{ - redisContext *c = NULL; - if(node == NULL) - { - return NULL; - } - - c = node->con; - if(c != NULL) - { - if(c->err) - { - redisReconnect(c); - } - - return c; - } - - if(node->host == NULL || node->port <= 0) - { - return NULL; - } - - if(flags & REDIS_BLOCK) - { - if(timeout) - { - c = redisConnectWithTimeout(node->host, node->port, *timeout); - } - else - { - c = redisConnect(node->host, node->port); - } - } - else - { - c = redisConnectNonBlock(node->host, node->port); - } - - node->con = c; - - return c; -} - -static cluster_node *node_get_by_slot(redisClusterContext *cc, uint32_t slot_num) -{ - struct hiarray *slots; - uint32_t slot_count; - cluster_slot **slot; - uint32_t middle, start, end; - uint8_t stop = 0; - - if(cc == NULL) - { - return NULL; - } - - if(slot_num >= REDIS_CLUSTER_SLOTS) - { - return NULL; - } - - slots = cc->slots; - if(slots == NULL) - { - return NULL; - } - slot_count = hiarray_n(slots); - - start = 0; - end = slot_count - 1; - middle = 0; - - do{ - if(start >= end) - { - stop = 1; - middle = end; - } - else - { - middle = start + (end - start)/2; - } - - ASSERT(middle < slot_count); - - slot = hiarray_get(slots, middle); - if((*slot)->start > slot_num) - { - end = middle - 1; - } - else if((*slot)->end < slot_num) - { - start = middle + 1; - } - else - { - return (*slot)->node; - } - - - }while(!stop); - - printf("slot_num : %d\n", slot_num); - printf("slot_count : %d\n", slot_count); - printf("start : %d\n", start); - printf("end : %d\n", end); - printf("middle : %d\n", middle); - - return NULL; -} - - -static cluster_node *node_get_by_table(redisClusterContext *cc, uint32_t slot_num) -{ - if(cc == NULL) - { - return NULL; - } - - if(slot_num >= REDIS_CLUSTER_SLOTS) - { - return NULL; - } - - return cc->table[slot_num]; - -} - -static cluster_node *node_get_witch_connected(redisClusterContext *cc) -{ - dictIterator *di; - dictEntry *de; - struct cluster_node *node; - redisContext *c = NULL; - redisReply *reply = NULL; - - if(cc == NULL || cc->nodes == NULL) - { - return NULL; - } - - di = dictGetIterator(cc->nodes); - while((de = dictNext(di)) != NULL) - { - node = dictGetEntryVal(de); - if(node == NULL) - { - continue; - } - - c = ctx_get_by_node(node, cc->timeout, REDIS_BLOCK); - if(c == NULL || c->err) - { - continue; - } - - reply = redisCommand(c, REDIS_COMMAND_PING); - if(reply != NULL && reply->type == REDIS_REPLY_STATUS && - reply->str != NULL && strcmp(reply->str, "PONG") == 0) - { - freeReplyObject(reply); - reply = NULL; - - dictReleaseIterator(di); - - return node; - } - else if(reply != NULL) - { - freeReplyObject(reply); - reply = NULL; - } - } - - dictReleaseIterator(di); - - return NULL; -} - -static int slot_get_by_command(redisClusterContext *cc, char *cmd, int len) -{ - struct cmd *command = NULL; - struct keypos *kp; - int key_count; - uint32_t i; - int slot_num = -1; - - if(cc == NULL || cmd == NULL || len <= 0) - { - goto done; - } - - command = command_get(); - if(command == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - goto done; - } - - command->cmd = cmd; - command->clen = len; - redis_parse_cmd(command); - if(command->result != CMD_PARSE_OK) - { - __redisClusterSetError(cc, REDIS_ERR_PROTOCOL, "parse command error"); - goto done; - } - - key_count = hiarray_n(command->keys); - - if(key_count <= 0) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "no keys in command(must have keys for redis cluster mode)"); - goto done; - } - else if(key_count == 1) - { - kp = hiarray_get(command->keys, 0); - slot_num = keyHashSlot(kp->start, kp->end - kp->start); - - goto done; - } - - for(i = 0; i < hiarray_n(command->keys); i ++) - { - kp = hiarray_get(command->keys, i); - - slot_num = keyHashSlot(kp->start, kp->end - kp->start); - } - -done: - - if(command != NULL) - { - command->cmd = NULL; - command_destroy(command); - } - - return slot_num; -} - -/* Get the cluster config from one node. - * Return value: config_value string must free by usr. - */ -static char * cluster_config_get(redisClusterContext *cc, - const char *config_name, int *config_value_len) -{ - redisContext *c; - cluster_node *node; - redisReply *reply = NULL, *sub_reply; - char *config_value = NULL; - - if(cc == NULL || config_name == NULL - || config_value_len == NULL) - { - return NULL; - } - - node = node_get_witch_connected(cc); - if(node == NULL) - { - __redisClusterSetError(cc, - REDIS_ERR_OTHER, "no reachable node in cluster"); - goto error; - } - - c = ctx_get_by_node(node, cc->timeout, cc->flags); - - reply = redisCommand(c, "config get %s", config_name); - if(reply == NULL) - { - __redisClusterSetError(cc, - REDIS_ERR_OTHER, "reply for config get is null"); - goto error; - } - - if(reply->type != REDIS_REPLY_ARRAY) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "reply for config get type is not array"); - goto error; - } - - if(reply->elements != 2) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "reply for config get elements number is not 2"); - goto error; - } - - sub_reply = reply->element[0]; - if(sub_reply == NULL || sub_reply->type != REDIS_REPLY_STRING) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "reply for config get config name is not string"); - goto error; - } - - if(strcmp(sub_reply->str, config_name)) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "reply for config get config name is not we want"); - goto error; - } - - sub_reply = reply->element[1]; - if(sub_reply == NULL || sub_reply->type != REDIS_REPLY_STRING) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "reply for config get config value type is not string"); - goto error; - } - - config_value = sub_reply->str; - *config_value_len = sub_reply->len; - sub_reply->str= NULL; - - if(reply != NULL) - { - freeReplyObject(reply); - } - - return config_value; - -error: - - if(reply != NULL) - { - freeReplyObject(reply); - } - - return NULL; -} - -/* Helper function for the redisClusterAppendCommand* family of functions. - * - * Write a formatted command to the output buffer. When this family - * is used, you need to call redisGetReply yourself to retrieve - * the reply (or replies in pub/sub). - */ -static int __redisClusterAppendCommand(redisClusterContext *cc, - struct cmd *command) { - - cluster_node *node; - redisContext *c = NULL; - - if(cc == NULL || command == NULL) - { - return REDIS_ERR; - } - - node = node_get_by_table(cc, (uint32_t)command->slot_num); - if(node == NULL) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "node get by slot error"); - return REDIS_ERR; - } - - c = ctx_get_by_node(node, cc->timeout, cc->flags); - if(c == NULL) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node is null"); - return REDIS_ERR; - } - else if(c->err) - { - __redisClusterSetError(cc, c->err, c->errstr); - return REDIS_ERR; - } - - if (__redisAppendCommand(c, command->cmd, command->clen) != REDIS_OK) - { - __redisClusterSetError(cc, c->err, c->errstr); - return REDIS_ERR; - } - - return REDIS_OK; -} - -/* Helper function for the redisClusterGetReply* family of functions. - */ -static int __redisClusterGetReply(redisClusterContext *cc, int slot_num, void **reply) -{ - cluster_node *node; - redisContext *c; - - if(cc == NULL || slot_num < 0 || reply == NULL) - { - return REDIS_ERR; - } - - node = node_get_by_table(cc, (uint32_t)slot_num); - if(node == NULL) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "node get by table is null"); - return REDIS_ERR; - } - - c = ctx_get_by_node(node, cc->timeout, cc->flags); - if(c == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } - else if(c->err) - { - if(cc->need_update_route == 0) - { - cc->retry_count ++; - if(cc->retry_count > cc->max_redirect_count) - { - cc->need_update_route = 1; - cc->retry_count = 0; - } - } - __redisClusterSetError(cc, c->err, c->errstr); - return REDIS_ERR; - } - - if(redisGetReply(c, reply) != REDIS_OK) - { - __redisClusterSetError(cc, c->err, c->errstr); - return REDIS_ERR; - } - - if(cluster_reply_error_type(*reply) == CLUSTER_ERR_MOVED) - { - cc->need_update_route = 1; - } - - return REDIS_OK; -} - -static cluster_node *node_get_by_ask_error_reply( - redisClusterContext *cc, redisReply *reply) -{ - sds *part = NULL, *ip_port = NULL; - int part_len = 0, ip_port_len; - dictEntry *de; - cluster_node *node = NULL; - - if(cc == NULL || reply == NULL) - { - return NULL; - } - - if(cluster_reply_error_type(reply) != CLUSTER_ERR_ASK) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "reply is not ask error!"); - return NULL; - } - - part = sdssplitlen(reply->str, reply->len, " ", 1, &part_len); - - if(part != NULL && part_len == 3) - { - ip_port = sdssplitlen(part[2], sdslen(part[2]), - ":", 1, &ip_port_len); - - if(ip_port != NULL && ip_port_len == 2) - { - de = dictFind(cc->nodes, part[2]); - if(de == NULL) - { - node = hi_alloc(sizeof(cluster_node)); - if(node == NULL) - { - __redisClusterSetError(cc, - REDIS_ERR_OOM, "Out of memory"); - - goto done; - } - - cluster_node_init(node); - node->addr = part[1]; - node->host = ip_port[0]; - node->port = hi_atoi(ip_port[1], sdslen(ip_port[1])); - node->role = REDIS_ROLE_MASTER; - - dictAdd(cc->nodes, sdsnewlen(node->addr, sdslen(node->addr)), node); - - part = NULL; - ip_port = NULL; - } - else - { - node = de->val; - - goto done; - } - } - else - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "ask error reply address part parse error!"); - - goto done; - } - - } - else - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "ask error reply parse error!"); - - goto done; - } - -done: - - if(part != NULL) - { - sdsfreesplitres(part, part_len); - part = NULL; - } - - if(ip_port != NULL) - { - sdsfreesplitres(ip_port, ip_port_len); - ip_port = NULL; - } - - return node; -} - -static void *redis_cluster_command_execute(redisClusterContext *cc, - struct cmd *command) -{ - int ret; - void *reply = NULL; - cluster_node *node; - redisContext *c = NULL; - int error_type; - -retry: - - node = node_get_by_table(cc, (uint32_t)command->slot_num); - if(node == NULL) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "node get by table error"); - return NULL; - } - - c = ctx_get_by_node(node, cc->timeout, cc->flags); - if(c == NULL) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node is null"); - return NULL; - } - else if(c->err) - { - node = node_get_witch_connected(cc); - if(node == NULL) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "no reachable node in cluster"); - return NULL; - } - - cc->retry_count ++; - if(cc->retry_count > cc->max_redirect_count) - { - __redisClusterSetError(cc, REDIS_ERR_CLUSTER_TOO_MANY_REDIRECT, - "too many cluster redirect"); - return NULL; - } - - c = ctx_get_by_node(node, cc->timeout, cc->flags); - if(c == NULL) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node error"); - return NULL; - } - else if(c->err) - { - __redisClusterSetError(cc, c->err, c->errstr); - return NULL; - } - } - -ask_retry: - - if (__redisAppendCommand(c,command->cmd, command->clen) != REDIS_OK) - { - __redisClusterSetError(cc, c->err, c->errstr); - return NULL; - } - - reply = __redisBlockForReply(c); - if(reply == NULL) - { - __redisClusterSetError(cc, c->err, c->errstr); - return NULL; - } - - error_type = cluster_reply_error_type(reply); - if(error_type > CLUSTER_NOT_ERR && error_type < CLUSTER_ERR_SENTINEL) - { - cc->retry_count ++; - if(cc->retry_count > cc->max_redirect_count) - { - __redisClusterSetError(cc, REDIS_ERR_CLUSTER_TOO_MANY_REDIRECT, - "too many cluster redirect"); - freeReplyObject(reply); - return NULL; - } - - switch(error_type) - { - case CLUSTER_ERR_MOVED: - freeReplyObject(reply); - reply = NULL; - ret = cluster_update_route(cc); - if(ret != REDIS_OK) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "route update error, please recreate redisClusterContext!"); - return NULL; - } - - goto retry; - - break; - case CLUSTER_ERR_ASK: - node = node_get_by_ask_error_reply(cc, reply); - if(node == NULL) - { - freeReplyObject(reply); - return NULL; - } - - freeReplyObject(reply); - reply = NULL; - - c = ctx_get_by_node(node, cc->timeout, cc->flags); - if(c == NULL) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "ctx get by node error"); - return NULL; - } - else if(c->err) - { - __redisClusterSetError(cc, c->err, c->errstr); - return NULL; - } - - reply = redisCommand(c, REDIS_COMMAND_ASKING); - if(reply == NULL) - { - __redisClusterSetError(cc, c->err, c->errstr); - return NULL; - } - - freeReplyObject(reply); - reply = NULL; - - goto ask_retry; - - break; - case CLUSTER_ERR_TRYAGAIN: - case CLUSTER_ERR_CROSSSLOT: - case CLUSTER_ERR_CLUSTERDOWN: - freeReplyObject(reply); - reply = NULL; - goto retry; - - break; - default: - - break; - } - } - - return reply; -} - -static int command_pre_fragment(redisClusterContext *cc, - struct cmd *command, hilist *commands) -{ - - struct keypos *kp, *sub_kp; - uint32_t key_count; - uint32_t i, j; - uint32_t idx; - uint32_t key_len; - int slot_num = -1; - struct cmd *sub_command; - struct cmd **sub_commands = NULL; - char num_str[12]; - uint8_t num_str_len; - - - if(command == NULL || commands == NULL) - { - goto done; - } - - key_count = hiarray_n(command->keys); - - sub_commands = hi_zalloc(REDIS_CLUSTER_SLOTS * sizeof(*sub_commands)); - if (sub_commands == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - goto done; - } - - command->frag_seq = hi_alloc(key_count * sizeof(*command->frag_seq)); - if(command->frag_seq == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - goto done; - } - - - for(i = 0; i < key_count; i ++) - { - kp = hiarray_get(command->keys, i); - - slot_num = keyHashSlot(kp->start, kp->end - kp->start); - - if(slot_num < 0 || slot_num >= REDIS_CLUSTER_SLOTS) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER,"keyHashSlot return error"); - goto done; - } - - if (sub_commands[slot_num] == NULL) { - sub_commands[slot_num] = command_get(); - if (sub_commands[slot_num] == NULL) { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - slot_num = -1; - goto done; - } - } - - command->frag_seq[i] = sub_command = sub_commands[slot_num]; - - sub_command->narg++; - - sub_kp = hiarray_push(sub_command->keys); - if (sub_kp == NULL) { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - slot_num = -1; - goto done; - } - - sub_kp->start = kp->start; - sub_kp->end = kp->end; - - key_len = (uint32_t)(kp->end - kp->start); - - sub_command->clen += key_len + uint_len(key_len); - - sub_command->slot_num = slot_num; - - if (command->type == CMD_REQ_REDIS_MSET) { - uint32_t len = 0; - char *p; - - for (p = sub_kp->end + 1; !isdigit(*p); p++){} - - p = sub_kp->end + 1; - while(!isdigit(*p)) - { - p ++; - } - - for (; isdigit(*p); p++) { - len = len * 10 + (uint32_t)(*p - '0'); - } - - len += CRLF_LEN * 2; - len += (p - sub_kp->end); - sub_kp->remain_len = len; - sub_command->clen += len; - } - } - - for (i = 0; i < REDIS_CLUSTER_SLOTS; i++) { /* prepend command header */ - sub_command = sub_commands[i]; - if (sub_command == NULL) { - continue; - } - - idx = 0; - if (command->type == CMD_REQ_REDIS_MGET) { - //"*%d\r\n$4\r\nmget\r\n" - - sub_command->clen += 5*sub_command->narg; - - sub_command->narg ++; - - hi_itoa(num_str, sub_command->narg); - num_str_len = (uint8_t)(strlen(num_str)); - - sub_command->clen += 13 + num_str_len; - - sub_command->cmd = hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); - if(sub_command->cmd == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - slot_num = -1; - goto done; - } - - sub_command->cmd[idx++] = '*'; - memcpy(sub_command->cmd + idx, num_str, num_str_len); - idx += num_str_len; - memcpy(sub_command->cmd + idx, "\r\n$4\r\nmget\r\n", 12); - idx += 12; - - for(j = 0; j < hiarray_n(sub_command->keys); j ++) - { - kp = hiarray_get(sub_command->keys, j); - key_len = (uint32_t)(kp->end - kp->start); - hi_itoa(num_str, key_len); - num_str_len = strlen(num_str); - - sub_command->cmd[idx++] = '$'; - memcpy(sub_command->cmd + idx, num_str, num_str_len); - idx += num_str_len; - memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); - idx += CRLF_LEN; - memcpy(sub_command->cmd + idx, kp->start, key_len); - idx += key_len; - memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); - idx += CRLF_LEN; - } - } else if (command->type == CMD_REQ_REDIS_DEL) { - //"*%d\r\n$3\r\ndel\r\n" - - sub_command->clen += 5*sub_command->narg; - - sub_command->narg ++; - - hi_itoa(num_str, sub_command->narg); - num_str_len = (uint8_t)strlen(num_str); - - sub_command->clen += 12 + num_str_len; - - sub_command->cmd = hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); - if(sub_command->cmd == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - slot_num = -1; - goto done; - } - - sub_command->cmd[idx++] = '*'; - memcpy(sub_command->cmd + idx, num_str, num_str_len); - idx += num_str_len; - memcpy(sub_command->cmd + idx, "\r\n$3\r\ndel\r\n", 11); - idx += 11; - - for(j = 0; j < hiarray_n(sub_command->keys); j ++) - { - kp = hiarray_get(sub_command->keys, j); - key_len = (uint32_t)(kp->end - kp->start); - hi_itoa(num_str, key_len); - num_str_len = strlen(num_str); - - sub_command->cmd[idx++] = '$'; - memcpy(sub_command->cmd + idx, num_str, num_str_len); - idx += num_str_len; - memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); - idx += CRLF_LEN; - memcpy(sub_command->cmd + idx, kp->start, key_len); - idx += key_len; - memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); - idx += CRLF_LEN; - } - } else if (command->type == CMD_REQ_REDIS_MSET) { - //"*%d\r\n$4\r\nmset\r\n" - - sub_command->clen += 3*sub_command->narg; - - sub_command->narg *= 2; - - sub_command->narg ++; - - hi_itoa(num_str, sub_command->narg); - num_str_len = (uint8_t)strlen(num_str); - - sub_command->clen += 13 + num_str_len; - - sub_command->cmd = hi_zalloc(sub_command->clen * sizeof(*sub_command->cmd)); - if(sub_command->cmd == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - slot_num = -1; - goto done; - } - - sub_command->cmd[idx++] = '*'; - memcpy(sub_command->cmd + idx, num_str, num_str_len); - idx += num_str_len; - memcpy(sub_command->cmd + idx, "\r\n$4\r\nmset\r\n", 12); - idx += 12; - - for(j = 0; j < hiarray_n(sub_command->keys); j ++) - { - kp = hiarray_get(sub_command->keys, j); - key_len = (uint32_t)(kp->end - kp->start); - hi_itoa(num_str, key_len); - num_str_len = strlen(num_str); - - sub_command->cmd[idx++] = '$'; - memcpy(sub_command->cmd + idx, num_str, num_str_len); - idx += num_str_len; - memcpy(sub_command->cmd + idx, CRLF, CRLF_LEN); - idx += CRLF_LEN; - memcpy(sub_command->cmd + idx, kp->start, key_len + kp->remain_len); - idx += key_len + kp->remain_len; - - } - } else { - NOT_REACHED(); - } - - //printf("len : %d\n", sub_command->clen); - //print_string_with_length_fix_CRLF(sub_command->cmd, sub_command->clen); - - sub_command->type = command->type; - - listAddNodeTail(commands, sub_command); - } - -done: - - if(sub_commands != NULL) - { - hi_free(sub_commands); - } - - if(slot_num >= 0 && commands != NULL - && listLength(commands) == 1) - { - listNode *list_node = listFirst(commands); - listDelNode(commands, list_node); - if(command->frag_seq) - { - hi_free(command->frag_seq); - command->frag_seq = NULL; - } - - command->slot_num = slot_num; - } - - return slot_num; -} - -static void *command_post_fragment(redisClusterContext *cc, - struct cmd *command, hilist *commands) -{ - struct cmd *sub_command; - listNode *list_node; - listIter *list_iter; - redisReply *reply, *sub_reply; - long long count = 0; - - list_iter = listGetIterator(commands, AL_START_HEAD); - while((list_node = listNext(list_iter)) != NULL) - { - sub_command = list_node->value; - reply = sub_command->reply; - if(reply == NULL) - { - return NULL; - } - else if(reply->type == REDIS_REPLY_ERROR) - { - return reply; - } - - if (command->type == CMD_REQ_REDIS_MGET) { - if(reply->type != REDIS_REPLY_ARRAY) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER,"reply type is error(here only can be array)"); - return NULL; - } - }else if(command->type == CMD_REQ_REDIS_DEL){ - if(reply->type != REDIS_REPLY_INTEGER) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER,"reply type is error(here only can be integer)"); - return NULL; - } - - count += reply->integer; - }else if(command->type == CMD_REQ_REDIS_MSET){ - if(reply->type != REDIS_REPLY_STATUS || - reply->len != 2 || strcmp(reply->str, REDIS_STATUS_OK) != 0) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER,"reply type is error(here only can be status and ok)"); - return NULL; - } - }else { - NOT_REACHED(); - } - } - - reply = hi_calloc(1,sizeof(*reply)); - - if (reply == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - return NULL; - } - - if (command->type == CMD_REQ_REDIS_MGET) { - int i; - uint32_t key_count; - - reply->type = REDIS_REPLY_ARRAY; - - key_count = hiarray_n(command->keys); - - reply->elements = key_count; - reply->element = hi_calloc(key_count, sizeof(*reply)); - if (reply->element == NULL) { - freeReplyObject(reply); - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - return NULL; - } - - for (i = key_count - 1; i >= 0; i--) { /* for each key */ - sub_reply = command->frag_seq[i]->reply; /* get it's reply */ - if (sub_reply == NULL) { - freeReplyObject(reply); - __redisClusterSetError(cc,REDIS_ERR_OTHER,"sub reply is null"); - return NULL; - } - - if(sub_reply->type == REDIS_REPLY_STRING) - { - reply->element[i] = sub_reply; - } - else if(sub_reply->type == REDIS_REPLY_ARRAY) - { - if(sub_reply->elements == 0) - { - freeReplyObject(reply); - __redisClusterSetError(cc,REDIS_ERR_OTHER,"sub reply elements error"); - return NULL; - } - - reply->element[i] = sub_reply->element[sub_reply->elements - 1]; - sub_reply->elements --; - } - } - }else if(command->type == CMD_REQ_REDIS_DEL){ - reply->type = REDIS_REPLY_INTEGER; - reply->integer = count; - }else if(command->type == CMD_REQ_REDIS_MSET){ - reply->type = REDIS_REPLY_STATUS; - uint32_t str_len = strlen(REDIS_STATUS_OK); - reply->str = hi_alloc((str_len + 1) * sizeof(char*)); - if(reply->str == NULL) - { - freeReplyObject(reply); - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - return NULL; - } - - reply->len = str_len; - memcpy(reply->str, REDIS_STATUS_OK, str_len); - reply->str[str_len] = '\0'; - }else { - NOT_REACHED(); - } - - return reply; -} - -/* - * Split the command into subcommands by slot - * - * Returns slot_num - * If slot_num < 0 or slot_num >= REDIS_CLUSTER_SLOTS means this function runs error; - * Otherwise if the commands > 1 , slot_num is the last subcommand slot number. - */ -static int command_format_by_slot(redisClusterContext *cc, - struct cmd *command, hilist *commands) -{ - struct keypos *kp; - int key_count; - int slot_num = -1; - - if(cc == NULL || commands == NULL || - command == NULL || - command->cmd == NULL || command->clen <= 0) - { - goto done; - } - - - redis_parse_cmd(command); - if(command->result == CMD_PARSE_ENOMEM) - { - __redisClusterSetError(cc, REDIS_ERR_PROTOCOL, "Parse command error: out of memory"); - goto done; - } - else if(command->result != CMD_PARSE_OK) - { - __redisClusterSetError(cc, REDIS_ERR_PROTOCOL, command->errstr); - goto done; - } - - key_count = hiarray_n(command->keys); - - if(key_count <= 0) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, "No keys in command(must have keys for redis cluster mode)"); - goto done; - } - else if(key_count == 1) - { - kp = hiarray_get(command->keys, 0); - slot_num = keyHashSlot(kp->start, kp->end - kp->start); - command->slot_num = slot_num; - - goto done; - } - - slot_num = command_pre_fragment(cc, command, commands); - -done: - - return slot_num; -} - - -void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count) -{ - if(cc == NULL || max_redirect_count <= 0) - { - return; - } - - cc->max_redirect_count = max_redirect_count; -} - -void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, int len) { - redisReply *reply = NULL; - int slot_num; - struct cmd *command = NULL, *sub_command; - hilist *commands = NULL; - listNode *list_node; - listIter *list_iter = NULL; - - if(cc == NULL) - { - return NULL; - } - - if(cc->err) - { - cc->err = 0; - memset(cc->errstr, '\0', strlen(cc->errstr)); - } - - command = command_get(); - if(command == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - return NULL; - } - - command->cmd = cmd; - command->clen = len; - - commands = listCreate(); - if(commands == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - goto error; - } - - commands->free = listCommandFree; - - slot_num = command_format_by_slot(cc, command, commands); - - if(slot_num < 0) - { - goto error; - } - else if(slot_num >= REDIS_CLUSTER_SLOTS) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER,"slot_num is out of range"); - goto error; - } - - //all keys belong to one slot - if(listLength(commands) == 0) - { - reply = redis_cluster_command_execute(cc, command); - goto done; - } - - ASSERT(listLength(commands) != 1); - - list_iter = listGetIterator(commands, AL_START_HEAD); - while((list_node = listNext(list_iter)) != NULL) - { - sub_command = list_node->value; - - reply = redis_cluster_command_execute(cc, sub_command); - if(reply == NULL) - { - goto error; - } - else if(reply->type == REDIS_REPLY_ERROR) - { - goto done; - } - - sub_command->reply = reply; - } - - reply = command_post_fragment(cc, command, commands); - -done: - - command->cmd = NULL; - command_destroy(command); - - if(commands != NULL) - { - listRelease(commands); - } - - if(list_iter != NULL) - { - listReleaseIterator(list_iter); - } - - cc->retry_count = 0; - - return reply; - -error: - - if(command != NULL) - { - command->cmd = NULL; - command_destroy(command); - } - - if(commands != NULL) - { - listRelease(commands); - } - - if(list_iter != NULL) - { - listReleaseIterator(list_iter); - } - - cc->retry_count = 0; - - return NULL; -} - -void *redisClustervCommand(redisClusterContext *cc, const char *format, va_list ap) { - redisReply *reply; - char *cmd; - int len; - - if(cc == NULL) - { - return NULL; - } - - len = redisvFormatCommand(&cmd,format,ap); - - if (len == -1) { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - return NULL; - } else if (len == -2) { - __redisClusterSetError(cc,REDIS_ERR_OTHER,"Invalid format string"); - return NULL; - } - - reply = redisClusterFormattedCommand(cc, cmd, len); - - free(cmd); - - return reply; -} - -void *redisClusterCommand(redisClusterContext *cc, const char *format, ...) { - va_list ap; - redisReply *reply = NULL; - - va_start(ap,format); - reply = redisClustervCommand(cc, format, ap); - va_end(ap); - - return reply; -} - -void *redisClusterCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen) { - redisReply *reply = NULL; - char *cmd; - int len; - - len = redisFormatCommandArgv(&cmd,argc,argv,argvlen); - if (len == -1) { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - return NULL; - } - - reply = redisClusterFormattedCommand(cc, cmd, len); - - free(cmd); - - return reply; -} - -int redisClusterAppendFormattedCommand(redisClusterContext *cc, - char *cmd, int len) { - int slot_num; - struct cmd *command = NULL, *sub_command; - hilist *commands = NULL; - listNode *list_node; - listIter *list_iter = NULL; - - if(cc->requests == NULL) - { - cc->requests = listCreate(); - if(cc->requests == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - goto error; - } - - cc->requests->free = listCommandFree; - } - - command = command_get(); - if(command == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - goto error; - } - - command->cmd = cmd; - command->clen = len; - - commands = listCreate(); - if(commands == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - goto error; - } - - commands->free = listCommandFree; - - slot_num = command_format_by_slot(cc, command, commands); - - if(slot_num < 0) - { - goto error; - } - else if(slot_num >= REDIS_CLUSTER_SLOTS) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER,"slot_num is out of range"); - goto error; - } - - //all keys belong to one slot - if(listLength(commands) == 0) - { - if(__redisClusterAppendCommand(cc, command) == REDIS_OK) - { - goto done; - } - else - { - goto error; - } - } - - ASSERT(listLength(commands) != 1); - - list_iter = listGetIterator(commands, AL_START_HEAD); - while((list_node = listNext(list_iter)) != NULL) - { - sub_command = list_node->value; - - if(__redisClusterAppendCommand(cc, sub_command) == REDIS_OK) - { - continue; - } - else - { - goto error; - } - } - -done: - - if(command->cmd != NULL) - { - command->cmd = NULL; - } - else - { - goto error; - } - - if(commands != NULL) - { - if(listLength(commands) > 0) - { - command->sub_commands = commands; - } - else - { - listRelease(commands); - } - } - - if(list_iter != NULL) - { - listReleaseIterator(list_iter); - } - - listAddNodeTail(cc->requests, command); - - return REDIS_OK; - -error: - - if(command != NULL) - { - command->cmd = NULL; - command_destroy(command); - } - - if(commands != NULL) - { - listRelease(commands); - } - - if(list_iter != NULL) - { - listReleaseIterator(list_iter); - } - - /* Attention: mybe here we must pop the - sub_commands that had append to the nodes. - But now we do not handle it. */ - - return REDIS_ERR; -} - - -int redisClustervAppendCommand(redisClusterContext *cc, - const char *format, va_list ap) { - int ret; - char *cmd; - int len; - - len = redisvFormatCommand(&cmd,format,ap); - if (len == -1) { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } else if (len == -2) { - __redisClusterSetError(cc,REDIS_ERR_OTHER,"Invalid format string"); - return REDIS_ERR; - } - - ret = redisClusterAppendFormattedCommand(cc, cmd, len); - - free(cmd); - - return ret; -} - -int redisClusterAppendCommand(redisClusterContext *cc, - const char *format, ...) { - - int ret; - va_list ap; - - if(cc == NULL || format == NULL) - { - return REDIS_ERR; - } - - va_start(ap,format); - ret = redisClustervAppendCommand(cc, format, ap); - va_end(ap); - - return ret; -} - -int redisClusterAppendCommandArgv(redisClusterContext *cc, - int argc, const char **argv, const size_t *argvlen) { - int ret; - char *cmd; - int len; - - len = redisFormatCommandArgv(&cmd,argc,argv,argvlen); - if (len == -1) { - __redisClusterSetError(cc,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } - - ret = redisClusterAppendFormattedCommand(cc, cmd, len); - - free(cmd); - - return ret; -} - -static int redisCLusterSendAll(redisClusterContext *cc) -{ - dictIterator *di; - dictEntry *de; - struct cluster_node *node; - redisContext *c = NULL; - int wdone = 0; - - if(cc == NULL || cc->nodes == NULL) - { - return REDIS_ERR; - } - - di = dictGetIterator(cc->nodes); - while((de = dictNext(di)) != NULL) - { - node = dictGetEntryVal(de); - if(node == NULL) - { - continue; - } - - c = ctx_get_by_node(node, cc->timeout, cc->flags); - if(c == NULL) - { - continue; - } - - if (c->flags & REDIS_BLOCK) { - /* Write until done */ - do { - if (redisBufferWrite(c,&wdone) == REDIS_ERR) - { - dictReleaseIterator(di); - return REDIS_ERR; - } - } while (!wdone); - } - } - - dictReleaseIterator(di); - - return REDIS_OK; -} - -static int redisCLusterClearAll(redisClusterContext *cc) -{ - dictIterator *di; - dictEntry *de; - struct cluster_node *node; - redisContext *c = NULL; - - if (cc == NULL) { - return REDIS_ERR; - } - - if (cc->err) { - cc->err = 0; - memset(cc->errstr, '\0', strlen(cc->errstr)); - } - - if (cc->nodes == NULL) { - return REDIS_ERR; - } - di = dictGetIterator(cc->nodes); - while((de = dictNext(di)) != NULL) - { - node = dictGetEntryVal(de); - if(node == NULL) - { - continue; - } - - c = node->con; - if(c == NULL) - { - continue; - } - - redisFree(c); - node->con = NULL; - } - - dictReleaseIterator(di); - - return REDIS_OK; -} - -int redisClusterGetReply(redisClusterContext *cc, void **reply) { - - struct cmd *command, *sub_command; - hilist *commands = NULL; - listNode *list_command, *list_sub_command; - listIter *list_iter; - int slot_num; - void *sub_reply; - - if(cc == NULL || reply == NULL) - return REDIS_ERR; - - cc->err = 0; - cc->errstr[0] = '\0'; - - *reply = NULL; - - if (cc->requests == NULL) - return REDIS_ERR; - - list_command = listFirst(cc->requests); - - //no more reply - if(list_command == NULL) - { - *reply = NULL; - return REDIS_OK; - } - - command = list_command->value; - if(command == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "command in the requests list is null"); - goto error; - } - - slot_num = command->slot_num; - if(slot_num >= 0) - { - listDelNode(cc->requests, list_command); - return __redisClusterGetReply(cc, slot_num, reply); - } - - commands = command->sub_commands; - if(commands == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "sub_commands in command is null"); - goto error; - } - - ASSERT(listLength(commands) != 1); - - list_iter = listGetIterator(commands, AL_START_HEAD); - while((list_sub_command = listNext(list_iter)) != NULL) - { - sub_command = list_sub_command->value; - if(sub_command == NULL) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "sub_command is null"); - goto error; - } - - slot_num = sub_command->slot_num; - if(slot_num < 0) - { - __redisClusterSetError(cc,REDIS_ERR_OTHER, - "sub_command slot_num is less then zero"); - goto error; - } - - if(__redisClusterGetReply(cc, slot_num, &sub_reply) != REDIS_OK) - { - goto error; - } - - sub_command->reply = sub_reply; - } - - *reply = command_post_fragment(cc, command, commands); - if(*reply == NULL) - { - goto error; - } - - listDelNode(cc->requests, list_command); - return REDIS_OK; - -error: - - listDelNode(cc->requests, list_command); - return REDIS_ERR; -} - -void redisClusterReset(redisClusterContext *cc) -{ - int status; - void *reply; - - if(cc == NULL || cc->nodes == NULL) - { - return; - } - - if (cc->err) { - redisCLusterClearAll(cc); - } else { - redisCLusterSendAll(cc); - - do { - status = redisClusterGetReply(cc, &reply); - if (status == REDIS_OK) { - freeReplyObject(reply); - } else { - redisCLusterClearAll(cc); - break; - } - } while(reply != NULL); - } - - if(cc->requests) - { - listRelease(cc->requests); - cc->requests = NULL; - } - - if(cc->need_update_route) - { - status = cluster_update_route(cc); - if(status != REDIS_OK) - { - __redisClusterSetError(cc, REDIS_ERR_OTHER, - "route update error, please recreate redisClusterContext!"); - return; - } - cc->need_update_route = 0; - } -} - -/*############redis cluster async############*/ - -/* We want the error field to be accessible directly instead of requiring - * an indirection to the redisContext struct. */ -static void __redisClusterAsyncCopyError(redisClusterAsyncContext *acc) { - if (!acc) - return; - - redisClusterContext *cc = acc->cc; - acc->err = cc->err; - memcpy(acc->errstr, cc->errstr, 128); -} - -static void __redisClusterAsyncSetError(redisClusterAsyncContext *acc, - int type, const char *str) { - - size_t len; - - acc->err = type; - if (str != NULL) { - len = strlen(str); - len = len < (sizeof(acc->errstr)-1) ? len : (sizeof(acc->errstr)-1); - memcpy(acc->errstr,str,len); - acc->errstr[len] = '\0'; - } else { - /* Only REDIS_ERR_IO may lack a description! */ - assert(type == REDIS_ERR_IO); - __redis_strerror_r(errno, acc->errstr, sizeof(acc->errstr)); - } -} - -static redisClusterAsyncContext *redisClusterAsyncInitialize(redisClusterContext *cc) { - redisClusterAsyncContext *acc; - - if(cc == NULL) - { - return NULL; - } - - acc = hi_alloc(sizeof(redisClusterAsyncContext)); - if (acc == NULL) - return NULL; - - acc->cc = cc; - - acc->err = 0; - acc->data = NULL; - acc->adapter = NULL; - acc->attach_fn = NULL; - - acc->onConnect = NULL; - acc->onDisconnect = NULL; - - return acc; -} - -static cluster_async_data *cluster_async_data_get(void) -{ - cluster_async_data *cad; - - cad = hi_alloc(sizeof(cluster_async_data)); - if(cad == NULL) - { - return NULL; - } - - cad->acc = NULL; - cad->command = NULL; - cad->callback = NULL; - cad->privdata = NULL; - cad->retry_count = 0; - - return cad; -} - -static void cluster_async_data_free(cluster_async_data *cad) -{ - if(cad == NULL) - { - return; - } - - if(cad->command != NULL) - { - command_destroy(cad->command); - } - - hi_free(cad); - cad = NULL; -} - -static void unlinkAsyncContextAndNode(redisAsyncContext* ac) -{ - cluster_node *node; - - if (ac->data) { - node = (cluster_node *)(ac->data); - node->acon = NULL; - } -} - -redisAsyncContext * actx_get_by_node(redisClusterAsyncContext *acc, - cluster_node *node) -{ - redisAsyncContext *ac; - - if(node == NULL) - { - return NULL; - } - - ac = node->acon; - if(ac != NULL) - { - if (ac->c.err == 0) { - return ac; - } else { - NOT_REACHED(); - } - } - - if(node->host == NULL || node->port <= 0) - { - __redisClusterAsyncSetError(acc, REDIS_ERR_OTHER, "node host or port is error"); - return NULL; - } - - ac = redisAsyncConnect(node->host, node->port); - if(ac == NULL) - { - __redisClusterAsyncSetError(acc, REDIS_ERR_OTHER, "node host or port is error"); - return NULL; - } - - if(acc->adapter) - { - acc->attach_fn(ac, acc->adapter); - } - - if(acc->onConnect) - { - redisAsyncSetConnectCallback(ac, acc->onConnect); - } - - if(acc->onDisconnect) - { - redisAsyncSetDisconnectCallback(ac, acc->onDisconnect); - } - - ac->data = node; - ac->dataHandler = unlinkAsyncContextAndNode; - node->acon = ac; - - return ac; -} - -static redisAsyncContext *actx_get_after_update_route_by_slot( - redisClusterAsyncContext *acc, int slot_num) -{ - int ret; - redisClusterContext *cc; - redisAsyncContext *ac; - cluster_node *node; - - if(acc == NULL || slot_num < 0) - { - return NULL; - } - - cc = acc->cc; - if(cc == NULL) - { - return NULL; - } - - ret = cluster_update_route(cc); - if(ret != REDIS_OK) - { - __redisClusterAsyncSetError(acc, REDIS_ERR_OTHER, - "route update error, please recreate redisClusterContext!"); - return NULL; - } - - node = node_get_by_table(cc, (uint32_t)slot_num); - if(node == NULL) - { - __redisClusterAsyncSetError(acc, - REDIS_ERR_OTHER, "node get by table error"); - return NULL; - } - - ac = actx_get_by_node(acc, node); - if(ac == NULL) - { - __redisClusterAsyncSetError(acc, - REDIS_ERR_OTHER, "actx get by node error"); - return NULL; - } - else if(ac->err) - { - __redisClusterAsyncSetError(acc, ac->err, ac->errstr); - return NULL; - } - - return ac; -} - -redisClusterAsyncContext *redisClusterAsyncConnect(const char *addrs, int flags) { - - redisClusterContext *cc; - redisClusterAsyncContext *acc; - - cc = redisClusterConnectNonBlock(addrs, flags); - if(cc == NULL) - { - return NULL; - } - - acc = redisClusterAsyncInitialize(cc); - if (acc == NULL) { - redisClusterFree(cc); - return NULL; - } - - __redisClusterAsyncCopyError(acc); - - return acc; -} - - -int redisClusterAsyncSetConnectCallback( - redisClusterAsyncContext *acc, redisConnectCallback *fn) -{ - if (acc->onConnect == NULL) { - acc->onConnect = fn; - return REDIS_OK; - } - return REDIS_ERR; -} - -int redisClusterAsyncSetDisconnectCallback( - redisClusterAsyncContext *acc, redisDisconnectCallback *fn) -{ - if (acc->onDisconnect == NULL) { - acc->onDisconnect = fn; - return REDIS_OK; - } - return REDIS_ERR; -} - -static void redisClusterAsyncCallback(redisAsyncContext *ac, void *r, void *privdata) { - int ret; - redisReply *reply = r; - cluster_async_data *cad = privdata; - redisClusterAsyncContext *acc; - redisClusterContext *cc; - redisAsyncContext *ac_retry = NULL; - int error_type; - cluster_node *node; - struct cmd *command; - int64_t now, next; - - if(cad == NULL) - { - goto error; - } - - acc = cad->acc; - if(acc == NULL) - { - goto error; - } - - cc = acc->cc; - if(cc == NULL) - { - goto error; - } - - command = cad->command; - if(command == NULL) - { - goto error; - } - - if(reply == NULL) - { - //Note: - //I can't decide witch is the best way to deal with connect - //problem for hiredis cluster async api. - //But now the way is : when enough null reply for a node, - //we will update the route after the cluster node timeout. - //If you have a better idea, please contact with me. Thank you. - //My email: diguo58@gmail.com - - node = (cluster_node *)(ac->data); - ASSERT(node != NULL); - - __redisClusterAsyncSetError(acc, - ac->err, ac->errstr); - - if(cc->update_route_time != 0) - { - now = hi_usec_now(); - if(now >= cc->update_route_time) - { - ret = cluster_update_route(cc); - if(ret != REDIS_OK) - { - __redisClusterAsyncSetError(acc, REDIS_ERR_OTHER, - "route update error, please recreate redisClusterContext!"); - } - - cc->update_route_time = 0LL; - } - - goto done; - } - - node->failure_count ++; - if(node->failure_count > cc->max_redirect_count) - { - char *cluster_timeout_str; - int cluster_timeout_str_len; - int cluster_timeout; - - node->failure_count = 0; - if(cc->update_route_time != 0) - { - goto done; - } - - cluster_timeout_str = cluster_config_get(cc, - "cluster-node-timeout", &cluster_timeout_str_len); - if(cluster_timeout_str == NULL) - { - __redisClusterAsyncSetError(acc, - cc->err, cc->errstr); - goto done; - } - - cluster_timeout = hi_atoi(cluster_timeout_str, - cluster_timeout_str_len); - free(cluster_timeout_str); - if(cluster_timeout <= 0) - { - __redisClusterAsyncSetError(acc, - REDIS_ERR_OTHER, - "cluster_timeout_str convert to integer error"); - goto done; - } - - now = hi_usec_now(); - if (now < 0) { - __redisClusterAsyncSetError(acc, - REDIS_ERR_OTHER, - "get now usec time error"); - goto done; - } - - next = now + (cluster_timeout * 1000LL); - - cc->update_route_time = next; - - } - - goto done; - } - - error_type = cluster_reply_error_type(reply); - - if(error_type > CLUSTER_NOT_ERR && error_type < CLUSTER_ERR_SENTINEL) - { - cad->retry_count ++; - if(cad->retry_count > cc->max_redirect_count) - { - cad->retry_count = 0; - __redisClusterAsyncSetError(acc, - REDIS_ERR_CLUSTER_TOO_MANY_REDIRECT, - "too many cluster redirect"); - goto done; - } - - switch(error_type) - { - case CLUSTER_ERR_MOVED: - ac_retry = actx_get_after_update_route_by_slot(acc, command->slot_num); - if(ac_retry == NULL) - { - goto done; - } - - break; - case CLUSTER_ERR_ASK: - node = node_get_by_ask_error_reply(cc, reply); - if(node == NULL) - { - __redisClusterAsyncSetError(acc, - cc->err, cc->errstr); - goto done; - } - - ac_retry = actx_get_by_node(acc, node); - if(ac_retry == NULL) - { - __redisClusterAsyncSetError(acc, - REDIS_ERR_OTHER, "actx get by node error"); - goto done; - } - else if(ac_retry->err) - { - __redisClusterAsyncSetError(acc, - ac_retry->err, ac_retry->errstr); - goto done; - } - - ret = redisAsyncCommand(ac_retry, - NULL,NULL,REDIS_COMMAND_ASKING); - if(ret != REDIS_OK) - { - goto error; - } - - break; - case CLUSTER_ERR_TRYAGAIN: - case CLUSTER_ERR_CROSSSLOT: - case CLUSTER_ERR_CLUSTERDOWN: - ac_retry = ac; - - break; - default: - - goto done; - break; - } - - goto retry; - } - -done: - - if(acc->err) - { - cad->callback(acc, NULL, cad->privdata); - } - else - { - cad->callback(acc, r, cad->privdata); - } - - if(cc->err) - { - cc->err = 0; - memset(cc->errstr, '\0', strlen(cc->errstr)); - } - - if(acc->err) - { - acc->err = 0; - memset(acc->errstr, '\0', strlen(acc->errstr)); - } - - if(cad != NULL) - { - cluster_async_data_free(cad); - } - - return; - -retry: - - ret = redisAsyncFormattedCommand(ac_retry, - redisClusterAsyncCallback,cad,command->cmd,command->clen); - if(ret != REDIS_OK) - { - goto error; - } - - return; - -error: - - if(cad != NULL) - { - cluster_async_data_free(cad); - } -} - -int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, - redisClusterCallbackFn *fn, void *privdata, char *cmd, int len) { - - redisClusterContext *cc; - int status = REDIS_OK; - int slot_num; - cluster_node *node; - redisAsyncContext *ac; - struct cmd *command = NULL; - hilist *commands = NULL; - cluster_async_data *cad; - - if(acc == NULL) - { - return REDIS_ERR; - } - - cc = acc->cc; - - if(cc->err) - { - cc->err = 0; - memset(cc->errstr, '\0', strlen(cc->errstr)); - } - - if(acc->err) - { - acc->err = 0; - memset(acc->errstr, '\0', strlen(acc->errstr)); - } - - command = command_get(); - if(command == NULL) - { - __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); - goto error; - } - - command->cmd = malloc(len*sizeof(*command->cmd)); - if(command->cmd == NULL) - { - __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); - goto error; - } - memcpy(command->cmd, cmd, len); - command->clen = len; - - commands = listCreate(); - if(commands == NULL) - { - __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); - goto error; - } - - commands->free = listCommandFree; - - slot_num = command_format_by_slot(cc, command, commands); - - if(slot_num < 0) - { - __redisClusterAsyncSetError(acc, - cc->err, cc->errstr); - goto error; - } - else if(slot_num >= REDIS_CLUSTER_SLOTS) - { - __redisClusterAsyncSetError(acc, - REDIS_ERR_OTHER,"slot_num is out of range"); - goto error; - } - - //all keys not belong to one slot - if(listLength(commands) > 0) - { - ASSERT(listLength(commands) != 1); - - __redisClusterAsyncSetError(acc,REDIS_ERR_OTHER, - "Asynchronous API now not support multi-key command"); - goto error; - } - - node = node_get_by_table(cc, (uint32_t) slot_num); - if(node == NULL) - { - __redisClusterAsyncSetError(acc, - REDIS_ERR_OTHER, "node get by table error"); - goto error; - } - - ac = actx_get_by_node(acc, node); - if(ac == NULL) - { - __redisClusterAsyncSetError(acc, - REDIS_ERR_OTHER, "actx get by node error"); - goto error; - } - else if(ac->err) - { - __redisClusterAsyncSetError(acc, ac->err, ac->errstr); - goto error; - } - - cad = cluster_async_data_get(); - if(cad == NULL) - { - __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); - goto error; - } - - cad->acc = acc; - cad->command = command; - cad->callback = fn; - cad->privdata = privdata; - - status = redisAsyncFormattedCommand(ac, - redisClusterAsyncCallback,cad,cmd,len); - if(status != REDIS_OK) - { - goto error; - } - - if(commands != NULL) - { - listRelease(commands); - } - - return REDIS_OK; - -error: - - if(command != NULL) - { - command_destroy(command); - } - - if(commands != NULL) - { - listRelease(commands); - } - - return REDIS_ERR; -} - - -int redisClustervAsyncCommand(redisClusterAsyncContext *acc, - redisClusterCallbackFn *fn, void *privdata, const char *format, va_list ap) { - int ret; - char *cmd; - int len; - - if(acc == NULL) - { - return REDIS_ERR; - } - - len = redisvFormatCommand(&cmd,format,ap); - if (len == -1) { - __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } else if (len == -2) { - __redisClusterAsyncSetError(acc,REDIS_ERR_OTHER,"Invalid format string"); - return REDIS_ERR; - } - - ret = redisClusterAsyncFormattedCommand(acc, fn, privdata, cmd, len); - - free(cmd); - - return ret; -} - -int redisClusterAsyncCommand(redisClusterAsyncContext *acc, - redisClusterCallbackFn *fn, void *privdata, const char *format, ...) { - int ret; - va_list ap; - - va_start(ap,format); - ret = redisClustervAsyncCommand(acc, fn, privdata, format, ap); - va_end(ap); - - return ret; -} - -int redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, - redisClusterCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) { - int ret; - char *cmd; - int len; - - len = redisFormatCommandArgv(&cmd,argc,argv,argvlen); - if (len == -1) { - __redisClusterAsyncSetError(acc,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } - - ret = redisClusterAsyncFormattedCommand(acc, fn, privdata, cmd, len); - - free(cmd); - - return ret; -} - -void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc) { - - redisClusterContext *cc; - redisAsyncContext *ac; - dictIterator *di; - dictEntry *de; - dict *nodes; - struct cluster_node *node; - - if(acc == NULL) - { - return; - } - - cc = acc->cc; - - nodes = cc->nodes; - - if(nodes == NULL) - { - return; - } - - di = dictGetIterator(nodes); - - while((de = dictNext(di)) != NULL) - { - node = dictGetEntryVal(de); - - ac = node->acon; - - if(ac == NULL || ac->err) - { - continue; - } - - redisAsyncDisconnect(ac); - - node->acon = NULL; - } -} - -void redisClusterAsyncFree(redisClusterAsyncContext *acc) -{ - redisClusterContext *cc; - - if(acc == NULL) - { - return; - } - - cc = acc->cc; - - redisClusterFree(cc); - - hi_free(acc); -} - diff --git a/ext/hiredis-vip-0.3.0/hircluster.h b/ext/hiredis-vip-0.3.0/hircluster.h deleted file mode 100644 index 5b9c5a358..000000000 --- a/ext/hiredis-vip-0.3.0/hircluster.h +++ /dev/null @@ -1,178 +0,0 @@ - -#ifndef __HIRCLUSTER_H -#define __HIRCLUSTER_H - -#include "hiredis.h" -#include "async.h" - -#define HIREDIS_VIP_MAJOR 0 -#define HIREDIS_VIP_MINOR 3 -#define HIREDIS_VIP_PATCH 0 - -#define REDIS_CLUSTER_SLOTS 16384 - -#define REDIS_ROLE_NULL 0 -#define REDIS_ROLE_MASTER 1 -#define REDIS_ROLE_SLAVE 2 - - -#define HIRCLUSTER_FLAG_NULL 0x0 -/* The flag to decide whether add slave node in - * redisClusterContext->nodes. This is set in the - * least significant bit of the flags field in - * redisClusterContext. (1000000000000) */ -#define HIRCLUSTER_FLAG_ADD_SLAVE 0x1000 -/* The flag to decide whether add open slot - * for master node. (10000000000000) */ -#define HIRCLUSTER_FLAG_ADD_OPENSLOT 0x2000 -/* The flag to decide whether get the route - * table by 'cluster slots' command. Default - * is 'cluster nodes' command.*/ -#define HIRCLUSTER_FLAG_ROUTE_USE_SLOTS 0x4000 - -struct dict; -struct hilist; - -typedef struct cluster_node -{ - sds name; - sds addr; - sds host; - int port; - uint8_t role; - uint8_t myself; /* myself ? */ - redisContext *con; - redisAsyncContext *acon; - struct hilist *slots; - struct hilist *slaves; - int failure_count; - void *data; /* Not used by hiredis */ - struct hiarray *migrating; /* copen_slot[] */ - struct hiarray *importing; /* copen_slot[] */ -}cluster_node; - -typedef struct cluster_slot -{ - uint32_t start; - uint32_t end; - cluster_node *node; /* master that this slot region belong to */ -}cluster_slot; - -typedef struct copen_slot -{ - uint32_t slot_num; /* slot number */ - int migrate; /* migrating or importing? */ - sds remote_name; /* name for the node that this slot migrating to/importing from */ - cluster_node *node; /* master that this slot belong to */ -}copen_slot; - -#ifdef __cplusplus -extern "C" { -#endif - -/* Context for a connection to Redis cluster */ -typedef struct redisClusterContext { - int err; /* Error flags, 0 when there is no error */ - char errstr[128]; /* String representation of error when applicable */ - sds ip; - int port; - - int flags; - - enum redisConnectionType connection_type; - struct timeval *timeout; - - struct hiarray *slots; - - struct dict *nodes; - cluster_node *table[REDIS_CLUSTER_SLOTS]; - - uint64_t route_version; - - int max_redirect_count; - int retry_count; - - struct hilist *requests; - - int need_update_route; - int64_t update_route_time; -} redisClusterContext; - -redisClusterContext *redisClusterConnect(const char *addrs, int flags); -redisClusterContext *redisClusterConnectWithTimeout(const char *addrs, - const struct timeval tv, int flags); -redisClusterContext *redisClusterConnectNonBlock(const char *addrs, int flags); - -void redisClusterFree(redisClusterContext *cc); - -void redisClusterSetMaxRedirect(redisClusterContext *cc, int max_redirect_count); - -void *redisClusterFormattedCommand(redisClusterContext *cc, char *cmd, int len); -void *redisClustervCommand(redisClusterContext *cc, const char *format, va_list ap); -void *redisClusterCommand(redisClusterContext *cc, const char *format, ...); -void *redisClusterCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); - -redisContext *ctx_get_by_node(struct cluster_node *node, const struct timeval *timeout, int flags); - -int redisClusterAppendFormattedCommand(redisClusterContext *cc, char *cmd, int len); -int redisClustervAppendCommand(redisClusterContext *cc, const char *format, va_list ap); -int redisClusterAppendCommand(redisClusterContext *cc, const char *format, ...); -int redisClusterAppendCommandArgv(redisClusterContext *cc, int argc, const char **argv, const size_t *argvlen); -int redisClusterGetReply(redisClusterContext *cc, void **reply); -void redisClusterReset(redisClusterContext *cc); - -int cluster_update_route(redisClusterContext *cc); -int test_cluster_update_route(redisClusterContext *cc); -struct dict *parse_cluster_nodes(redisClusterContext *cc, char *str, int str_len, int flags); -struct dict *parse_cluster_slots(redisClusterContext *cc, redisReply *reply, int flags); - - -/*############redis cluster async############*/ - -struct redisClusterAsyncContext; - -typedef int (adapterAttachFn)(redisAsyncContext*, void*); - -typedef void (redisClusterCallbackFn)(struct redisClusterAsyncContext*, void*, void*); - -/* Context for an async connection to Redis */ -typedef struct redisClusterAsyncContext { - - redisClusterContext *cc; - - /* Setup error flags so they can be used directly. */ - int err; - char errstr[128]; /* String representation of error when applicable */ - - /* Not used by hiredis */ - void *data; - - void *adapter; - adapterAttachFn *attach_fn; - - /* Called when either the connection is terminated due to an error or per - * user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */ - redisDisconnectCallback *onDisconnect; - - /* Called when the first write event was received. */ - redisConnectCallback *onConnect; - -} redisClusterAsyncContext; - -redisClusterAsyncContext *redisClusterAsyncConnect(const char *addrs, int flags); -int redisClusterAsyncSetConnectCallback(redisClusterAsyncContext *acc, redisConnectCallback *fn); -int redisClusterAsyncSetDisconnectCallback(redisClusterAsyncContext *acc, redisDisconnectCallback *fn); -int redisClusterAsyncFormattedCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, char *cmd, int len); -int redisClustervAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, va_list ap); -int redisClusterAsyncCommand(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, const char *format, ...); -int redisClusterAsyncCommandArgv(redisClusterAsyncContext *acc, redisClusterCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); -void redisClusterAsyncDisconnect(redisClusterAsyncContext *acc); -void redisClusterAsyncFree(redisClusterAsyncContext *acc); - -redisAsyncContext *actx_get_by_node(redisClusterAsyncContext *acc, cluster_node *node); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/ext/hiredis-vip-0.3.0/hiredis.c b/ext/hiredis-vip-0.3.0/hiredis.c deleted file mode 100644 index 73d0251bc..000000000 --- a/ext/hiredis-vip-0.3.0/hiredis.c +++ /dev/null @@ -1,1021 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2014, Pieter Noordhuis - * Copyright (c) 2015, Matt Stancliff , - * Jan-Erik Rediger - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include -#include -#include -#include -#include -#include - -#include "hiredis.h" -#include "net.h" -#include "sds.h" - -static redisReply *createReplyObject(int type); -static void *createStringObject(const redisReadTask *task, char *str, size_t len); -static void *createArrayObject(const redisReadTask *task, int elements); -static void *createIntegerObject(const redisReadTask *task, long long value); -static void *createNilObject(const redisReadTask *task); - -/* Default set of functions to build the reply. Keep in mind that such a - * function returning NULL is interpreted as OOM. */ -static redisReplyObjectFunctions defaultFunctions = { - createStringObject, - createArrayObject, - createIntegerObject, - createNilObject, - freeReplyObject -}; - -/* Create a reply object */ -static redisReply *createReplyObject(int type) { - redisReply *r = calloc(1,sizeof(*r)); - - if (r == NULL) - return NULL; - - r->type = type; - return r; -} - -/* Free a reply object */ -void freeReplyObject(void *reply) { - redisReply *r = reply; - size_t j; - - if (r == NULL) - return; - - switch(r->type) { - case REDIS_REPLY_INTEGER: - break; /* Nothing to free */ - case REDIS_REPLY_ARRAY: - if (r->element != NULL) { - for (j = 0; j < r->elements; j++) - if (r->element[j] != NULL) - freeReplyObject(r->element[j]); - free(r->element); - } - break; - case REDIS_REPLY_ERROR: - case REDIS_REPLY_STATUS: - case REDIS_REPLY_STRING: - if (r->str != NULL) - free(r->str); - break; - } - free(r); -} - -static void *createStringObject(const redisReadTask *task, char *str, size_t len) { - redisReply *r, *parent; - char *buf; - - r = createReplyObject(task->type); - if (r == NULL) - return NULL; - - buf = malloc(len+1); - if (buf == NULL) { - freeReplyObject(r); - return NULL; - } - - assert(task->type == REDIS_REPLY_ERROR || - task->type == REDIS_REPLY_STATUS || - task->type == REDIS_REPLY_STRING); - - /* Copy string value */ - memcpy(buf,str,len); - buf[len] = '\0'; - r->str = buf; - r->len = len; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY); - parent->element[task->idx] = r; - } - return r; -} - -static void *createArrayObject(const redisReadTask *task, int elements) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_ARRAY); - if (r == NULL) - return NULL; - - if (elements > 0) { - r->element = calloc(elements,sizeof(redisReply*)); - if (r->element == NULL) { - freeReplyObject(r); - return NULL; - } - } - - r->elements = elements; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY); - parent->element[task->idx] = r; - } - return r; -} - -static void *createIntegerObject(const redisReadTask *task, long long value) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_INTEGER); - if (r == NULL) - return NULL; - - r->integer = value; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY); - parent->element[task->idx] = r; - } - return r; -} - -static void *createNilObject(const redisReadTask *task) { - redisReply *r, *parent; - - r = createReplyObject(REDIS_REPLY_NIL); - if (r == NULL) - return NULL; - - if (task->parent) { - parent = task->parent->obj; - assert(parent->type == REDIS_REPLY_ARRAY); - parent->element[task->idx] = r; - } - return r; -} - -/* Return the number of digits of 'v' when converted to string in radix 10. - * Implementation borrowed from link in redis/src/util.c:string2ll(). */ -static uint32_t countDigits(uint64_t v) { - uint32_t result = 1; - for (;;) { - if (v < 10) return result; - if (v < 100) return result + 1; - if (v < 1000) return result + 2; - if (v < 10000) return result + 3; - v /= 10000U; - result += 4; - } -} - -/* Helper that calculates the bulk length given a certain string length. */ -static size_t bulklen(size_t len) { - return 1+countDigits(len)+2+len+2; -} - -int redisvFormatCommand(char **target, const char *format, va_list ap) { - const char *c = format; - char *cmd = NULL; /* final command */ - int pos; /* position in final command */ - sds curarg, newarg; /* current argument */ - int touched = 0; /* was the current argument touched? */ - char **curargv = NULL, **newargv = NULL; - int argc = 0; - int totlen = 0; - int error_type = 0; /* 0 = no error; -1 = memory error; -2 = format error */ - int j; - - /* Abort if there is not target to set */ - if (target == NULL) - return -1; - - /* Build the command string accordingly to protocol */ - curarg = sdsempty(); - if (curarg == NULL) - return -1; - - while(*c != '\0') { - if (*c != '%' || c[1] == '\0') { - if (*c == ' ') { - if (touched) { - newargv = realloc(curargv,sizeof(char*)*(argc+1)); - if (newargv == NULL) goto memory_err; - curargv = newargv; - curargv[argc++] = curarg; - totlen += bulklen(sdslen(curarg)); - - /* curarg is put in argv so it can be overwritten. */ - curarg = sdsempty(); - if (curarg == NULL) goto memory_err; - touched = 0; - } - } else { - newarg = sdscatlen(curarg,c,1); - if (newarg == NULL) goto memory_err; - curarg = newarg; - touched = 1; - } - } else { - char *arg; - size_t size; - - /* Set newarg so it can be checked even if it is not touched. */ - newarg = curarg; - - switch(c[1]) { - case 's': - arg = va_arg(ap,char*); - size = strlen(arg); - if (size > 0) - newarg = sdscatlen(curarg,arg,size); - break; - case 'b': - arg = va_arg(ap,char*); - size = va_arg(ap,size_t); - if (size > 0) - newarg = sdscatlen(curarg,arg,size); - break; - case '%': - newarg = sdscat(curarg,"%"); - break; - default: - /* Try to detect printf format */ - { - static const char intfmts[] = "diouxX"; - static const char flags[] = "#0-+ "; - char _format[16]; - const char *_p = c+1; - size_t _l = 0; - va_list _cpy; - - /* Flags */ - while (*_p != '\0' && strchr(flags,*_p) != NULL) _p++; - - /* Field width */ - while (*_p != '\0' && isdigit(*_p)) _p++; - - /* Precision */ - if (*_p == '.') { - _p++; - while (*_p != '\0' && isdigit(*_p)) _p++; - } - - /* Copy va_list before consuming with va_arg */ - va_copy(_cpy,ap); - - /* Integer conversion (without modifiers) */ - if (strchr(intfmts,*_p) != NULL) { - va_arg(ap,int); - goto fmt_valid; - } - - /* Double conversion (without modifiers) */ - if (strchr("eEfFgGaA",*_p) != NULL) { - va_arg(ap,double); - goto fmt_valid; - } - - /* Size: char */ - if (_p[0] == 'h' && _p[1] == 'h') { - _p += 2; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,int); /* char gets promoted to int */ - goto fmt_valid; - } - goto fmt_invalid; - } - - /* Size: short */ - if (_p[0] == 'h') { - _p += 1; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,int); /* short gets promoted to int */ - goto fmt_valid; - } - goto fmt_invalid; - } - - /* Size: long long */ - if (_p[0] == 'l' && _p[1] == 'l') { - _p += 2; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,long long); - goto fmt_valid; - } - goto fmt_invalid; - } - - /* Size: long */ - if (_p[0] == 'l') { - _p += 1; - if (*_p != '\0' && strchr(intfmts,*_p) != NULL) { - va_arg(ap,long); - goto fmt_valid; - } - goto fmt_invalid; - } - - fmt_invalid: - va_end(_cpy); - goto format_err; - - fmt_valid: - _l = (_p+1)-c; - if (_l < sizeof(_format)-2) { - memcpy(_format,c,_l); - _format[_l] = '\0'; - newarg = sdscatvprintf(curarg,_format,_cpy); - - /* Update current position (note: outer blocks - * increment c twice so compensate here) */ - c = _p-1; - } - - va_end(_cpy); - break; - } - } - - if (newarg == NULL) goto memory_err; - curarg = newarg; - - touched = 1; - c++; - } - c++; - } - - /* Add the last argument if needed */ - if (touched) { - newargv = realloc(curargv,sizeof(char*)*(argc+1)); - if (newargv == NULL) goto memory_err; - curargv = newargv; - curargv[argc++] = curarg; - totlen += bulklen(sdslen(curarg)); - } else { - sdsfree(curarg); - } - - /* Clear curarg because it was put in curargv or was free'd. */ - curarg = NULL; - - /* Add bytes needed to hold multi bulk count */ - totlen += 1+countDigits(argc)+2; - - /* Build the command at protocol level */ - cmd = malloc(totlen+1); - if (cmd == NULL) goto memory_err; - - pos = sprintf(cmd,"*%d\r\n",argc); - for (j = 0; j < argc; j++) { - pos += sprintf(cmd+pos,"$%zu\r\n",sdslen(curargv[j])); - memcpy(cmd+pos,curargv[j],sdslen(curargv[j])); - pos += sdslen(curargv[j]); - sdsfree(curargv[j]); - cmd[pos++] = '\r'; - cmd[pos++] = '\n'; - } - assert(pos == totlen); - cmd[pos] = '\0'; - - free(curargv); - *target = cmd; - return totlen; - -format_err: - error_type = -2; - goto cleanup; - -memory_err: - error_type = -1; - goto cleanup; - -cleanup: - if (curargv) { - while(argc--) - sdsfree(curargv[argc]); - free(curargv); - } - - sdsfree(curarg); - - /* No need to check cmd since it is the last statement that can fail, - * but do it anyway to be as defensive as possible. */ - if (cmd != NULL) - free(cmd); - - return error_type; -} - -/* Format a command according to the Redis protocol. This function - * takes a format similar to printf: - * - * %s represents a C null terminated string you want to interpolate - * %b represents a binary safe string - * - * When using %b you need to provide both the pointer to the string - * and the length in bytes as a size_t. Examples: - * - * len = redisFormatCommand(target, "GET %s", mykey); - * len = redisFormatCommand(target, "SET %s %b", mykey, myval, myvallen); - */ -int redisFormatCommand(char **target, const char *format, ...) { - va_list ap; - int len; - va_start(ap,format); - len = redisvFormatCommand(target,format,ap); - va_end(ap); - - /* The API says "-1" means bad result, but we now also return "-2" in some - * cases. Force the return value to always be -1. */ - if (len < 0) - len = -1; - - return len; -} - -/* Format a command according to the Redis protocol using an sds string and - * sdscatfmt for the processing of arguments. This function takes the - * number of arguments, an array with arguments and an array with their - * lengths. If the latter is set to NULL, strlen will be used to compute the - * argument lengths. - */ -int redisFormatSdsCommandArgv(sds *target, int argc, const char **argv, - const size_t *argvlen) -{ - sds cmd; - unsigned long long totlen; - int j; - size_t len; - - /* Abort on a NULL target */ - if (target == NULL) - return -1; - - /* Calculate our total size */ - totlen = 1+countDigits(argc)+2; - for (j = 0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - totlen += bulklen(len); - } - - /* Use an SDS string for command construction */ - cmd = sdsempty(); - if (cmd == NULL) - return -1; - - /* We already know how much storage we need */ - cmd = sdsMakeRoomFor(cmd, totlen); - if (cmd == NULL) - return -1; - - /* Construct command */ - cmd = sdscatfmt(cmd, "*%i\r\n", argc); - for (j=0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - cmd = sdscatfmt(cmd, "$%T\r\n", len); - cmd = sdscatlen(cmd, argv[j], len); - cmd = sdscatlen(cmd, "\r\n", sizeof("\r\n")-1); - } - - assert(sdslen(cmd)==totlen); - - *target = cmd; - return totlen; -} - -void redisFreeSdsCommand(sds cmd) { - sdsfree(cmd); -} - -/* Format a command according to the Redis protocol. This function takes the - * number of arguments, an array with arguments and an array with their - * lengths. If the latter is set to NULL, strlen will be used to compute the - * argument lengths. - */ -int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen) { - char *cmd = NULL; /* final command */ - int pos; /* position in final command */ - size_t len; - int totlen, j; - - /* Abort on a NULL target */ - if (target == NULL) - return -1; - - /* Calculate number of bytes needed for the command */ - totlen = 1+countDigits(argc)+2; - for (j = 0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - totlen += bulklen(len); - } - - /* Build the command at protocol level */ - cmd = malloc(totlen+1); - if (cmd == NULL) - return -1; - - pos = sprintf(cmd,"*%d\r\n",argc); - for (j = 0; j < argc; j++) { - len = argvlen ? argvlen[j] : strlen(argv[j]); - pos += sprintf(cmd+pos,"$%zu\r\n",len); - memcpy(cmd+pos,argv[j],len); - pos += len; - cmd[pos++] = '\r'; - cmd[pos++] = '\n'; - } - assert(pos == totlen); - cmd[pos] = '\0'; - - *target = cmd; - return totlen; -} - -void redisFreeCommand(char *cmd) { - free(cmd); -} - -void __redisSetError(redisContext *c, int type, const char *str) { - size_t len; - - c->err = type; - if (str != NULL) { - len = strlen(str); - len = len < (sizeof(c->errstr)-1) ? len : (sizeof(c->errstr)-1); - memcpy(c->errstr,str,len); - c->errstr[len] = '\0'; - } else { - /* Only REDIS_ERR_IO may lack a description! */ - assert(type == REDIS_ERR_IO); - __redis_strerror_r(errno, c->errstr, sizeof(c->errstr)); - } -} - -redisReader *redisReaderCreate(void) { - return redisReaderCreateWithFunctions(&defaultFunctions); -} - -static redisContext *redisContextInit(void) { - redisContext *c; - - c = calloc(1,sizeof(redisContext)); - if (c == NULL) - return NULL; - - c->err = 0; - c->errstr[0] = '\0'; - c->obuf = sdsempty(); - c->reader = redisReaderCreate(); - c->tcp.host = NULL; - c->tcp.source_addr = NULL; - c->unix_sock.path = NULL; - c->timeout = NULL; - - if (c->obuf == NULL || c->reader == NULL) { - redisFree(c); - return NULL; - } - - return c; -} - -void redisFree(redisContext *c) { - if (c == NULL) - return; - if (c->fd > 0) - close(c->fd); - if (c->obuf != NULL) - sdsfree(c->obuf); - if (c->reader != NULL) - redisReaderFree(c->reader); - if (c->tcp.host) - free(c->tcp.host); - if (c->tcp.source_addr) - free(c->tcp.source_addr); - if (c->unix_sock.path) - free(c->unix_sock.path); - if (c->timeout) - free(c->timeout); - free(c); -} - -int redisFreeKeepFd(redisContext *c) { - int fd = c->fd; - c->fd = -1; - redisFree(c); - return fd; -} - -int redisReconnect(redisContext *c) { - c->err = 0; - memset(c->errstr, '\0', strlen(c->errstr)); - - if (c->fd > 0) { - close(c->fd); - } - - sdsfree(c->obuf); - redisReaderFree(c->reader); - - c->obuf = sdsempty(); - c->reader = redisReaderCreate(); - - if (c->connection_type == REDIS_CONN_TCP) { - return redisContextConnectBindTcp(c, c->tcp.host, c->tcp.port, - c->timeout, c->tcp.source_addr); - } else if (c->connection_type == REDIS_CONN_UNIX) { - return redisContextConnectUnix(c, c->unix_sock.path, c->timeout); - } else { - /* Something bad happened here and shouldn't have. There isn't - enough information in the context to reconnect. */ - __redisSetError(c,REDIS_ERR_OTHER,"Not enough information to reconnect"); - } - - return REDIS_ERR; -} - -/* Connect to a Redis instance. On error the field error in the returned - * context will be set to the return value of the error function. - * When no set of reply functions is given, the default set will be used. */ -redisContext *redisConnect(const char *ip, int port) { - redisContext *c; - - c = redisContextInit(); - if (c == NULL) - return NULL; - - c->flags |= REDIS_BLOCK; - redisContextConnectTcp(c,ip,port,NULL); - return c; -} - -redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) { - redisContext *c; - - c = redisContextInit(); - if (c == NULL) - return NULL; - - c->flags |= REDIS_BLOCK; - redisContextConnectTcp(c,ip,port,&tv); - return c; -} - -redisContext *redisConnectNonBlock(const char *ip, int port) { - redisContext *c; - - c = redisContextInit(); - if (c == NULL) - return NULL; - - c->flags &= ~REDIS_BLOCK; - redisContextConnectTcp(c,ip,port,NULL); - return c; -} - -redisContext *redisConnectBindNonBlock(const char *ip, int port, - const char *source_addr) { - redisContext *c = redisContextInit(); - c->flags &= ~REDIS_BLOCK; - redisContextConnectBindTcp(c,ip,port,NULL,source_addr); - return c; -} - -redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, - const char *source_addr) { - redisContext *c = redisContextInit(); - c->flags &= ~REDIS_BLOCK; - c->flags |= REDIS_REUSEADDR; - redisContextConnectBindTcp(c,ip,port,NULL,source_addr); - return c; -} - -redisContext *redisConnectUnix(const char *path) { - redisContext *c; - - c = redisContextInit(); - if (c == NULL) - return NULL; - - c->flags |= REDIS_BLOCK; - redisContextConnectUnix(c,path,NULL); - return c; -} - -redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv) { - redisContext *c; - - c = redisContextInit(); - if (c == NULL) - return NULL; - - c->flags |= REDIS_BLOCK; - redisContextConnectUnix(c,path,&tv); - return c; -} - -redisContext *redisConnectUnixNonBlock(const char *path) { - redisContext *c; - - c = redisContextInit(); - if (c == NULL) - return NULL; - - c->flags &= ~REDIS_BLOCK; - redisContextConnectUnix(c,path,NULL); - return c; -} - -redisContext *redisConnectFd(int fd) { - redisContext *c; - - c = redisContextInit(); - if (c == NULL) - return NULL; - - c->fd = fd; - c->flags |= REDIS_BLOCK | REDIS_CONNECTED; - return c; -} - -/* Set read/write timeout on a blocking socket. */ -int redisSetTimeout(redisContext *c, const struct timeval tv) { - if (c->flags & REDIS_BLOCK) - return redisContextSetTimeout(c,tv); - return REDIS_ERR; -} - -/* Enable connection KeepAlive. */ -int redisEnableKeepAlive(redisContext *c) { - if (redisKeepAlive(c, REDIS_KEEPALIVE_INTERVAL) != REDIS_OK) - return REDIS_ERR; - return REDIS_OK; -} - -/* Use this function to handle a read event on the descriptor. It will try - * and read some bytes from the socket and feed them to the reply parser. - * - * After this function is called, you may use redisContextReadReply to - * see if there is a reply available. */ -int redisBufferRead(redisContext *c) { - char buf[1024*16]; - int nread; - - /* Return early when the context has seen an error. */ - if (c->err) - return REDIS_ERR; - - nread = read(c->fd,buf,sizeof(buf)); - if (nread == -1) { - if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { - /* Try again later */ - } else { - __redisSetError(c,REDIS_ERR_IO,NULL); - return REDIS_ERR; - } - } else if (nread == 0) { - __redisSetError(c,REDIS_ERR_EOF,"Server closed the connection"); - return REDIS_ERR; - } else { - if (redisReaderFeed(c->reader,buf,nread) != REDIS_OK) { - __redisSetError(c,c->reader->err,c->reader->errstr); - return REDIS_ERR; - } - } - return REDIS_OK; -} - -/* Write the output buffer to the socket. - * - * Returns REDIS_OK when the buffer is empty, or (a part of) the buffer was - * succesfully written to the socket. When the buffer is empty after the - * write operation, "done" is set to 1 (if given). - * - * Returns REDIS_ERR if an error occured trying to write and sets - * c->errstr to hold the appropriate error string. - */ -int redisBufferWrite(redisContext *c, int *done) { - int nwritten; - - /* Return early when the context has seen an error. */ - if (c->err) - return REDIS_ERR; - - if (sdslen(c->obuf) > 0) { - nwritten = write(c->fd,c->obuf,sdslen(c->obuf)); - if (nwritten == -1) { - if ((errno == EAGAIN && !(c->flags & REDIS_BLOCK)) || (errno == EINTR)) { - /* Try again later */ - } else { - __redisSetError(c,REDIS_ERR_IO,NULL); - return REDIS_ERR; - } - } else if (nwritten > 0) { - if (nwritten == (signed)sdslen(c->obuf)) { - sdsfree(c->obuf); - c->obuf = sdsempty(); - } else { - sdsrange(c->obuf,nwritten,-1); - } - } - } - if (done != NULL) *done = (sdslen(c->obuf) == 0); - return REDIS_OK; -} - -/* Internal helper function to try and get a reply from the reader, - * or set an error in the context otherwise. */ -int redisGetReplyFromReader(redisContext *c, void **reply) { - if (redisReaderGetReply(c->reader,reply) == REDIS_ERR) { - __redisSetError(c,c->reader->err,c->reader->errstr); - return REDIS_ERR; - } - return REDIS_OK; -} - -int redisGetReply(redisContext *c, void **reply) { - int wdone = 0; - void *aux = NULL; - - /* Try to read pending replies */ - if (redisGetReplyFromReader(c,&aux) == REDIS_ERR) - return REDIS_ERR; - - /* For the blocking context, flush output buffer and read reply */ - if (aux == NULL && c->flags & REDIS_BLOCK) { - /* Write until done */ - do { - if (redisBufferWrite(c,&wdone) == REDIS_ERR) - return REDIS_ERR; - } while (!wdone); - - /* Read until there is a reply */ - do { - if (redisBufferRead(c) == REDIS_ERR) - return REDIS_ERR; - if (redisGetReplyFromReader(c,&aux) == REDIS_ERR) - return REDIS_ERR; - } while (aux == NULL); - } - - /* Set reply object */ - if (reply != NULL) *reply = aux; - return REDIS_OK; -} - - -/* Helper function for the redisAppendCommand* family of functions. - * - * Write a formatted command to the output buffer. When this family - * is used, you need to call redisGetReply yourself to retrieve - * the reply (or replies in pub/sub). - */ -int __redisAppendCommand(redisContext *c, const char *cmd, size_t len) { - sds newbuf; - - newbuf = sdscatlen(c->obuf,cmd,len); - if (newbuf == NULL) { - __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } - - c->obuf = newbuf; - return REDIS_OK; -} - -int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len) { - - if (__redisAppendCommand(c, cmd, len) != REDIS_OK) { - return REDIS_ERR; - } - - return REDIS_OK; -} - -int redisvAppendCommand(redisContext *c, const char *format, va_list ap) { - char *cmd; - int len; - - len = redisvFormatCommand(&cmd,format,ap); - if (len == -1) { - __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } else if (len == -2) { - __redisSetError(c,REDIS_ERR_OTHER,"Invalid format string"); - return REDIS_ERR; - } - - if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { - free(cmd); - return REDIS_ERR; - } - - free(cmd); - return REDIS_OK; -} - -int redisAppendCommand(redisContext *c, const char *format, ...) { - va_list ap; - int ret; - - va_start(ap,format); - ret = redisvAppendCommand(c,format,ap); - va_end(ap); - return ret; -} - -int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { - sds cmd; - int len; - - len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen); - if (len == -1) { - __redisSetError(c,REDIS_ERR_OOM,"Out of memory"); - return REDIS_ERR; - } - - if (__redisAppendCommand(c,cmd,len) != REDIS_OK) { - sdsfree(cmd); - return REDIS_ERR; - } - - sdsfree(cmd); - return REDIS_OK; -} - -/* Helper function for the redisCommand* family of functions. - * - * Write a formatted command to the output buffer. If the given context is - * blocking, immediately read the reply into the "reply" pointer. When the - * context is non-blocking, the "reply" pointer will not be used and the - * command is simply appended to the write buffer. - * - * Returns the reply when a reply was succesfully retrieved. Returns NULL - * otherwise. When NULL is returned in a blocking context, the error field - * in the context will be set. - */ -static void *__redisBlockForReply(redisContext *c) { - void *reply; - - if (c->flags & REDIS_BLOCK) { - if (redisGetReply(c,&reply) != REDIS_OK) - return NULL; - return reply; - } - return NULL; -} - -void *redisvCommand(redisContext *c, const char *format, va_list ap) { - if (redisvAppendCommand(c,format,ap) != REDIS_OK) - return NULL; - return __redisBlockForReply(c); -} - -void *redisCommand(redisContext *c, const char *format, ...) { - va_list ap; - void *reply = NULL; - va_start(ap,format); - reply = redisvCommand(c,format,ap); - va_end(ap); - return reply; -} - -void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen) { - if (redisAppendCommandArgv(c,argc,argv,argvlen) != REDIS_OK) - return NULL; - return __redisBlockForReply(c); -} diff --git a/ext/hiredis-vip-0.3.0/hiutil.c b/ext/hiredis-vip-0.3.0/hiutil.c deleted file mode 100644 index d10cdacea..000000000 --- a/ext/hiredis-vip-0.3.0/hiutil.c +++ /dev/null @@ -1,554 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - - -#include "hiutil.h" - -#ifdef HI_HAVE_BACKTRACE -# include -#endif - -int -hi_set_blocking(int sd) -{ - int flags; - - flags = fcntl(sd, F_GETFL, 0); - if (flags < 0) { - return flags; - } - - return fcntl(sd, F_SETFL, flags & ~O_NONBLOCK); -} - -int -hi_set_nonblocking(int sd) -{ - int flags; - - flags = fcntl(sd, F_GETFL, 0); - if (flags < 0) { - return flags; - } - - return fcntl(sd, F_SETFL, flags | O_NONBLOCK); -} - -int -hi_set_reuseaddr(int sd) -{ - int reuse; - socklen_t len; - - reuse = 1; - len = sizeof(reuse); - - return setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &reuse, len); -} - -/* - * Disable Nagle algorithm on TCP socket. - * - * This option helps to minimize transmit latency by disabling coalescing - * of data to fill up a TCP segment inside the kernel. Sockets with this - * option must use readv() or writev() to do data transfer in bulk and - * hence avoid the overhead of small packets. - */ -int -hi_set_tcpnodelay(int sd) -{ - int nodelay; - socklen_t len; - - nodelay = 1; - len = sizeof(nodelay); - - return setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, &nodelay, len); -} - -int -hi_set_linger(int sd, int timeout) -{ - struct linger linger; - socklen_t len; - - linger.l_onoff = 1; - linger.l_linger = timeout; - - len = sizeof(linger); - - return setsockopt(sd, SOL_SOCKET, SO_LINGER, &linger, len); -} - -int -hi_set_sndbuf(int sd, int size) -{ - socklen_t len; - - len = sizeof(size); - - return setsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, len); -} - -int -hi_set_rcvbuf(int sd, int size) -{ - socklen_t len; - - len = sizeof(size); - - return setsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, len); -} - -int -hi_get_soerror(int sd) -{ - int status, err; - socklen_t len; - - err = 0; - len = sizeof(err); - - status = getsockopt(sd, SOL_SOCKET, SO_ERROR, &err, &len); - if (status == 0) { - errno = err; - } - - return status; -} - -int -hi_get_sndbuf(int sd) -{ - int status, size; - socklen_t len; - - size = 0; - len = sizeof(size); - - status = getsockopt(sd, SOL_SOCKET, SO_SNDBUF, &size, &len); - if (status < 0) { - return status; - } - - return size; -} - -int -hi_get_rcvbuf(int sd) -{ - int status, size; - socklen_t len; - - size = 0; - len = sizeof(size); - - status = getsockopt(sd, SOL_SOCKET, SO_RCVBUF, &size, &len); - if (status < 0) { - return status; - } - - return size; -} - -int -_hi_atoi(uint8_t *line, size_t n) -{ - int value; - - if (n == 0) { - return -1; - } - - for (value = 0; n--; line++) { - if (*line < '0' || *line > '9') { - return -1; - } - - value = value * 10 + (*line - '0'); - } - - if (value < 0) { - return -1; - } - - return value; -} - -void -_hi_itoa(uint8_t *s, int num) -{ - uint8_t c; - uint8_t sign = 0; - - if(s == NULL) - { - return; - } - - uint32_t len, i; - len = 0; - - if(num < 0) - { - sign = 1; - num = abs(num); - } - else if(num == 0) - { - s[len++] = '0'; - return; - } - - while(num % 10 || num /10) - { - c = num %10 + '0'; - num = num /10; - s[len+1] = s[len]; - s[len] = c; - len ++; - } - - if(sign == 1) - { - s[len++] = '-'; - } - - s[len] = '\0'; - - for(i = 0; i < len/2; i ++) - { - c = s[i]; - s[i] = s[len - i -1]; - s[len - i -1] = c; - } - -} - - -int -hi_valid_port(int n) -{ - if (n < 1 || n > UINT16_MAX) { - return 0; - } - - return 1; -} - -int _uint_len(uint32_t num) -{ - int n = 0; - - if(num == 0) - { - return 1; - } - - while(num != 0) - { - n ++; - num /= 10; - } - - return n; -} - -void * -_hi_alloc(size_t size, const char *name, int line) -{ - void *p; - - ASSERT(size != 0); - - p = malloc(size); - - if(name == NULL && line == 1) - { - - } - - return p; -} - -void * -_hi_zalloc(size_t size, const char *name, int line) -{ - void *p; - - p = _hi_alloc(size, name, line); - if (p != NULL) { - memset(p, 0, size); - } - - return p; -} - -void * -_hi_calloc(size_t nmemb, size_t size, const char *name, int line) -{ - return _hi_zalloc(nmemb * size, name, line); -} - -void * -_hi_realloc(void *ptr, size_t size, const char *name, int line) -{ - void *p; - - ASSERT(size != 0); - - p = realloc(ptr, size); - - if(name == NULL && line == 1) - { - - } - - return p; -} - -void -_hi_free(void *ptr, const char *name, int line) -{ - ASSERT(ptr != NULL); - - if(name == NULL && line == 1) - { - - } - - free(ptr); -} - -void -hi_stacktrace(int skip_count) -{ - if(skip_count > 0) - { - - } - -#ifdef HI_HAVE_BACKTRACE - void *stack[64]; - char **symbols; - int size, i, j; - - size = backtrace(stack, 64); - symbols = backtrace_symbols(stack, size); - if (symbols == NULL) { - return; - } - - skip_count++; /* skip the current frame also */ - - for (i = skip_count, j = 0; i < size; i++, j++) { - printf("[%d] %s\n", j, symbols[i]); - } - - free(symbols); -#endif -} - -void -hi_stacktrace_fd(int fd) -{ - if(fd > 0) - { - - } -#ifdef HI_HAVE_BACKTRACE - void *stack[64]; - int size; - - size = backtrace(stack, 64); - backtrace_symbols_fd(stack, size, fd); -#endif -} - -void -hi_assert(const char *cond, const char *file, int line, int panic) -{ - - printf("File: %s Line: %d: %s\n", file, line, cond); - - if (panic) { - hi_stacktrace(1); - abort(); - } - abort(); -} - -int -_vscnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - int n; - - n = vsnprintf(buf, size, fmt, args); - - /* - * The return value is the number of characters which would be written - * into buf not including the trailing '\0'. If size is == 0 the - * function returns 0. - * - * On error, the function also returns 0. This is to allow idiom such - * as len += _vscnprintf(...) - * - * See: http://lwn.net/Articles/69419/ - */ - if (n <= 0) { - return 0; - } - - if (n < (int) size) { - return n; - } - - return (int)(size - 1); -} - -int -_scnprintf(char *buf, size_t size, const char *fmt, ...) -{ - va_list args; - int n; - - va_start(args, fmt); - n = _vscnprintf(buf, size, fmt, args); - va_end(args); - - return n; -} - -/* - * Send n bytes on a blocking descriptor - */ -ssize_t -_hi_sendn(int sd, const void *vptr, size_t n) -{ - size_t nleft; - ssize_t nsend; - const char *ptr; - - ptr = vptr; - nleft = n; - while (nleft > 0) { - nsend = send(sd, ptr, nleft, 0); - if (nsend < 0) { - if (errno == EINTR) { - continue; - } - return nsend; - } - if (nsend == 0) { - return -1; - } - - nleft -= (size_t)nsend; - ptr += nsend; - } - - return (ssize_t)n; -} - -/* - * Recv n bytes from a blocking descriptor - */ -ssize_t -_hi_recvn(int sd, void *vptr, size_t n) -{ - size_t nleft; - ssize_t nrecv; - char *ptr; - - ptr = vptr; - nleft = n; - while (nleft > 0) { - nrecv = recv(sd, ptr, nleft, 0); - if (nrecv < 0) { - if (errno == EINTR) { - continue; - } - return nrecv; - } - if (nrecv == 0) { - break; - } - - nleft -= (size_t)nrecv; - ptr += nrecv; - } - - return (ssize_t)(n - nleft); -} - -/* - * Return the current time in microseconds since Epoch - */ -int64_t -hi_usec_now(void) -{ - struct timeval now; - int64_t usec; - int status; - - status = gettimeofday(&now, NULL); - if (status < 0) { - return -1; - } - - usec = (int64_t)now.tv_sec * 1000000LL + (int64_t)now.tv_usec; - - return usec; -} - -/* - * Return the current time in milliseconds since Epoch - */ -int64_t -hi_msec_now(void) -{ - return hi_usec_now() / 1000LL; -} - -void print_string_with_length(char *s, size_t len) -{ - char *token; - for(token = s; token <= s + len; token ++) - { - printf("%c", *token); - } - printf("\n"); -} - -void print_string_with_length_fix_CRLF(char *s, size_t len) -{ - char *token; - for(token = s; token < s + len; token ++) - { - if(*token == CR) - { - printf("\\r"); - } - else if(*token == LF) - { - printf("\\n"); - } - else - { - printf("%c", *token); - } - } - printf("\n"); -} - diff --git a/ext/hiredis-vip-0.3.0/hiutil.h b/ext/hiredis-vip-0.3.0/hiutil.h deleted file mode 100644 index d9e1ddb0b..000000000 --- a/ext/hiredis-vip-0.3.0/hiutil.h +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef __HIUTIL_H_ -#define __HIUTIL_H_ - -#include -#include -#include - -#define HI_OK 0 -#define HI_ERROR -1 -#define HI_EAGAIN -2 -#define HI_ENOMEM -3 - -typedef int rstatus_t; /* return type */ - -#define LF (uint8_t) 10 -#define CR (uint8_t) 13 -#define CRLF "\x0d\x0a" -#define CRLF_LEN (sizeof("\x0d\x0a") - 1) - -#define NELEMS(a) ((sizeof(a)) / sizeof((a)[0])) - -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define SQUARE(d) ((d) * (d)) -#define VAR(s, s2, n) (((n) < 2) ? 0.0 : ((s2) - SQUARE(s)/(n)) / ((n) - 1)) -#define STDDEV(s, s2, n) (((n) < 2) ? 0.0 : sqrt(VAR((s), (s2), (n)))) - -#define HI_INET4_ADDRSTRLEN (sizeof("255.255.255.255") - 1) -#define HI_INET6_ADDRSTRLEN \ - (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1) -#define HI_INET_ADDRSTRLEN MAX(HI_INET4_ADDRSTRLEN, HI_INET6_ADDRSTRLEN) -#define HI_UNIX_ADDRSTRLEN \ - (sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path)) - -#define HI_MAXHOSTNAMELEN 256 - -/* - * Length of 1 byte, 2 bytes, 4 bytes, 8 bytes and largest integral - * type (uintmax_t) in ascii, including the null terminator '\0' - * - * From stdint.h, we have: - * # define UINT8_MAX (255) - * # define UINT16_MAX (65535) - * # define UINT32_MAX (4294967295U) - * # define UINT64_MAX (__UINT64_C(18446744073709551615)) - */ -#define HI_UINT8_MAXLEN (3 + 1) -#define HI_UINT16_MAXLEN (5 + 1) -#define HI_UINT32_MAXLEN (10 + 1) -#define HI_UINT64_MAXLEN (20 + 1) -#define HI_UINTMAX_MAXLEN HI_UINT64_MAXLEN - -/* - * Make data 'd' or pointer 'p', n-byte aligned, where n is a power of 2 - * of 2. - */ -#define HI_ALIGNMENT sizeof(unsigned long) /* platform word */ -#define HI_ALIGN(d, n) (((d) + (n - 1)) & ~(n - 1)) -#define HI_ALIGN_PTR(p, n) \ - (void *) (((uintptr_t) (p) + ((uintptr_t) n - 1)) & ~((uintptr_t) n - 1)) - - - -#define str3icmp(m, c0, c1, c2) \ - ((m[0] == c0 || m[0] == (c0 ^ 0x20)) && \ - (m[1] == c1 || m[1] == (c1 ^ 0x20)) && \ - (m[2] == c2 || m[2] == (c2 ^ 0x20))) - -#define str4icmp(m, c0, c1, c2, c3) \ - (str3icmp(m, c0, c1, c2) && (m[3] == c3 || m[3] == (c3 ^ 0x20))) - -#define str5icmp(m, c0, c1, c2, c3, c4) \ - (str4icmp(m, c0, c1, c2, c3) && (m[4] == c4 || m[4] == (c4 ^ 0x20))) - -#define str6icmp(m, c0, c1, c2, c3, c4, c5) \ - (str5icmp(m, c0, c1, c2, c3, c4) && (m[5] == c5 || m[5] == (c5 ^ 0x20))) - -#define str7icmp(m, c0, c1, c2, c3, c4, c5, c6) \ - (str6icmp(m, c0, c1, c2, c3, c4, c5) && \ - (m[6] == c6 || m[6] == (c6 ^ 0x20))) - -#define str8icmp(m, c0, c1, c2, c3, c4, c5, c6, c7) \ - (str7icmp(m, c0, c1, c2, c3, c4, c5, c6) && \ - (m[7] == c7 || m[7] == (c7 ^ 0x20))) - -#define str9icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) \ - (str8icmp(m, c0, c1, c2, c3, c4, c5, c6, c7) && \ - (m[8] == c8 || m[8] == (c8 ^ 0x20))) - -#define str10icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) \ - (str9icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8) && \ - (m[9] == c9 || m[9] == (c9 ^ 0x20))) - -#define str11icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) \ - (str10icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9) && \ - (m[10] == c10 || m[10] == (c10 ^ 0x20))) - -#define str12icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) \ - (str11icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10) && \ - (m[11] == c11 || m[11] == (c11 ^ 0x20))) - -#define str13icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) \ - (str12icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) && \ - (m[12] == c12 || m[12] == (c12 ^ 0x20))) - -#define str14icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) \ - (str13icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12) && \ - (m[13] == c13 || m[13] == (c13 ^ 0x20))) - -#define str15icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14) \ - (str14icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13) && \ - (m[14] == c14 || m[14] == (c14 ^ 0x20))) - -#define str16icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15) \ - (str15icmp(m, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14) && \ - (m[15] == c15 || m[15] == (c15 ^ 0x20))) - - - -/* - * Wrapper to workaround well known, safe, implicit type conversion when - * invoking system calls. - */ -#define hi_gethostname(_name, _len) \ - gethostname((char *)_name, (size_t)_len) - -#define hi_atoi(_line, _n) \ - _hi_atoi((uint8_t *)_line, (size_t)_n) -#define hi_itoa(_line, _n) \ - _hi_itoa((uint8_t *)_line, (int)_n) - -#define uint_len(_n) \ - _uint_len((uint32_t)_n) - - -int hi_set_blocking(int sd); -int hi_set_nonblocking(int sd); -int hi_set_reuseaddr(int sd); -int hi_set_tcpnodelay(int sd); -int hi_set_linger(int sd, int timeout); -int hi_set_sndbuf(int sd, int size); -int hi_set_rcvbuf(int sd, int size); -int hi_get_soerror(int sd); -int hi_get_sndbuf(int sd); -int hi_get_rcvbuf(int sd); - -int _hi_atoi(uint8_t *line, size_t n); -void _hi_itoa(uint8_t *s, int num); - -int hi_valid_port(int n); - -int _uint_len(uint32_t num); - - -/* - * Memory allocation and free wrappers. - * - * These wrappers enables us to loosely detect double free, dangling - * pointer access and zero-byte alloc. - */ -#define hi_alloc(_s) \ - _hi_alloc((size_t)(_s), __FILE__, __LINE__) - -#define hi_zalloc(_s) \ - _hi_zalloc((size_t)(_s), __FILE__, __LINE__) - -#define hi_calloc(_n, _s) \ - _hi_calloc((size_t)(_n), (size_t)(_s), __FILE__, __LINE__) - -#define hi_realloc(_p, _s) \ - _hi_realloc(_p, (size_t)(_s), __FILE__, __LINE__) - -#define hi_free(_p) do { \ - _hi_free(_p, __FILE__, __LINE__); \ - (_p) = NULL; \ -} while (0) - -void *_hi_alloc(size_t size, const char *name, int line); -void *_hi_zalloc(size_t size, const char *name, int line); -void *_hi_calloc(size_t nmemb, size_t size, const char *name, int line); -void *_hi_realloc(void *ptr, size_t size, const char *name, int line); -void _hi_free(void *ptr, const char *name, int line); - - -#define hi_strndup(_s, _n) \ - strndup((char *)(_s), (size_t)(_n)); - -/* - * Wrappers to send or receive n byte message on a blocking - * socket descriptor. - */ -#define hi_sendn(_s, _b, _n) \ - _hi_sendn(_s, _b, (size_t)(_n)) - -#define hi_recvn(_s, _b, _n) \ - _hi_recvn(_s, _b, (size_t)(_n)) - -/* - * Wrappers to read or write data to/from (multiple) buffers - * to a file or socket descriptor. - */ -#define hi_read(_d, _b, _n) \ - read(_d, _b, (size_t)(_n)) - -#define hi_readv(_d, _b, _n) \ - readv(_d, _b, (int)(_n)) - -#define hi_write(_d, _b, _n) \ - write(_d, _b, (size_t)(_n)) - -#define hi_writev(_d, _b, _n) \ - writev(_d, _b, (int)(_n)) - -ssize_t _hi_sendn(int sd, const void *vptr, size_t n); -ssize_t _hi_recvn(int sd, void *vptr, size_t n); - -/* - * Wrappers for defining custom assert based on whether macro - * HI_ASSERT_PANIC or HI_ASSERT_LOG was defined at the moment - * ASSERT was called. - */ -#ifdef HI_ASSERT_PANIC - -#define ASSERT(_x) do { \ - if (!(_x)) { \ - hi_assert(#_x, __FILE__, __LINE__, 1); \ - } \ -} while (0) - -#define NOT_REACHED() ASSERT(0) - -#elif HI_ASSERT_LOG - -#define ASSERT(_x) do { \ - if (!(_x)) { \ - hi_assert(#_x, __FILE__, __LINE__, 0); \ - } \ -} while (0) - -#define NOT_REACHED() ASSERT(0) - -#else - -#define ASSERT(_x) - -#define NOT_REACHED() - -#endif - -void hi_assert(const char *cond, const char *file, int line, int panic); -void hi_stacktrace(int skip_count); -void hi_stacktrace_fd(int fd); - -int _scnprintf(char *buf, size_t size, const char *fmt, ...); -int _vscnprintf(char *buf, size_t size, const char *fmt, va_list args); -int64_t hi_usec_now(void); -int64_t hi_msec_now(void); - -void print_string_with_length(char *s, size_t len); -void print_string_with_length_fix_CRLF(char *s, size_t len); - -uint16_t crc16(const char *buf, int len); - -#endif diff --git a/ext/hiredis-vip-0.3.0/net.c b/ext/hiredis-vip-0.3.0/net.c deleted file mode 100644 index 60a2dc754..000000000 --- a/ext/hiredis-vip-0.3.0/net.c +++ /dev/null @@ -1,458 +0,0 @@ -/* Extracted from anet.c to work properly with Hiredis error reporting. - * - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2014, Pieter Noordhuis - * Copyright (c) 2015, Matt Stancliff , - * Jan-Erik Rediger - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "fmacros.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "net.h" -#include "sds.h" - -/* Defined in hiredis.c */ -void __redisSetError(redisContext *c, int type, const char *str); - -static void redisContextCloseFd(redisContext *c) { - if (c && c->fd >= 0) { - close(c->fd); - c->fd = -1; - } -} - -static void __redisSetErrorFromErrno(redisContext *c, int type, const char *prefix) { - char buf[128] = { 0 }; - size_t len = 0; - - if (prefix != NULL) - len = snprintf(buf,sizeof(buf),"%s: ",prefix); - __redis_strerror_r(errno, (char *)(buf + len), sizeof(buf) - len); - __redisSetError(c,type,buf); -} - -static int redisSetReuseAddr(redisContext *c) { - int on = 1; - if (setsockopt(c->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - redisContextCloseFd(c); - return REDIS_ERR; - } - return REDIS_OK; -} - -static int redisCreateSocket(redisContext *c, int type) { - int s; - if ((s = socket(type, SOCK_STREAM, 0)) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - return REDIS_ERR; - } - c->fd = s; - if (type == AF_INET) { - if (redisSetReuseAddr(c) == REDIS_ERR) { - return REDIS_ERR; - } - } - return REDIS_OK; -} - -static int redisSetBlocking(redisContext *c, int blocking) { - int flags; - - /* Set the socket nonblocking. - * Note that fcntl(2) for F_GETFL and F_SETFL can't be - * interrupted by a signal. */ - if ((flags = fcntl(c->fd, F_GETFL)) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_GETFL)"); - redisContextCloseFd(c); - return REDIS_ERR; - } - - if (blocking) - flags &= ~O_NONBLOCK; - else - flags |= O_NONBLOCK; - - if (fcntl(c->fd, F_SETFL, flags) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"fcntl(F_SETFL)"); - redisContextCloseFd(c); - return REDIS_ERR; - } - return REDIS_OK; -} - -int redisKeepAlive(redisContext *c, int interval) { - int val = 1; - int fd = c->fd; - - if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1){ - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } - - val = interval; - -#ifdef _OSX - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)) < 0) { - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } -#else -#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) - val = interval; - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) { - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } - - val = interval/3; - if (val == 0) val = 1; - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) { - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } - - val = 3; - if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { - __redisSetError(c,REDIS_ERR_OTHER,strerror(errno)); - return REDIS_ERR; - } -#endif -#endif - - return REDIS_OK; -} - -static int redisSetTcpNoDelay(redisContext *c) { - int yes = 1; - if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof(yes)) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(TCP_NODELAY)"); - redisContextCloseFd(c); - return REDIS_ERR; - } - return REDIS_OK; -} - -#define __MAX_MSEC (((LONG_MAX) - 999) / 1000) - -static int redisContextWaitReady(redisContext *c, const struct timeval *timeout) { - struct pollfd wfd[1]; - long msec; - - msec = -1; - wfd[0].fd = c->fd; - wfd[0].events = POLLOUT; - - /* Only use timeout when not NULL. */ - if (timeout != NULL) { - if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) { - __redisSetErrorFromErrno(c, REDIS_ERR_IO, NULL); - redisContextCloseFd(c); - return REDIS_ERR; - } - - msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000); - - if (msec < 0 || msec > INT_MAX) { - msec = INT_MAX; - } - } - - if (errno == EINPROGRESS) { - int res; - - if ((res = poll(wfd, 1, msec)) == -1) { - __redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)"); - redisContextCloseFd(c); - return REDIS_ERR; - } else if (res == 0) { - errno = ETIMEDOUT; - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - redisContextCloseFd(c); - return REDIS_ERR; - } - - if (redisCheckSocketError(c) != REDIS_OK) - return REDIS_ERR; - - return REDIS_OK; - } - - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - redisContextCloseFd(c); - return REDIS_ERR; -} - -int redisCheckSocketError(redisContext *c) { - int err = 0; - socklen_t errlen = sizeof(err); - - if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"getsockopt(SO_ERROR)"); - return REDIS_ERR; - } - - if (err) { - errno = err; - __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL); - return REDIS_ERR; - } - - return REDIS_OK; -} - -int redisContextSetTimeout(redisContext *c, const struct timeval tv) { - if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv)) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)"); - return REDIS_ERR; - } - if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,&tv,sizeof(tv)) == -1) { - __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)"); - return REDIS_ERR; - } - return REDIS_OK; -} - -static int _redisContextConnectTcp(redisContext *c, const char *addr, int port, - const struct timeval *timeout, - const char *source_addr) { - int s, rv, n; - char _port[6]; /* strlen("65535"); */ - struct addrinfo hints, *servinfo, *bservinfo, *p, *b; - int blocking = (c->flags & REDIS_BLOCK); - int reuseaddr = (c->flags & REDIS_REUSEADDR); - int reuses = 0; - - c->connection_type = REDIS_CONN_TCP; - c->tcp.port = port; - - /* We need to take possession of the passed parameters - * to make them reusable for a reconnect. - * We also carefully check we don't free data we already own, - * as in the case of the reconnect method. - * - * This is a bit ugly, but atleast it works and doesn't leak memory. - **/ - if (c->tcp.host != addr) { - if (c->tcp.host) - free(c->tcp.host); - - c->tcp.host = strdup(addr); - } - - if (timeout) { - if (c->timeout != timeout) { - if (c->timeout == NULL) - c->timeout = malloc(sizeof(struct timeval)); - - memcpy(c->timeout, timeout, sizeof(struct timeval)); - } - } else { - if (c->timeout) - free(c->timeout); - c->timeout = NULL; - } - - if (source_addr == NULL) { - free(c->tcp.source_addr); - c->tcp.source_addr = NULL; - } else if (c->tcp.source_addr != source_addr) { - free(c->tcp.source_addr); - c->tcp.source_addr = strdup(source_addr); - } - - snprintf(_port, 6, "%d", port); - memset(&hints,0,sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - /* Try with IPv6 if no IPv4 address was found. We do it in this order since - * in a Redis client you can't afford to test if you have IPv6 connectivity - * as this would add latency to every connect. Otherwise a more sensible - * route could be: Use IPv6 if both addresses are available and there is IPv6 - * connectivity. */ - if ((rv = getaddrinfo(c->tcp.host,_port,&hints,&servinfo)) != 0) { - hints.ai_family = AF_INET6; - if ((rv = getaddrinfo(addr,_port,&hints,&servinfo)) != 0) { - __redisSetError(c,REDIS_ERR_OTHER,gai_strerror(rv)); - return REDIS_ERR; - } - } - for (p = servinfo; p != NULL; p = p->ai_next) { -addrretry: - if ((s = socket(p->ai_family,p->ai_socktype,p->ai_protocol)) == -1) - continue; - - c->fd = s; - if (redisSetBlocking(c,0) != REDIS_OK) - goto error; - if (c->tcp.source_addr) { - int bound = 0; - /* Using getaddrinfo saves us from self-determining IPv4 vs IPv6 */ - if ((rv = getaddrinfo(c->tcp.source_addr, NULL, &hints, &bservinfo)) != 0) { - char buf[128]; - snprintf(buf,sizeof(buf),"Can't get addr: %s",gai_strerror(rv)); - __redisSetError(c,REDIS_ERR_OTHER,buf); - goto error; - } - - if (reuseaddr) { - n = 1; - if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*) &n, - sizeof(n)) < 0) { - goto error; - } - } - - for (b = bservinfo; b != NULL; b = b->ai_next) { - if (bind(s,b->ai_addr,b->ai_addrlen) != -1) { - bound = 1; - break; - } - } - freeaddrinfo(bservinfo); - if (!bound) { - char buf[128]; - snprintf(buf,sizeof(buf),"Can't bind socket: %s",strerror(errno)); - __redisSetError(c,REDIS_ERR_OTHER,buf); - goto error; - } - } - if (connect(s,p->ai_addr,p->ai_addrlen) == -1) { - if (errno == EHOSTUNREACH) { - redisContextCloseFd(c); - continue; - } else if (errno == EINPROGRESS && !blocking) { - /* This is ok. */ - } else if (errno == EADDRNOTAVAIL && reuseaddr) { - if (++reuses >= REDIS_CONNECT_RETRIES) { - goto error; - } else { - goto addrretry; - } - } else { - if (redisContextWaitReady(c,c->timeout) != REDIS_OK) - goto error; - } - } - if (blocking && redisSetBlocking(c,1) != REDIS_OK) - goto error; - if (redisSetTcpNoDelay(c) != REDIS_OK) - goto error; - - c->flags |= REDIS_CONNECTED; - rv = REDIS_OK; - goto end; - } - if (p == NULL) { - char buf[128]; - snprintf(buf,sizeof(buf),"Can't create socket: %s",strerror(errno)); - __redisSetError(c,REDIS_ERR_OTHER,buf); - goto error; - } - -error: - rv = REDIS_ERR; -end: - freeaddrinfo(servinfo); - return rv; // Need to return REDIS_OK if alright -} - -int redisContextConnectTcp(redisContext *c, const char *addr, int port, - const struct timeval *timeout) { - return _redisContextConnectTcp(c, addr, port, timeout, NULL); -} - -int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, - const struct timeval *timeout, - const char *source_addr) { - return _redisContextConnectTcp(c, addr, port, timeout, source_addr); -} - -int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout) { - int blocking = (c->flags & REDIS_BLOCK); - struct sockaddr_un sa; - - if (redisCreateSocket(c,AF_LOCAL) < 0) - return REDIS_ERR; - if (redisSetBlocking(c,0) != REDIS_OK) - return REDIS_ERR; - - c->connection_type = REDIS_CONN_UNIX; - if (c->unix_sock.path != path) - c->unix_sock.path = strdup(path); - - if (timeout) { - if (c->timeout != timeout) { - if (c->timeout == NULL) - c->timeout = malloc(sizeof(struct timeval)); - - memcpy(c->timeout, timeout, sizeof(struct timeval)); - } - } else { - if (c->timeout) - free(c->timeout); - c->timeout = NULL; - } - - sa.sun_family = AF_LOCAL; - strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1); - if (connect(c->fd, (struct sockaddr*)&sa, sizeof(sa)) == -1) { - if (errno == EINPROGRESS && !blocking) { - /* This is ok. */ - } else { - if (redisContextWaitReady(c,c->timeout) != REDIS_OK) - return REDIS_ERR; - } - } - - /* Reset socket to be blocking after connect(2). */ - if (blocking && redisSetBlocking(c,1) != REDIS_OK) - return REDIS_ERR; - - c->flags |= REDIS_CONNECTED; - return REDIS_OK; -} diff --git a/ext/hiredis-vip-0.3.0/read.c b/ext/hiredis-vip-0.3.0/read.c deleted file mode 100644 index df1a467a9..000000000 --- a/ext/hiredis-vip-0.3.0/read.c +++ /dev/null @@ -1,525 +0,0 @@ -/* - * Copyright (c) 2009-2011, Salvatore Sanfilippo - * Copyright (c) 2010-2011, Pieter Noordhuis - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -#include "fmacros.h" -#include -#include -#ifndef _MSC_VER -#include -#endif -#include -#include -#include - -#include "read.h" -#include "sds.h" - -static void __redisReaderSetError(redisReader *r, int type, const char *str) { - size_t len; - - if (r->reply != NULL && r->fn && r->fn->freeObject) { - r->fn->freeObject(r->reply); - r->reply = NULL; - } - - /* Clear input buffer on errors. */ - if (r->buf != NULL) { - sdsfree(r->buf); - r->buf = NULL; - r->pos = r->len = 0; - } - - /* Reset task stack. */ - r->ridx = -1; - - /* Set error. */ - r->err = type; - len = strlen(str); - len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1); - memcpy(r->errstr,str,len); - r->errstr[len] = '\0'; -} - -static size_t chrtos(char *buf, size_t size, char byte) { - size_t len = 0; - - switch(byte) { - case '\\': - case '"': - len = snprintf(buf,size,"\"\\%c\"",byte); - break; - case '\n': len = snprintf(buf,size,"\"\\n\""); break; - case '\r': len = snprintf(buf,size,"\"\\r\""); break; - case '\t': len = snprintf(buf,size,"\"\\t\""); break; - case '\a': len = snprintf(buf,size,"\"\\a\""); break; - case '\b': len = snprintf(buf,size,"\"\\b\""); break; - default: - if (isprint(byte)) - len = snprintf(buf,size,"\"%c\"",byte); - else - len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte); - break; - } - - return len; -} - -static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) { - char cbuf[8], sbuf[128]; - - chrtos(cbuf,sizeof(cbuf),byte); - snprintf(sbuf,sizeof(sbuf), - "Protocol error, got %s as reply type byte", cbuf); - __redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf); -} - -static void __redisReaderSetErrorOOM(redisReader *r) { - __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory"); -} - -static char *readBytes(redisReader *r, unsigned int bytes) { - char *p; - if (r->len-r->pos >= bytes) { - p = r->buf+r->pos; - r->pos += bytes; - return p; - } - return NULL; -} - -/* Find pointer to \r\n. */ -static char *seekNewline(char *s, size_t len) { - int pos = 0; - int _len = len-1; - - /* Position should be < len-1 because the character at "pos" should be - * followed by a \n. Note that strchr cannot be used because it doesn't - * allow to search a limited length and the buffer that is being searched - * might not have a trailing NULL character. */ - while (pos < _len) { - while(pos < _len && s[pos] != '\r') pos++; - if (s[pos] != '\r') { - /* Not found. */ - return NULL; - } else { - if (s[pos+1] == '\n') { - /* Found. */ - return s+pos; - } else { - /* Continue searching. */ - pos++; - } - } - } - return NULL; -} - -/* Read a long long value starting at *s, under the assumption that it will be - * terminated by \r\n. Ambiguously returns -1 for unexpected input. */ -static long long readLongLong(char *s) { - long long v = 0; - int dec, mult = 1; - char c; - - if (*s == '-') { - mult = -1; - s++; - } else if (*s == '+') { - mult = 1; - s++; - } - - while ((c = *(s++)) != '\r') { - dec = c - '0'; - if (dec >= 0 && dec < 10) { - v *= 10; - v += dec; - } else { - /* Should not happen... */ - return -1; - } - } - - return mult*v; -} - -static char *readLine(redisReader *r, int *_len) { - char *p, *s; - int len; - - p = r->buf+r->pos; - s = seekNewline(p,(r->len-r->pos)); - if (s != NULL) { - len = s-(r->buf+r->pos); - r->pos += len+2; /* skip \r\n */ - if (_len) *_len = len; - return p; - } - return NULL; -} - -static void moveToNextTask(redisReader *r) { - redisReadTask *cur, *prv; - while (r->ridx >= 0) { - /* Return a.s.a.p. when the stack is now empty. */ - if (r->ridx == 0) { - r->ridx--; - return; - } - - cur = &(r->rstack[r->ridx]); - prv = &(r->rstack[r->ridx-1]); - assert(prv->type == REDIS_REPLY_ARRAY); - if (cur->idx == prv->elements-1) { - r->ridx--; - } else { - /* Reset the type because the next item can be anything */ - assert(cur->idx < prv->elements); - cur->type = -1; - cur->elements = -1; - cur->idx++; - return; - } - } -} - -static int processLineItem(redisReader *r) { - redisReadTask *cur = &(r->rstack[r->ridx]); - void *obj; - char *p; - int len; - - if ((p = readLine(r,&len)) != NULL) { - if (cur->type == REDIS_REPLY_INTEGER) { - if (r->fn && r->fn->createInteger) - obj = r->fn->createInteger(cur,readLongLong(p)); - else - obj = (void*)REDIS_REPLY_INTEGER; - } else { - /* Type will be error or status. */ - if (r->fn && r->fn->createString) - obj = r->fn->createString(cur,p,len); - else - obj = (void*)(size_t)(cur->type); - } - - if (obj == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - /* Set reply if this is the root object. */ - if (r->ridx == 0) r->reply = obj; - moveToNextTask(r); - return REDIS_OK; - } - - return REDIS_ERR; -} - -static int processBulkItem(redisReader *r) { - redisReadTask *cur = &(r->rstack[r->ridx]); - void *obj = NULL; - char *p, *s; - long len; - unsigned long bytelen; - int success = 0; - - p = r->buf+r->pos; - s = seekNewline(p,r->len-r->pos); - if (s != NULL) { - p = r->buf+r->pos; - bytelen = s-(r->buf+r->pos)+2; /* include \r\n */ - len = readLongLong(p); - - if (len < 0) { - /* The nil object can always be created. */ - if (r->fn && r->fn->createNil) - obj = r->fn->createNil(cur); - else - obj = (void*)REDIS_REPLY_NIL; - success = 1; - } else { - /* Only continue when the buffer contains the entire bulk item. */ - bytelen += len+2; /* include \r\n */ - if (r->pos+bytelen <= r->len) { - if (r->fn && r->fn->createString) - obj = r->fn->createString(cur,s+2,len); - else - obj = (void*)REDIS_REPLY_STRING; - success = 1; - } - } - - /* Proceed when obj was created. */ - if (success) { - if (obj == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - r->pos += bytelen; - - /* Set reply if this is the root object. */ - if (r->ridx == 0) r->reply = obj; - moveToNextTask(r); - return REDIS_OK; - } - } - - return REDIS_ERR; -} - -static int processMultiBulkItem(redisReader *r) { - redisReadTask *cur = &(r->rstack[r->ridx]); - void *obj; - char *p; - long elements; - int root = 0; - - /* Set error for nested multi bulks with depth > 7 */ - if (r->ridx == 8) { - __redisReaderSetError(r,REDIS_ERR_PROTOCOL, - "No support for nested multi bulk replies with depth > 7"); - return REDIS_ERR; - } - - if ((p = readLine(r,NULL)) != NULL) { - elements = readLongLong(p); - root = (r->ridx == 0); - - if (elements == -1) { - if (r->fn && r->fn->createNil) - obj = r->fn->createNil(cur); - else - obj = (void*)REDIS_REPLY_NIL; - - if (obj == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - moveToNextTask(r); - } else { - if (r->fn && r->fn->createArray) - obj = r->fn->createArray(cur,elements); - else - obj = (void*)REDIS_REPLY_ARRAY; - - if (obj == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - /* Modify task stack when there are more than 0 elements. */ - if (elements > 0) { - cur->elements = elements; - cur->obj = obj; - r->ridx++; - r->rstack[r->ridx].type = -1; - r->rstack[r->ridx].elements = -1; - r->rstack[r->ridx].idx = 0; - r->rstack[r->ridx].obj = NULL; - r->rstack[r->ridx].parent = cur; - r->rstack[r->ridx].privdata = r->privdata; - } else { - moveToNextTask(r); - } - } - - /* Set reply if this is the root object. */ - if (root) r->reply = obj; - return REDIS_OK; - } - - return REDIS_ERR; -} - -static int processItem(redisReader *r) { - redisReadTask *cur = &(r->rstack[r->ridx]); - char *p; - - /* check if we need to read type */ - if (cur->type < 0) { - if ((p = readBytes(r,1)) != NULL) { - switch (p[0]) { - case '-': - cur->type = REDIS_REPLY_ERROR; - break; - case '+': - cur->type = REDIS_REPLY_STATUS; - break; - case ':': - cur->type = REDIS_REPLY_INTEGER; - break; - case '$': - cur->type = REDIS_REPLY_STRING; - break; - case '*': - cur->type = REDIS_REPLY_ARRAY; - break; - default: - __redisReaderSetErrorProtocolByte(r,*p); - return REDIS_ERR; - } - } else { - /* could not consume 1 byte */ - return REDIS_ERR; - } - } - - /* process typed item */ - switch(cur->type) { - case REDIS_REPLY_ERROR: - case REDIS_REPLY_STATUS: - case REDIS_REPLY_INTEGER: - return processLineItem(r); - case REDIS_REPLY_STRING: - return processBulkItem(r); - case REDIS_REPLY_ARRAY: - return processMultiBulkItem(r); - default: - assert(NULL); - return REDIS_ERR; /* Avoid warning. */ - } -} - -redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) { - redisReader *r; - - r = calloc(sizeof(redisReader),1); - if (r == NULL) - return NULL; - - r->err = 0; - r->errstr[0] = '\0'; - r->fn = fn; - r->buf = sdsempty(); - r->maxbuf = REDIS_READER_MAX_BUF; - if (r->buf == NULL) { - free(r); - return NULL; - } - - r->ridx = -1; - return r; -} - -void redisReaderFree(redisReader *r) { - if (r->reply != NULL && r->fn && r->fn->freeObject) - r->fn->freeObject(r->reply); - if (r->buf != NULL) - sdsfree(r->buf); - free(r); -} - -int redisReaderFeed(redisReader *r, const char *buf, size_t len) { - sds newbuf; - - /* Return early when this reader is in an erroneous state. */ - if (r->err) - return REDIS_ERR; - - /* Copy the provided buffer. */ - if (buf != NULL && len >= 1) { - /* Destroy internal buffer when it is empty and is quite large. */ - if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) { - sdsfree(r->buf); - r->buf = sdsempty(); - r->pos = 0; - - /* r->buf should not be NULL since we just free'd a larger one. */ - assert(r->buf != NULL); - } - - newbuf = sdscatlen(r->buf,buf,len); - if (newbuf == NULL) { - __redisReaderSetErrorOOM(r); - return REDIS_ERR; - } - - r->buf = newbuf; - r->len = sdslen(r->buf); - } - - return REDIS_OK; -} - -int redisReaderGetReply(redisReader *r, void **reply) { - /* Default target pointer to NULL. */ - if (reply != NULL) - *reply = NULL; - - /* Return early when this reader is in an erroneous state. */ - if (r->err) - return REDIS_ERR; - - /* When the buffer is empty, there will never be a reply. */ - if (r->len == 0) - return REDIS_OK; - - /* Set first item to process when the stack is empty. */ - if (r->ridx == -1) { - r->rstack[0].type = -1; - r->rstack[0].elements = -1; - r->rstack[0].idx = -1; - r->rstack[0].obj = NULL; - r->rstack[0].parent = NULL; - r->rstack[0].privdata = r->privdata; - r->ridx = 0; - } - - /* Process items in reply. */ - while (r->ridx >= 0) - if (processItem(r) != REDIS_OK) - break; - - /* Return ASAP when an error occurred. */ - if (r->err) - return REDIS_ERR; - - /* Discard part of the buffer when we've consumed at least 1k, to avoid - * doing unnecessary calls to memmove() in sds.c. */ - if (r->pos >= 1024) { - sdsrange(r->buf,r->pos,-1); - r->pos = 0; - r->len = sdslen(r->buf); - } - - /* Emit a reply when there is one. */ - if (r->ridx == -1) { - if (reply != NULL) - *reply = r->reply; - r->reply = NULL; - } - return REDIS_OK; -} diff --git a/ext/hiredis-vip-0.3.0/sds.c b/ext/hiredis-vip-0.3.0/sds.c deleted file mode 100644 index 5d55b7792..000000000 --- a/ext/hiredis-vip-0.3.0/sds.c +++ /dev/null @@ -1,1095 +0,0 @@ -/* SDS (Simple Dynamic Strings), A C dynamic strings library. - * - * Copyright (c) 2006-2014, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include - -#include "sds.h" - -/* Create a new sds string with the content specified by the 'init' pointer - * and 'initlen'. - * If NULL is used for 'init' the string is initialized with zero bytes. - * - * The string is always null-termined (all the sds strings are, always) so - * even if you create an sds string with: - * - * mystring = sdsnewlen("abc",3"); - * - * You can print the string with printf() as there is an implicit \0 at the - * end of the string. However the string is binary safe and can contain - * \0 characters in the middle, as the length is stored in the sds header. */ -sds sdsnewlen(const void *init, size_t initlen) { - struct sdshdr *sh; - - if (init) { - sh = malloc(sizeof *sh+initlen+1); - } else { - sh = calloc(sizeof *sh+initlen+1,1); - } - if (sh == NULL) return NULL; - sh->len = initlen; - sh->free = 0; - if (initlen && init) - memcpy(sh->buf, init, initlen); - sh->buf[initlen] = '\0'; - return (char*)sh->buf; -} - -/* Create an empty (zero length) sds string. Even in this case the string - * always has an implicit null term. */ -sds sdsempty(void) { - return sdsnewlen("",0); -} - -/* Create a new sds string starting from a null termined C string. */ -sds sdsnew(const char *init) { - size_t initlen = (init == NULL) ? 0 : strlen(init); - return sdsnewlen(init, initlen); -} - -/* Duplicate an sds string. */ -sds sdsdup(const sds s) { - return sdsnewlen(s, sdslen(s)); -} - -/* Free an sds string. No operation is performed if 's' is NULL. */ -void sdsfree(sds s) { - if (s == NULL) return; - free(s-sizeof(struct sdshdr)); -} - -/* Set the sds string length to the length as obtained with strlen(), so - * considering as content only up to the first null term character. - * - * This function is useful when the sds string is hacked manually in some - * way, like in the following example: - * - * s = sdsnew("foobar"); - * s[2] = '\0'; - * sdsupdatelen(s); - * printf("%d\n", sdslen(s)); - * - * The output will be "2", but if we comment out the call to sdsupdatelen() - * the output will be "6" as the string was modified but the logical length - * remains 6 bytes. */ -void sdsupdatelen(sds s) { - struct sdshdr *sh = (void*) (s-sizeof *sh); - int reallen = strlen(s); - sh->free += (sh->len-reallen); - sh->len = reallen; -} - -/* Modify an sds string on-place to make it empty (zero length). - * However all the existing buffer is not discarded but set as free space - * so that next append operations will not require allocations up to the - * number of bytes previously available. */ -void sdsclear(sds s) { - struct sdshdr *sh = (void*) (s-sizeof *sh); - sh->free += sh->len; - sh->len = 0; - sh->buf[0] = '\0'; -} - -/* Enlarge the free space at the end of the sds string so that the caller - * is sure that after calling this function can overwrite up to addlen - * bytes after the end of the string, plus one more byte for nul term. - * - * Note: this does not change the *length* of the sds string as returned - * by sdslen(), but only the free buffer space we have. */ -sds sdsMakeRoomFor(sds s, size_t addlen) { - struct sdshdr *sh, *newsh; - size_t free = sdsavail(s); - size_t len, newlen; - - if (free >= addlen) return s; - len = sdslen(s); - sh = (void*) (s-sizeof *sh); - newlen = (len+addlen); - if (newlen < SDS_MAX_PREALLOC) - newlen *= 2; - else - newlen += SDS_MAX_PREALLOC; - newsh = realloc(sh, sizeof *newsh+newlen+1); - if (newsh == NULL) return NULL; - - newsh->free = newlen - len; - return newsh->buf; -} - -/* Reallocate the sds string so that it has no free space at the end. The - * contained string remains not altered, but next concatenation operations - * will require a reallocation. - * - * After the call, the passed sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdsRemoveFreeSpace(sds s) { - struct sdshdr *sh; - - sh = (void*) (s-sizeof *sh); - sh = realloc(sh, sizeof *sh+sh->len+1); - sh->free = 0; - return sh->buf; -} - -/* Return the total size of the allocation of the specifed sds string, - * including: - * 1) The sds header before the pointer. - * 2) The string. - * 3) The free buffer at the end if any. - * 4) The implicit null term. - */ -size_t sdsAllocSize(sds s) { - struct sdshdr *sh = (void*) (s-sizeof *sh); - - return sizeof(*sh)+sh->len+sh->free+1; -} - -/* Increment the sds length and decrements the left free space at the - * end of the string according to 'incr'. Also set the null term - * in the new end of the string. - * - * This function is used in order to fix the string length after the - * user calls sdsMakeRoomFor(), writes something after the end of - * the current string, and finally needs to set the new length. - * - * Note: it is possible to use a negative increment in order to - * right-trim the string. - * - * Usage example: - * - * Using sdsIncrLen() and sdsMakeRoomFor() it is possible to mount the - * following schema, to cat bytes coming from the kernel to the end of an - * sds string without copying into an intermediate buffer: - * - * oldlen = sdslen(s); - * s = sdsMakeRoomFor(s, BUFFER_SIZE); - * nread = read(fd, s+oldlen, BUFFER_SIZE); - * ... check for nread <= 0 and handle it ... - * sdsIncrLen(s, nread); - */ -void sdsIncrLen(sds s, int incr) { - struct sdshdr *sh = (void*) (s-sizeof *sh); - - assert(sh->free >= incr); - sh->len += incr; - sh->free -= incr; - assert(sh->free >= 0); - s[sh->len] = '\0'; -} - -/* Grow the sds to have the specified length. Bytes that were not part of - * the original length of the sds will be set to zero. - * - * if the specified length is smaller than the current length, no operation - * is performed. */ -sds sdsgrowzero(sds s, size_t len) { - struct sdshdr *sh = (void*) (s-sizeof *sh); - size_t totlen, curlen = sh->len; - - if (len <= curlen) return s; - s = sdsMakeRoomFor(s,len-curlen); - if (s == NULL) return NULL; - - /* Make sure added region doesn't contain garbage */ - sh = (void*)(s-sizeof *sh); - memset(s+curlen,0,(len-curlen+1)); /* also set trailing \0 byte */ - totlen = sh->len+sh->free; - sh->len = len; - sh->free = totlen-sh->len; - return s; -} - -/* Append the specified binary-safe string pointed by 't' of 'len' bytes to the - * end of the specified sds string 's'. - * - * After the call, the passed sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdscatlen(sds s, const void *t, size_t len) { - struct sdshdr *sh; - size_t curlen = sdslen(s); - - s = sdsMakeRoomFor(s,len); - if (s == NULL) return NULL; - sh = (void*) (s-sizeof *sh); - memcpy(s+curlen, t, len); - sh->len = curlen+len; - sh->free = sh->free-len; - s[curlen+len] = '\0'; - return s; -} - -/* Append the specified null termianted C string to the sds string 's'. - * - * After the call, the passed sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdscat(sds s, const char *t) { - return sdscatlen(s, t, strlen(t)); -} - -/* Append the specified sds 't' to the existing sds 's'. - * - * After the call, the modified sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdscatsds(sds s, const sds t) { - return sdscatlen(s, t, sdslen(t)); -} - -/* Destructively modify the sds string 's' to hold the specified binary - * safe string pointed by 't' of length 'len' bytes. */ -sds sdscpylen(sds s, const char *t, size_t len) { - struct sdshdr *sh = (void*) (s-sizeof *sh); - size_t totlen = sh->free+sh->len; - - if (totlen < len) { - s = sdsMakeRoomFor(s,len-sh->len); - if (s == NULL) return NULL; - sh = (void*) (s-sizeof *sh); - totlen = sh->free+sh->len; - } - memcpy(s, t, len); - s[len] = '\0'; - sh->len = len; - sh->free = totlen-len; - return s; -} - -/* Like sdscpylen() but 't' must be a null-termined string so that the length - * of the string is obtained with strlen(). */ -sds sdscpy(sds s, const char *t) { - return sdscpylen(s, t, strlen(t)); -} - -/* Helper for sdscatlonglong() doing the actual number -> string - * conversion. 's' must point to a string with room for at least - * SDS_LLSTR_SIZE bytes. - * - * The function returns the lenght of the null-terminated string - * representation stored at 's'. */ -#define SDS_LLSTR_SIZE 21 -int sdsll2str(char *s, long long value) { - char *p, aux; - unsigned long long v; - size_t l; - - /* Generate the string representation, this method produces - * an reversed string. */ - v = (value < 0) ? -value : value; - p = s; - do { - *p++ = '0'+(v%10); - v /= 10; - } while(v); - if (value < 0) *p++ = '-'; - - /* Compute length and add null term. */ - l = p-s; - *p = '\0'; - - /* Reverse the string. */ - p--; - while(s < p) { - aux = *s; - *s = *p; - *p = aux; - s++; - p--; - } - return l; -} - -/* Identical sdsll2str(), but for unsigned long long type. */ -int sdsull2str(char *s, unsigned long long v) { - char *p, aux; - size_t l; - - /* Generate the string representation, this method produces - * an reversed string. */ - p = s; - do { - *p++ = '0'+(v%10); - v /= 10; - } while(v); - - /* Compute length and add null term. */ - l = p-s; - *p = '\0'; - - /* Reverse the string. */ - p--; - while(s < p) { - aux = *s; - *s = *p; - *p = aux; - s++; - p--; - } - return l; -} - -/* Like sdscatpritf() but gets va_list instead of being variadic. */ -sds sdscatvprintf(sds s, const char *fmt, va_list ap) { - va_list cpy; - char *buf, *t; - size_t buflen = 16; - - while(1) { - buf = malloc(buflen); - if (buf == NULL) return NULL; - buf[buflen-2] = '\0'; - va_copy(cpy,ap); - vsnprintf(buf, buflen, fmt, cpy); - if (buf[buflen-2] != '\0') { - free(buf); - buflen *= 2; - continue; - } - break; - } - t = sdscat(s, buf); - free(buf); - return t; -} - -/* Append to the sds string 's' a string obtained using printf-alike format - * specifier. - * - * After the call, the modified sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. - * - * Example: - * - * s = sdsnew("Sum is: "); - * s = sdscatprintf(s,"%d+%d = %d",a,b,a+b); - * - * Often you need to create a string from scratch with the printf-alike - * format. When this is the need, just use sdsempty() as the target string: - * - * s = sdscatprintf(sdsempty(), "... your format ...", args); - */ -sds sdscatprintf(sds s, const char *fmt, ...) { - va_list ap; - char *t; - va_start(ap, fmt); - t = sdscatvprintf(s,fmt,ap); - va_end(ap); - return t; -} - -/* This function is similar to sdscatprintf, but much faster as it does - * not rely on sprintf() family functions implemented by the libc that - * are often very slow. Moreover directly handling the sds string as - * new data is concatenated provides a performance improvement. - * - * However this function only handles an incompatible subset of printf-alike - * format specifiers: - * - * %s - C String - * %S - SDS string - * %i - signed int - * %I - 64 bit signed integer (long long, int64_t) - * %u - unsigned int - * %U - 64 bit unsigned integer (unsigned long long, uint64_t) - * %T - A size_t variable. - * %% - Verbatim "%" character. - */ -sds sdscatfmt(sds s, char const *fmt, ...) { - struct sdshdr *sh = (void*) (s-(sizeof(struct sdshdr))); - size_t initlen = sdslen(s); - const char *f = fmt; - int i; - va_list ap; - - va_start(ap,fmt); - f = fmt; /* Next format specifier byte to process. */ - i = initlen; /* Position of the next byte to write to dest str. */ - while(*f) { - char next, *str; - int l; - long long num; - unsigned long long unum; - - /* Make sure there is always space for at least 1 char. */ - if (sh->free == 0) { - s = sdsMakeRoomFor(s,1); - sh = (void*) (s-(sizeof(struct sdshdr))); - } - - switch(*f) { - case '%': - next = *(f+1); - f++; - switch(next) { - case 's': - case 'S': - str = va_arg(ap,char*); - l = (next == 's') ? strlen(str) : sdslen(str); - if (sh->free < l) { - s = sdsMakeRoomFor(s,l); - sh = (void*) (s-(sizeof(struct sdshdr))); - } - memcpy(s+i,str,l); - sh->len += l; - sh->free -= l; - i += l; - break; - case 'i': - case 'I': - if (next == 'i') - num = va_arg(ap,int); - else - num = va_arg(ap,long long); - { - char buf[SDS_LLSTR_SIZE]; - l = sdsll2str(buf,num); - if (sh->free < l) { - s = sdsMakeRoomFor(s,l); - sh = (void*) (s-(sizeof(struct sdshdr))); - } - memcpy(s+i,buf,l); - sh->len += l; - sh->free -= l; - i += l; - } - break; - case 'u': - case 'U': - case 'T': - if (next == 'u') - unum = va_arg(ap,unsigned int); - else if(next == 'U') - unum = va_arg(ap,unsigned long long); - else - unum = (unsigned long long)va_arg(ap,size_t); - { - char buf[SDS_LLSTR_SIZE]; - l = sdsull2str(buf,unum); - if (sh->free < l) { - s = sdsMakeRoomFor(s,l); - sh = (void*) (s-(sizeof(struct sdshdr))); - } - memcpy(s+i,buf,l); - sh->len += l; - sh->free -= l; - i += l; - } - break; - default: /* Handle %% and generally %. */ - s[i++] = next; - sh->len += 1; - sh->free -= 1; - break; - } - break; - default: - s[i++] = *f; - sh->len += 1; - sh->free -= 1; - break; - } - f++; - } - va_end(ap); - - /* Add null-term */ - s[i] = '\0'; - return s; -} - - -/* Remove the part of the string from left and from right composed just of - * contiguous characters found in 'cset', that is a null terminted C string. - * - * After the call, the modified sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. - * - * Example: - * - * s = sdsnew("AA...AA.a.aa.aHelloWorld :::"); - * s = sdstrim(s,"A. :"); - * printf("%s\n", s); - * - * Output will be just "Hello World". - */ -void sdstrim(sds s, const char *cset) { - struct sdshdr *sh = (void*) (s-sizeof *sh); - char *start, *end, *sp, *ep; - size_t len; - - sp = start = s; - ep = end = s+sdslen(s)-1; - while(sp <= end && strchr(cset, *sp)) sp++; - while(ep > start && strchr(cset, *ep)) ep--; - len = (sp > ep) ? 0 : ((ep-sp)+1); - if (sh->buf != sp) memmove(sh->buf, sp, len); - sh->buf[len] = '\0'; - sh->free = sh->free+(sh->len-len); - sh->len = len; -} - -/* Turn the string into a smaller (or equal) string containing only the - * substring specified by the 'start' and 'end' indexes. - * - * start and end can be negative, where -1 means the last character of the - * string, -2 the penultimate character, and so forth. - * - * The interval is inclusive, so the start and end characters will be part - * of the resulting string. - * - * The string is modified in-place. - * - * Example: - * - * s = sdsnew("Hello World"); - * sdsrange(s,1,-1); => "ello World" - */ -void sdsrange(sds s, int start, int end) { - struct sdshdr *sh = (void*) (s-sizeof *sh); - size_t newlen, len = sdslen(s); - - if (len == 0) return; - if (start < 0) { - start = len+start; - if (start < 0) start = 0; - } - if (end < 0) { - end = len+end; - if (end < 0) end = 0; - } - newlen = (start > end) ? 0 : (end-start)+1; - if (newlen != 0) { - if (start >= (signed)len) { - newlen = 0; - } else if (end >= (signed)len) { - end = len-1; - newlen = (start > end) ? 0 : (end-start)+1; - } - } else { - start = 0; - } - if (start && newlen) memmove(sh->buf, sh->buf+start, newlen); - sh->buf[newlen] = 0; - sh->free = sh->free+(sh->len-newlen); - sh->len = newlen; -} - -/* Apply tolower() to every character of the sds string 's'. */ -void sdstolower(sds s) { - int len = sdslen(s), j; - - for (j = 0; j < len; j++) s[j] = tolower(s[j]); -} - -/* Apply toupper() to every character of the sds string 's'. */ -void sdstoupper(sds s) { - int len = sdslen(s), j; - - for (j = 0; j < len; j++) s[j] = toupper(s[j]); -} - -/* Compare two sds strings s1 and s2 with memcmp(). - * - * Return value: - * - * 1 if s1 > s2. - * -1 if s1 < s2. - * 0 if s1 and s2 are exactly the same binary string. - * - * If two strings share exactly the same prefix, but one of the two has - * additional characters, the longer string is considered to be greater than - * the smaller one. */ -int sdscmp(const sds s1, const sds s2) { - size_t l1, l2, minlen; - int cmp; - - l1 = sdslen(s1); - l2 = sdslen(s2); - minlen = (l1 < l2) ? l1 : l2; - cmp = memcmp(s1,s2,minlen); - if (cmp == 0) return l1-l2; - return cmp; -} - -/* Split 's' with separator in 'sep'. An array - * of sds strings is returned. *count will be set - * by reference to the number of tokens returned. - * - * On out of memory, zero length string, zero length - * separator, NULL is returned. - * - * Note that 'sep' is able to split a string using - * a multi-character separator. For example - * sdssplit("foo_-_bar","_-_"); will return two - * elements "foo" and "bar". - * - * This version of the function is binary-safe but - * requires length arguments. sdssplit() is just the - * same function but for zero-terminated strings. - */ -sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count) { - int elements = 0, slots = 5, start = 0, j; - sds *tokens; - - if (seplen < 1 || len < 0) return NULL; - - tokens = malloc(sizeof(sds)*slots); - if (tokens == NULL) return NULL; - - if (len == 0) { - *count = 0; - return tokens; - } - for (j = 0; j < (len-(seplen-1)); j++) { - /* make sure there is room for the next element and the final one */ - if (slots < elements+2) { - sds *newtokens; - - slots *= 2; - newtokens = realloc(tokens,sizeof(sds)*slots); - if (newtokens == NULL) goto cleanup; - tokens = newtokens; - } - /* search the separator */ - if ((seplen == 1 && *(s+j) == sep[0]) || (memcmp(s+j,sep,seplen) == 0)) { - tokens[elements] = sdsnewlen(s+start,j-start); - if (tokens[elements] == NULL) goto cleanup; - elements++; - start = j+seplen; - j = j+seplen-1; /* skip the separator */ - } - } - /* Add the final element. We are sure there is room in the tokens array. */ - tokens[elements] = sdsnewlen(s+start,len-start); - if (tokens[elements] == NULL) goto cleanup; - elements++; - *count = elements; - return tokens; - -cleanup: - { - int i; - for (i = 0; i < elements; i++) sdsfree(tokens[i]); - free(tokens); - *count = 0; - return NULL; - } -} - -/* Free the result returned by sdssplitlen(), or do nothing if 'tokens' is NULL. */ -void sdsfreesplitres(sds *tokens, int count) { - if (!tokens) return; - while(count--) - sdsfree(tokens[count]); - free(tokens); -} - -/* Create an sds string from a long long value. It is much faster than: - * - * sdscatprintf(sdsempty(),"%lld\n", value); - */ -sds sdsfromlonglong(long long value) { - char buf[32], *p; - unsigned long long v; - - v = (value < 0) ? -value : value; - p = buf+31; /* point to the last character */ - do { - *p-- = '0'+(v%10); - v /= 10; - } while(v); - if (value < 0) *p-- = '-'; - p++; - return sdsnewlen(p,32-(p-buf)); -} - -/* Append to the sds string "s" an escaped string representation where - * all the non-printable characters (tested with isprint()) are turned into - * escapes in the form "\n\r\a...." or "\x". - * - * After the call, the modified sds string is no longer valid and all the - * references must be substituted with the new pointer returned by the call. */ -sds sdscatrepr(sds s, const char *p, size_t len) { - s = sdscatlen(s,"\"",1); - while(len--) { - switch(*p) { - case '\\': - case '"': - s = sdscatprintf(s,"\\%c",*p); - break; - case '\n': s = sdscatlen(s,"\\n",2); break; - case '\r': s = sdscatlen(s,"\\r",2); break; - case '\t': s = sdscatlen(s,"\\t",2); break; - case '\a': s = sdscatlen(s,"\\a",2); break; - case '\b': s = sdscatlen(s,"\\b",2); break; - default: - if (isprint(*p)) - s = sdscatprintf(s,"%c",*p); - else - s = sdscatprintf(s,"\\x%02x",(unsigned char)*p); - break; - } - p++; - } - return sdscatlen(s,"\"",1); -} - -/* Helper function for sdssplitargs() that returns non zero if 'c' - * is a valid hex digit. */ -int is_hex_digit(char c) { - return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F'); -} - -/* Helper function for sdssplitargs() that converts a hex digit into an - * integer from 0 to 15 */ -int hex_digit_to_int(char c) { - switch(c) { - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case 'a': case 'A': return 10; - case 'b': case 'B': return 11; - case 'c': case 'C': return 12; - case 'd': case 'D': return 13; - case 'e': case 'E': return 14; - case 'f': case 'F': return 15; - default: return 0; - } -} - -/* Split a line into arguments, where every argument can be in the - * following programming-language REPL-alike form: - * - * foo bar "newline are supported\n" and "\xff\x00otherstuff" - * - * The number of arguments is stored into *argc, and an array - * of sds is returned. - * - * The caller should free the resulting array of sds strings with - * sdsfreesplitres(). - * - * Note that sdscatrepr() is able to convert back a string into - * a quoted string in the same format sdssplitargs() is able to parse. - * - * The function returns the allocated tokens on success, even when the - * input string is empty, or NULL if the input contains unbalanced - * quotes or closed quotes followed by non space characters - * as in: "foo"bar or "foo' - */ -sds *sdssplitargs(const char *line, int *argc) { - const char *p = line; - char *current = NULL; - char **vector = NULL; - - *argc = 0; - while(1) { - /* skip blanks */ - while(*p && isspace(*p)) p++; - if (*p) { - /* get a token */ - int inq=0; /* set to 1 if we are in "quotes" */ - int insq=0; /* set to 1 if we are in 'single quotes' */ - int done=0; - - if (current == NULL) current = sdsempty(); - while(!done) { - if (inq) { - if (*p == '\\' && *(p+1) == 'x' && - is_hex_digit(*(p+2)) && - is_hex_digit(*(p+3))) - { - unsigned char byte; - - byte = (hex_digit_to_int(*(p+2))*16)+ - hex_digit_to_int(*(p+3)); - current = sdscatlen(current,(char*)&byte,1); - p += 3; - } else if (*p == '\\' && *(p+1)) { - char c; - - p++; - switch(*p) { - case 'n': c = '\n'; break; - case 'r': c = '\r'; break; - case 't': c = '\t'; break; - case 'b': c = '\b'; break; - case 'a': c = '\a'; break; - default: c = *p; break; - } - current = sdscatlen(current,&c,1); - } else if (*p == '"') { - /* closing quote must be followed by a space or - * nothing at all. */ - if (*(p+1) && !isspace(*(p+1))) goto err; - done=1; - } else if (!*p) { - /* unterminated quotes */ - goto err; - } else { - current = sdscatlen(current,p,1); - } - } else if (insq) { - if (*p == '\\' && *(p+1) == '\'') { - p++; - current = sdscatlen(current,"'",1); - } else if (*p == '\'') { - /* closing quote must be followed by a space or - * nothing at all. */ - if (*(p+1) && !isspace(*(p+1))) goto err; - done=1; - } else if (!*p) { - /* unterminated quotes */ - goto err; - } else { - current = sdscatlen(current,p,1); - } - } else { - switch(*p) { - case ' ': - case '\n': - case '\r': - case '\t': - case '\0': - done=1; - break; - case '"': - inq=1; - break; - case '\'': - insq=1; - break; - default: - current = sdscatlen(current,p,1); - break; - } - } - if (*p) p++; - } - /* add the token to the vector */ - vector = realloc(vector,((*argc)+1)*sizeof(char*)); - vector[*argc] = current; - (*argc)++; - current = NULL; - } else { - /* Even on empty input string return something not NULL. */ - if (vector == NULL) vector = malloc(sizeof(void*)); - return vector; - } - } - -err: - while((*argc)--) - sdsfree(vector[*argc]); - free(vector); - if (current) sdsfree(current); - *argc = 0; - return NULL; -} - -/* Modify the string substituting all the occurrences of the set of - * characters specified in the 'from' string to the corresponding character - * in the 'to' array. - * - * For instance: sdsmapchars(mystring, "ho", "01", 2) - * will have the effect of turning the string "hello" into "0ell1". - * - * The function returns the sds string pointer, that is always the same - * as the input pointer since no resize is needed. */ -sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen) { - size_t j, i, l = sdslen(s); - - for (j = 0; j < l; j++) { - for (i = 0; i < setlen; i++) { - if (s[j] == from[i]) { - s[j] = to[i]; - break; - } - } - } - return s; -} - -/* Join an array of C strings using the specified separator (also a C string). - * Returns the result as an sds string. */ -sds sdsjoin(char **argv, int argc, char *sep, size_t seplen) { - sds join = sdsempty(); - int j; - - for (j = 0; j < argc; j++) { - join = sdscat(join, argv[j]); - if (j != argc-1) join = sdscatlen(join,sep,seplen); - } - return join; -} - -/* Like sdsjoin, but joins an array of SDS strings. */ -sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen) { - sds join = sdsempty(); - int j; - - for (j = 0; j < argc; j++) { - join = sdscatsds(join, argv[j]); - if (j != argc-1) join = sdscatlen(join,sep,seplen); - } - return join; -} - -#ifdef SDS_TEST_MAIN -#include -#include "testhelp.h" - -int main(void) { - { - struct sdshdr *sh; - sds x = sdsnew("foo"), y; - - test_cond("Create a string and obtain the length", - sdslen(x) == 3 && memcmp(x,"foo\0",4) == 0) - - sdsfree(x); - x = sdsnewlen("foo",2); - test_cond("Create a string with specified length", - sdslen(x) == 2 && memcmp(x,"fo\0",3) == 0) - - x = sdscat(x,"bar"); - test_cond("Strings concatenation", - sdslen(x) == 5 && memcmp(x,"fobar\0",6) == 0); - - x = sdscpy(x,"a"); - test_cond("sdscpy() against an originally longer string", - sdslen(x) == 1 && memcmp(x,"a\0",2) == 0) - - x = sdscpy(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk"); - test_cond("sdscpy() against an originally shorter string", - sdslen(x) == 33 && - memcmp(x,"xyzxxxxxxxxxxyyyyyyyyyykkkkkkkkkk\0",33) == 0) - - sdsfree(x); - x = sdscatprintf(sdsempty(),"%d",123); - test_cond("sdscatprintf() seems working in the base case", - sdslen(x) == 3 && memcmp(x,"123\0",4) ==0) - - sdsfree(x); - x = sdsnew("xxciaoyyy"); - sdstrim(x,"xy"); - test_cond("sdstrim() correctly trims characters", - sdslen(x) == 4 && memcmp(x,"ciao\0",5) == 0) - - y = sdsdup(x); - sdsrange(y,1,1); - test_cond("sdsrange(...,1,1)", - sdslen(y) == 1 && memcmp(y,"i\0",2) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,1,-1); - test_cond("sdsrange(...,1,-1)", - sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,-2,-1); - test_cond("sdsrange(...,-2,-1)", - sdslen(y) == 2 && memcmp(y,"ao\0",3) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,2,1); - test_cond("sdsrange(...,2,1)", - sdslen(y) == 0 && memcmp(y,"\0",1) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,1,100); - test_cond("sdsrange(...,1,100)", - sdslen(y) == 3 && memcmp(y,"iao\0",4) == 0) - - sdsfree(y); - y = sdsdup(x); - sdsrange(y,100,100); - test_cond("sdsrange(...,100,100)", - sdslen(y) == 0 && memcmp(y,"\0",1) == 0) - - sdsfree(y); - sdsfree(x); - x = sdsnew("foo"); - y = sdsnew("foa"); - test_cond("sdscmp(foo,foa)", sdscmp(x,y) > 0) - - sdsfree(y); - sdsfree(x); - x = sdsnew("bar"); - y = sdsnew("bar"); - test_cond("sdscmp(bar,bar)", sdscmp(x,y) == 0) - - sdsfree(y); - sdsfree(x); - x = sdsnew("aar"); - y = sdsnew("bar"); - test_cond("sdscmp(bar,bar)", sdscmp(x,y) < 0) - - sdsfree(y); - sdsfree(x); - x = sdsnewlen("\a\n\0foo\r",7); - y = sdscatrepr(sdsempty(),x,sdslen(x)); - test_cond("sdscatrepr(...data...)", - memcmp(y,"\"\\a\\n\\x00foo\\r\"",15) == 0) - - { - int oldfree; - - sdsfree(x); - x = sdsnew("0"); - sh = (void*) (x-(sizeof(struct sdshdr))); - test_cond("sdsnew() free/len buffers", sh->len == 1 && sh->free == 0); - x = sdsMakeRoomFor(x,1); - sh = (void*) (x-(sizeof(struct sdshdr))); - test_cond("sdsMakeRoomFor()", sh->len == 1 && sh->free > 0); - oldfree = sh->free; - x[1] = '1'; - sdsIncrLen(x,1); - test_cond("sdsIncrLen() -- content", x[0] == '0' && x[1] == '1'); - test_cond("sdsIncrLen() -- len", sh->len == 2); - test_cond("sdsIncrLen() -- free", sh->free == oldfree-1); - } - } - test_report() - return 0; -} -#endif diff --git a/ext/hiredis-vip-0.3.0/sds.h b/ext/hiredis-vip-0.3.0/sds.h deleted file mode 100644 index 19a2abd31..000000000 --- a/ext/hiredis-vip-0.3.0/sds.h +++ /dev/null @@ -1,105 +0,0 @@ -/* SDS (Simple Dynamic Strings), A C dynamic strings library. - * - * Copyright (c) 2006-2014, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SDS_H -#define __SDS_H - -#define SDS_MAX_PREALLOC (1024*1024) - -#include -#include -#ifdef _MSC_VER -#include "win32.h" -#endif - -typedef char *sds; - -struct sdshdr { - int len; - int free; - char buf[]; -}; - -static inline size_t sdslen(const sds s) { - struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); - return sh->len; -} - -static inline size_t sdsavail(const sds s) { - struct sdshdr *sh = (struct sdshdr *)(s-sizeof *sh); - return sh->free; -} - -sds sdsnewlen(const void *init, size_t initlen); -sds sdsnew(const char *init); -sds sdsempty(void); -size_t sdslen(const sds s); -sds sdsdup(const sds s); -void sdsfree(sds s); -size_t sdsavail(const sds s); -sds sdsgrowzero(sds s, size_t len); -sds sdscatlen(sds s, const void *t, size_t len); -sds sdscat(sds s, const char *t); -sds sdscatsds(sds s, const sds t); -sds sdscpylen(sds s, const char *t, size_t len); -sds sdscpy(sds s, const char *t); - -sds sdscatvprintf(sds s, const char *fmt, va_list ap); -#ifdef __GNUC__ -sds sdscatprintf(sds s, const char *fmt, ...) - __attribute__((format(printf, 2, 3))); -#else -sds sdscatprintf(sds s, const char *fmt, ...); -#endif - -sds sdscatfmt(sds s, char const *fmt, ...); -void sdstrim(sds s, const char *cset); -void sdsrange(sds s, int start, int end); -void sdsupdatelen(sds s); -void sdsclear(sds s); -int sdscmp(const sds s1, const sds s2); -sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); -void sdsfreesplitres(sds *tokens, int count); -void sdstolower(sds s); -void sdstoupper(sds s); -sds sdsfromlonglong(long long value); -sds sdscatrepr(sds s, const char *p, size_t len); -sds *sdssplitargs(const char *line, int *argc); -sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); -sds sdsjoin(char **argv, int argc, char *sep, size_t seplen); -sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); - -/* Low level functions exposed to the user API */ -sds sdsMakeRoomFor(sds s, size_t addlen); -void sdsIncrLen(sds s, int incr); -sds sdsRemoveFreeSpace(sds s); -size_t sdsAllocSize(sds s); - -#endif diff --git a/ext/hiredis-vip-0.3.0/test.c b/ext/hiredis-vip-0.3.0/test.c deleted file mode 100644 index 8fde55446..000000000 --- a/ext/hiredis-vip-0.3.0/test.c +++ /dev/null @@ -1,806 +0,0 @@ -#include "fmacros.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hiredis.h" -#include "net.h" - -enum connection_type { - CONN_TCP, - CONN_UNIX, - CONN_FD -}; - -struct config { - enum connection_type type; - - struct { - const char *host; - int port; - struct timeval timeout; - } tcp; - - struct { - const char *path; - } unix; -}; - -/* The following lines make up our testing "framework" :) */ -static int tests = 0, fails = 0; -#define test(_s) { printf("#%02d ", ++tests); printf(_s); } -#define test_cond(_c) if(_c) printf("\033[0;32mPASSED\033[0;0m\n"); else {printf("\033[0;31mFAILED\033[0;0m\n"); fails++;} - -static long long usec(void) { - struct timeval tv; - gettimeofday(&tv,NULL); - return (((long long)tv.tv_sec)*1000000)+tv.tv_usec; -} - -/* The assert() calls below have side effects, so we need assert() - * even if we are compiling without asserts (-DNDEBUG). */ -#ifdef NDEBUG -#undef assert -#define assert(e) (void)(e) -#endif - -static redisContext *select_database(redisContext *c) { - redisReply *reply; - - /* Switch to DB 9 for testing, now that we know we can chat. */ - reply = redisCommand(c,"SELECT 9"); - assert(reply != NULL); - freeReplyObject(reply); - - /* Make sure the DB is emtpy */ - reply = redisCommand(c,"DBSIZE"); - assert(reply != NULL); - if (reply->type == REDIS_REPLY_INTEGER && reply->integer == 0) { - /* Awesome, DB 9 is empty and we can continue. */ - freeReplyObject(reply); - } else { - printf("Database #9 is not empty, test can not continue\n"); - exit(1); - } - - return c; -} - -static int disconnect(redisContext *c, int keep_fd) { - redisReply *reply; - - /* Make sure we're on DB 9. */ - reply = redisCommand(c,"SELECT 9"); - assert(reply != NULL); - freeReplyObject(reply); - reply = redisCommand(c,"FLUSHDB"); - assert(reply != NULL); - freeReplyObject(reply); - - /* Free the context as well, but keep the fd if requested. */ - if (keep_fd) - return redisFreeKeepFd(c); - redisFree(c); - return -1; -} - -static redisContext *connect(struct config config) { - redisContext *c = NULL; - - if (config.type == CONN_TCP) { - c = redisConnect(config.tcp.host, config.tcp.port); - } else if (config.type == CONN_UNIX) { - c = redisConnectUnix(config.unix.path); - } else if (config.type == CONN_FD) { - /* Create a dummy connection just to get an fd to inherit */ - redisContext *dummy_ctx = redisConnectUnix(config.unix.path); - if (dummy_ctx) { - int fd = disconnect(dummy_ctx, 1); - printf("Connecting to inherited fd %d\n", fd); - c = redisConnectFd(fd); - } - } else { - assert(NULL); - } - - if (c == NULL) { - printf("Connection error: can't allocate redis context\n"); - exit(1); - } else if (c->err) { - printf("Connection error: %s\n", c->errstr); - redisFree(c); - exit(1); - } - - return select_database(c); -} - -static void test_format_commands(void) { - char *cmd; - int len; - - test("Format command without interpolation: "); - len = redisFormatCommand(&cmd,"SET foo bar"); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); - - test("Format command with %%s string interpolation: "); - len = redisFormatCommand(&cmd,"SET %s %s","foo","bar"); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); - - test("Format command with %%s and an empty string: "); - len = redisFormatCommand(&cmd,"SET %s %s","foo",""); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(0+2)); - free(cmd); - - test("Format command with an empty string in between proper interpolations: "); - len = redisFormatCommand(&cmd,"SET %s %s","","foo"); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$0\r\n\r\n$3\r\nfoo\r\n",len) == 0 && - len == 4+4+(3+2)+4+(0+2)+4+(3+2)); - free(cmd); - - test("Format command with %%b string interpolation: "); - len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"b\0r",(size_t)3); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nb\0r\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); - - test("Format command with %%b and an empty string: "); - len = redisFormatCommand(&cmd,"SET %b %b","foo",(size_t)3,"",(size_t)0); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$0\r\n\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(0+2)); - free(cmd); - - test("Format command with literal %%: "); - len = redisFormatCommand(&cmd,"SET %% %%"); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$1\r\n%\r\n$1\r\n%\r\n",len) == 0 && - len == 4+4+(3+2)+4+(1+2)+4+(1+2)); - free(cmd); - - /* Vararg width depends on the type. These tests make sure that the - * width is correctly determined using the format and subsequent varargs - * can correctly be interpolated. */ -#define INTEGER_WIDTH_TEST(fmt, type) do { \ - type value = 123; \ - test("Format command with printf-delegation (" #type "): "); \ - len = redisFormatCommand(&cmd,"key:%08" fmt " str:%s", value, "hello"); \ - test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:00000123\r\n$9\r\nstr:hello\r\n",len) == 0 && \ - len == 4+5+(12+2)+4+(9+2)); \ - free(cmd); \ -} while(0) - -#define FLOAT_WIDTH_TEST(type) do { \ - type value = 123.0; \ - test("Format command with printf-delegation (" #type "): "); \ - len = redisFormatCommand(&cmd,"key:%08.3f str:%s", value, "hello"); \ - test_cond(strncmp(cmd,"*2\r\n$12\r\nkey:0123.000\r\n$9\r\nstr:hello\r\n",len) == 0 && \ - len == 4+5+(12+2)+4+(9+2)); \ - free(cmd); \ -} while(0) - - INTEGER_WIDTH_TEST("d", int); - INTEGER_WIDTH_TEST("hhd", char); - INTEGER_WIDTH_TEST("hd", short); - INTEGER_WIDTH_TEST("ld", long); - INTEGER_WIDTH_TEST("lld", long long); - INTEGER_WIDTH_TEST("u", unsigned int); - INTEGER_WIDTH_TEST("hhu", unsigned char); - INTEGER_WIDTH_TEST("hu", unsigned short); - INTEGER_WIDTH_TEST("lu", unsigned long); - INTEGER_WIDTH_TEST("llu", unsigned long long); - FLOAT_WIDTH_TEST(float); - FLOAT_WIDTH_TEST(double); - - test("Format command with invalid printf format: "); - len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",(size_t)3); - test_cond(len == -1); - - const char *argv[3]; - argv[0] = "SET"; - argv[1] = "foo\0xxx"; - argv[2] = "bar"; - size_t lens[3] = { 3, 7, 3 }; - int argc = 3; - - test("Format command by passing argc/argv without lengths: "); - len = redisFormatCommandArgv(&cmd,argc,argv,NULL); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(3+2)+4+(3+2)); - free(cmd); - - test("Format command by passing argc/argv with lengths: "); - len = redisFormatCommandArgv(&cmd,argc,argv,lens); - test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 && - len == 4+4+(3+2)+4+(7+2)+4+(3+2)); - free(cmd); -} - -static void test_append_formatted_commands(struct config config) { - redisContext *c; - redisReply *reply; - char *cmd; - int len; - - c = connect(config); - - test("Append format command: "); - - len = redisFormatCommand(&cmd, "SET foo bar"); - - test_cond(redisAppendFormattedCommand(c, cmd, len) == REDIS_OK); - - assert(redisGetReply(c, (void*)&reply) == REDIS_OK); - - free(cmd); - freeReplyObject(reply); - - disconnect(c, 0); -} - -static void test_reply_reader(void) { - redisReader *reader; - void *reply; - int ret; - int i; - - test("Error handling in reply parser: "); - reader = redisReaderCreate(); - redisReaderFeed(reader,(char*)"@foo\r\n",6); - ret = redisReaderGetReply(reader,NULL); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0); - redisReaderFree(reader); - - /* when the reply already contains multiple items, they must be free'd - * on an error. valgrind will bark when this doesn't happen. */ - test("Memory cleanup in reply parser: "); - reader = redisReaderCreate(); - redisReaderFeed(reader,(char*)"*2\r\n",4); - redisReaderFeed(reader,(char*)"$5\r\nhello\r\n",11); - redisReaderFeed(reader,(char*)"@foo\r\n",6); - ret = redisReaderGetReply(reader,NULL); - test_cond(ret == REDIS_ERR && - strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0); - redisReaderFree(reader); - - test("Set error on nested multi bulks with depth > 7: "); - reader = redisReaderCreate(); - - for (i = 0; i < 9; i++) { - redisReaderFeed(reader,(char*)"*1\r\n",4); - } - - ret = redisReaderGetReply(reader,NULL); - test_cond(ret == REDIS_ERR && - strncasecmp(reader->errstr,"No support for",14) == 0); - redisReaderFree(reader); - - test("Works with NULL functions for reply: "); - reader = redisReaderCreate(); - reader->fn = NULL; - redisReaderFeed(reader,(char*)"+OK\r\n",5); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); - redisReaderFree(reader); - - test("Works when a single newline (\\r\\n) covers two calls to feed: "); - reader = redisReaderCreate(); - reader->fn = NULL; - redisReaderFeed(reader,(char*)"+OK\r",4); - ret = redisReaderGetReply(reader,&reply); - assert(ret == REDIS_OK && reply == NULL); - redisReaderFeed(reader,(char*)"\n",1); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && reply == (void*)REDIS_REPLY_STATUS); - redisReaderFree(reader); - - test("Don't reset state after protocol error: "); - reader = redisReaderCreate(); - reader->fn = NULL; - redisReaderFeed(reader,(char*)"x",1); - ret = redisReaderGetReply(reader,&reply); - assert(ret == REDIS_ERR); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_ERR && reply == NULL); - redisReaderFree(reader); - - /* Regression test for issue #45 on GitHub. */ - test("Don't do empty allocation for empty multi bulk: "); - reader = redisReaderCreate(); - redisReaderFeed(reader,(char*)"*0\r\n",4); - ret = redisReaderGetReply(reader,&reply); - test_cond(ret == REDIS_OK && - ((redisReply*)reply)->type == REDIS_REPLY_ARRAY && - ((redisReply*)reply)->elements == 0); - freeReplyObject(reply); - redisReaderFree(reader); -} - -static void test_free_null(void) { - void *redisContext = NULL; - void *reply = NULL; - - test("Don't fail when redisFree is passed a NULL value: "); - redisFree(redisContext); - test_cond(redisContext == NULL); - - test("Don't fail when freeReplyObject is passed a NULL value: "); - freeReplyObject(reply); - test_cond(reply == NULL); -} - -static void test_blocking_connection_errors(void) { - redisContext *c; - - test("Returns error when host cannot be resolved: "); - c = redisConnect((char*)"idontexist.test", 6379); - test_cond(c->err == REDIS_ERR_OTHER && - (strcmp(c->errstr,"Name or service not known") == 0 || - strcmp(c->errstr,"Can't resolve: idontexist.test") == 0 || - strcmp(c->errstr,"nodename nor servname provided, or not known") == 0 || - strcmp(c->errstr,"No address associated with hostname") == 0 || - strcmp(c->errstr,"Temporary failure in name resolution") == 0 || - strcmp(c->errstr,"no address associated with name") == 0)); - redisFree(c); - - test("Returns error when the port is not open: "); - c = redisConnect((char*)"localhost", 1); - test_cond(c->err == REDIS_ERR_IO && - strcmp(c->errstr,"Connection refused") == 0); - redisFree(c); - - test("Returns error when the unix socket path doesn't accept connections: "); - c = redisConnectUnix((char*)"/tmp/idontexist.sock"); - test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */ - redisFree(c); -} - -static void test_blocking_connection(struct config config) { - redisContext *c; - redisReply *reply; - - c = connect(config); - - test("Is able to deliver commands: "); - reply = redisCommand(c,"PING"); - test_cond(reply->type == REDIS_REPLY_STATUS && - strcasecmp(reply->str,"pong") == 0) - freeReplyObject(reply); - - test("Is a able to send commands verbatim: "); - reply = redisCommand(c,"SET foo bar"); - test_cond (reply->type == REDIS_REPLY_STATUS && - strcasecmp(reply->str,"ok") == 0) - freeReplyObject(reply); - - test("%%s String interpolation works: "); - reply = redisCommand(c,"SET %s %s","foo","hello world"); - freeReplyObject(reply); - reply = redisCommand(c,"GET foo"); - test_cond(reply->type == REDIS_REPLY_STRING && - strcmp(reply->str,"hello world") == 0); - freeReplyObject(reply); - - test("%%b String interpolation works: "); - reply = redisCommand(c,"SET %b %b","foo",(size_t)3,"hello\x00world",(size_t)11); - freeReplyObject(reply); - reply = redisCommand(c,"GET foo"); - test_cond(reply->type == REDIS_REPLY_STRING && - memcmp(reply->str,"hello\x00world",11) == 0) - - test("Binary reply length is correct: "); - test_cond(reply->len == 11) - freeReplyObject(reply); - - test("Can parse nil replies: "); - reply = redisCommand(c,"GET nokey"); - test_cond(reply->type == REDIS_REPLY_NIL) - freeReplyObject(reply); - - /* test 7 */ - test("Can parse integer replies: "); - reply = redisCommand(c,"INCR mycounter"); - test_cond(reply->type == REDIS_REPLY_INTEGER && reply->integer == 1) - freeReplyObject(reply); - - test("Can parse multi bulk replies: "); - freeReplyObject(redisCommand(c,"LPUSH mylist foo")); - freeReplyObject(redisCommand(c,"LPUSH mylist bar")); - reply = redisCommand(c,"LRANGE mylist 0 -1"); - test_cond(reply->type == REDIS_REPLY_ARRAY && - reply->elements == 2 && - !memcmp(reply->element[0]->str,"bar",3) && - !memcmp(reply->element[1]->str,"foo",3)) - freeReplyObject(reply); - - /* m/e with multi bulk reply *before* other reply. - * specifically test ordering of reply items to parse. */ - test("Can handle nested multi bulk replies: "); - freeReplyObject(redisCommand(c,"MULTI")); - freeReplyObject(redisCommand(c,"LRANGE mylist 0 -1")); - freeReplyObject(redisCommand(c,"PING")); - reply = (redisCommand(c,"EXEC")); - test_cond(reply->type == REDIS_REPLY_ARRAY && - reply->elements == 2 && - reply->element[0]->type == REDIS_REPLY_ARRAY && - reply->element[0]->elements == 2 && - !memcmp(reply->element[0]->element[0]->str,"bar",3) && - !memcmp(reply->element[0]->element[1]->str,"foo",3) && - reply->element[1]->type == REDIS_REPLY_STATUS && - strcasecmp(reply->element[1]->str,"pong") == 0); - freeReplyObject(reply); - - disconnect(c, 0); -} - -static void test_blocking_connection_timeouts(struct config config) { - redisContext *c; - redisReply *reply; - ssize_t s; - const char *cmd = "DEBUG SLEEP 3\r\n"; - struct timeval tv; - - c = connect(config); - test("Successfully completes a command when the timeout is not exceeded: "); - reply = redisCommand(c,"SET foo fast"); - freeReplyObject(reply); - tv.tv_sec = 0; - tv.tv_usec = 10000; - redisSetTimeout(c, tv); - reply = redisCommand(c, "GET foo"); - test_cond(reply != NULL && reply->type == REDIS_REPLY_STRING && memcmp(reply->str, "fast", 4) == 0); - freeReplyObject(reply); - disconnect(c, 0); - - c = connect(config); - test("Does not return a reply when the command times out: "); - s = write(c->fd, cmd, strlen(cmd)); - tv.tv_sec = 0; - tv.tv_usec = 10000; - redisSetTimeout(c, tv); - reply = redisCommand(c, "GET foo"); - test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO && strcmp(c->errstr, "Resource temporarily unavailable") == 0); - freeReplyObject(reply); - - test("Reconnect properly reconnects after a timeout: "); - redisReconnect(c); - reply = redisCommand(c, "PING"); - test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0); - freeReplyObject(reply); - - test("Reconnect properly uses owned parameters: "); - config.tcp.host = "foo"; - config.unix.path = "foo"; - redisReconnect(c); - reply = redisCommand(c, "PING"); - test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0); - freeReplyObject(reply); - - disconnect(c, 0); -} - -static void test_blocking_io_errors(struct config config) { - redisContext *c; - redisReply *reply; - void *_reply; - int major, minor; - - /* Connect to target given by config. */ - c = connect(config); - { - /* Find out Redis version to determine the path for the next test */ - const char *field = "redis_version:"; - char *p, *eptr; - - reply = redisCommand(c,"INFO"); - p = strstr(reply->str,field); - major = strtol(p+strlen(field),&eptr,10); - p = eptr+1; /* char next to the first "." */ - minor = strtol(p,&eptr,10); - freeReplyObject(reply); - } - - test("Returns I/O error when the connection is lost: "); - reply = redisCommand(c,"QUIT"); - if (major > 2 || (major == 2 && minor > 0)) { - /* > 2.0 returns OK on QUIT and read() should be issued once more - * to know the descriptor is at EOF. */ - test_cond(strcasecmp(reply->str,"OK") == 0 && - redisGetReply(c,&_reply) == REDIS_ERR); - freeReplyObject(reply); - } else { - test_cond(reply == NULL); - } - - /* On 2.0, QUIT will cause the connection to be closed immediately and - * the read(2) for the reply on QUIT will set the error to EOF. - * On >2.0, QUIT will return with OK and another read(2) needed to be - * issued to find out the socket was closed by the server. In both - * conditions, the error will be set to EOF. */ - assert(c->err == REDIS_ERR_EOF && - strcmp(c->errstr,"Server closed the connection") == 0); - redisFree(c); - - c = connect(config); - test("Returns I/O error on socket timeout: "); - struct timeval tv = { 0, 1000 }; - assert(redisSetTimeout(c,tv) == REDIS_OK); - test_cond(redisGetReply(c,&_reply) == REDIS_ERR && - c->err == REDIS_ERR_IO && errno == EAGAIN); - redisFree(c); -} - -static void test_invalid_timeout_errors(struct config config) { - redisContext *c; - - test("Set error when an invalid timeout usec value is given to redisConnectWithTimeout: "); - - config.tcp.timeout.tv_sec = 0; - config.tcp.timeout.tv_usec = 10000001; - - c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); - - test_cond(c->err == REDIS_ERR_IO); - redisFree(c); - - test("Set error when an invalid timeout sec value is given to redisConnectWithTimeout: "); - - config.tcp.timeout.tv_sec = (((LONG_MAX) - 999) / 1000) + 1; - config.tcp.timeout.tv_usec = 0; - - c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout); - - test_cond(c->err == REDIS_ERR_IO); - redisFree(c); -} - -static void test_throughput(struct config config) { - redisContext *c = connect(config); - redisReply **replies; - int i, num; - long long t1, t2; - - test("Throughput:\n"); - for (i = 0; i < 500; i++) - freeReplyObject(redisCommand(c,"LPUSH mylist foo")); - - num = 1000; - replies = malloc(sizeof(redisReply*)*num); - t1 = usec(); - for (i = 0; i < num; i++) { - replies[i] = redisCommand(c,"PING"); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx PING: %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = malloc(sizeof(redisReply*)*num); - t1 = usec(); - for (i = 0; i < num; i++) { - replies[i] = redisCommand(c,"LRANGE mylist 0 499"); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); - assert(replies[i] != NULL && replies[i]->elements == 500); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0); - - num = 10000; - replies = malloc(sizeof(redisReply*)*num); - for (i = 0; i < num; i++) - redisAppendCommand(c,"PING"); - t1 = usec(); - for (i = 0; i < num; i++) { - assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_STATUS); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx PING (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); - - replies = malloc(sizeof(redisReply*)*num); - for (i = 0; i < num; i++) - redisAppendCommand(c,"LRANGE mylist 0 499"); - t1 = usec(); - for (i = 0; i < num; i++) { - assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK); - assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_ARRAY); - assert(replies[i] != NULL && replies[i]->elements == 500); - } - t2 = usec(); - for (i = 0; i < num; i++) freeReplyObject(replies[i]); - free(replies); - printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0); - - disconnect(c, 0); -} - -// static long __test_callback_flags = 0; -// static void __test_callback(redisContext *c, void *privdata) { -// ((void)c); -// /* Shift to detect execution order */ -// __test_callback_flags <<= 8; -// __test_callback_flags |= (long)privdata; -// } -// -// static void __test_reply_callback(redisContext *c, redisReply *reply, void *privdata) { -// ((void)c); -// /* Shift to detect execution order */ -// __test_callback_flags <<= 8; -// __test_callback_flags |= (long)privdata; -// if (reply) freeReplyObject(reply); -// } -// -// static redisContext *__connect_nonblock() { -// /* Reset callback flags */ -// __test_callback_flags = 0; -// return redisConnectNonBlock("127.0.0.1", port, NULL); -// } -// -// static void test_nonblocking_connection() { -// redisContext *c; -// int wdone = 0; -// -// test("Calls command callback when command is issued: "); -// c = __connect_nonblock(); -// redisSetCommandCallback(c,__test_callback,(void*)1); -// redisCommand(c,"PING"); -// test_cond(__test_callback_flags == 1); -// redisFree(c); -// -// test("Calls disconnect callback on redisDisconnect: "); -// c = __connect_nonblock(); -// redisSetDisconnectCallback(c,__test_callback,(void*)2); -// redisDisconnect(c); -// test_cond(__test_callback_flags == 2); -// redisFree(c); -// -// test("Calls disconnect callback and free callback on redisFree: "); -// c = __connect_nonblock(); -// redisSetDisconnectCallback(c,__test_callback,(void*)2); -// redisSetFreeCallback(c,__test_callback,(void*)4); -// redisFree(c); -// test_cond(__test_callback_flags == ((2 << 8) | 4)); -// -// test("redisBufferWrite against empty write buffer: "); -// c = __connect_nonblock(); -// test_cond(redisBufferWrite(c,&wdone) == REDIS_OK && wdone == 1); -// redisFree(c); -// -// test("redisBufferWrite against not yet connected fd: "); -// c = __connect_nonblock(); -// redisCommand(c,"PING"); -// test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && -// strncmp(c->error,"write:",6) == 0); -// redisFree(c); -// -// test("redisBufferWrite against closed fd: "); -// c = __connect_nonblock(); -// redisCommand(c,"PING"); -// redisDisconnect(c); -// test_cond(redisBufferWrite(c,NULL) == REDIS_ERR && -// strncmp(c->error,"write:",6) == 0); -// redisFree(c); -// -// test("Process callbacks in the right sequence: "); -// c = __connect_nonblock(); -// redisCommandWithCallback(c,__test_reply_callback,(void*)1,"PING"); -// redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); -// redisCommandWithCallback(c,__test_reply_callback,(void*)3,"PING"); -// -// /* Write output buffer */ -// wdone = 0; -// while(!wdone) { -// usleep(500); -// redisBufferWrite(c,&wdone); -// } -// -// /* Read until at least one callback is executed (the 3 replies will -// * arrive in a single packet, causing all callbacks to be executed in -// * a single pass). */ -// while(__test_callback_flags == 0) { -// assert(redisBufferRead(c) == REDIS_OK); -// redisProcessCallbacks(c); -// } -// test_cond(__test_callback_flags == 0x010203); -// redisFree(c); -// -// test("redisDisconnect executes pending callbacks with NULL reply: "); -// c = __connect_nonblock(); -// redisSetDisconnectCallback(c,__test_callback,(void*)1); -// redisCommandWithCallback(c,__test_reply_callback,(void*)2,"PING"); -// redisDisconnect(c); -// test_cond(__test_callback_flags == 0x0201); -// redisFree(c); -// } - -int main(int argc, char **argv) { - struct config cfg = { - .tcp = { - .host = "127.0.0.1", - .port = 6379 - }, - .unix = { - .path = "/tmp/redis.sock" - } - }; - int throughput = 1; - int test_inherit_fd = 1; - - /* Ignore broken pipe signal (for I/O error tests). */ - signal(SIGPIPE, SIG_IGN); - - /* Parse command line options. */ - argv++; argc--; - while (argc) { - if (argc >= 2 && !strcmp(argv[0],"-h")) { - argv++; argc--; - cfg.tcp.host = argv[0]; - } else if (argc >= 2 && !strcmp(argv[0],"-p")) { - argv++; argc--; - cfg.tcp.port = atoi(argv[0]); - } else if (argc >= 2 && !strcmp(argv[0],"-s")) { - argv++; argc--; - cfg.unix.path = argv[0]; - } else if (argc >= 1 && !strcmp(argv[0],"--skip-throughput")) { - throughput = 0; - } else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) { - test_inherit_fd = 0; - } else { - fprintf(stderr, "Invalid argument: %s\n", argv[0]); - exit(1); - } - argv++; argc--; - } - - test_format_commands(); - test_reply_reader(); - test_blocking_connection_errors(); - test_free_null(); - - printf("\nTesting against TCP connection (%s:%d):\n", cfg.tcp.host, cfg.tcp.port); - cfg.type = CONN_TCP; - test_blocking_connection(cfg); - test_blocking_connection_timeouts(cfg); - test_blocking_io_errors(cfg); - test_invalid_timeout_errors(cfg); - test_append_formatted_commands(cfg); - if (throughput) test_throughput(cfg); - - printf("\nTesting against Unix socket connection (%s):\n", cfg.unix.path); - cfg.type = CONN_UNIX; - test_blocking_connection(cfg); - test_blocking_connection_timeouts(cfg); - test_blocking_io_errors(cfg); - if (throughput) test_throughput(cfg); - - if (test_inherit_fd) { - printf("\nTesting against inherited fd (%s):\n", cfg.unix.path); - cfg.type = CONN_FD; - test_blocking_connection(cfg); - } - - - if (fails) { - printf("*** %d TESTS FAILED ***\n", fails); - return 1; - } - - printf("ALL TESTS PASSED\n"); - return 0; -} diff --git a/make-mac.mk b/make-mac.mk index fccfea7bf..6625dc85e 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -28,10 +28,9 @@ include objects.mk ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o ext/http-parser/http_parser.o ifeq ($(ZT_CONTROLLER),1) - LIBS+=-L/usr/local/opt/libpq/lib -lpq + LIBS+=-L/usr/local/opt/libpq/lib -lpq -Lext/redis-plus-plus-1.1.1/install/macos/lib -lredis++ -Lext/hiredis-0.14.1/lib/macos -lhiredis DEFS+=-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER_USE_REDIS -DZT_CONTROLLER - INCLUDES+=-I/usr/local/opt/libpq/include -Iext/hiredis-vip-0.3.0 - ONE_OBJS+=ext/hiredis-vip-0.3.0/adlist.o ext/hiredis-vip-0.3.0/async.o ext/hiredis-vip-0.3.0/command.o ext/hiredis-vip-0.3.0/crc16.o ext/hiredis-vip-0.3.0/dict.o ext/hiredis-vip-0.3.0/hiarray.o ext/hiredis-vip-0.3.0/hircluster.o ext/hiredis-vip-0.3.0/hiredis.o ext/hiredis-vip-0.3.0/hiutil.o ext/hiredis-vip-0.3.0/net.o ext/hiredis-vip-0.3.0/read.o ext/hiredis-vip-0.3.0/sds.o + INCLUDES+=-I/usr/local/opt/libpq/include -Iext/hiredis-0.14.1/include/ -Iext/redis-plus-plus-1.1.1/install/macos/include/sw/ endif # Official releases are signed with our Apple cert and apply software updates by default diff --git a/objects.mk b/objects.mk index ed415a508..efa2f3c0f 100644 --- a/objects.mk +++ b/objects.mk @@ -33,7 +33,6 @@ ONE_OBJS=\ controller/FileDB.o \ controller/LFDB.o \ controller/PostgreSQL.o \ - controller/Redis.o \ osdep/EthernetTap.o \ osdep/ManagedRoute.o \ osdep/Http.o \