├── .gitignore ├── .gitmodules ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── RedisClient.cpp ├── RedisClient.h ├── experimental └── redisclient │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── RedisClient.cpp │ ├── RedisClient.h │ ├── RedisClientYaf.cpp │ ├── RedisClientYaf.h │ ├── hiredis │ ├── .gitignore │ ├── .travis.yml │ ├── CHANGELOG.md │ ├── COPYING │ ├── Makefile │ ├── README.md │ ├── adapters │ │ ├── ae.h │ │ ├── glib.h │ │ ├── ivykis.h │ │ ├── libev.h │ │ ├── libevent.h │ │ ├── libuv.h │ │ ├── macosx.h │ │ └── qt.h │ ├── appveyor.yml │ ├── async.c │ ├── async.h │ ├── dict.c │ ├── dict.h │ ├── examples │ │ ├── example-ae.c │ │ ├── example-glib.c │ │ ├── example-ivykis.c │ │ ├── example-libev.c │ │ ├── example-libevent.c │ │ ├── example-libuv.c │ │ ├── example-macosx.c │ │ ├── example-qt.cpp │ │ ├── example-qt.h │ │ └── example.c │ ├── fmacros.h │ ├── hiredis.c │ ├── hiredis.h │ ├── net.c │ ├── net.h │ ├── read.c │ ├── read.h │ ├── sds.c │ ├── sds.h │ ├── sdsalloc.h │ ├── test.c │ └── win32.h │ ├── hiredispool.c │ ├── hiredispool.h │ ├── test_RedisClient.cpp │ ├── test_RedisClient2.cpp │ ├── test_RedisClientYaf.cpp │ └── test_hiredispool.cpp ├── hiredispool.c ├── hiredispool.h ├── log.c ├── log.h ├── test_RedisClient.cpp ├── test_RedisClient2.cpp ├── test_hiredispool.cpp └── test_log.c /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | *.a 3 | *.o 4 | *.out 5 | *.exe 6 | log/ 7 | *.dSYM 8 | *.so 9 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "hiredis"] 2 | path = hiredis 3 | url = https://github.com/redis/hiredis.git 4 | branch = master -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:stretch 2 | LABEL maintainer="Alan Vieyra " 3 | 4 | ENV DEBIAN_FRONTEND noninteractive 5 | 6 | ADD $PWD /usr/src/hiredispool 7 | 8 | WORKDIR /usr/src/hiredispool 9 | 10 | RUN set -ex; \ 11 | \ 12 | savedAptMark="$(apt-mark showmanual)"; \ 13 | \ 14 | apt-get update; \ 15 | apt-get install -y --no-install-recommends \ 16 | build-essential \ 17 | ca-certificates \ 18 | cmake \ 19 | libev-dev \ 20 | ; \ 21 | \ 22 | make install; \ 23 | \ 24 | apt-mark auto '.*' > /dev/null; \ 25 | apt-mark manual $savedAptMark; \ 26 | apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false; \ 27 | rm -rf /var/lib/apt/lists/* -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LDFLAGS = hiredis/libhiredis.a 2 | 3 | OBJ = log.o hiredispool.o RedisClient.o 4 | LIBNAME = libhiredispool 5 | 6 | CC = gcc 7 | CXX = g++ 8 | OPTIMAZATION ?= -O3 9 | WARNINGS = -Wall -Wpedantic -W -Wstrict-prototypes -Wwrite-strings 10 | DEBUG_FLAGS ?= -g -ggdb 11 | MACROS = -D_GNU_SOURCE 12 | 13 | REAL_CFLAGS = $(OPTIMAZATION) -pthread -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS) $(ARCH) $(MACROS) 14 | REAL_CXXFLAGS = $(REAL_CFLAGS) -Wno-c99-extensions 15 | REAL_LDFLAGS = $(LDFLAGS) $(ARCH) 16 | 17 | STLIBSUFFIX = a 18 | STLIBNAME = $(LIBNAME).$(STLIBSUFFIX) 19 | STLIB_MAKE_CMD = ar rcs $(STLIBNAME) 20 | 21 | HIREDISPOOL_SONAME=0.1 22 | DYLIBSUFFIX=so 23 | DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) 24 | DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDISPOOL_SONAME) 25 | DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) 26 | INSTALL?= cp -a 27 | PREFIX?=/usr/local 28 | INCLUDE_PATH?=include/hiredispool 29 | LIBRARY_PATH?=lib 30 | INSTALL_INCLUDE_PATH= $(PREFIX)/$(INCLUDE_PATH) 31 | INSTALL_LIBRARY_PATH= $(PREFIX)/$(LIBRARY_PATH) 32 | 33 | all: $(STLIBNAME) 34 | 35 | # Deps (use make dep to generate this) 36 | hiredispool.o: hiredispool.c hiredispool.h log.h hiredis/hiredis.h \ 37 | hiredis/read.h hiredis/sds.h 38 | log.o: log.c log.h 39 | RedisClient.o: RedisClient.cpp RedisClient.h hiredispool.h \ 40 | hiredis/hiredis.h hiredis/read.h hiredis/sds.h log.h 41 | 42 | $(STLIBNAME): $(OBJ) 43 | $(STLIB_MAKE_CMD) $(OBJ) 44 | 45 | static: $(STLIBNAME) 46 | 47 | # Binaries 48 | test_log.exe: test_log.c log.h $(STLIBNAME) 49 | $(CC) -o $@ $(REAL_CFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) 50 | 51 | test_hiredispool.exe: test_hiredispool.cpp hiredispool.h log.h $(STLIBNAME) 52 | $(CXX) -std=c++11 -o $@ $(REAL_CXXFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) 53 | 54 | test_RedisClient.exe: test_RedisClient.cpp RedisClient.h hiredispool.h log.h $(STLIBNAME) 55 | $(CXX) -std=c++11 -o $@ $(REAL_CXXFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) 56 | 57 | test_RedisClient2.exe: test_RedisClient2.cpp RedisClient.h hiredispool.h log.h $(STLIBNAME) 58 | $(CXX) -std=c++11 -o $@ $(REAL_CXXFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) 59 | 60 | .c.o: 61 | $(CC) -std=c99 -c $(REAL_CFLAGS) $< 62 | 63 | .cpp.o: 64 | $(CXX) -std=c++11 -c $(REAL_CXXFLAGS) $< 65 | 66 | clean: 67 | rm -rf $(STLIBNAME) *.o *.out *.exe 68 | 69 | dep: 70 | $(CC) -MM *.c 71 | $(CXX) -MM *.cpp 72 | 73 | $(DYLIBNAME): $(OBJ) 74 | $(DYLIB_MAKE_CMD) $(OBJ) 75 | 76 | hiredis-install: 77 | cd hiredis && make install 78 | 79 | install: hiredis-install $(DYLIBNAME) $(STLIBNAME) 80 | mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) 81 | $(INSTALL) hiredispool.h RedisClient.h $(INSTALL_INCLUDE_PATH) 82 | $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH) 83 | $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) 84 | 85 | docker-image: 86 | docker build -t hiredispool . 87 | 88 | .PHONY: all static clean dep install hiredis-install docker-image 89 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hiredispool 2 | 3 | This library provides connection pooling and auto-reconnect for hiredis. It is also minimalistic and easy to do customization. The code has been thoroughly tested in a multi-threaded application, and used in production environments for a long time. It is proven to be thread-safe and no memory leak. 4 | 5 | ## Features 6 | 7 | * Connection pooling implemented in pure C 8 | * Auto-reconnect and retry instantly at the first failure 9 | * Comprehensive logging for diagnostic 10 | * No third-party dependency except hiredis 11 | * Thread safe C++ wrapper with automatic memory management 12 | * [Advanced] Multiple server endpoints can be provisioned, with automatic load-balancing and fail-over, to support scenarios such as high availablity redis-cluster and redis-proxy middleware. 13 | * [Experimental] Jedis-like C++ wrapper 14 | * [Experimental] On-the-fly re-provisioning 15 | 16 | ## Limitations 17 | 18 | * To support auto-reconnect and retry, you must use a wrapper of hiredis synchronous API 19 | 20 | ## How to use 21 | 22 | To build it, clone the repo and `make`. Check out the `test_*.cpp` for examples. 23 | 24 | ## Compile 25 | 26 | ```shell 27 | git clone 28 | cd hiredispool 29 | git submodule update --init 30 | make 31 | # optional 32 | make install 33 | ``` 34 | 35 | ## docker-hiredispool 36 | 37 | Dockerfile to build the [hiredispool](https://github.com/aclisp/hiredispool) library by [aclisp](https://github.com/aclisp). 38 | 39 | Use this image as part of a multistage build to get the library into your own containers without having to build it and clean up dependencies afterwards. 40 | ``` 41 | FROM alanvieyra333/hiredispool:latest as HIREDISPOOL 42 | 43 | FROM alpine:3.9 44 | 45 | COPY --from=HIREDISPOOL /usr/local/lib/libhiredis.so.0.13 /usr/local/lib/libhiredis.so 46 | COPY --from=HIREDISPOOL /usr/local/lib/libhiredispool.so.0.1 /usr/local/lib/libhiredispool.so 47 | ``` -------------------------------------------------------------------------------- /RedisClient.cpp: -------------------------------------------------------------------------------- 1 | #include "RedisClient.h" 2 | #include "log.h" 3 | 4 | #include 5 | 6 | 7 | using namespace std; 8 | 9 | 10 | RedisReplyPtr RedisClient::redisCommand(const char *format, ...) 11 | { 12 | RedisReplyPtr reply; 13 | va_list ap; 14 | 15 | va_start(ap, format); 16 | reply = redisvCommand(format, ap); 17 | va_end(ap); 18 | 19 | return reply; 20 | } 21 | 22 | RedisReplyPtr RedisClient::redisvCommand(const char *format, va_list ap) 23 | { 24 | void* reply = 0; 25 | PooledSocket socket(inst); 26 | 27 | if (socket.notNull()) { 28 | reply = redis_vcommand(socket, inst, format, ap); 29 | } else { 30 | log_(L_ERROR|L_CONS, "Can not get socket from redis connection pool, server down? or not enough connection?"); 31 | } 32 | 33 | return RedisReplyPtr(reply); 34 | } 35 | -------------------------------------------------------------------------------- /RedisClient.h: -------------------------------------------------------------------------------- 1 | /* Author: Huanghao 2 | * Date: 2017-2 3 | * Revision: 0.1 4 | * Function: Thread-safe redis client 5 | * Usage: see test_RedisClient.cpp 6 | */ 7 | 8 | #ifndef REDISCLIENT_H 9 | #define REDISCLIENT_H 10 | 11 | 12 | #include 13 | 14 | #include "hiredispool.h" 15 | 16 | #include "hiredis/hiredis.h" 17 | 18 | #include 19 | #include 20 | 21 | 22 | // PooledSocket is a pooled socket wrapper that provides a convenient 23 | // RAII-style mechanism for owning a socket for the duration of a 24 | // scoped block. 25 | class PooledSocket 26 | { 27 | private: 28 | // non construct copyable and non copyable 29 | PooledSocket(const PooledSocket&); 30 | PooledSocket& operator=(const PooledSocket&); 31 | public: 32 | // Get a pooled socket from a redis instance. 33 | // throw runtime_error if something wrong. 34 | PooledSocket(REDIS_INSTANCE* _inst) : inst(_inst) { 35 | sock = redis_get_socket(inst); 36 | } 37 | // Release the socket to pool 38 | ~PooledSocket() { 39 | redis_release_socket(inst, sock); 40 | } 41 | // Implicit convert to REDIS_SOCKET* 42 | operator REDIS_SOCKET*() const { return sock; } 43 | bool notNull() const { return (sock != NULL); } 44 | bool isNull() const { return (sock == NULL); } 45 | private: 46 | REDIS_INSTANCE* inst; 47 | REDIS_SOCKET* sock; 48 | }; 49 | 50 | // Helper 51 | struct RedisReplyRef 52 | { 53 | redisReply* p; 54 | explicit RedisReplyRef(redisReply* _p): p(_p) {} 55 | }; 56 | 57 | // RedisReplyPtr is a smart pointer encapsulate redisReply* 58 | class RedisReplyPtr 59 | { 60 | public: 61 | explicit RedisReplyPtr(void* _p = 0) : p((redisReply*)_p) {} 62 | ~RedisReplyPtr() { 63 | //printf("freeReplyObject %p\n", (void*)p); 64 | freeReplyObject(p); 65 | } 66 | 67 | // release ownership of the managed object 68 | redisReply* release() { 69 | redisReply* temp = p; 70 | p = NULL; 71 | return temp; 72 | } 73 | 74 | // transfer ownership 75 | RedisReplyPtr(RedisReplyPtr& other) { 76 | p = other.release(); 77 | } 78 | RedisReplyPtr& operator=(RedisReplyPtr& other) { 79 | if (this == &other) 80 | return *this; 81 | RedisReplyPtr temp(release()); 82 | p = other.release(); 83 | return *this; 84 | } 85 | 86 | // automatic conversions 87 | RedisReplyPtr(RedisReplyRef _ref) { 88 | p = _ref.p; 89 | } 90 | RedisReplyPtr& operator=(RedisReplyRef _ref) { 91 | if (p == _ref.p) 92 | return *this; 93 | RedisReplyPtr temp(release()); 94 | p = _ref.p; 95 | return *this; 96 | } 97 | operator RedisReplyRef() { return RedisReplyRef(release()); } 98 | 99 | bool notNull() const { return (p != 0); } 100 | bool isNull() const { return (p == 0); } 101 | redisReply* get() const { return p; } 102 | redisReply* operator->() const { return p; } 103 | redisReply& operator*() const { return *p; } 104 | 105 | private: 106 | redisReply* p; 107 | }; 108 | 109 | // RedisClient provides a threadsafe redis client 110 | class RedisClient 111 | { 112 | private: 113 | // non construct copyable and non copyable 114 | RedisClient(const RedisClient&); 115 | RedisClient& operator=(const RedisClient&); 116 | public: 117 | RedisClient(const REDIS_CONFIG& conf) { 118 | if (redis_pool_create(&conf, &inst) < 0) 119 | throw std::runtime_error("Can't create pool"); 120 | } 121 | ~RedisClient() { 122 | redis_pool_destroy(inst); 123 | } 124 | 125 | // ---------------------------------------------------- 126 | // Thread-safe command 127 | // ---------------------------------------------------- 128 | 129 | // redisCommand is a thread-safe wrapper of that function in hiredis 130 | // It first get a connection from pool, execute the command on that 131 | // connection and then release the connection to pool. 132 | // the command's reply is returned as a smart pointer, 133 | // which can be used just like raw redisReply pointer. 134 | RedisReplyPtr redisCommand(const char *format, ...); 135 | RedisReplyPtr redisvCommand(const char *format, va_list ap); 136 | 137 | private: 138 | REDIS_INSTANCE* inst; 139 | }; 140 | 141 | #endif // REDISCLIENT_H 142 | -------------------------------------------------------------------------------- /experimental/redisclient/.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | *.a 3 | *.o 4 | *.out 5 | *.exe 6 | -------------------------------------------------------------------------------- /experimental/redisclient/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /experimental/redisclient/Makefile: -------------------------------------------------------------------------------- 1 | LDFLAGS = hiredis/libhiredis.a ../lib/bamSDK.a ../utility/logger.o ../utility/syslog-nb.o ../utility/exception_errno.o ../lib/libanka.so ../lib/libs2sclient.so ../lib/config.a ../lib/mapi4anka.a -luuid ../lib/libcrypto.a -lrt 2 | 3 | OBJ = hiredispool.o RedisClient.o RedisClientYaf.o 4 | LIBNAME = libhiredispool 5 | 6 | CC = gcc 7 | CXX = g++ 8 | OPTIMAZATION ?= -O0 9 | WARNINGS = -Wall -W -Wwrite-strings -Wno-unused-parameter -Wno-unused-local-typedefs 10 | DEBUG_FLAGS ?= -g -ggdb 11 | MACROS = -D_GNU_SOURCE 12 | INCLUDES = -I../include -I../bamSDK -I../config -I../nameserver -I../utility -I.. -I../.. -I../core/net -I../core/thread -I../plugin -I../dbclient/mysql -I../dbclient/mysql/mysqlclient/include -I../redisclient -I../../third_party -I../../protocol 13 | 14 | REAL_CFLAGS = $(OPTIMAZATION) -pthread -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS) $(ARCH) $(MACROS) $(INCLUDES) 15 | REAL_CXXFLAGS = $(REAL_CFLAGS) 16 | REAL_LDFLAGS = $(LDFLAGS) $(ARCH) 17 | 18 | STLIBSUFFIX = a 19 | STLIBNAME = $(LIBNAME).$(STLIBSUFFIX) 20 | STLIB_MAKE_CMD = ar rcs $(STLIBNAME) 21 | 22 | all: $(STLIBNAME) 23 | 24 | # Deps (use make dep to generate this) 25 | hiredispool.o: hiredispool.c hiredispool.h hiredis/hiredis.h \ 26 | hiredis/read.h hiredis/sds.h 27 | RedisClient.o: RedisClient.cpp RedisClient.h hiredispool.h \ 28 | hiredis/hiredis.h hiredis/read.h hiredis/sds.h 29 | RedisClientYaf.o: RedisClientYaf.cpp RedisClientYaf.h 30 | 31 | $(STLIBNAME): $(OBJ) 32 | $(STLIB_MAKE_CMD) $(OBJ) 33 | cp -f $(STLIBNAME) ../lib 34 | cp -f hiredis/libhiredis.a ../lib 35 | 36 | static: $(STLIBNAME) 37 | 38 | # Binaries 39 | test_hiredispool.exe: test_hiredispool.cpp hiredispool.h $(STLIBNAME) 40 | $(CXX) -o $@ $(REAL_CXXFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) 41 | 42 | test_RedisClient.exe: test_RedisClient.cpp RedisClient.h hiredispool.h $(STLIBNAME) 43 | $(CXX) -o $@ $(REAL_CXXFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) 44 | 45 | test_RedisClient2.exe: test_RedisClient2.cpp RedisClient.h hiredispool.h $(STLIBNAME) 46 | $(CXX) -o $@ $(REAL_CXXFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) 47 | 48 | test_RedisClientYaf.exe: test_RedisClientYaf.cpp RedisClientYaf.h RedisClient.h hiredispool.h $(STLIBNAME) 49 | $(CXX) -o $@ $(REAL_CXXFLAGS) -I. $< $(STLIBNAME) $(REAL_LDFLAGS) 50 | 51 | .c.o: 52 | $(CXX) -c $(REAL_CFLAGS) $< 53 | 54 | .cpp.o: 55 | $(CXX) -c $(REAL_CXXFLAGS) $< 56 | 57 | clean: 58 | rm -rf $(STLIBNAME) *.o *.out *.exe 59 | 60 | dep: 61 | $(CC) -MM *.c $(REAL_CFLAGS) -I. 62 | $(CXX) -MM *.cpp $(REAL_CFLAGS) -I. 63 | 64 | .PHONY: all static clean dep 65 | -------------------------------------------------------------------------------- /experimental/redisclient/README.md: -------------------------------------------------------------------------------- 1 | # hiredispool [Experimental] 2 | 3 | The code here can only be run along with our in-house C++ framework. 4 | -------------------------------------------------------------------------------- /experimental/redisclient/RedisClient.cpp: -------------------------------------------------------------------------------- 1 | #include "RedisClient.h" 2 | #include "logger.h" 3 | 4 | #include 5 | 6 | 7 | using namespace std; 8 | 9 | 10 | void RedisClient::_setTarget(RedisReplyPack* p, REDIS_SOCKET* s) 11 | { 12 | p->info.err = 0; 13 | p->info.errstr = ""; 14 | p->info.target.host = ((redisContext*)(s->conn))->tcp.host; 15 | p->info.target.port = ((redisContext*)(s->conn))->tcp.port; 16 | } 17 | 18 | void RedisClient::_setError(RedisReplyPack* p, REDIS_SOCKET* s) 19 | { 20 | p->info.err = s->err; 21 | p->info.errstr = s->errstr; 22 | p->info.target.host = s->errhost; 23 | p->info.target.port = s->errport; 24 | } 25 | 26 | void RedisClient::_setError(RedisReplyPack* p, const char* errstr) 27 | { 28 | p->info.err = -1; 29 | p->info.errstr = errstr; 30 | p->info.target.host = "N/A"; 31 | p->info.target.port = -1; 32 | } 33 | 34 | RedisReplyPtr RedisClient::redisCommand(const char *format, ...) 35 | { 36 | RedisReplyPtr reply; 37 | va_list ap; 38 | 39 | va_start(ap, format); 40 | reply = redisvCommand(format, ap); 41 | va_end(ap); 42 | 43 | return reply; 44 | } 45 | 46 | RedisReplyPtr RedisClient::redisvCommand(const char *format, va_list ap) 47 | { 48 | RedisReplyPack* p(new RedisReplyPack); 49 | PooledSocket socket(inst); 50 | 51 | if (socket.notNull()) { 52 | p->reply = (redisReply*) redis_vcommand(socket.get(), inst, format, ap); 53 | if (p->reply) { 54 | _setTarget(p, socket.get()); 55 | } else { 56 | _setError(p, socket.get()); 57 | } 58 | } else { 59 | logth(Error, "Can not get socket from redis connection pool, server down? or not enough connection?"); 60 | _setError(p, "No available connection"); 61 | } 62 | 63 | return RedisReplyPtr(p); 64 | } 65 | 66 | RedisReplyPtr RedisClient::redisCommandArgv(int argc, const char **argv, const size_t *argvlen) 67 | { 68 | RedisReplyPack* p(new RedisReplyPack); 69 | PooledSocket socket(inst); 70 | 71 | if (socket.notNull()) { 72 | p->reply = (redisReply*) redis_command_argv(socket.get(), inst, argc, argv, argvlen); 73 | if (p->reply) { 74 | _setTarget(p, socket.get()); 75 | } else { 76 | _setError(p, socket.get()); 77 | } 78 | } else { 79 | logth(Error, "Can not get socket from redis connection pool, server down? or not enough connection?"); 80 | _setError(p, "No available connection"); 81 | } 82 | 83 | return RedisReplyPtr(p); 84 | } 85 | -------------------------------------------------------------------------------- /experimental/redisclient/RedisClient.h: -------------------------------------------------------------------------------- 1 | /* Author: Huanghao 2 | * Date: 2017-2 3 | * Revision: 0.1 4 | * Function: Thread-safe redis client 5 | * Usage: see test_RedisClient.cpp 6 | */ 7 | 8 | #ifndef REDISCLIENT_H 9 | #define REDISCLIENT_H 10 | 11 | 12 | #include 13 | 14 | #include "hiredispool.h" 15 | 16 | #include "hiredis/hiredis.h" 17 | 18 | #include 19 | #include 20 | 21 | 22 | // PooledSocket is a pooled socket wrapper that provides a convenient 23 | // RAII-style mechanism for owning a socket for the duration of a 24 | // scoped block. 25 | class PooledSocket 26 | { 27 | private: 28 | // non construct copyable and non copyable 29 | PooledSocket(const PooledSocket&); 30 | PooledSocket& operator=(const PooledSocket&); 31 | public: 32 | // Get a pooled socket from a redis instance. 33 | // throw runtime_error if something wrong. 34 | PooledSocket(REDIS_INSTANCE* _inst) : inst(_inst) { 35 | sock = redis_get_socket(inst); 36 | } 37 | // Release the socket to pool 38 | ~PooledSocket() { 39 | redis_release_socket(inst, sock); 40 | } 41 | // Implicit convert to REDIS_SOCKET* 42 | REDIS_SOCKET* get() const { return sock; } 43 | REDIS_SOCKET* operator->() const { return sock; } 44 | bool notNull() const { return (sock != NULL); } 45 | bool isNull() const { return (sock == NULL); } 46 | private: 47 | REDIS_INSTANCE* inst; 48 | REDIS_SOCKET* sock; 49 | }; 50 | 51 | // RedisCommandInfo holds the executed redis command info 52 | struct RedisCommandInfo 53 | { 54 | int err; 55 | std::string errstr; 56 | struct { std::string host; int port; } target; 57 | }; 58 | 59 | // RedisReplyPack holds the reply pointer and command info 60 | struct RedisReplyPack 61 | { 62 | redisReply* reply; 63 | RedisCommandInfo info; 64 | RedisReplyPack(): reply(0) {} 65 | ~RedisReplyPack() { freeReplyObject(reply); } 66 | private: 67 | RedisReplyPack(const RedisReplyPack&); 68 | RedisReplyPack& operator=(const RedisReplyPack&); 69 | }; 70 | 71 | // Helper 72 | struct RedisReplyRef 73 | { 74 | RedisReplyPack* p; 75 | explicit RedisReplyRef(RedisReplyPack* _p): p(_p) {} 76 | }; 77 | 78 | // RedisReplyPtr is a smart pointer encapsulate redisReply* 79 | class RedisReplyPtr 80 | { 81 | public: 82 | explicit RedisReplyPtr(RedisReplyPack* _p = 0) : p(_p) {} 83 | ~RedisReplyPtr() { 84 | //printf("RedisReplyPtr free %p\n", (void*)p); 85 | delete p; 86 | } 87 | 88 | // release ownership of the managed object 89 | RedisReplyPack* release() { 90 | RedisReplyPack* temp = p; 91 | p = NULL; 92 | return temp; 93 | } 94 | 95 | // transfer ownership 96 | RedisReplyPtr(RedisReplyPtr& other) { 97 | p = other.release(); 98 | } 99 | RedisReplyPtr& operator=(RedisReplyPtr& other) { 100 | if (this == &other) 101 | return *this; 102 | RedisReplyPtr temp(release()); 103 | p = other.release(); 104 | return *this; 105 | } 106 | 107 | // automatic conversions 108 | RedisReplyPtr(RedisReplyRef _ref) { 109 | p = _ref.p; 110 | } 111 | RedisReplyPtr& operator=(RedisReplyRef _ref) { 112 | if (p == _ref.p) 113 | return *this; 114 | RedisReplyPtr temp(release()); 115 | p = _ref.p; 116 | return *this; 117 | } 118 | operator RedisReplyRef() { return RedisReplyRef(release()); } 119 | 120 | bool notNull() const { return (p != 0 && p->reply != 0); } 121 | bool isNull() const { return (p == 0 || p->reply == 0); } 122 | operator RedisReplyPack*() const { return p; } 123 | operator redisReply*() const { return (p ? p->reply : 0); } 124 | redisReply* operator->() const { return (p ? p->reply : 0); } 125 | redisReply& operator*() const { return *(p ? p->reply : 0); } 126 | 127 | private: 128 | RedisReplyPack* p; 129 | }; 130 | 131 | // RedisClient provides a threadsafe redis client 132 | class RedisClient 133 | { 134 | private: 135 | // non construct copyable and non copyable 136 | RedisClient(const RedisClient&); 137 | RedisClient& operator=(const RedisClient&); 138 | public: 139 | RedisClient(const REDIS_CONFIG& conf) { 140 | if (redis_pool_create(&conf, &inst) < 0) 141 | throw std::runtime_error("Can't create pool"); 142 | } 143 | ~RedisClient() { 144 | redis_pool_destroy(inst); 145 | } 146 | 147 | // ---------------------------------------------------- 148 | // Thread-safe command 149 | // ---------------------------------------------------- 150 | 151 | // redisCommand is a thread-safe wrapper of that function in hiredis 152 | // It first get a connection from pool, execute the command on that 153 | // connection and then release the connection to pool. 154 | // the command's reply is returned as a smart pointer, 155 | // which can be used just like raw redisReply pointer. 156 | RedisReplyPtr redisCommand(const char *format, ...); 157 | RedisReplyPtr redisvCommand(const char *format, va_list ap); 158 | RedisReplyPtr redisCommandArgv(int argc, const char **argv, const size_t *argvlen); 159 | 160 | private: 161 | REDIS_INSTANCE* inst; 162 | 163 | static void _setError(RedisReplyPack* p, const char* errstr); 164 | static void _setError(RedisReplyPack* p, REDIS_SOCKET* s); 165 | static void _setTarget(RedisReplyPack* p, REDIS_SOCKET* s); 166 | }; 167 | 168 | #endif // REDISCLIENT_H 169 | -------------------------------------------------------------------------------- /experimental/redisclient/RedisClientYaf.h: -------------------------------------------------------------------------------- 1 | #ifndef REDISCLIENTYAF_H 2 | #define REDISCLIENTYAF_H 3 | 4 | 5 | #include "RedisClient.h" 6 | #include "logger.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | 19 | namespace _internal { 20 | inline int _atom_inc(int& v) { return __sync_add_and_fetch(&v, 1); } 21 | inline int _atom_dec(int& v) { return __sync_sub_and_fetch(&v, 1); } 22 | inline int _atom_finc(int& v) { return __sync_fetch_and_add(&v, 1); } 23 | inline int _atom_fdec(int& v) { return __sync_fetch_and_sub(&v, 1); } 24 | inline int _atom_get(int& v) { return __sync_fetch_and_or(&v, 0); } 25 | 26 | class SharedCount 27 | { 28 | public: 29 | SharedCount() : c(1) {} 30 | void addRef() { _atom_inc(c); } 31 | int release() { return _atom_dec(c); } 32 | int get() { return _atom_get(c); } 33 | private: 34 | int c; 35 | }; 36 | 37 | // RedisClientPtr is a smart pointer encapsulate RedisClient* 38 | class RedisClientPtr 39 | { 40 | public: 41 | explicit RedisClientPtr(RedisClient* _p = 0) 42 | : p(_p), c(new SharedCount) { 43 | //printf("RedisClientPtr create %p, %d\n", (void*)p, c->get()); 44 | logth(Info, "RedisClientPtr create %p, %d\n", (void*)p, c->get()); 45 | } 46 | ~RedisClientPtr() { 47 | //printf("RedisClientPtr releas %p, %d\n", (void*)p, c->get()); 48 | //logth(Info, "RedisClientPtr releas %p, %d\n", (void*)p, c->get()); 49 | if (c->release() == 0) { 50 | //printf("RedisClientPtr destro %p, %d\n", (void*)p, c->get()); 51 | logth(Info, "RedisClientPtr destro %p, %d\n", (void*)p, c->get()); 52 | delete p; 53 | delete c; 54 | } 55 | } 56 | 57 | RedisClientPtr(const RedisClientPtr& other) 58 | : p(other.p), c(other.c) { 59 | c->addRef(); 60 | //printf("RedisClientPtr copied %p, %d\n", (void*)p, c->get()); 61 | //logth(Info, "RedisClientPtr copied %p, %d\n", (void*)p, c->get()); 62 | } 63 | RedisClientPtr& operator=(RedisClientPtr other) { 64 | this->swap(other); 65 | return *this; 66 | } 67 | void swap(RedisClientPtr& other) { 68 | std::swap(p, other.p); 69 | std::swap(c, other.c); 70 | } 71 | 72 | bool notNull() const { return (p != 0); } 73 | bool isNull() const { return (p == 0); } 74 | RedisClient* get() const { return p; } 75 | RedisClient* operator->() const { return p; } 76 | RedisClient& operator*() const { return *p; } 77 | 78 | int getrc() const { return c->get(); } 79 | private: 80 | RedisClient* p; 81 | SharedCount* c; 82 | }; 83 | } // namespace _internal 84 | 85 | 86 | namespace anka { 87 | 88 | class IConfigObserver; 89 | 90 | namespace ramcloud { 91 | 92 | void init(IConfigObserver *, void * fwk = 0); 93 | void fini(); 94 | 95 | // 命令执行状态 96 | class Status 97 | { 98 | public: 99 | // 命令成功执行,或者KEY没有找到,都认为本次操作是成功的 100 | bool ok() const { return code_ == "ok" || code_ == "not_found"; } 101 | bool not_found() const { return code_ == "not_found"; } 102 | std::string code() const { return code_; } 103 | void code(const std::string & c) { code_ = c; } 104 | Status() :code_("") {} 105 | Status(const std::string &code) { code_ = code; } 106 | Status(const Status & s) { code_ = s.code_; } 107 | private: 108 | std::string code_; 109 | }; 110 | 111 | int64_t microsec(); // 当前时间戳,微秒 112 | 113 | class Command 114 | { 115 | private: 116 | int64_t start_; 117 | std::string command_; 118 | public: 119 | explicit Command(const std::string & command) { start_ = microsec(); command_ = command; } 120 | int64_t duration() const { return microsec() - start_; } 121 | const char * c_str() const { return command_.c_str(); } 122 | std::string::size_type length() const { return command_.length(); } 123 | const std::string & str() const { return command_; } 124 | }; 125 | 126 | class Client 127 | { // 线程安全 128 | public: 129 | Client(const std::string& dbname = "default"); 130 | virtual ~Client(); 131 | 132 | // 命令 133 | // 生命期控制 134 | virtual Status type(const std::string & key, std::string & type); 135 | virtual Status delStringKey(const std::string & key, int * affected = 0); 136 | virtual Status delStringKey(const std::set & keys, int * affected = 0); 137 | virtual Status delOtherKeyUnsafe(const std::string & key, int * affected = 0); 138 | virtual Status expire(const std::string & key, unsigned ttl, int * affected = 0); 139 | virtual Status ttl(const std::string &key, int & ttl); 140 | virtual Status persist(const std::string & key, int *affected = 0); 141 | 142 | // key-string 143 | virtual Status set(const std::string & key, const std::string & val); 144 | virtual Status setex(const std::string & key, const std::string & val, int ttl); 145 | virtual Status mset(const std::map & kvs); // 不是原子操作 146 | virtual Status get(const std::string & key, std::string & val); 147 | virtual Status mget(const std::set & keys, std::map & vals); 148 | virtual Status incrby(const std::string & key, int64_t increment, int64_t * newval = 0); 149 | // add for redisHelper 150 | virtual Status setMapValue(const std::string & key, const std::map & val, int ttl = -1); 151 | virtual Status getMapValue(const std::string & key, std::map& value, bool& keyExist); 152 | 153 | // set 154 | virtual Status scard(const std::string & key, int & count); 155 | virtual Status sadd(const std::string & key, const std::string & member); 156 | virtual Status sadd(const std::string & key, const std::set & members); 157 | virtual Status srem(const std::string & key, const std::string & member, int * delcount = 0); 158 | virtual Status srem(const std::string & key, const std::set & members, int * delcount = 0); 159 | virtual Status smembers(const std::string & key, std::set & members); 160 | virtual Status sismember(const std::string & key, const std::string & member, bool & ismember); 161 | 162 | // hash 163 | virtual Status hdel(const std::string & key, const std::string &field, int * delcount = 0); 164 | virtual Status hdel(const std::string & key, const std::set &field, int * delcount = 0); 165 | virtual Status hset(const std::string & key, const std::string & field, const std::string & val); 166 | virtual Status hmset(const std::string & key, const std::map & field2val); 167 | virtual Status hget(const std::string & key, const std::string & field, std::string & val); 168 | virtual Status hmget(const std::string & key, const std::set & fields, std::map & field2val); 169 | virtual Status hgetall(const std::string & key, std::map & allfield); 170 | virtual Status hlen(const std::string & key, int & fieldcount); 171 | virtual Status hincrby(const std::string & key, const std::string & field, int64_t increment, int64_t * newval = 0); 172 | 173 | virtual Status zcard(const std::string & key, int & count); 174 | virtual Status zadd(const std::string & key, double score, const std::string & member); 175 | virtual Status zadd(const std::string & key, const std::map & member2score); 176 | virtual Status zrem(const std::string & key, const std::string & member, int * delcount = 0); 177 | virtual Status zrem(const std::string & key, const std::set & members, int * delcount = 0); 178 | virtual Status zscore(const std::string & key, const std::string & member, double & score); 179 | virtual Status zrembyscore(const std::string& key, const int min, const int max); 180 | virtual Status zcount(const std::string & key, double minScore, double maxScore, int & count); 181 | virtual Status zrevrank(const std::string& key, const std::string& member, int* rank); 182 | virtual Status zrank(const std::string& key, const std::string& member, int& rank); 183 | virtual Status zrange(const std::string & key, int startIndex, int stopIndex, std::vector & members); 184 | virtual Status zrangeWithScores(const std::string & key, int startIndex, int stopIndex, std::vector > & members); 185 | virtual Status zrevrange(const std::string & key, int startIndex, int stopIndex, std::vector & members); 186 | virtual Status zrevrangeWithScores(const std::string & key, int startIndex, int stopIndex, std::vector > & members); 187 | virtual Status zincrby(const std::string& key, const std::string& field, int64_t increment, int64_t& newval); 188 | virtual Status zrangebyscore(const std::string & key, const std::string & score1, const std::string & score2, std::vector & members); 189 | virtual Status zrangebyscoreWithScores(const std::string & key, const std::string & score1, const std::string & score2, std::vector > & members); 190 | virtual Status zrevrangebyscore(const std::string & key, const std::string & score1, const std::string & score2, std::vector & members); 191 | virtual Status zrevrangebyscoreWithScores(const std::string & key, const std::string & score1, const std::string & score2, std::vector > & members); 192 | 193 | protected: 194 | Status zrangbyscore_impl(const std::string & cmd, const std::string & key, const std::string & score1, const std::string & score2, std::vector & members); 195 | Status zrangbyscoreWithScores_impl(const std::string & cmd, const std::string & key, const std::string & score1, const std::string & score2, std::vector > & members); 196 | Status zrange_impl(const std::string & command, const std::string & key, int startIndex, int stopIndex, std::vector & members); 197 | Status zrangeWithScores_impl(const std::string & command, const std::string & key, int startIndex, int stopIndex, std::vector > & members); 198 | 199 | protected: 200 | std::string dbname; // 当前使用的实例名,默认为 default 201 | _internal::RedisClientPtr client; // 当前使用哪个实例,延迟初始化 202 | virtual void _init(); 203 | 204 | virtual RedisReplyPtr myRedisCommand(const char *format, ...); 205 | virtual RedisReplyPtr myRedisvCommand(const char *format, va_list ap); 206 | virtual RedisReplyPtr myRedisCommandArgv(int argc, const char **argv, const size_t *argvlen); 207 | 208 | static Status reply2status(const RedisReplyPack* p); 209 | static std::string reply2string(const redisReply* reply); 210 | static int64_t reply2integer(const redisReply* reply); 211 | static void reportStatus(const RedisReplyPack* p, const Command& command, const Status& status); 212 | static void appendArgs(const std::set & coll, std::vector &args, std::vector &lens); 213 | }; 214 | 215 | } // namespace ramcloud 216 | 217 | namespace redis { 218 | 219 | void init(IConfigObserver *, void * fwk = 0); 220 | void fini(); 221 | 222 | using ramcloud::Status; 223 | using ramcloud::Command; 224 | 225 | class Client : public ramcloud::Client 226 | { // 线程安全 227 | public: 228 | Client(const std::string& dbname = "default"); 229 | protected: 230 | virtual void _init(); 231 | }; 232 | 233 | } // namespace redis 234 | 235 | } // namespace anka 236 | 237 | 238 | #endif//REDISCLIENTYAF_H 239 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/.gitignore: -------------------------------------------------------------------------------- 1 | /hiredis-test 2 | /examples/hiredis-example* 3 | /*.o 4 | /*.so 5 | /*.dylib 6 | /*.a 7 | /*.pc 8 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/.travis.yml: -------------------------------------------------------------------------------- 1 | language: c 2 | sudo: false 3 | compiler: 4 | - gcc 5 | - clang 6 | 7 | os: 8 | - linux 9 | - osx 10 | 11 | before_script: 12 | - if [ "$TRAVIS_OS_NAME" == "osx" ] ; then brew update; brew install redis; fi 13 | 14 | addons: 15 | apt: 16 | packages: 17 | - libc6-dbg 18 | - libc6-dev 19 | - libc6:i386 20 | - libc6-dev-i386 21 | - libc6-dbg:i386 22 | - gcc-multilib 23 | - valgrind 24 | 25 | env: 26 | - CFLAGS="-Werror" 27 | - PRE="valgrind --track-origins=yes --leak-check=full" 28 | - TARGET="32bit" TARGET_VARS="32bit-vars" CFLAGS="-Werror" 29 | - TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full" 30 | 31 | matrix: 32 | exclude: 33 | - os: osx 34 | env: PRE="valgrind --track-origins=yes --leak-check=full" 35 | 36 | - os: osx 37 | env: TARGET="32bit" TARGET_VARS="32bit-vars" PRE="valgrind --track-origins=yes --leak-check=full" 38 | 39 | script: make $TARGET CFLAGS="$CFLAGS" && make check PRE="$PRE" && make $TARGET_VARS hiredis-example 40 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### 1.0.0 (unreleased) 2 | 3 | **Fixes**: 4 | 5 | * Catch a buffer overflow when formatting the error message 6 | * Import latest upstream sds. This breaks applications that are linked against the old hiredis v0.13 7 | * Fix warnings, when compiled with -Wshadow 8 | * Make hiredis compile in Cygwin on Windows, now CI-tested 9 | 10 | **BREAKING CHANGES**: 11 | 12 | * Change `redisReply.len` to `size_t`, as it denotes the the size of a string 13 | 14 | User code should compare this to `size_t` values as well. 15 | If it was used to compare to other values, casting might be necessary or can be removed, if casting was applied before. 16 | 17 | * Remove backwards compatibility macro's 18 | 19 | This removes the following old function aliases, use the new name now: 20 | 21 | | Old | New | 22 | | --------------------------- | ---------------------- | 23 | | redisReplyReaderCreate | redisReaderCreate | 24 | | redisReplyReaderCreate | redisReaderCreate | 25 | | redisReplyReaderFree | redisReaderFree | 26 | | redisReplyReaderFeed | redisReaderFeed | 27 | | redisReplyReaderGetReply | redisReaderGetReply | 28 | | redisReplyReaderSetPrivdata | redisReaderSetPrivdata | 29 | | redisReplyReaderGetObject | redisReaderGetObject | 30 | | redisReplyReaderGetError | redisReaderGetError | 31 | 32 | * The `DEBUG` variable in the Makefile was renamed to `DEBUG_FLAGS` 33 | 34 | Previously it broke some builds for people that had `DEBUG` set to some arbitrary value, 35 | due to debugging other software. 36 | By renaming we avoid unintentional name clashes. 37 | 38 | Simply rename `DEBUG` to `DEBUG_FLAGS` in your environment to make it working again. 39 | 40 | ### 0.13.3 (2015-09-16) 41 | 42 | * Revert "Clear `REDIS_CONNECTED` flag when connection is closed". 43 | * Make tests pass on FreeBSD (Thanks, Giacomo Olgeni) 44 | 45 | 46 | If the `REDIS_CONNECTED` flag is cleared, 47 | the async onDisconnect callback function will never be called. 48 | This causes problems as the disconnect is never reported back to the user. 49 | 50 | ### 0.13.2 (2015-08-25) 51 | 52 | * Prevent crash on pending replies in async code (Thanks, @switch-st) 53 | * Clear `REDIS_CONNECTED` flag when connection is closed (Thanks, Jerry Jacobs) 54 | * Add MacOS X addapter (Thanks, @dizzus) 55 | * Add Qt adapter (Thanks, Pietro Cerutti) 56 | * Add Ivykis adapter (Thanks, Gergely Nagy) 57 | 58 | All adapters are provided as is and are only tested where possible. 59 | 60 | ### 0.13.1 (2015-05-03) 61 | 62 | This is a bug fix release. 63 | The new `reconnect` method introduced new struct members, which clashed with pre-defined names in pre-C99 code. 64 | Another commit forced C99 compilation just to make it work, but of course this is not desirable for outside projects. 65 | Other non-C99 code can now use hiredis as usual again. 66 | Sorry for the inconvenience. 67 | 68 | * Fix memory leak in async reply handling (Salvatore Sanfilippo) 69 | * Rename struct member to avoid name clash with pre-c99 code (Alex Balashov, ncopa) 70 | 71 | ### 0.13.0 (2015-04-16) 72 | 73 | This release adds a minimal Windows compatibility layer. 74 | The parser, standalone since v0.12.0, can now be compiled on Windows 75 | (and thus used in other client libraries as well) 76 | 77 | * Windows compatibility layer for parser code (tzickel) 78 | * Properly escape data printed to PKGCONF file (Dan Skorupski) 79 | * Fix tests when assert() undefined (Keith Bennett, Matt Stancliff) 80 | * Implement a reconnect method for the client context, this changes the structure of `redisContext` (Aaron Bedra) 81 | 82 | ### 0.12.1 (2015-01-26) 83 | 84 | * Fix `make install`: DESTDIR support, install all required files, install PKGCONF in proper location 85 | * Fix `make test` as 32 bit build on 64 bit platform 86 | 87 | ### 0.12.0 (2015-01-22) 88 | 89 | * Add optional KeepAlive support 90 | 91 | * Try again on EINTR errors 92 | 93 | * Add libuv adapter 94 | 95 | * Add IPv6 support 96 | 97 | * Remove possiblity of multiple close on same fd 98 | 99 | * Add ability to bind source address on connect 100 | 101 | * Add redisConnectFd() and redisFreeKeepFd() 102 | 103 | * Fix getaddrinfo() memory leak 104 | 105 | * Free string if it is unused (fixes memory leak) 106 | 107 | * Improve redisAppendCommandArgv performance 2.5x 108 | 109 | * Add support for SO_REUSEADDR 110 | 111 | * Fix redisvFormatCommand format parsing 112 | 113 | * Add GLib 2.0 adapter 114 | 115 | * Refactor reading code into read.c 116 | 117 | * Fix errno error buffers to not clobber errors 118 | 119 | * Generate pkgconf during build 120 | 121 | * Silence _BSD_SOURCE warnings 122 | 123 | * Improve digit counting for multibulk creation 124 | 125 | 126 | ### 0.11.0 127 | 128 | * Increase the maximum multi-bulk reply depth to 7. 129 | 130 | * Increase the read buffer size from 2k to 16k. 131 | 132 | * Use poll(2) instead of select(2) to support large fds (>= 1024). 133 | 134 | ### 0.10.1 135 | 136 | * Makefile overhaul. Important to check out if you override one or more 137 | variables using environment variables or via arguments to the "make" tool. 138 | 139 | * Issue #45: Fix potential memory leak for a multi bulk reply with 0 elements 140 | being created by the default reply object functions. 141 | 142 | * Issue #43: Don't crash in an asynchronous context when Redis returns an error 143 | reply after the connection has been made (this happens when the maximum 144 | number of connections is reached). 145 | 146 | ### 0.10.0 147 | 148 | * See commit log. 149 | 150 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2011, Salvatore Sanfilippo 2 | Copyright (c) 2010-2011, Pieter Noordhuis 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of Redis nor the names of its contributors may be used 17 | to endorse or promote products derived from this software without specific 18 | prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 24 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 27 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/Makefile: -------------------------------------------------------------------------------- 1 | # Hiredis Makefile 2 | # Copyright (C) 2010-2011 Salvatore Sanfilippo 3 | # Copyright (C) 2010-2011 Pieter Noordhuis 4 | # This file is released under the BSD license, see the COPYING file 5 | 6 | OBJ=net.o hiredis.o sds.o async.o read.o 7 | EXAMPLES=hiredis-example hiredis-example-libevent hiredis-example-libev hiredis-example-glib 8 | TESTS=hiredis-test 9 | LIBNAME=libhiredis 10 | PKGCONFNAME=hiredis.pc 11 | 12 | HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}') 13 | HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}') 14 | HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredis.h | awk '{print $$3}') 15 | HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredis.h | awk '{print $$3}') 16 | 17 | # Installation related variables and target 18 | PREFIX?=/usr/local 19 | INCLUDE_PATH?=include/hiredis 20 | LIBRARY_PATH?=lib 21 | PKGCONF_PATH?=pkgconfig 22 | INSTALL_INCLUDE_PATH= $(DESTDIR)$(PREFIX)/$(INCLUDE_PATH) 23 | INSTALL_LIBRARY_PATH= $(DESTDIR)$(PREFIX)/$(LIBRARY_PATH) 24 | INSTALL_PKGCONF_PATH= $(INSTALL_LIBRARY_PATH)/$(PKGCONF_PATH) 25 | 26 | # redis-server configuration used for testing 27 | REDIS_PORT=56379 28 | REDIS_SERVER=redis-server 29 | define REDIS_TEST_CONFIG 30 | daemonize yes 31 | pidfile /tmp/hiredis-test-redis.pid 32 | port $(REDIS_PORT) 33 | bind 127.0.0.1 34 | unixsocket /tmp/hiredis-test-redis.sock 35 | endef 36 | export REDIS_TEST_CONFIG 37 | 38 | # Fallback to gcc when $CC is not in $PATH. 39 | CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc') 40 | CXX:=$(shell sh -c 'type $(CXX) >/dev/null 2>/dev/null && echo $(CXX) || echo g++') 41 | OPTIMIZATION?=-O3 42 | WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings 43 | DEBUG_FLAGS?= -g -ggdb 44 | REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS) $(ARCH) 45 | REAL_LDFLAGS=$(LDFLAGS) $(ARCH) 46 | 47 | DYLIBSUFFIX=so 48 | STLIBSUFFIX=a 49 | DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME) 50 | DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR) 51 | DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX) 52 | DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) 53 | STLIBNAME=$(LIBNAME).$(STLIBSUFFIX) 54 | STLIB_MAKE_CMD=ar rcs $(STLIBNAME) 55 | 56 | # Platform-specific overrides 57 | uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not') 58 | ifeq ($(uname_S),SunOS) 59 | REAL_LDFLAGS+= -ldl -lnsl -lsocket 60 | DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS) 61 | INSTALL= cp -r 62 | endif 63 | ifeq ($(uname_S),Darwin) 64 | DYLIBSUFFIX=dylib 65 | DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX) 66 | DYLIB_MAKE_CMD=$(CC) -shared -Wl,-install_name,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS) 67 | endif 68 | 69 | all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME) 70 | 71 | # Deps (use make dep to generate this) 72 | async.o: async.c fmacros.h async.h hiredis.h read.h sds.h net.h dict.c dict.h 73 | dict.o: dict.c fmacros.h dict.h 74 | hiredis.o: hiredis.c fmacros.h hiredis.h read.h sds.h net.h 75 | net.o: net.c fmacros.h net.h hiredis.h read.h sds.h 76 | read.o: read.c fmacros.h read.h sds.h 77 | sds.o: sds.c sds.h 78 | test.o: test.c fmacros.h hiredis.h read.h sds.h 79 | 80 | $(DYLIBNAME): $(OBJ) 81 | $(DYLIB_MAKE_CMD) $(OBJ) 82 | 83 | $(STLIBNAME): $(OBJ) 84 | $(STLIB_MAKE_CMD) $(OBJ) 85 | 86 | dynamic: $(DYLIBNAME) 87 | static: $(STLIBNAME) 88 | 89 | # Binaries: 90 | hiredis-example-libevent: examples/example-libevent.c adapters/libevent.h $(STLIBNAME) 91 | $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -levent $(STLIBNAME) 92 | 93 | hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME) 94 | $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME) 95 | 96 | hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME) 97 | $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) $(shell pkg-config --cflags --libs glib-2.0) -I. $< $(STLIBNAME) 98 | 99 | hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME) 100 | $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -livykis $(STLIBNAME) 101 | 102 | hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME) 103 | $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME) 104 | 105 | ifndef AE_DIR 106 | hiredis-example-ae: 107 | @echo "Please specify AE_DIR (e.g. /src)" 108 | @false 109 | else 110 | hiredis-example-ae: examples/example-ae.c adapters/ae.h $(STLIBNAME) 111 | $(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) 112 | endif 113 | 114 | ifndef LIBUV_DIR 115 | hiredis-example-libuv: 116 | @echo "Please specify LIBUV_DIR (e.g. ../libuv/)" 117 | @false 118 | else 119 | hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME) 120 | $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME) 121 | endif 122 | 123 | ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),) 124 | hiredis-example-qt: 125 | @echo "Please specify QT_MOC, QT_INCLUDE_DIR AND QT_LIBRARY_DIR" 126 | @false 127 | else 128 | hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME) 129 | $(QT_MOC) adapters/qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ 130 | $(CXX) -x c++ -o qt-adapter-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore 131 | $(QT_MOC) examples/example-qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \ 132 | $(CXX) -x c++ -o qt-example-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore 133 | $(CXX) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore -L$(QT_LIBRARY_DIR) qt-adapter-moc.o qt-example-moc.o $< -pthread $(STLIBNAME) -lQtCore 134 | endif 135 | 136 | hiredis-example: examples/example.c $(STLIBNAME) 137 | $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(STLIBNAME) 138 | 139 | examples: $(EXAMPLES) 140 | 141 | hiredis-test: test.o $(STLIBNAME) 142 | 143 | hiredis-%: %.o $(STLIBNAME) 144 | $(CC) $(REAL_CFLAGS) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME) 145 | 146 | test: hiredis-test 147 | ./hiredis-test 148 | 149 | check: hiredis-test 150 | @echo "$$REDIS_TEST_CONFIG" | $(REDIS_SERVER) - 151 | $(PRE) ./hiredis-test -h 127.0.0.1 -p $(REDIS_PORT) -s /tmp/hiredis-test-redis.sock || \ 152 | ( kill `cat /tmp/hiredis-test-redis.pid` && false ) 153 | kill `cat /tmp/hiredis-test-redis.pid` 154 | 155 | .c.o: 156 | $(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) $< 157 | 158 | clean: 159 | rm -rf $(DYLIBNAME) $(STLIBNAME) $(TESTS) $(PKGCONFNAME) examples/hiredis-example* *.o *.gcda *.gcno *.gcov 160 | 161 | dep: 162 | $(CC) -MM *.c 163 | 164 | ifeq ($(uname_S),SunOS) 165 | INSTALL?= cp -r 166 | endif 167 | 168 | INSTALL?= cp -a 169 | 170 | $(PKGCONFNAME): hiredis.h 171 | @echo "Generating $@ for pkgconfig..." 172 | @echo prefix=$(PREFIX) > $@ 173 | @echo exec_prefix=\$${prefix} >> $@ 174 | @echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@ 175 | @echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@ 176 | @echo >> $@ 177 | @echo Name: hiredis >> $@ 178 | @echo Description: Minimalistic C client library for Redis. >> $@ 179 | @echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@ 180 | @echo Libs: -L\$${libdir} -lhiredis >> $@ 181 | @echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@ 182 | 183 | install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME) 184 | mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH) 185 | $(INSTALL) hiredis.h async.h read.h sds.h adapters $(INSTALL_INCLUDE_PATH) 186 | $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME) 187 | cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME) 188 | $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH) 189 | mkdir -p $(INSTALL_PKGCONF_PATH) 190 | $(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH) 191 | 192 | 32bit: 193 | @echo "" 194 | @echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386" 195 | @echo "" 196 | $(MAKE) CFLAGS="-m32" LDFLAGS="-m32" 197 | 198 | 32bit-vars: 199 | $(eval CFLAGS=-m32) 200 | $(eval LDFLAGS=-m32) 201 | 202 | gprof: 203 | $(MAKE) CFLAGS="-pg" LDFLAGS="-pg" 204 | 205 | gcov: 206 | $(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs" 207 | 208 | coverage: gcov 209 | make check 210 | mkdir -p tmp/lcov 211 | lcov -d . -c -o tmp/lcov/hiredis.info 212 | genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info 213 | 214 | noopt: 215 | $(MAKE) OPTIMIZATION="" 216 | 217 | .PHONY: all test check clean dep install 32bit 32bit-vars gprof gcov noopt 218 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/adapters/ae.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, Pieter Noordhuis 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __HIREDIS_AE_H__ 32 | #define __HIREDIS_AE_H__ 33 | #include 34 | #include 35 | #include "../hiredis.h" 36 | #include "../async.h" 37 | 38 | typedef struct redisAeEvents { 39 | redisAsyncContext *context; 40 | aeEventLoop *loop; 41 | int fd; 42 | int reading, writing; 43 | } redisAeEvents; 44 | 45 | static void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) { 46 | ((void)el); ((void)fd); ((void)mask); 47 | 48 | redisAeEvents *e = (redisAeEvents*)privdata; 49 | redisAsyncHandleRead(e->context); 50 | } 51 | 52 | static void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) { 53 | ((void)el); ((void)fd); ((void)mask); 54 | 55 | redisAeEvents *e = (redisAeEvents*)privdata; 56 | redisAsyncHandleWrite(e->context); 57 | } 58 | 59 | static void redisAeAddRead(void *privdata) { 60 | redisAeEvents *e = (redisAeEvents*)privdata; 61 | aeEventLoop *loop = e->loop; 62 | if (!e->reading) { 63 | e->reading = 1; 64 | aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e); 65 | } 66 | } 67 | 68 | static void redisAeDelRead(void *privdata) { 69 | redisAeEvents *e = (redisAeEvents*)privdata; 70 | aeEventLoop *loop = e->loop; 71 | if (e->reading) { 72 | e->reading = 0; 73 | aeDeleteFileEvent(loop,e->fd,AE_READABLE); 74 | } 75 | } 76 | 77 | static void redisAeAddWrite(void *privdata) { 78 | redisAeEvents *e = (redisAeEvents*)privdata; 79 | aeEventLoop *loop = e->loop; 80 | if (!e->writing) { 81 | e->writing = 1; 82 | aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e); 83 | } 84 | } 85 | 86 | static void redisAeDelWrite(void *privdata) { 87 | redisAeEvents *e = (redisAeEvents*)privdata; 88 | aeEventLoop *loop = e->loop; 89 | if (e->writing) { 90 | e->writing = 0; 91 | aeDeleteFileEvent(loop,e->fd,AE_WRITABLE); 92 | } 93 | } 94 | 95 | static void redisAeCleanup(void *privdata) { 96 | redisAeEvents *e = (redisAeEvents*)privdata; 97 | redisAeDelRead(privdata); 98 | redisAeDelWrite(privdata); 99 | free(e); 100 | } 101 | 102 | static int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) { 103 | redisContext *c = &(ac->c); 104 | redisAeEvents *e; 105 | 106 | /* Nothing should be attached when something is already attached */ 107 | if (ac->ev.data != NULL) 108 | return REDIS_ERR; 109 | 110 | /* Create container for context and r/w events */ 111 | e = (redisAeEvents*)malloc(sizeof(*e)); 112 | e->context = ac; 113 | e->loop = loop; 114 | e->fd = c->fd; 115 | e->reading = e->writing = 0; 116 | 117 | /* Register functions to start/stop listening for events */ 118 | ac->ev.addRead = redisAeAddRead; 119 | ac->ev.delRead = redisAeDelRead; 120 | ac->ev.addWrite = redisAeAddWrite; 121 | ac->ev.delWrite = redisAeDelWrite; 122 | ac->ev.cleanup = redisAeCleanup; 123 | ac->ev.data = e; 124 | 125 | return REDIS_OK; 126 | } 127 | #endif 128 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/adapters/glib.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_GLIB_H__ 2 | #define __HIREDIS_GLIB_H__ 3 | 4 | #include 5 | 6 | #include "../hiredis.h" 7 | #include "../async.h" 8 | 9 | typedef struct 10 | { 11 | GSource source; 12 | redisAsyncContext *ac; 13 | GPollFD poll_fd; 14 | } RedisSource; 15 | 16 | static void 17 | redis_source_add_read (gpointer data) 18 | { 19 | RedisSource *source = (RedisSource *)data; 20 | g_return_if_fail(source); 21 | source->poll_fd.events |= G_IO_IN; 22 | g_main_context_wakeup(g_source_get_context((GSource *)data)); 23 | } 24 | 25 | static void 26 | redis_source_del_read (gpointer data) 27 | { 28 | RedisSource *source = (RedisSource *)data; 29 | g_return_if_fail(source); 30 | source->poll_fd.events &= ~G_IO_IN; 31 | g_main_context_wakeup(g_source_get_context((GSource *)data)); 32 | } 33 | 34 | static void 35 | redis_source_add_write (gpointer data) 36 | { 37 | RedisSource *source = (RedisSource *)data; 38 | g_return_if_fail(source); 39 | source->poll_fd.events |= G_IO_OUT; 40 | g_main_context_wakeup(g_source_get_context((GSource *)data)); 41 | } 42 | 43 | static void 44 | redis_source_del_write (gpointer data) 45 | { 46 | RedisSource *source = (RedisSource *)data; 47 | g_return_if_fail(source); 48 | source->poll_fd.events &= ~G_IO_OUT; 49 | g_main_context_wakeup(g_source_get_context((GSource *)data)); 50 | } 51 | 52 | static void 53 | redis_source_cleanup (gpointer data) 54 | { 55 | RedisSource *source = (RedisSource *)data; 56 | 57 | g_return_if_fail(source); 58 | 59 | redis_source_del_read(source); 60 | redis_source_del_write(source); 61 | /* 62 | * It is not our responsibility to remove ourself from the 63 | * current main loop. However, we will remove the GPollFD. 64 | */ 65 | if (source->poll_fd.fd >= 0) { 66 | g_source_remove_poll((GSource *)data, &source->poll_fd); 67 | source->poll_fd.fd = -1; 68 | } 69 | } 70 | 71 | static gboolean 72 | redis_source_prepare (GSource *source, 73 | gint *timeout_) 74 | { 75 | RedisSource *redis = (RedisSource *)source; 76 | *timeout_ = -1; 77 | return !!(redis->poll_fd.events & redis->poll_fd.revents); 78 | } 79 | 80 | static gboolean 81 | redis_source_check (GSource *source) 82 | { 83 | RedisSource *redis = (RedisSource *)source; 84 | return !!(redis->poll_fd.events & redis->poll_fd.revents); 85 | } 86 | 87 | static gboolean 88 | redis_source_dispatch (GSource *source, 89 | GSourceFunc callback, 90 | gpointer user_data) 91 | { 92 | RedisSource *redis = (RedisSource *)source; 93 | 94 | if ((redis->poll_fd.revents & G_IO_OUT)) { 95 | redisAsyncHandleWrite(redis->ac); 96 | redis->poll_fd.revents &= ~G_IO_OUT; 97 | } 98 | 99 | if ((redis->poll_fd.revents & G_IO_IN)) { 100 | redisAsyncHandleRead(redis->ac); 101 | redis->poll_fd.revents &= ~G_IO_IN; 102 | } 103 | 104 | if (callback) { 105 | return callback(user_data); 106 | } 107 | 108 | return TRUE; 109 | } 110 | 111 | static void 112 | redis_source_finalize (GSource *source) 113 | { 114 | RedisSource *redis = (RedisSource *)source; 115 | 116 | if (redis->poll_fd.fd >= 0) { 117 | g_source_remove_poll(source, &redis->poll_fd); 118 | redis->poll_fd.fd = -1; 119 | } 120 | } 121 | 122 | static GSource * 123 | redis_source_new (redisAsyncContext *ac) 124 | { 125 | static GSourceFuncs source_funcs = { 126 | .prepare = redis_source_prepare, 127 | .check = redis_source_check, 128 | .dispatch = redis_source_dispatch, 129 | .finalize = redis_source_finalize, 130 | }; 131 | redisContext *c = &ac->c; 132 | RedisSource *source; 133 | 134 | g_return_val_if_fail(ac != NULL, NULL); 135 | 136 | source = (RedisSource *)g_source_new(&source_funcs, sizeof *source); 137 | source->ac = ac; 138 | source->poll_fd.fd = c->fd; 139 | source->poll_fd.events = 0; 140 | source->poll_fd.revents = 0; 141 | g_source_add_poll((GSource *)source, &source->poll_fd); 142 | 143 | ac->ev.addRead = redis_source_add_read; 144 | ac->ev.delRead = redis_source_del_read; 145 | ac->ev.addWrite = redis_source_add_write; 146 | ac->ev.delWrite = redis_source_del_write; 147 | ac->ev.cleanup = redis_source_cleanup; 148 | ac->ev.data = source; 149 | 150 | return (GSource *)source; 151 | } 152 | 153 | #endif /* __HIREDIS_GLIB_H__ */ 154 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/adapters/ivykis.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_IVYKIS_H__ 2 | #define __HIREDIS_IVYKIS_H__ 3 | #include 4 | #include "../hiredis.h" 5 | #include "../async.h" 6 | 7 | typedef struct redisIvykisEvents { 8 | redisAsyncContext *context; 9 | struct iv_fd fd; 10 | } redisIvykisEvents; 11 | 12 | static void redisIvykisReadEvent(void *arg) { 13 | redisAsyncContext *context = (redisAsyncContext *)arg; 14 | redisAsyncHandleRead(context); 15 | } 16 | 17 | static void redisIvykisWriteEvent(void *arg) { 18 | redisAsyncContext *context = (redisAsyncContext *)arg; 19 | redisAsyncHandleWrite(context); 20 | } 21 | 22 | static void redisIvykisAddRead(void *privdata) { 23 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 24 | iv_fd_set_handler_in(&e->fd, redisIvykisReadEvent); 25 | } 26 | 27 | static void redisIvykisDelRead(void *privdata) { 28 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 29 | iv_fd_set_handler_in(&e->fd, NULL); 30 | } 31 | 32 | static void redisIvykisAddWrite(void *privdata) { 33 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 34 | iv_fd_set_handler_out(&e->fd, redisIvykisWriteEvent); 35 | } 36 | 37 | static void redisIvykisDelWrite(void *privdata) { 38 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 39 | iv_fd_set_handler_out(&e->fd, NULL); 40 | } 41 | 42 | static void redisIvykisCleanup(void *privdata) { 43 | redisIvykisEvents *e = (redisIvykisEvents*)privdata; 44 | 45 | iv_fd_unregister(&e->fd); 46 | free(e); 47 | } 48 | 49 | static int redisIvykisAttach(redisAsyncContext *ac) { 50 | redisContext *c = &(ac->c); 51 | redisIvykisEvents *e; 52 | 53 | /* Nothing should be attached when something is already attached */ 54 | if (ac->ev.data != NULL) 55 | return REDIS_ERR; 56 | 57 | /* Create container for context and r/w events */ 58 | e = (redisIvykisEvents*)malloc(sizeof(*e)); 59 | e->context = ac; 60 | 61 | /* Register functions to start/stop listening for events */ 62 | ac->ev.addRead = redisIvykisAddRead; 63 | ac->ev.delRead = redisIvykisDelRead; 64 | ac->ev.addWrite = redisIvykisAddWrite; 65 | ac->ev.delWrite = redisIvykisDelWrite; 66 | ac->ev.cleanup = redisIvykisCleanup; 67 | ac->ev.data = e; 68 | 69 | /* Initialize and install read/write events */ 70 | IV_FD_INIT(&e->fd); 71 | e->fd.fd = c->fd; 72 | e->fd.handler_in = redisIvykisReadEvent; 73 | e->fd.handler_out = redisIvykisWriteEvent; 74 | e->fd.handler_err = NULL; 75 | e->fd.cookie = e->context; 76 | 77 | iv_fd_register(&e->fd); 78 | 79 | return REDIS_OK; 80 | } 81 | #endif 82 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/adapters/libev.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, Pieter Noordhuis 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __HIREDIS_LIBEV_H__ 32 | #define __HIREDIS_LIBEV_H__ 33 | #include 34 | #include 35 | #include 36 | #include "../hiredis.h" 37 | #include "../async.h" 38 | 39 | typedef struct redisLibevEvents { 40 | redisAsyncContext *context; 41 | struct ev_loop *loop; 42 | int reading, writing; 43 | ev_io rev, wev; 44 | } redisLibevEvents; 45 | 46 | static void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) { 47 | #if EV_MULTIPLICITY 48 | ((void)loop); 49 | #endif 50 | ((void)revents); 51 | 52 | redisLibevEvents *e = (redisLibevEvents*)watcher->data; 53 | redisAsyncHandleRead(e->context); 54 | } 55 | 56 | static void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) { 57 | #if EV_MULTIPLICITY 58 | ((void)loop); 59 | #endif 60 | ((void)revents); 61 | 62 | redisLibevEvents *e = (redisLibevEvents*)watcher->data; 63 | redisAsyncHandleWrite(e->context); 64 | } 65 | 66 | static void redisLibevAddRead(void *privdata) { 67 | redisLibevEvents *e = (redisLibevEvents*)privdata; 68 | struct ev_loop *loop = e->loop; 69 | ((void)loop); 70 | if (!e->reading) { 71 | e->reading = 1; 72 | ev_io_start(EV_A_ &e->rev); 73 | } 74 | } 75 | 76 | static void redisLibevDelRead(void *privdata) { 77 | redisLibevEvents *e = (redisLibevEvents*)privdata; 78 | struct ev_loop *loop = e->loop; 79 | ((void)loop); 80 | if (e->reading) { 81 | e->reading = 0; 82 | ev_io_stop(EV_A_ &e->rev); 83 | } 84 | } 85 | 86 | static void redisLibevAddWrite(void *privdata) { 87 | redisLibevEvents *e = (redisLibevEvents*)privdata; 88 | struct ev_loop *loop = e->loop; 89 | ((void)loop); 90 | if (!e->writing) { 91 | e->writing = 1; 92 | ev_io_start(EV_A_ &e->wev); 93 | } 94 | } 95 | 96 | static void redisLibevDelWrite(void *privdata) { 97 | redisLibevEvents *e = (redisLibevEvents*)privdata; 98 | struct ev_loop *loop = e->loop; 99 | ((void)loop); 100 | if (e->writing) { 101 | e->writing = 0; 102 | ev_io_stop(EV_A_ &e->wev); 103 | } 104 | } 105 | 106 | static void redisLibevCleanup(void *privdata) { 107 | redisLibevEvents *e = (redisLibevEvents*)privdata; 108 | redisLibevDelRead(privdata); 109 | redisLibevDelWrite(privdata); 110 | free(e); 111 | } 112 | 113 | static int redisLibevAttach(EV_P_ redisAsyncContext *ac) { 114 | redisContext *c = &(ac->c); 115 | redisLibevEvents *e; 116 | 117 | /* Nothing should be attached when something is already attached */ 118 | if (ac->ev.data != NULL) 119 | return REDIS_ERR; 120 | 121 | /* Create container for context and r/w events */ 122 | e = (redisLibevEvents*)malloc(sizeof(*e)); 123 | e->context = ac; 124 | #if EV_MULTIPLICITY 125 | e->loop = loop; 126 | #else 127 | e->loop = NULL; 128 | #endif 129 | e->reading = e->writing = 0; 130 | e->rev.data = e; 131 | e->wev.data = e; 132 | 133 | /* Register functions to start/stop listening for events */ 134 | ac->ev.addRead = redisLibevAddRead; 135 | ac->ev.delRead = redisLibevDelRead; 136 | ac->ev.addWrite = redisLibevAddWrite; 137 | ac->ev.delWrite = redisLibevDelWrite; 138 | ac->ev.cleanup = redisLibevCleanup; 139 | ac->ev.data = e; 140 | 141 | /* Initialize read/write events */ 142 | ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ); 143 | ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE); 144 | return REDIS_OK; 145 | } 146 | 147 | #endif 148 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/adapters/libevent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2010-2011, Pieter Noordhuis 3 | * 4 | * All rights reserved. 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are met: 8 | * 9 | * * Redistributions of source code must retain the above copyright notice, 10 | * this list of conditions and the following disclaimer. 11 | * * Redistributions in binary form must reproduce the above copyright 12 | * notice, this list of conditions and the following disclaimer in the 13 | * documentation and/or other materials provided with the distribution. 14 | * * Neither the name of Redis nor the names of its contributors may be used 15 | * to endorse or promote products derived from this software without 16 | * specific prior written permission. 17 | * 18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 22 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 | * POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef __HIREDIS_LIBEVENT_H__ 32 | #define __HIREDIS_LIBEVENT_H__ 33 | #include 34 | #include "../hiredis.h" 35 | #include "../async.h" 36 | 37 | typedef struct redisLibeventEvents { 38 | redisAsyncContext *context; 39 | struct event *rev, *wev; 40 | } redisLibeventEvents; 41 | 42 | static void redisLibeventReadEvent(int fd, short event, void *arg) { 43 | ((void)fd); ((void)event); 44 | redisLibeventEvents *e = (redisLibeventEvents*)arg; 45 | redisAsyncHandleRead(e->context); 46 | } 47 | 48 | static void redisLibeventWriteEvent(int fd, short event, void *arg) { 49 | ((void)fd); ((void)event); 50 | redisLibeventEvents *e = (redisLibeventEvents*)arg; 51 | redisAsyncHandleWrite(e->context); 52 | } 53 | 54 | static void redisLibeventAddRead(void *privdata) { 55 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 56 | event_add(e->rev,NULL); 57 | } 58 | 59 | static void redisLibeventDelRead(void *privdata) { 60 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 61 | event_del(e->rev); 62 | } 63 | 64 | static void redisLibeventAddWrite(void *privdata) { 65 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 66 | event_add(e->wev,NULL); 67 | } 68 | 69 | static void redisLibeventDelWrite(void *privdata) { 70 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 71 | event_del(e->wev); 72 | } 73 | 74 | static void redisLibeventCleanup(void *privdata) { 75 | redisLibeventEvents *e = (redisLibeventEvents*)privdata; 76 | event_del(e->rev); 77 | event_del(e->wev); 78 | free(e); 79 | } 80 | 81 | static int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) { 82 | redisContext *c = &(ac->c); 83 | redisLibeventEvents *e; 84 | 85 | /* Nothing should be attached when something is already attached */ 86 | if (ac->ev.data != NULL) 87 | return REDIS_ERR; 88 | 89 | /* Create container for context and r/w events */ 90 | e = (redisLibeventEvents*)malloc(sizeof(*e)); 91 | e->context = ac; 92 | 93 | /* Register functions to start/stop listening for events */ 94 | ac->ev.addRead = redisLibeventAddRead; 95 | ac->ev.delRead = redisLibeventDelRead; 96 | ac->ev.addWrite = redisLibeventAddWrite; 97 | ac->ev.delWrite = redisLibeventDelWrite; 98 | ac->ev.cleanup = redisLibeventCleanup; 99 | ac->ev.data = e; 100 | 101 | /* Initialize and install read/write events */ 102 | e->rev = event_new(base, c->fd, EV_READ, redisLibeventReadEvent, e); 103 | e->wev = event_new(base, c->fd, EV_WRITE, redisLibeventWriteEvent, e); 104 | event_add(e->rev, NULL); 105 | event_add(e->wev, NULL); 106 | return REDIS_OK; 107 | } 108 | #endif 109 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/adapters/libuv.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_LIBUV_H__ 2 | #define __HIREDIS_LIBUV_H__ 3 | #include 4 | #include 5 | #include "../hiredis.h" 6 | #include "../async.h" 7 | #include 8 | 9 | typedef struct redisLibuvEvents { 10 | redisAsyncContext* context; 11 | uv_poll_t handle; 12 | int events; 13 | } redisLibuvEvents; 14 | 15 | 16 | static void redisLibuvPoll(uv_poll_t* handle, int status, int events) { 17 | redisLibuvEvents* p = (redisLibuvEvents*)handle->data; 18 | 19 | if (status != 0) { 20 | return; 21 | } 22 | 23 | if (p->context != NULL && (events & UV_READABLE)) { 24 | redisAsyncHandleRead(p->context); 25 | } 26 | if (p->context != NULL && (events & UV_WRITABLE)) { 27 | redisAsyncHandleWrite(p->context); 28 | } 29 | } 30 | 31 | 32 | static void redisLibuvAddRead(void *privdata) { 33 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 34 | 35 | p->events |= UV_READABLE; 36 | 37 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 38 | } 39 | 40 | 41 | static void redisLibuvDelRead(void *privdata) { 42 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 43 | 44 | p->events &= ~UV_READABLE; 45 | 46 | if (p->events) { 47 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 48 | } else { 49 | uv_poll_stop(&p->handle); 50 | } 51 | } 52 | 53 | 54 | static void redisLibuvAddWrite(void *privdata) { 55 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 56 | 57 | p->events |= UV_WRITABLE; 58 | 59 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 60 | } 61 | 62 | 63 | static void redisLibuvDelWrite(void *privdata) { 64 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 65 | 66 | p->events &= ~UV_WRITABLE; 67 | 68 | if (p->events) { 69 | uv_poll_start(&p->handle, p->events, redisLibuvPoll); 70 | } else { 71 | uv_poll_stop(&p->handle); 72 | } 73 | } 74 | 75 | 76 | static void on_close(uv_handle_t* handle) { 77 | redisLibuvEvents* p = (redisLibuvEvents*)handle->data; 78 | 79 | free(p); 80 | } 81 | 82 | 83 | static void redisLibuvCleanup(void *privdata) { 84 | redisLibuvEvents* p = (redisLibuvEvents*)privdata; 85 | 86 | p->context = NULL; // indicate that context might no longer exist 87 | uv_close((uv_handle_t*)&p->handle, on_close); 88 | } 89 | 90 | 91 | static int redisLibuvAttach(redisAsyncContext* ac, uv_loop_t* loop) { 92 | redisContext *c = &(ac->c); 93 | 94 | if (ac->ev.data != NULL) { 95 | return REDIS_ERR; 96 | } 97 | 98 | ac->ev.addRead = redisLibuvAddRead; 99 | ac->ev.delRead = redisLibuvDelRead; 100 | ac->ev.addWrite = redisLibuvAddWrite; 101 | ac->ev.delWrite = redisLibuvDelWrite; 102 | ac->ev.cleanup = redisLibuvCleanup; 103 | 104 | redisLibuvEvents* p = (redisLibuvEvents*)malloc(sizeof(*p)); 105 | 106 | if (!p) { 107 | return REDIS_ERR; 108 | } 109 | 110 | memset(p, 0, sizeof(*p)); 111 | 112 | if (uv_poll_init(loop, &p->handle, c->fd) != 0) { 113 | return REDIS_ERR; 114 | } 115 | 116 | ac->ev.data = p; 117 | p->handle.data = p; 118 | p->context = ac; 119 | 120 | return REDIS_OK; 121 | } 122 | #endif 123 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/adapters/macosx.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Дмитрий Бахвалов on 13.07.15. 3 | // Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. 4 | // 5 | 6 | #ifndef __HIREDIS_MACOSX_H__ 7 | #define __HIREDIS_MACOSX_H__ 8 | 9 | #include 10 | 11 | #include "../hiredis.h" 12 | #include "../async.h" 13 | 14 | typedef struct { 15 | redisAsyncContext *context; 16 | CFSocketRef socketRef; 17 | CFRunLoopSourceRef sourceRef; 18 | } RedisRunLoop; 19 | 20 | static int freeRedisRunLoop(RedisRunLoop* redisRunLoop) { 21 | if( redisRunLoop != NULL ) { 22 | if( redisRunLoop->sourceRef != NULL ) { 23 | CFRunLoopSourceInvalidate(redisRunLoop->sourceRef); 24 | CFRelease(redisRunLoop->sourceRef); 25 | } 26 | if( redisRunLoop->socketRef != NULL ) { 27 | CFSocketInvalidate(redisRunLoop->socketRef); 28 | CFRelease(redisRunLoop->socketRef); 29 | } 30 | free(redisRunLoop); 31 | } 32 | return REDIS_ERR; 33 | } 34 | 35 | static void redisMacOSAddRead(void *privdata) { 36 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 37 | CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); 38 | } 39 | 40 | static void redisMacOSDelRead(void *privdata) { 41 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 42 | CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketReadCallBack); 43 | } 44 | 45 | static void redisMacOSAddWrite(void *privdata) { 46 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 47 | CFSocketEnableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); 48 | } 49 | 50 | static void redisMacOSDelWrite(void *privdata) { 51 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 52 | CFSocketDisableCallBacks(redisRunLoop->socketRef, kCFSocketWriteCallBack); 53 | } 54 | 55 | static void redisMacOSCleanup(void *privdata) { 56 | RedisRunLoop *redisRunLoop = (RedisRunLoop*)privdata; 57 | freeRedisRunLoop(redisRunLoop); 58 | } 59 | 60 | static void redisMacOSAsyncCallback(CFSocketRef __unused s, CFSocketCallBackType callbackType, CFDataRef __unused address, const void __unused *data, void *info) { 61 | redisAsyncContext* context = (redisAsyncContext*) info; 62 | 63 | switch (callbackType) { 64 | case kCFSocketReadCallBack: 65 | redisAsyncHandleRead(context); 66 | break; 67 | 68 | case kCFSocketWriteCallBack: 69 | redisAsyncHandleWrite(context); 70 | break; 71 | 72 | default: 73 | break; 74 | } 75 | } 76 | 77 | static int redisMacOSAttach(redisAsyncContext *redisAsyncCtx, CFRunLoopRef runLoop) { 78 | redisContext *redisCtx = &(redisAsyncCtx->c); 79 | 80 | /* Nothing should be attached when something is already attached */ 81 | if( redisAsyncCtx->ev.data != NULL ) return REDIS_ERR; 82 | 83 | RedisRunLoop* redisRunLoop = (RedisRunLoop*) calloc(1, sizeof(RedisRunLoop)); 84 | if( !redisRunLoop ) return REDIS_ERR; 85 | 86 | /* Setup redis stuff */ 87 | redisRunLoop->context = redisAsyncCtx; 88 | 89 | redisAsyncCtx->ev.addRead = redisMacOSAddRead; 90 | redisAsyncCtx->ev.delRead = redisMacOSDelRead; 91 | redisAsyncCtx->ev.addWrite = redisMacOSAddWrite; 92 | redisAsyncCtx->ev.delWrite = redisMacOSDelWrite; 93 | redisAsyncCtx->ev.cleanup = redisMacOSCleanup; 94 | redisAsyncCtx->ev.data = redisRunLoop; 95 | 96 | /* Initialize and install read/write events */ 97 | CFSocketContext socketCtx = { 0, redisAsyncCtx, NULL, NULL, NULL }; 98 | 99 | redisRunLoop->socketRef = CFSocketCreateWithNative(NULL, redisCtx->fd, 100 | kCFSocketReadCallBack | kCFSocketWriteCallBack, 101 | redisMacOSAsyncCallback, 102 | &socketCtx); 103 | if( !redisRunLoop->socketRef ) return freeRedisRunLoop(redisRunLoop); 104 | 105 | redisRunLoop->sourceRef = CFSocketCreateRunLoopSource(NULL, redisRunLoop->socketRef, 0); 106 | if( !redisRunLoop->sourceRef ) return freeRedisRunLoop(redisRunLoop); 107 | 108 | CFRunLoopAddSource(runLoop, redisRunLoop->sourceRef, kCFRunLoopDefaultMode); 109 | 110 | return REDIS_OK; 111 | } 112 | 113 | #endif 114 | 115 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/adapters/qt.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (C) 2014 Pietro Cerutti 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions 6 | * are met: 7 | * 1. Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * 2. Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * 13 | * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 17 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 | * SUCH DAMAGE. 24 | */ 25 | 26 | #ifndef __HIREDIS_QT_H__ 27 | #define __HIREDIS_QT_H__ 28 | #include 29 | #include "../async.h" 30 | 31 | static void RedisQtAddRead(void *); 32 | static void RedisQtDelRead(void *); 33 | static void RedisQtAddWrite(void *); 34 | static void RedisQtDelWrite(void *); 35 | static void RedisQtCleanup(void *); 36 | 37 | class RedisQtAdapter : public QObject { 38 | 39 | Q_OBJECT 40 | 41 | friend 42 | void RedisQtAddRead(void * adapter) { 43 | RedisQtAdapter * a = static_cast(adapter); 44 | a->addRead(); 45 | } 46 | 47 | friend 48 | void RedisQtDelRead(void * adapter) { 49 | RedisQtAdapter * a = static_cast(adapter); 50 | a->delRead(); 51 | } 52 | 53 | friend 54 | void RedisQtAddWrite(void * adapter) { 55 | RedisQtAdapter * a = static_cast(adapter); 56 | a->addWrite(); 57 | } 58 | 59 | friend 60 | void RedisQtDelWrite(void * adapter) { 61 | RedisQtAdapter * a = static_cast(adapter); 62 | a->delWrite(); 63 | } 64 | 65 | friend 66 | void RedisQtCleanup(void * adapter) { 67 | RedisQtAdapter * a = static_cast(adapter); 68 | a->cleanup(); 69 | } 70 | 71 | public: 72 | RedisQtAdapter(QObject * parent = 0) 73 | : QObject(parent), m_ctx(0), m_read(0), m_write(0) { } 74 | 75 | ~RedisQtAdapter() { 76 | if (m_ctx != 0) { 77 | m_ctx->ev.data = NULL; 78 | } 79 | } 80 | 81 | int setContext(redisAsyncContext * ac) { 82 | if (ac->ev.data != NULL) { 83 | return REDIS_ERR; 84 | } 85 | m_ctx = ac; 86 | m_ctx->ev.data = this; 87 | m_ctx->ev.addRead = RedisQtAddRead; 88 | m_ctx->ev.delRead = RedisQtDelRead; 89 | m_ctx->ev.addWrite = RedisQtAddWrite; 90 | m_ctx->ev.delWrite = RedisQtDelWrite; 91 | m_ctx->ev.cleanup = RedisQtCleanup; 92 | return REDIS_OK; 93 | } 94 | 95 | private: 96 | void addRead() { 97 | if (m_read) return; 98 | m_read = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Read, 0); 99 | connect(m_read, SIGNAL(activated(int)), this, SLOT(read())); 100 | } 101 | 102 | void delRead() { 103 | if (!m_read) return; 104 | delete m_read; 105 | m_read = 0; 106 | } 107 | 108 | void addWrite() { 109 | if (m_write) return; 110 | m_write = new QSocketNotifier(m_ctx->c.fd, QSocketNotifier::Write, 0); 111 | connect(m_write, SIGNAL(activated(int)), this, SLOT(write())); 112 | } 113 | 114 | void delWrite() { 115 | if (!m_write) return; 116 | delete m_write; 117 | m_write = 0; 118 | } 119 | 120 | void cleanup() { 121 | delRead(); 122 | delWrite(); 123 | } 124 | 125 | private slots: 126 | void read() { redisAsyncHandleRead(m_ctx); } 127 | void write() { redisAsyncHandleWrite(m_ctx); } 128 | 129 | private: 130 | redisAsyncContext * m_ctx; 131 | QSocketNotifier * m_read; 132 | QSocketNotifier * m_write; 133 | }; 134 | 135 | #endif /* !__HIREDIS_QT_H__ */ 136 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/appveyor.yml: -------------------------------------------------------------------------------- 1 | # Appveyor configuration file for CI build of hiredis on Windows (under Cygwin) 2 | environment: 3 | matrix: 4 | - CYG_ROOT: C:\cygwin64 5 | CYG_SETUP: setup-x86_64.exe 6 | CYG_MIRROR: http://cygwin.mirror.constant.com 7 | CYG_CACHE: C:\cygwin64\var\cache\setup 8 | CYG_BASH: C:\cygwin64\bin\bash 9 | CC: gcc 10 | - CYG_ROOT: C:\cygwin 11 | CYG_SETUP: setup-x86.exe 12 | CYG_MIRROR: http://cygwin.mirror.constant.com 13 | CYG_CACHE: C:\cygwin\var\cache\setup 14 | CYG_BASH: C:\cygwin\bin\bash 15 | CC: gcc 16 | TARGET: 32bit 17 | TARGET_VARS: 32bit-vars 18 | 19 | # Cache Cygwin files to speed up build 20 | cache: 21 | - '%CYG_CACHE%' 22 | clone_depth: 1 23 | 24 | # Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail 25 | init: 26 | - git config --global core.autocrlf input 27 | 28 | # Install needed build dependencies 29 | install: 30 | - ps: 'Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP"' 31 | - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages automake,bison,gcc-core,libtool,make,gettext-devel,gettext,intltool,pkg-config,clang,llvm > NUL 2>&1' 32 | - '%CYG_BASH% -lc "cygcheck -dc cygwin"' 33 | 34 | build_script: 35 | - 'echo building...' 36 | - '%CYG_BASH% -lc "cd $APPVEYOR_BUILD_FOLDER; exec 0 3 | * Copyright (c) 2010-2011, Pieter Noordhuis 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * * Neither the name of Redis nor the names of its contributors may be used 16 | * to endorse or promote products derived from this software without 17 | * specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | #ifndef __HIREDIS_ASYNC_H 33 | #define __HIREDIS_ASYNC_H 34 | #include "hiredis.h" 35 | 36 | #ifdef __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | struct redisAsyncContext; /* need forward declaration of redisAsyncContext */ 41 | struct dict; /* dictionary header is included in async.c */ 42 | 43 | /* Reply callback prototype and container */ 44 | typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*); 45 | typedef struct redisCallback { 46 | struct redisCallback *next; /* simple singly linked list */ 47 | redisCallbackFn *fn; 48 | void *privdata; 49 | } redisCallback; 50 | 51 | /* List of callbacks for either regular replies or pub/sub */ 52 | typedef struct redisCallbackList { 53 | redisCallback *head, *tail; 54 | } redisCallbackList; 55 | 56 | /* Connection callback prototypes */ 57 | typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status); 58 | typedef void (redisConnectCallback)(const struct redisAsyncContext*, int status); 59 | 60 | /* Context for an async connection to Redis */ 61 | typedef struct redisAsyncContext { 62 | /* Hold the regular context, so it can be realloc'ed. */ 63 | redisContext c; 64 | 65 | /* Setup error flags so they can be used directly. */ 66 | int err; 67 | char *errstr; 68 | 69 | /* Not used by hiredis */ 70 | void *data; 71 | 72 | /* Event library data and hooks */ 73 | struct { 74 | void *data; 75 | 76 | /* Hooks that are called when the library expects to start 77 | * reading/writing. These functions should be idempotent. */ 78 | void (*addRead)(void *privdata); 79 | void (*delRead)(void *privdata); 80 | void (*addWrite)(void *privdata); 81 | void (*delWrite)(void *privdata); 82 | void (*cleanup)(void *privdata); 83 | } ev; 84 | 85 | /* Called when either the connection is terminated due to an error or per 86 | * user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */ 87 | redisDisconnectCallback *onDisconnect; 88 | 89 | /* Called when the first write event was received. */ 90 | redisConnectCallback *onConnect; 91 | 92 | /* Regular command callbacks */ 93 | redisCallbackList replies; 94 | 95 | /* Subscription callbacks */ 96 | struct { 97 | redisCallbackList invalid; 98 | struct dict *channels; 99 | struct dict *patterns; 100 | } sub; 101 | } redisAsyncContext; 102 | 103 | /* Functions that proxy to hiredis */ 104 | redisAsyncContext *redisAsyncConnect(const char *ip, int port); 105 | redisAsyncContext *redisAsyncConnectBind(const char *ip, int port, const char *source_addr); 106 | redisAsyncContext *redisAsyncConnectBindWithReuse(const char *ip, int port, 107 | const char *source_addr); 108 | redisAsyncContext *redisAsyncConnectUnix(const char *path); 109 | int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn); 110 | int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn); 111 | void redisAsyncDisconnect(redisAsyncContext *ac); 112 | void redisAsyncFree(redisAsyncContext *ac); 113 | 114 | /* Handle read/write events */ 115 | void redisAsyncHandleRead(redisAsyncContext *ac); 116 | void redisAsyncHandleWrite(redisAsyncContext *ac); 117 | 118 | /* Command functions for an async context. Write the command to the 119 | * output buffer and register the provided callback. */ 120 | int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap); 121 | int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...); 122 | int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen); 123 | int redisAsyncFormattedCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len); 124 | 125 | #ifdef __cplusplus 126 | } 127 | #endif 128 | 129 | #endif 130 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/dict.c: -------------------------------------------------------------------------------- 1 | /* Hash table implementation. 2 | * 3 | * This file implements in memory hash tables with insert/del/replace/find/ 4 | * get-random-element operations. Hash tables will auto resize if needed 5 | * tables of power of two in size are used, collisions are handled by 6 | * chaining. See the source code for more information... :) 7 | * 8 | * Copyright (c) 2006-2010, Salvatore Sanfilippo 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions are met: 13 | * 14 | * * Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * * Neither the name of Redis nor the names of its contributors may be used 20 | * to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 | * POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #include "fmacros.h" 37 | #include 38 | #include 39 | #include 40 | #include "dict.h" 41 | 42 | /* -------------------------- private prototypes ---------------------------- */ 43 | 44 | static int _dictExpandIfNeeded(dict *ht); 45 | static unsigned long _dictNextPower(unsigned long size); 46 | static int _dictKeyIndex(dict *ht, const void *key); 47 | static int _dictInit(dict *ht, dictType *type, void *privDataPtr); 48 | 49 | /* -------------------------- hash functions -------------------------------- */ 50 | 51 | /* Generic hash function (a popular one from Bernstein). 52 | * I tested a few and this was the best. */ 53 | static unsigned int dictGenHashFunction(const unsigned char *buf, int len) { 54 | unsigned int hash = 5381; 55 | 56 | while (len--) 57 | hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */ 58 | return hash; 59 | } 60 | 61 | /* ----------------------------- API implementation ------------------------- */ 62 | 63 | /* Reset an hashtable already initialized with ht_init(). 64 | * NOTE: This function should only called by ht_destroy(). */ 65 | static void _dictReset(dict *ht) { 66 | ht->table = NULL; 67 | ht->size = 0; 68 | ht->sizemask = 0; 69 | ht->used = 0; 70 | } 71 | 72 | /* Create a new hash table */ 73 | static dict *dictCreate(dictType *type, void *privDataPtr) { 74 | dict *ht = malloc(sizeof(*ht)); 75 | _dictInit(ht,type,privDataPtr); 76 | return ht; 77 | } 78 | 79 | /* Initialize the hash table */ 80 | static int _dictInit(dict *ht, dictType *type, void *privDataPtr) { 81 | _dictReset(ht); 82 | ht->type = type; 83 | ht->privdata = privDataPtr; 84 | return DICT_OK; 85 | } 86 | 87 | /* Expand or create the hashtable */ 88 | static int dictExpand(dict *ht, unsigned long size) { 89 | dict n; /* the new hashtable */ 90 | unsigned long realsize = _dictNextPower(size), i; 91 | 92 | /* the size is invalid if it is smaller than the number of 93 | * elements already inside the hashtable */ 94 | if (ht->used > size) 95 | return DICT_ERR; 96 | 97 | _dictInit(&n, ht->type, ht->privdata); 98 | n.size = realsize; 99 | n.sizemask = realsize-1; 100 | n.table = calloc(realsize,sizeof(dictEntry*)); 101 | 102 | /* Copy all the elements from the old to the new table: 103 | * note that if the old hash table is empty ht->size is zero, 104 | * so dictExpand just creates an hash table. */ 105 | n.used = ht->used; 106 | for (i = 0; i < ht->size && ht->used > 0; i++) { 107 | dictEntry *he, *nextHe; 108 | 109 | if (ht->table[i] == NULL) continue; 110 | 111 | /* For each hash entry on this slot... */ 112 | he = ht->table[i]; 113 | while(he) { 114 | unsigned int h; 115 | 116 | nextHe = he->next; 117 | /* Get the new element index */ 118 | h = dictHashKey(ht, he->key) & n.sizemask; 119 | he->next = n.table[h]; 120 | n.table[h] = he; 121 | ht->used--; 122 | /* Pass to the next element */ 123 | he = nextHe; 124 | } 125 | } 126 | assert(ht->used == 0); 127 | free(ht->table); 128 | 129 | /* Remap the new hashtable in the old */ 130 | *ht = n; 131 | return DICT_OK; 132 | } 133 | 134 | /* Add an element to the target hash table */ 135 | static int dictAdd(dict *ht, void *key, void *val) { 136 | int index; 137 | dictEntry *entry; 138 | 139 | /* Get the index of the new element, or -1 if 140 | * the element already exists. */ 141 | if ((index = _dictKeyIndex(ht, key)) == -1) 142 | return DICT_ERR; 143 | 144 | /* Allocates the memory and stores key */ 145 | entry = malloc(sizeof(*entry)); 146 | entry->next = ht->table[index]; 147 | ht->table[index] = entry; 148 | 149 | /* Set the hash entry fields. */ 150 | dictSetHashKey(ht, entry, key); 151 | dictSetHashVal(ht, entry, val); 152 | ht->used++; 153 | return DICT_OK; 154 | } 155 | 156 | /* Add an element, discarding the old if the key already exists. 157 | * Return 1 if the key was added from scratch, 0 if there was already an 158 | * element with such key and dictReplace() just performed a value update 159 | * operation. */ 160 | static int dictReplace(dict *ht, void *key, void *val) { 161 | dictEntry *entry, auxentry; 162 | 163 | /* Try to add the element. If the key 164 | * does not exists dictAdd will succeed. */ 165 | if (dictAdd(ht, key, val) == DICT_OK) 166 | return 1; 167 | /* It already exists, get the entry */ 168 | entry = dictFind(ht, key); 169 | /* Free the old value and set the new one */ 170 | /* Set the new value and free the old one. Note that it is important 171 | * to do that in this order, as the value may just be exactly the same 172 | * as the previous one. In this context, think to reference counting, 173 | * you want to increment (set), and then decrement (free), and not the 174 | * reverse. */ 175 | auxentry = *entry; 176 | dictSetHashVal(ht, entry, val); 177 | dictFreeEntryVal(ht, &auxentry); 178 | return 0; 179 | } 180 | 181 | /* Search and remove an element */ 182 | static int dictDelete(dict *ht, const void *key) { 183 | unsigned int h; 184 | dictEntry *de, *prevde; 185 | 186 | if (ht->size == 0) 187 | return DICT_ERR; 188 | h = dictHashKey(ht, key) & ht->sizemask; 189 | de = ht->table[h]; 190 | 191 | prevde = NULL; 192 | while(de) { 193 | if (dictCompareHashKeys(ht,key,de->key)) { 194 | /* Unlink the element from the list */ 195 | if (prevde) 196 | prevde->next = de->next; 197 | else 198 | ht->table[h] = de->next; 199 | 200 | dictFreeEntryKey(ht,de); 201 | dictFreeEntryVal(ht,de); 202 | free(de); 203 | ht->used--; 204 | return DICT_OK; 205 | } 206 | prevde = de; 207 | de = de->next; 208 | } 209 | return DICT_ERR; /* not found */ 210 | } 211 | 212 | /* Destroy an entire hash table */ 213 | static int _dictClear(dict *ht) { 214 | unsigned long i; 215 | 216 | /* Free all the elements */ 217 | for (i = 0; i < ht->size && ht->used > 0; i++) { 218 | dictEntry *he, *nextHe; 219 | 220 | if ((he = ht->table[i]) == NULL) continue; 221 | while(he) { 222 | nextHe = he->next; 223 | dictFreeEntryKey(ht, he); 224 | dictFreeEntryVal(ht, he); 225 | free(he); 226 | ht->used--; 227 | he = nextHe; 228 | } 229 | } 230 | /* Free the table and the allocated cache structure */ 231 | free(ht->table); 232 | /* Re-initialize the table */ 233 | _dictReset(ht); 234 | return DICT_OK; /* never fails */ 235 | } 236 | 237 | /* Clear & Release the hash table */ 238 | static void dictRelease(dict *ht) { 239 | _dictClear(ht); 240 | free(ht); 241 | } 242 | 243 | static dictEntry *dictFind(dict *ht, const void *key) { 244 | dictEntry *he; 245 | unsigned int h; 246 | 247 | if (ht->size == 0) return NULL; 248 | h = dictHashKey(ht, key) & ht->sizemask; 249 | he = ht->table[h]; 250 | while(he) { 251 | if (dictCompareHashKeys(ht, key, he->key)) 252 | return he; 253 | he = he->next; 254 | } 255 | return NULL; 256 | } 257 | 258 | static dictIterator *dictGetIterator(dict *ht) { 259 | dictIterator *iter = malloc(sizeof(*iter)); 260 | 261 | iter->ht = ht; 262 | iter->index = -1; 263 | iter->entry = NULL; 264 | iter->nextEntry = NULL; 265 | return iter; 266 | } 267 | 268 | static dictEntry *dictNext(dictIterator *iter) { 269 | while (1) { 270 | if (iter->entry == NULL) { 271 | iter->index++; 272 | if (iter->index >= 273 | (signed)iter->ht->size) break; 274 | iter->entry = iter->ht->table[iter->index]; 275 | } else { 276 | iter->entry = iter->nextEntry; 277 | } 278 | if (iter->entry) { 279 | /* We need to save the 'next' here, the iterator user 280 | * may delete the entry we are returning. */ 281 | iter->nextEntry = iter->entry->next; 282 | return iter->entry; 283 | } 284 | } 285 | return NULL; 286 | } 287 | 288 | static void dictReleaseIterator(dictIterator *iter) { 289 | free(iter); 290 | } 291 | 292 | /* ------------------------- private functions ------------------------------ */ 293 | 294 | /* Expand the hash table if needed */ 295 | static int _dictExpandIfNeeded(dict *ht) { 296 | /* If the hash table is empty expand it to the initial size, 297 | * if the table is "full" dobule its size. */ 298 | if (ht->size == 0) 299 | return dictExpand(ht, DICT_HT_INITIAL_SIZE); 300 | if (ht->used == ht->size) 301 | return dictExpand(ht, ht->size*2); 302 | return DICT_OK; 303 | } 304 | 305 | /* Our hash table capability is a power of two */ 306 | static unsigned long _dictNextPower(unsigned long size) { 307 | unsigned long i = DICT_HT_INITIAL_SIZE; 308 | 309 | if (size >= LONG_MAX) return LONG_MAX; 310 | while(1) { 311 | if (i >= size) 312 | return i; 313 | i *= 2; 314 | } 315 | } 316 | 317 | /* Returns the index of a free slot that can be populated with 318 | * an hash entry for the given 'key'. 319 | * If the key already exists, -1 is returned. */ 320 | static int _dictKeyIndex(dict *ht, const void *key) { 321 | unsigned int h; 322 | dictEntry *he; 323 | 324 | /* Expand the hashtable if needed */ 325 | if (_dictExpandIfNeeded(ht) == DICT_ERR) 326 | return -1; 327 | /* Compute the key hash value */ 328 | h = dictHashKey(ht, key) & ht->sizemask; 329 | /* Search if this slot does not already contain the given key */ 330 | he = ht->table[h]; 331 | while(he) { 332 | if (dictCompareHashKeys(ht, key, he->key)) 333 | return -1; 334 | he = he->next; 335 | } 336 | return h; 337 | } 338 | 339 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/dict.h: -------------------------------------------------------------------------------- 1 | /* Hash table implementation. 2 | * 3 | * This file implements in memory hash tables with insert/del/replace/find/ 4 | * get-random-element operations. Hash tables will auto resize if needed 5 | * tables of power of two in size are used, collisions are handled by 6 | * chaining. See the source code for more information... :) 7 | * 8 | * Copyright (c) 2006-2010, Salvatore Sanfilippo 9 | * All rights reserved. 10 | * 11 | * Redistribution and use in source and binary forms, with or without 12 | * modification, are permitted provided that the following conditions are met: 13 | * 14 | * * Redistributions of source code must retain the above copyright notice, 15 | * this list of conditions and the following disclaimer. 16 | * * Redistributions in binary form must reproduce the above copyright 17 | * notice, this list of conditions and the following disclaimer in the 18 | * documentation and/or other materials provided with the distribution. 19 | * * Neither the name of Redis nor the names of its contributors may be used 20 | * to endorse or promote products derived from this software without 21 | * specific prior written permission. 22 | * 23 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 24 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 27 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33 | * POSSIBILITY OF SUCH DAMAGE. 34 | */ 35 | 36 | #ifndef __DICT_H 37 | #define __DICT_H 38 | 39 | #define DICT_OK 0 40 | #define DICT_ERR 1 41 | 42 | /* Unused arguments generate annoying warnings... */ 43 | #define DICT_NOTUSED(V) ((void) V) 44 | 45 | typedef struct dictEntry { 46 | void *key; 47 | void *val; 48 | struct dictEntry *next; 49 | } dictEntry; 50 | 51 | typedef struct dictType { 52 | unsigned int (*hashFunction)(const void *key); 53 | void *(*keyDup)(void *privdata, const void *key); 54 | void *(*valDup)(void *privdata, const void *obj); 55 | int (*keyCompare)(void *privdata, const void *key1, const void *key2); 56 | void (*keyDestructor)(void *privdata, void *key); 57 | void (*valDestructor)(void *privdata, void *obj); 58 | } dictType; 59 | 60 | typedef struct dict { 61 | dictEntry **table; 62 | dictType *type; 63 | unsigned long size; 64 | unsigned long sizemask; 65 | unsigned long used; 66 | void *privdata; 67 | } dict; 68 | 69 | typedef struct dictIterator { 70 | dict *ht; 71 | int index; 72 | dictEntry *entry, *nextEntry; 73 | } dictIterator; 74 | 75 | /* This is the initial size of every hash table */ 76 | #define DICT_HT_INITIAL_SIZE 4 77 | 78 | /* ------------------------------- Macros ------------------------------------*/ 79 | #define dictFreeEntryVal(ht, entry) \ 80 | if ((ht)->type->valDestructor) \ 81 | (ht)->type->valDestructor((ht)->privdata, (entry)->val) 82 | 83 | #define dictSetHashVal(ht, entry, _val_) do { \ 84 | if ((ht)->type->valDup) \ 85 | entry->val = (ht)->type->valDup((ht)->privdata, _val_); \ 86 | else \ 87 | entry->val = (_val_); \ 88 | } while(0) 89 | 90 | #define dictFreeEntryKey(ht, entry) \ 91 | if ((ht)->type->keyDestructor) \ 92 | (ht)->type->keyDestructor((ht)->privdata, (entry)->key) 93 | 94 | #define dictSetHashKey(ht, entry, _key_) do { \ 95 | if ((ht)->type->keyDup) \ 96 | entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \ 97 | else \ 98 | entry->key = (_key_); \ 99 | } while(0) 100 | 101 | #define dictCompareHashKeys(ht, key1, key2) \ 102 | (((ht)->type->keyCompare) ? \ 103 | (ht)->type->keyCompare((ht)->privdata, key1, key2) : \ 104 | (key1) == (key2)) 105 | 106 | #define dictHashKey(ht, key) (ht)->type->hashFunction(key) 107 | 108 | #define dictGetEntryKey(he) ((he)->key) 109 | #define dictGetEntryVal(he) ((he)->val) 110 | #define dictSlots(ht) ((ht)->size) 111 | #define dictSize(ht) ((ht)->used) 112 | 113 | /* API */ 114 | static unsigned int dictGenHashFunction(const unsigned char *buf, int len); 115 | static dict *dictCreate(dictType *type, void *privDataPtr); 116 | static int dictExpand(dict *ht, unsigned long size); 117 | static int dictAdd(dict *ht, void *key, void *val); 118 | static int dictReplace(dict *ht, void *key, void *val); 119 | static int dictDelete(dict *ht, const void *key); 120 | static void dictRelease(dict *ht); 121 | static dictEntry * dictFind(dict *ht, const void *key); 122 | static dictIterator *dictGetIterator(dict *ht); 123 | static dictEntry *dictNext(dictIterator *iter); 124 | static void dictReleaseIterator(dictIterator *iter); 125 | 126 | #endif /* __DICT_H */ 127 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example-ae.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | /* Put event loop in the global scope, so it can be explicitly stopped */ 11 | static aeEventLoop *loop; 12 | 13 | void getCallback(redisAsyncContext *c, void *r, void *privdata) { 14 | redisReply *reply = r; 15 | if (reply == NULL) return; 16 | printf("argv[%s]: %s\n", (char*)privdata, reply->str); 17 | 18 | /* Disconnect after receiving the reply to GET */ 19 | redisAsyncDisconnect(c); 20 | } 21 | 22 | void connectCallback(const redisAsyncContext *c, int status) { 23 | if (status != REDIS_OK) { 24 | printf("Error: %s\n", c->errstr); 25 | aeStop(loop); 26 | return; 27 | } 28 | 29 | printf("Connected...\n"); 30 | } 31 | 32 | void disconnectCallback(const redisAsyncContext *c, int status) { 33 | if (status != REDIS_OK) { 34 | printf("Error: %s\n", c->errstr); 35 | aeStop(loop); 36 | return; 37 | } 38 | 39 | printf("Disconnected...\n"); 40 | aeStop(loop); 41 | } 42 | 43 | int main (int argc, char **argv) { 44 | signal(SIGPIPE, SIG_IGN); 45 | 46 | redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); 47 | if (c->err) { 48 | /* Let *c leak for now... */ 49 | printf("Error: %s\n", c->errstr); 50 | return 1; 51 | } 52 | 53 | loop = aeCreateEventLoop(64); 54 | redisAeAttach(loop, c); 55 | redisAsyncSetConnectCallback(c,connectCallback); 56 | redisAsyncSetDisconnectCallback(c,disconnectCallback); 57 | redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); 58 | redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); 59 | aeMain(loop); 60 | return 0; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example-glib.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | static GMainLoop *mainloop; 8 | 9 | static void 10 | connect_cb (const redisAsyncContext *ac G_GNUC_UNUSED, 11 | int status) 12 | { 13 | if (status != REDIS_OK) { 14 | g_printerr("Failed to connect: %s\n", ac->errstr); 15 | g_main_loop_quit(mainloop); 16 | } else { 17 | g_printerr("Connected...\n"); 18 | } 19 | } 20 | 21 | static void 22 | disconnect_cb (const redisAsyncContext *ac G_GNUC_UNUSED, 23 | int status) 24 | { 25 | if (status != REDIS_OK) { 26 | g_error("Failed to disconnect: %s", ac->errstr); 27 | } else { 28 | g_printerr("Disconnected...\n"); 29 | g_main_loop_quit(mainloop); 30 | } 31 | } 32 | 33 | static void 34 | command_cb(redisAsyncContext *ac, 35 | gpointer r, 36 | gpointer user_data G_GNUC_UNUSED) 37 | { 38 | redisReply *reply = r; 39 | 40 | if (reply) { 41 | g_print("REPLY: %s\n", reply->str); 42 | } 43 | 44 | redisAsyncDisconnect(ac); 45 | } 46 | 47 | gint 48 | main (gint argc G_GNUC_UNUSED, 49 | gchar *argv[] G_GNUC_UNUSED) 50 | { 51 | redisAsyncContext *ac; 52 | GMainContext *context = NULL; 53 | GSource *source; 54 | 55 | ac = redisAsyncConnect("127.0.0.1", 6379); 56 | if (ac->err) { 57 | g_printerr("%s\n", ac->errstr); 58 | exit(EXIT_FAILURE); 59 | } 60 | 61 | source = redis_source_new(ac); 62 | mainloop = g_main_loop_new(context, FALSE); 63 | g_source_attach(source, context); 64 | 65 | redisAsyncSetConnectCallback(ac, connect_cb); 66 | redisAsyncSetDisconnectCallback(ac, disconnect_cb); 67 | redisAsyncCommand(ac, command_cb, NULL, "SET key 1234"); 68 | redisAsyncCommand(ac, command_cb, NULL, "GET key"); 69 | 70 | g_main_loop_run(mainloop); 71 | 72 | return EXIT_SUCCESS; 73 | } 74 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example-ivykis.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | void getCallback(redisAsyncContext *c, void *r, void *privdata) { 11 | redisReply *reply = r; 12 | if (reply == NULL) return; 13 | printf("argv[%s]: %s\n", (char*)privdata, reply->str); 14 | 15 | /* Disconnect after receiving the reply to GET */ 16 | redisAsyncDisconnect(c); 17 | } 18 | 19 | void connectCallback(const redisAsyncContext *c, int status) { 20 | if (status != REDIS_OK) { 21 | printf("Error: %s\n", c->errstr); 22 | return; 23 | } 24 | printf("Connected...\n"); 25 | } 26 | 27 | void disconnectCallback(const redisAsyncContext *c, int status) { 28 | if (status != REDIS_OK) { 29 | printf("Error: %s\n", c->errstr); 30 | return; 31 | } 32 | printf("Disconnected...\n"); 33 | } 34 | 35 | int main (int argc, char **argv) { 36 | signal(SIGPIPE, SIG_IGN); 37 | 38 | iv_init(); 39 | 40 | redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); 41 | if (c->err) { 42 | /* Let *c leak for now... */ 43 | printf("Error: %s\n", c->errstr); 44 | return 1; 45 | } 46 | 47 | redisIvykisAttach(c); 48 | redisAsyncSetConnectCallback(c,connectCallback); 49 | redisAsyncSetDisconnectCallback(c,disconnectCallback); 50 | redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); 51 | redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); 52 | 53 | iv_main(); 54 | 55 | iv_deinit(); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example-libev.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | void getCallback(redisAsyncContext *c, void *r, void *privdata) { 11 | redisReply *reply = r; 12 | if (reply == NULL) return; 13 | printf("argv[%s]: %s\n", (char*)privdata, reply->str); 14 | 15 | /* Disconnect after receiving the reply to GET */ 16 | redisAsyncDisconnect(c); 17 | } 18 | 19 | void connectCallback(const redisAsyncContext *c, int status) { 20 | if (status != REDIS_OK) { 21 | printf("Error: %s\n", c->errstr); 22 | return; 23 | } 24 | printf("Connected...\n"); 25 | } 26 | 27 | void disconnectCallback(const redisAsyncContext *c, int status) { 28 | if (status != REDIS_OK) { 29 | printf("Error: %s\n", c->errstr); 30 | return; 31 | } 32 | printf("Disconnected...\n"); 33 | } 34 | 35 | int main (int argc, char **argv) { 36 | signal(SIGPIPE, SIG_IGN); 37 | 38 | redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); 39 | if (c->err) { 40 | /* Let *c leak for now... */ 41 | printf("Error: %s\n", c->errstr); 42 | return 1; 43 | } 44 | 45 | redisLibevAttach(EV_DEFAULT_ c); 46 | redisAsyncSetConnectCallback(c,connectCallback); 47 | redisAsyncSetDisconnectCallback(c,disconnectCallback); 48 | redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); 49 | redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); 50 | ev_loop(EV_DEFAULT_ 0); 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example-libevent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | void getCallback(redisAsyncContext *c, void *r, void *privdata) { 11 | redisReply *reply = r; 12 | if (reply == NULL) return; 13 | printf("argv[%s]: %s\n", (char*)privdata, reply->str); 14 | 15 | /* Disconnect after receiving the reply to GET */ 16 | redisAsyncDisconnect(c); 17 | } 18 | 19 | void connectCallback(const redisAsyncContext *c, int status) { 20 | if (status != REDIS_OK) { 21 | printf("Error: %s\n", c->errstr); 22 | return; 23 | } 24 | printf("Connected...\n"); 25 | } 26 | 27 | void disconnectCallback(const redisAsyncContext *c, int status) { 28 | if (status != REDIS_OK) { 29 | printf("Error: %s\n", c->errstr); 30 | return; 31 | } 32 | printf("Disconnected...\n"); 33 | } 34 | 35 | int main (int argc, char **argv) { 36 | signal(SIGPIPE, SIG_IGN); 37 | struct event_base *base = event_base_new(); 38 | 39 | redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); 40 | if (c->err) { 41 | /* Let *c leak for now... */ 42 | printf("Error: %s\n", c->errstr); 43 | return 1; 44 | } 45 | 46 | redisLibeventAttach(c,base); 47 | redisAsyncSetConnectCallback(c,connectCallback); 48 | redisAsyncSetDisconnectCallback(c,disconnectCallback); 49 | redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); 50 | redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); 51 | event_base_dispatch(base); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example-libuv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | void getCallback(redisAsyncContext *c, void *r, void *privdata) { 11 | redisReply *reply = r; 12 | if (reply == NULL) return; 13 | printf("argv[%s]: %s\n", (char*)privdata, reply->str); 14 | 15 | /* Disconnect after receiving the reply to GET */ 16 | redisAsyncDisconnect(c); 17 | } 18 | 19 | void connectCallback(const redisAsyncContext *c, int status) { 20 | if (status != REDIS_OK) { 21 | printf("Error: %s\n", c->errstr); 22 | return; 23 | } 24 | printf("Connected...\n"); 25 | } 26 | 27 | void disconnectCallback(const redisAsyncContext *c, int status) { 28 | if (status != REDIS_OK) { 29 | printf("Error: %s\n", c->errstr); 30 | return; 31 | } 32 | printf("Disconnected...\n"); 33 | } 34 | 35 | int main (int argc, char **argv) { 36 | signal(SIGPIPE, SIG_IGN); 37 | uv_loop_t* loop = uv_default_loop(); 38 | 39 | redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); 40 | if (c->err) { 41 | /* Let *c leak for now... */ 42 | printf("Error: %s\n", c->errstr); 43 | return 1; 44 | } 45 | 46 | redisLibuvAttach(c,loop); 47 | redisAsyncSetConnectCallback(c,connectCallback); 48 | redisAsyncSetDisconnectCallback(c,disconnectCallback); 49 | redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); 50 | redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); 51 | uv_run(loop, UV_RUN_DEFAULT); 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example-macosx.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Дмитрий Бахвалов on 13.07.15. 3 | // Copyright (c) 2015 Dmitry Bakhvalov. All rights reserved. 4 | // 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | void getCallback(redisAsyncContext *c, void *r, void *privdata) { 13 | redisReply *reply = r; 14 | if (reply == NULL) return; 15 | printf("argv[%s]: %s\n", (char*)privdata, reply->str); 16 | 17 | /* Disconnect after receiving the reply to GET */ 18 | redisAsyncDisconnect(c); 19 | } 20 | 21 | void connectCallback(const redisAsyncContext *c, int status) { 22 | if (status != REDIS_OK) { 23 | printf("Error: %s\n", c->errstr); 24 | return; 25 | } 26 | printf("Connected...\n"); 27 | } 28 | 29 | void disconnectCallback(const redisAsyncContext *c, int status) { 30 | if (status != REDIS_OK) { 31 | printf("Error: %s\n", c->errstr); 32 | return; 33 | } 34 | CFRunLoopStop(CFRunLoopGetCurrent()); 35 | printf("Disconnected...\n"); 36 | } 37 | 38 | int main (int argc, char **argv) { 39 | signal(SIGPIPE, SIG_IGN); 40 | 41 | CFRunLoopRef loop = CFRunLoopGetCurrent(); 42 | if( !loop ) { 43 | printf("Error: Cannot get current run loop\n"); 44 | return 1; 45 | } 46 | 47 | redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); 48 | if (c->err) { 49 | /* Let *c leak for now... */ 50 | printf("Error: %s\n", c->errstr); 51 | return 1; 52 | } 53 | 54 | redisMacOSAttach(c, loop); 55 | 56 | redisAsyncSetConnectCallback(c,connectCallback); 57 | redisAsyncSetDisconnectCallback(c,disconnectCallback); 58 | 59 | redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1])); 60 | redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key"); 61 | 62 | CFRunLoopRun(); 63 | 64 | return 0; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example-qt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #include 5 | #include 6 | 7 | #include "example-qt.h" 8 | 9 | void getCallback(redisAsyncContext *, void * r, void * privdata) { 10 | 11 | redisReply * reply = static_cast(r); 12 | ExampleQt * ex = static_cast(privdata); 13 | if (reply == nullptr || ex == nullptr) return; 14 | 15 | cout << "key: " << reply->str << endl; 16 | 17 | ex->finish(); 18 | } 19 | 20 | void ExampleQt::run() { 21 | 22 | m_ctx = redisAsyncConnect("localhost", 6379); 23 | 24 | if (m_ctx->err) { 25 | cerr << "Error: " << m_ctx->errstr << endl; 26 | redisAsyncFree(m_ctx); 27 | emit finished(); 28 | } 29 | 30 | m_adapter.setContext(m_ctx); 31 | 32 | redisAsyncCommand(m_ctx, NULL, NULL, "SET key %s", m_value); 33 | redisAsyncCommand(m_ctx, getCallback, this, "GET key"); 34 | } 35 | 36 | int main (int argc, char **argv) { 37 | 38 | QCoreApplication app(argc, argv); 39 | 40 | ExampleQt example(argv[argc-1]); 41 | 42 | QObject::connect(&example, SIGNAL(finished()), &app, SLOT(quit())); 43 | QTimer::singleShot(0, &example, SLOT(run())); 44 | 45 | return app.exec(); 46 | } 47 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example-qt.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_EXAMPLE_QT_H 2 | #define __HIREDIS_EXAMPLE_QT_H 3 | 4 | #include 5 | 6 | class ExampleQt : public QObject { 7 | 8 | Q_OBJECT 9 | 10 | public: 11 | ExampleQt(const char * value, QObject * parent = 0) 12 | : QObject(parent), m_value(value) {} 13 | 14 | signals: 15 | void finished(); 16 | 17 | public slots: 18 | void run(); 19 | 20 | private: 21 | void finish() { emit finished(); } 22 | 23 | private: 24 | const char * m_value; 25 | redisAsyncContext * m_ctx; 26 | RedisQtAdapter m_adapter; 27 | 28 | friend 29 | void getCallback(redisAsyncContext *, void *, void *); 30 | }; 31 | 32 | #endif /* !__HIREDIS_EXAMPLE_QT_H */ 33 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/examples/example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | int main(int argc, char **argv) { 8 | unsigned int j; 9 | redisContext *c; 10 | redisReply *reply; 11 | const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; 12 | int port = (argc > 2) ? atoi(argv[2]) : 6379; 13 | 14 | struct timeval timeout = { 1, 500000 }; // 1.5 seconds 15 | c = redisConnectWithTimeout(hostname, port, timeout); 16 | if (c == NULL || c->err) { 17 | if (c) { 18 | printf("Connection error: %s\n", c->errstr); 19 | redisFree(c); 20 | } else { 21 | printf("Connection error: can't allocate redis context\n"); 22 | } 23 | exit(1); 24 | } 25 | 26 | /* PING server */ 27 | reply = redisCommand(c,"PING"); 28 | printf("PING: %s\n", reply->str); 29 | freeReplyObject(reply); 30 | 31 | /* Set a key */ 32 | reply = redisCommand(c,"SET %s %s", "foo", "hello world"); 33 | printf("SET: %s\n", reply->str); 34 | freeReplyObject(reply); 35 | 36 | /* Set a key using binary safe API */ 37 | reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5); 38 | printf("SET (binary API): %s\n", reply->str); 39 | freeReplyObject(reply); 40 | 41 | /* Try a GET and two INCR */ 42 | reply = redisCommand(c,"GET foo"); 43 | printf("GET foo: %s\n", reply->str); 44 | freeReplyObject(reply); 45 | 46 | reply = redisCommand(c,"INCR counter"); 47 | printf("INCR counter: %lld\n", reply->integer); 48 | freeReplyObject(reply); 49 | /* again ... */ 50 | reply = redisCommand(c,"INCR counter"); 51 | printf("INCR counter: %lld\n", reply->integer); 52 | freeReplyObject(reply); 53 | 54 | /* Create a list of numbers, from 0 to 9 */ 55 | reply = redisCommand(c,"DEL mylist"); 56 | freeReplyObject(reply); 57 | for (j = 0; j < 10; j++) { 58 | char buf[64]; 59 | 60 | snprintf(buf,64,"%u",j); 61 | reply = redisCommand(c,"LPUSH mylist element-%s", buf); 62 | freeReplyObject(reply); 63 | } 64 | 65 | /* Let's check what we have inside the list */ 66 | reply = redisCommand(c,"LRANGE mylist 0 -1"); 67 | if (reply->type == REDIS_REPLY_ARRAY) { 68 | for (j = 0; j < reply->elements; j++) { 69 | printf("%u) %s\n", j, reply->element[j]->str); 70 | } 71 | } 72 | freeReplyObject(reply); 73 | 74 | /* Disconnects and frees the context */ 75 | redisFree(c); 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/fmacros.h: -------------------------------------------------------------------------------- 1 | #ifndef __HIREDIS_FMACRO_H 2 | #define __HIREDIS_FMACRO_H 3 | 4 | #if defined(__linux__) 5 | #define _BSD_SOURCE 6 | #define _DEFAULT_SOURCE 7 | #endif 8 | 9 | #if defined(__CYGWIN__) 10 | #include 11 | #endif 12 | 13 | #if defined(__sun__) 14 | #define _POSIX_C_SOURCE 200112L 15 | #else 16 | #if !(defined(__APPLE__) && defined(__MACH__)) 17 | #define _XOPEN_SOURCE 600 18 | #endif 19 | #endif 20 | 21 | #if defined(__APPLE__) && defined(__MACH__) 22 | #define _OSX 23 | #endif 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/hiredis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2011, Salvatore Sanfilippo 3 | * Copyright (c) 2010-2014, Pieter Noordhuis 4 | * Copyright (c) 2015, Matt Stancliff , 5 | * Jan-Erik Rediger 6 | * 7 | * All rights reserved. 8 | * 9 | * Redistribution and use in source and binary forms, with or without 10 | * modification, are permitted provided that the following conditions are met: 11 | * 12 | * * Redistributions of source code must retain the above copyright notice, 13 | * this list of conditions and the following disclaimer. 14 | * * Redistributions in binary form must reproduce the above copyright 15 | * notice, this list of conditions and the following disclaimer in the 16 | * documentation and/or other materials provided with the distribution. 17 | * * Neither the name of Redis nor the names of its contributors may be used 18 | * to endorse or promote products derived from this software without 19 | * specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 22 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 25 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 | * POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | #ifndef __HIREDIS_H 35 | #define __HIREDIS_H 36 | #include "read.h" 37 | #include /* for va_list */ 38 | #include /* for struct timeval */ 39 | #include /* uintXX_t, etc */ 40 | #include "sds.h" /* for sds */ 41 | 42 | #define HIREDIS_MAJOR 0 43 | #define HIREDIS_MINOR 13 44 | #define HIREDIS_PATCH 3 45 | #define HIREDIS_SONAME 0.13 46 | 47 | /* Connection type can be blocking or non-blocking and is set in the 48 | * least significant bit of the flags field in redisContext. */ 49 | #define REDIS_BLOCK 0x1 50 | 51 | /* Connection may be disconnected before being free'd. The second bit 52 | * in the flags field is set when the context is connected. */ 53 | #define REDIS_CONNECTED 0x2 54 | 55 | /* The async API might try to disconnect cleanly and flush the output 56 | * buffer and read all subsequent replies before disconnecting. 57 | * This flag means no new commands can come in and the connection 58 | * should be terminated once all replies have been read. */ 59 | #define REDIS_DISCONNECTING 0x4 60 | 61 | /* Flag specific to the async API which means that the context should be clean 62 | * up as soon as possible. */ 63 | #define REDIS_FREEING 0x8 64 | 65 | /* Flag that is set when an async callback is executed. */ 66 | #define REDIS_IN_CALLBACK 0x10 67 | 68 | /* Flag that is set when the async context has one or more subscriptions. */ 69 | #define REDIS_SUBSCRIBED 0x20 70 | 71 | /* Flag that is set when monitor mode is active */ 72 | #define REDIS_MONITORING 0x40 73 | 74 | /* Flag that is set when we should set SO_REUSEADDR before calling bind() */ 75 | #define REDIS_REUSEADDR 0x80 76 | 77 | #define REDIS_KEEPALIVE_INTERVAL 15 /* seconds */ 78 | 79 | /* number of times we retry to connect in the case of EADDRNOTAVAIL and 80 | * SO_REUSEADDR is being used. */ 81 | #define REDIS_CONNECT_RETRIES 10 82 | 83 | /* strerror_r has two completely different prototypes and behaviors 84 | * depending on system issues, so we need to operate on the error buffer 85 | * differently depending on which strerror_r we're using. */ 86 | #ifndef _GNU_SOURCE 87 | /* "regular" POSIX strerror_r that does the right thing. */ 88 | #define __redis_strerror_r(errno, buf, len) \ 89 | do { \ 90 | strerror_r((errno), (buf), (len)); \ 91 | } while (0) 92 | #else 93 | /* "bad" GNU strerror_r we need to clean up after. */ 94 | #define __redis_strerror_r(errno, buf, len) \ 95 | do { \ 96 | char *err_str = strerror_r((errno), (buf), (len)); \ 97 | /* If return value _isn't_ the start of the buffer we passed in, \ 98 | * then GNU strerror_r returned an internal static buffer and we \ 99 | * need to copy the result into our private buffer. */ \ 100 | if (err_str != (buf)) { \ 101 | strncpy((buf), err_str, ((len) - 1)); \ 102 | buf[(len)-1] = '\0'; \ 103 | } \ 104 | } while (0) 105 | #endif 106 | 107 | #ifdef __cplusplus 108 | extern "C" { 109 | #endif 110 | 111 | /* This is the reply object returned by redisCommand() */ 112 | typedef struct redisReply { 113 | int type; /* REDIS_REPLY_* */ 114 | long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ 115 | size_t len; /* Length of string */ 116 | char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */ 117 | size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ 118 | struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */ 119 | } redisReply; 120 | 121 | redisReader *redisReaderCreate(void); 122 | 123 | /* Function to free the reply objects hiredis returns by default. */ 124 | void freeReplyObject(void *reply); 125 | 126 | /* Functions to format a command according to the protocol. */ 127 | int redisvFormatCommand(char **target, const char *format, va_list ap); 128 | int redisFormatCommand(char **target, const char *format, ...); 129 | int redisFormatCommandArgv(char **target, int argc, const char **argv, const size_t *argvlen); 130 | int redisFormatSdsCommandArgv(sds *target, int argc, const char ** argv, const size_t *argvlen); 131 | void redisFreeCommand(char *cmd); 132 | void redisFreeSdsCommand(sds cmd); 133 | 134 | enum redisConnectionType { 135 | REDIS_CONN_TCP, 136 | REDIS_CONN_UNIX 137 | }; 138 | 139 | /* Context for a connection to Redis */ 140 | typedef struct redisContext { 141 | int err; /* Error flags, 0 when there is no error */ 142 | char errstr[128]; /* String representation of error when applicable */ 143 | int fd; 144 | int flags; 145 | char *obuf; /* Write buffer */ 146 | redisReader *reader; /* Protocol reader */ 147 | 148 | enum redisConnectionType connection_type; 149 | struct timeval *timeout; 150 | 151 | struct { 152 | char *host; 153 | char *source_addr; 154 | int port; 155 | } tcp; 156 | 157 | struct { 158 | char *path; 159 | } unix_sock; 160 | 161 | } redisContext; 162 | 163 | redisContext *redisConnect(const char *ip, int port); 164 | redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv); 165 | redisContext *redisConnectNonBlock(const char *ip, int port); 166 | redisContext *redisConnectBindNonBlock(const char *ip, int port, 167 | const char *source_addr); 168 | redisContext *redisConnectBindNonBlockWithReuse(const char *ip, int port, 169 | const char *source_addr); 170 | redisContext *redisConnectUnix(const char *path); 171 | redisContext *redisConnectUnixWithTimeout(const char *path, const struct timeval tv); 172 | redisContext *redisConnectUnixNonBlock(const char *path); 173 | redisContext *redisConnectFd(int fd); 174 | 175 | /** 176 | * Reconnect the given context using the saved information. 177 | * 178 | * This re-uses the exact same connect options as in the initial connection. 179 | * host, ip (or path), timeout and bind address are reused, 180 | * flags are used unmodified from the existing context. 181 | * 182 | * Returns REDIS_OK on successful connect or REDIS_ERR otherwise. 183 | */ 184 | int redisReconnect(redisContext *c); 185 | 186 | int redisSetTimeout(redisContext *c, const struct timeval tv); 187 | int redisEnableKeepAlive(redisContext *c); 188 | void redisFree(redisContext *c); 189 | int redisFreeKeepFd(redisContext *c); 190 | int redisBufferRead(redisContext *c); 191 | int redisBufferWrite(redisContext *c, int *done); 192 | 193 | /* In a blocking context, this function first checks if there are unconsumed 194 | * replies to return and returns one if so. Otherwise, it flushes the output 195 | * buffer to the socket and reads until it has a reply. In a non-blocking 196 | * context, it will return unconsumed replies until there are no more. */ 197 | int redisGetReply(redisContext *c, void **reply); 198 | int redisGetReplyFromReader(redisContext *c, void **reply); 199 | 200 | /* Write a formatted command to the output buffer. Use these functions in blocking mode 201 | * to get a pipeline of commands. */ 202 | int redisAppendFormattedCommand(redisContext *c, const char *cmd, size_t len); 203 | 204 | /* Write a command to the output buffer. Use these functions in blocking mode 205 | * to get a pipeline of commands. */ 206 | int redisvAppendCommand(redisContext *c, const char *format, va_list ap); 207 | int redisAppendCommand(redisContext *c, const char *format, ...); 208 | int redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); 209 | 210 | /* Issue a command to Redis. In a blocking context, it is identical to calling 211 | * redisAppendCommand, followed by redisGetReply. The function will return 212 | * NULL if there was an error in performing the request, otherwise it will 213 | * return the reply. In a non-blocking context, it is identical to calling 214 | * only redisAppendCommand and will always return NULL. */ 215 | void *redisvCommand(redisContext *c, const char *format, va_list ap); 216 | void *redisCommand(redisContext *c, const char *format, ...); 217 | void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen); 218 | 219 | #ifdef __cplusplus 220 | } 221 | #endif 222 | 223 | #endif 224 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/net.h: -------------------------------------------------------------------------------- 1 | /* Extracted from anet.c to work properly with Hiredis error reporting. 2 | * 3 | * Copyright (c) 2009-2011, Salvatore Sanfilippo 4 | * Copyright (c) 2010-2014, Pieter Noordhuis 5 | * Copyright (c) 2015, Matt Stancliff , 6 | * Jan-Erik Rediger 7 | * 8 | * All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions are met: 12 | * 13 | * * Redistributions of source code must retain the above copyright notice, 14 | * this list of conditions and the following disclaimer. 15 | * * Redistributions in binary form must reproduce the above copyright 16 | * notice, this list of conditions and the following disclaimer in the 17 | * documentation and/or other materials provided with the distribution. 18 | * * Neither the name of Redis nor the names of its contributors may be used 19 | * to endorse or promote products derived from this software without 20 | * specific prior written permission. 21 | * 22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | * POSSIBILITY OF SUCH DAMAGE. 33 | */ 34 | 35 | #ifndef __NET_H 36 | #define __NET_H 37 | 38 | #include "hiredis.h" 39 | 40 | #if defined(__sun) 41 | #define AF_LOCAL AF_UNIX 42 | #endif 43 | 44 | int redisCheckSocketError(redisContext *c); 45 | int redisContextSetTimeout(redisContext *c, const struct timeval tv); 46 | int redisContextConnectTcp(redisContext *c, const char *addr, int port, const struct timeval *timeout); 47 | int redisContextConnectBindTcp(redisContext *c, const char *addr, int port, 48 | const struct timeval *timeout, 49 | const char *source_addr); 50 | int redisContextConnectUnix(redisContext *c, const char *path, const struct timeval *timeout); 51 | int redisKeepAlive(redisContext *c, int interval); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/read.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2011, Salvatore Sanfilippo 3 | * Copyright (c) 2010-2011, Pieter Noordhuis 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * * Neither the name of Redis nor the names of its contributors may be used 16 | * to endorse or promote products derived from this software without 17 | * specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | 33 | #include "fmacros.h" 34 | #include 35 | #include 36 | #ifndef _MSC_VER 37 | #include 38 | #endif 39 | #include 40 | #include 41 | #include 42 | 43 | #include "read.h" 44 | #include "sds.h" 45 | 46 | static void __redisReaderSetError(redisReader *r, int type, const char *str) { 47 | size_t len; 48 | 49 | if (r->reply != NULL && r->fn && r->fn->freeObject) { 50 | r->fn->freeObject(r->reply); 51 | r->reply = NULL; 52 | } 53 | 54 | /* Clear input buffer on errors. */ 55 | if (r->buf != NULL) { 56 | sdsfree(r->buf); 57 | r->buf = NULL; 58 | r->pos = r->len = 0; 59 | } 60 | 61 | /* Reset task stack. */ 62 | r->ridx = -1; 63 | 64 | /* Set error. */ 65 | r->err = type; 66 | len = strlen(str); 67 | len = len < (sizeof(r->errstr)-1) ? len : (sizeof(r->errstr)-1); 68 | memcpy(r->errstr,str,len); 69 | r->errstr[len] = '\0'; 70 | } 71 | 72 | static size_t chrtos(char *buf, size_t size, char byte) { 73 | size_t len = 0; 74 | 75 | switch(byte) { 76 | case '\\': 77 | case '"': 78 | len = snprintf(buf,size,"\"\\%c\"",byte); 79 | break; 80 | case '\n': len = snprintf(buf,size,"\"\\n\""); break; 81 | case '\r': len = snprintf(buf,size,"\"\\r\""); break; 82 | case '\t': len = snprintf(buf,size,"\"\\t\""); break; 83 | case '\a': len = snprintf(buf,size,"\"\\a\""); break; 84 | case '\b': len = snprintf(buf,size,"\"\\b\""); break; 85 | default: 86 | if (isprint(byte)) 87 | len = snprintf(buf,size,"\"%c\"",byte); 88 | else 89 | len = snprintf(buf,size,"\"\\x%02x\"",(unsigned char)byte); 90 | break; 91 | } 92 | 93 | return len; 94 | } 95 | 96 | static void __redisReaderSetErrorProtocolByte(redisReader *r, char byte) { 97 | char cbuf[8], sbuf[128]; 98 | 99 | chrtos(cbuf,sizeof(cbuf),byte); 100 | snprintf(sbuf,sizeof(sbuf), 101 | "Protocol error, got %s as reply type byte", cbuf); 102 | __redisReaderSetError(r,REDIS_ERR_PROTOCOL,sbuf); 103 | } 104 | 105 | static void __redisReaderSetErrorOOM(redisReader *r) { 106 | __redisReaderSetError(r,REDIS_ERR_OOM,"Out of memory"); 107 | } 108 | 109 | static char *readBytes(redisReader *r, unsigned int bytes) { 110 | char *p; 111 | if (r->len-r->pos >= bytes) { 112 | p = r->buf+r->pos; 113 | r->pos += bytes; 114 | return p; 115 | } 116 | return NULL; 117 | } 118 | 119 | /* Find pointer to \r\n. */ 120 | static char *seekNewline(char *s, size_t len) { 121 | int pos = 0; 122 | int _len = len-1; 123 | 124 | /* Position should be < len-1 because the character at "pos" should be 125 | * followed by a \n. Note that strchr cannot be used because it doesn't 126 | * allow to search a limited length and the buffer that is being searched 127 | * might not have a trailing NULL character. */ 128 | while (pos < _len) { 129 | while(pos < _len && s[pos] != '\r') pos++; 130 | if (pos==_len) { 131 | /* Not found. */ 132 | return NULL; 133 | } else { 134 | if (s[pos+1] == '\n') { 135 | /* Found. */ 136 | return s+pos; 137 | } else { 138 | /* Continue searching. */ 139 | pos++; 140 | } 141 | } 142 | } 143 | return NULL; 144 | } 145 | 146 | /* Read a long long value starting at *s, under the assumption that it will be 147 | * terminated by \r\n. Ambiguously returns -1 for unexpected input. */ 148 | static long long readLongLong(char *s) { 149 | long long v = 0; 150 | int dec, mult = 1; 151 | char c; 152 | 153 | if (*s == '-') { 154 | mult = -1; 155 | s++; 156 | } else if (*s == '+') { 157 | mult = 1; 158 | s++; 159 | } 160 | 161 | while ((c = *(s++)) != '\r') { 162 | dec = c - '0'; 163 | if (dec >= 0 && dec < 10) { 164 | v *= 10; 165 | v += dec; 166 | } else { 167 | /* Should not happen... */ 168 | return -1; 169 | } 170 | } 171 | 172 | return mult*v; 173 | } 174 | 175 | static char *readLine(redisReader *r, int *_len) { 176 | char *p, *s; 177 | int len; 178 | 179 | p = r->buf+r->pos; 180 | s = seekNewline(p,(r->len-r->pos)); 181 | if (s != NULL) { 182 | len = s-(r->buf+r->pos); 183 | r->pos += len+2; /* skip \r\n */ 184 | if (_len) *_len = len; 185 | return p; 186 | } 187 | return NULL; 188 | } 189 | 190 | static void moveToNextTask(redisReader *r) { 191 | redisReadTask *cur, *prv; 192 | while (r->ridx >= 0) { 193 | /* Return a.s.a.p. when the stack is now empty. */ 194 | if (r->ridx == 0) { 195 | r->ridx--; 196 | return; 197 | } 198 | 199 | cur = &(r->rstack[r->ridx]); 200 | prv = &(r->rstack[r->ridx-1]); 201 | assert(prv->type == REDIS_REPLY_ARRAY); 202 | if (cur->idx == prv->elements-1) { 203 | r->ridx--; 204 | } else { 205 | /* Reset the type because the next item can be anything */ 206 | assert(cur->idx < prv->elements); 207 | cur->type = -1; 208 | cur->elements = -1; 209 | cur->idx++; 210 | return; 211 | } 212 | } 213 | } 214 | 215 | static int processLineItem(redisReader *r) { 216 | redisReadTask *cur = &(r->rstack[r->ridx]); 217 | void *obj; 218 | char *p; 219 | int len; 220 | 221 | if ((p = readLine(r,&len)) != NULL) { 222 | if (cur->type == REDIS_REPLY_INTEGER) { 223 | if (r->fn && r->fn->createInteger) 224 | obj = r->fn->createInteger(cur,readLongLong(p)); 225 | else 226 | obj = (void*)REDIS_REPLY_INTEGER; 227 | } else { 228 | /* Type will be error or status. */ 229 | if (r->fn && r->fn->createString) 230 | obj = r->fn->createString(cur,p,len); 231 | else 232 | obj = (void*)(size_t)(cur->type); 233 | } 234 | 235 | if (obj == NULL) { 236 | __redisReaderSetErrorOOM(r); 237 | return REDIS_ERR; 238 | } 239 | 240 | /* Set reply if this is the root object. */ 241 | if (r->ridx == 0) r->reply = obj; 242 | moveToNextTask(r); 243 | return REDIS_OK; 244 | } 245 | 246 | return REDIS_ERR; 247 | } 248 | 249 | static int processBulkItem(redisReader *r) { 250 | redisReadTask *cur = &(r->rstack[r->ridx]); 251 | void *obj = NULL; 252 | char *p, *s; 253 | long len; 254 | unsigned long bytelen; 255 | int success = 0; 256 | 257 | p = r->buf+r->pos; 258 | s = seekNewline(p,r->len-r->pos); 259 | if (s != NULL) { 260 | p = r->buf+r->pos; 261 | bytelen = s-(r->buf+r->pos)+2; /* include \r\n */ 262 | len = readLongLong(p); 263 | 264 | if (len < 0) { 265 | /* The nil object can always be created. */ 266 | if (r->fn && r->fn->createNil) 267 | obj = r->fn->createNil(cur); 268 | else 269 | obj = (void*)REDIS_REPLY_NIL; 270 | success = 1; 271 | } else { 272 | /* Only continue when the buffer contains the entire bulk item. */ 273 | bytelen += len+2; /* include \r\n */ 274 | if (r->pos+bytelen <= r->len) { 275 | if (r->fn && r->fn->createString) 276 | obj = r->fn->createString(cur,s+2,len); 277 | else 278 | obj = (void*)REDIS_REPLY_STRING; 279 | success = 1; 280 | } 281 | } 282 | 283 | /* Proceed when obj was created. */ 284 | if (success) { 285 | if (obj == NULL) { 286 | __redisReaderSetErrorOOM(r); 287 | return REDIS_ERR; 288 | } 289 | 290 | r->pos += bytelen; 291 | 292 | /* Set reply if this is the root object. */ 293 | if (r->ridx == 0) r->reply = obj; 294 | moveToNextTask(r); 295 | return REDIS_OK; 296 | } 297 | } 298 | 299 | return REDIS_ERR; 300 | } 301 | 302 | static int processMultiBulkItem(redisReader *r) { 303 | redisReadTask *cur = &(r->rstack[r->ridx]); 304 | void *obj; 305 | char *p; 306 | long elements; 307 | int root = 0; 308 | 309 | /* Set error for nested multi bulks with depth > 7 */ 310 | if (r->ridx == 8) { 311 | __redisReaderSetError(r,REDIS_ERR_PROTOCOL, 312 | "No support for nested multi bulk replies with depth > 7"); 313 | return REDIS_ERR; 314 | } 315 | 316 | if ((p = readLine(r,NULL)) != NULL) { 317 | elements = readLongLong(p); 318 | root = (r->ridx == 0); 319 | 320 | if (elements == -1) { 321 | if (r->fn && r->fn->createNil) 322 | obj = r->fn->createNil(cur); 323 | else 324 | obj = (void*)REDIS_REPLY_NIL; 325 | 326 | if (obj == NULL) { 327 | __redisReaderSetErrorOOM(r); 328 | return REDIS_ERR; 329 | } 330 | 331 | moveToNextTask(r); 332 | } else { 333 | if (r->fn && r->fn->createArray) 334 | obj = r->fn->createArray(cur,elements); 335 | else 336 | obj = (void*)REDIS_REPLY_ARRAY; 337 | 338 | if (obj == NULL) { 339 | __redisReaderSetErrorOOM(r); 340 | return REDIS_ERR; 341 | } 342 | 343 | /* Modify task stack when there are more than 0 elements. */ 344 | if (elements > 0) { 345 | cur->elements = elements; 346 | cur->obj = obj; 347 | r->ridx++; 348 | r->rstack[r->ridx].type = -1; 349 | r->rstack[r->ridx].elements = -1; 350 | r->rstack[r->ridx].idx = 0; 351 | r->rstack[r->ridx].obj = NULL; 352 | r->rstack[r->ridx].parent = cur; 353 | r->rstack[r->ridx].privdata = r->privdata; 354 | } else { 355 | moveToNextTask(r); 356 | } 357 | } 358 | 359 | /* Set reply if this is the root object. */ 360 | if (root) r->reply = obj; 361 | return REDIS_OK; 362 | } 363 | 364 | return REDIS_ERR; 365 | } 366 | 367 | static int processItem(redisReader *r) { 368 | redisReadTask *cur = &(r->rstack[r->ridx]); 369 | char *p; 370 | 371 | /* check if we need to read type */ 372 | if (cur->type < 0) { 373 | if ((p = readBytes(r,1)) != NULL) { 374 | switch (p[0]) { 375 | case '-': 376 | cur->type = REDIS_REPLY_ERROR; 377 | break; 378 | case '+': 379 | cur->type = REDIS_REPLY_STATUS; 380 | break; 381 | case ':': 382 | cur->type = REDIS_REPLY_INTEGER; 383 | break; 384 | case '$': 385 | cur->type = REDIS_REPLY_STRING; 386 | break; 387 | case '*': 388 | cur->type = REDIS_REPLY_ARRAY; 389 | break; 390 | default: 391 | __redisReaderSetErrorProtocolByte(r,*p); 392 | return REDIS_ERR; 393 | } 394 | } else { 395 | /* could not consume 1 byte */ 396 | return REDIS_ERR; 397 | } 398 | } 399 | 400 | /* process typed item */ 401 | switch(cur->type) { 402 | case REDIS_REPLY_ERROR: 403 | case REDIS_REPLY_STATUS: 404 | case REDIS_REPLY_INTEGER: 405 | return processLineItem(r); 406 | case REDIS_REPLY_STRING: 407 | return processBulkItem(r); 408 | case REDIS_REPLY_ARRAY: 409 | return processMultiBulkItem(r); 410 | default: 411 | assert(NULL); 412 | return REDIS_ERR; /* Avoid warning. */ 413 | } 414 | } 415 | 416 | redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn) { 417 | redisReader *r; 418 | 419 | r = calloc(sizeof(redisReader),1); 420 | if (r == NULL) 421 | return NULL; 422 | 423 | r->err = 0; 424 | r->errstr[0] = '\0'; 425 | r->fn = fn; 426 | r->buf = sdsempty(); 427 | r->maxbuf = REDIS_READER_MAX_BUF; 428 | if (r->buf == NULL) { 429 | free(r); 430 | return NULL; 431 | } 432 | 433 | r->ridx = -1; 434 | return r; 435 | } 436 | 437 | void redisReaderFree(redisReader *r) { 438 | if (r->reply != NULL && r->fn && r->fn->freeObject) 439 | r->fn->freeObject(r->reply); 440 | if (r->buf != NULL) 441 | sdsfree(r->buf); 442 | free(r); 443 | } 444 | 445 | int redisReaderFeed(redisReader *r, const char *buf, size_t len) { 446 | sds newbuf; 447 | 448 | /* Return early when this reader is in an erroneous state. */ 449 | if (r->err) 450 | return REDIS_ERR; 451 | 452 | /* Copy the provided buffer. */ 453 | if (buf != NULL && len >= 1) { 454 | /* Destroy internal buffer when it is empty and is quite large. */ 455 | if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) { 456 | sdsfree(r->buf); 457 | r->buf = sdsempty(); 458 | r->pos = 0; 459 | 460 | /* r->buf should not be NULL since we just free'd a larger one. */ 461 | assert(r->buf != NULL); 462 | } 463 | 464 | newbuf = sdscatlen(r->buf,buf,len); 465 | if (newbuf == NULL) { 466 | __redisReaderSetErrorOOM(r); 467 | return REDIS_ERR; 468 | } 469 | 470 | r->buf = newbuf; 471 | r->len = sdslen(r->buf); 472 | } 473 | 474 | return REDIS_OK; 475 | } 476 | 477 | int redisReaderGetReply(redisReader *r, void **reply) { 478 | /* Default target pointer to NULL. */ 479 | if (reply != NULL) 480 | *reply = NULL; 481 | 482 | /* Return early when this reader is in an erroneous state. */ 483 | if (r->err) 484 | return REDIS_ERR; 485 | 486 | /* When the buffer is empty, there will never be a reply. */ 487 | if (r->len == 0) 488 | return REDIS_OK; 489 | 490 | /* Set first item to process when the stack is empty. */ 491 | if (r->ridx == -1) { 492 | r->rstack[0].type = -1; 493 | r->rstack[0].elements = -1; 494 | r->rstack[0].idx = -1; 495 | r->rstack[0].obj = NULL; 496 | r->rstack[0].parent = NULL; 497 | r->rstack[0].privdata = r->privdata; 498 | r->ridx = 0; 499 | } 500 | 501 | /* Process items in reply. */ 502 | while (r->ridx >= 0) 503 | if (processItem(r) != REDIS_OK) 504 | break; 505 | 506 | /* Return ASAP when an error occurred. */ 507 | if (r->err) 508 | return REDIS_ERR; 509 | 510 | /* Discard part of the buffer when we've consumed at least 1k, to avoid 511 | * doing unnecessary calls to memmove() in sds.c. */ 512 | if (r->pos >= 1024) { 513 | sdsrange(r->buf,r->pos,-1); 514 | r->pos = 0; 515 | r->len = sdslen(r->buf); 516 | } 517 | 518 | /* Emit a reply when there is one. */ 519 | if (r->ridx == -1) { 520 | if (reply != NULL) 521 | *reply = r->reply; 522 | r->reply = NULL; 523 | } 524 | return REDIS_OK; 525 | } 526 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/read.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009-2011, Salvatore Sanfilippo 3 | * Copyright (c) 2010-2011, Pieter Noordhuis 4 | * 5 | * All rights reserved. 6 | * 7 | * Redistribution and use in source and binary forms, with or without 8 | * modification, are permitted provided that the following conditions are met: 9 | * 10 | * * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * * Redistributions in binary form must reproduce the above copyright 13 | * notice, this list of conditions and the following disclaimer in the 14 | * documentation and/or other materials provided with the distribution. 15 | * * Neither the name of Redis nor the names of its contributors may be used 16 | * to endorse or promote products derived from this software without 17 | * specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | * POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | 33 | #ifndef __HIREDIS_READ_H 34 | #define __HIREDIS_READ_H 35 | #include /* for size_t */ 36 | 37 | #define REDIS_ERR -1 38 | #define REDIS_OK 0 39 | 40 | /* When an error occurs, the err flag in a context is set to hold the type of 41 | * error that occurred. REDIS_ERR_IO means there was an I/O error and you 42 | * should use the "errno" variable to find out what is wrong. 43 | * For other values, the "errstr" field will hold a description. */ 44 | #define REDIS_ERR_IO 1 /* Error in read or write */ 45 | #define REDIS_ERR_EOF 3 /* End of file */ 46 | #define REDIS_ERR_PROTOCOL 4 /* Protocol error */ 47 | #define REDIS_ERR_OOM 5 /* Out of memory */ 48 | #define REDIS_ERR_OTHER 2 /* Everything else... */ 49 | 50 | #define REDIS_REPLY_STRING 1 51 | #define REDIS_REPLY_ARRAY 2 52 | #define REDIS_REPLY_INTEGER 3 53 | #define REDIS_REPLY_NIL 4 54 | #define REDIS_REPLY_STATUS 5 55 | #define REDIS_REPLY_ERROR 6 56 | 57 | #define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */ 58 | 59 | #ifdef __cplusplus 60 | extern "C" { 61 | #endif 62 | 63 | typedef struct redisReadTask { 64 | int type; 65 | int elements; /* number of elements in multibulk container */ 66 | int idx; /* index in parent (array) object */ 67 | void *obj; /* holds user-generated value for a read task */ 68 | struct redisReadTask *parent; /* parent task */ 69 | void *privdata; /* user-settable arbitrary field */ 70 | } redisReadTask; 71 | 72 | typedef struct redisReplyObjectFunctions { 73 | void *(*createString)(const redisReadTask*, char*, size_t); 74 | void *(*createArray)(const redisReadTask*, int); 75 | void *(*createInteger)(const redisReadTask*, long long); 76 | void *(*createNil)(const redisReadTask*); 77 | void (*freeObject)(void*); 78 | } redisReplyObjectFunctions; 79 | 80 | typedef struct redisReader { 81 | int err; /* Error flags, 0 when there is no error */ 82 | char errstr[128]; /* String representation of error when applicable */ 83 | 84 | char *buf; /* Read buffer */ 85 | size_t pos; /* Buffer cursor */ 86 | size_t len; /* Buffer length */ 87 | size_t maxbuf; /* Max length of unused buffer */ 88 | 89 | redisReadTask rstack[9]; 90 | int ridx; /* Index of current read task */ 91 | void *reply; /* Temporary reply pointer */ 92 | 93 | redisReplyObjectFunctions *fn; 94 | void *privdata; 95 | } redisReader; 96 | 97 | /* Public API for the protocol parser. */ 98 | redisReader *redisReaderCreateWithFunctions(redisReplyObjectFunctions *fn); 99 | void redisReaderFree(redisReader *r); 100 | int redisReaderFeed(redisReader *r, const char *buf, size_t len); 101 | int redisReaderGetReply(redisReader *r, void **reply); 102 | 103 | #define redisReaderSetPrivdata(_r, _p) (int)(((redisReader*)(_r))->privdata = (_p)) 104 | #define redisReaderGetObject(_r) (((redisReader*)(_r))->reply) 105 | #define redisReaderGetError(_r) (((redisReader*)(_r))->errstr) 106 | 107 | #ifdef __cplusplus 108 | } 109 | #endif 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/sds.h: -------------------------------------------------------------------------------- 1 | /* SDSLib 2.0 -- A C dynamic strings library 2 | * 3 | * Copyright (c) 2006-2015, Salvatore Sanfilippo 4 | * Copyright (c) 2015, Oran Agra 5 | * Copyright (c) 2015, Redis Labs, Inc 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * * Neither the name of Redis nor the names of its contributors may be used 17 | * to endorse or promote products derived from this software without 18 | * specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | #ifndef __SDS_H 34 | #define __SDS_H 35 | 36 | #define SDS_MAX_PREALLOC (1024*1024) 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | typedef char *sds; 43 | 44 | /* Note: sdshdr5 is never used, we just access the flags byte directly. 45 | * However is here to document the layout of type 5 SDS strings. */ 46 | struct __attribute__ ((__packed__)) sdshdr5 { 47 | unsigned char flags; /* 3 lsb of type, and 5 msb of string length */ 48 | char buf[]; 49 | }; 50 | struct __attribute__ ((__packed__)) sdshdr8 { 51 | uint8_t len; /* used */ 52 | uint8_t alloc; /* excluding the header and null terminator */ 53 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 54 | char buf[]; 55 | }; 56 | struct __attribute__ ((__packed__)) sdshdr16 { 57 | uint16_t len; /* used */ 58 | uint16_t alloc; /* excluding the header and null terminator */ 59 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 60 | char buf[]; 61 | }; 62 | struct __attribute__ ((__packed__)) sdshdr32 { 63 | uint32_t len; /* used */ 64 | uint32_t alloc; /* excluding the header and null terminator */ 65 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 66 | char buf[]; 67 | }; 68 | struct __attribute__ ((__packed__)) sdshdr64 { 69 | uint64_t len; /* used */ 70 | uint64_t alloc; /* excluding the header and null terminator */ 71 | unsigned char flags; /* 3 lsb of type, 5 unused bits */ 72 | char buf[]; 73 | }; 74 | 75 | #define SDS_TYPE_5 0 76 | #define SDS_TYPE_8 1 77 | #define SDS_TYPE_16 2 78 | #define SDS_TYPE_32 3 79 | #define SDS_TYPE_64 4 80 | #define SDS_TYPE_MASK 7 81 | #define SDS_TYPE_BITS 3 82 | #define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))); 83 | #define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T)))) 84 | #define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS) 85 | 86 | static inline size_t sdslen(const sds s) { 87 | unsigned char flags = s[-1]; 88 | switch(flags&SDS_TYPE_MASK) { 89 | case SDS_TYPE_5: 90 | return SDS_TYPE_5_LEN(flags); 91 | case SDS_TYPE_8: 92 | return SDS_HDR(8,s)->len; 93 | case SDS_TYPE_16: 94 | return SDS_HDR(16,s)->len; 95 | case SDS_TYPE_32: 96 | return SDS_HDR(32,s)->len; 97 | case SDS_TYPE_64: 98 | return SDS_HDR(64,s)->len; 99 | } 100 | return 0; 101 | } 102 | 103 | static inline size_t sdsavail(const sds s) { 104 | unsigned char flags = s[-1]; 105 | switch(flags&SDS_TYPE_MASK) { 106 | case SDS_TYPE_5: { 107 | return 0; 108 | } 109 | case SDS_TYPE_8: { 110 | SDS_HDR_VAR(8,s); 111 | return sh->alloc - sh->len; 112 | } 113 | case SDS_TYPE_16: { 114 | SDS_HDR_VAR(16,s); 115 | return sh->alloc - sh->len; 116 | } 117 | case SDS_TYPE_32: { 118 | SDS_HDR_VAR(32,s); 119 | return sh->alloc - sh->len; 120 | } 121 | case SDS_TYPE_64: { 122 | SDS_HDR_VAR(64,s); 123 | return sh->alloc - sh->len; 124 | } 125 | } 126 | return 0; 127 | } 128 | 129 | static inline void sdssetlen(sds s, size_t newlen) { 130 | unsigned char flags = s[-1]; 131 | switch(flags&SDS_TYPE_MASK) { 132 | case SDS_TYPE_5: 133 | { 134 | unsigned char *fp = ((unsigned char*)s)-1; 135 | *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); 136 | } 137 | break; 138 | case SDS_TYPE_8: 139 | SDS_HDR(8,s)->len = newlen; 140 | break; 141 | case SDS_TYPE_16: 142 | SDS_HDR(16,s)->len = newlen; 143 | break; 144 | case SDS_TYPE_32: 145 | SDS_HDR(32,s)->len = newlen; 146 | break; 147 | case SDS_TYPE_64: 148 | SDS_HDR(64,s)->len = newlen; 149 | break; 150 | } 151 | } 152 | 153 | static inline void sdsinclen(sds s, size_t inc) { 154 | unsigned char flags = s[-1]; 155 | switch(flags&SDS_TYPE_MASK) { 156 | case SDS_TYPE_5: 157 | { 158 | unsigned char *fp = ((unsigned char*)s)-1; 159 | unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc; 160 | *fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS); 161 | } 162 | break; 163 | case SDS_TYPE_8: 164 | SDS_HDR(8,s)->len += inc; 165 | break; 166 | case SDS_TYPE_16: 167 | SDS_HDR(16,s)->len += inc; 168 | break; 169 | case SDS_TYPE_32: 170 | SDS_HDR(32,s)->len += inc; 171 | break; 172 | case SDS_TYPE_64: 173 | SDS_HDR(64,s)->len += inc; 174 | break; 175 | } 176 | } 177 | 178 | /* sdsalloc() = sdsavail() + sdslen() */ 179 | static inline size_t sdsalloc(const sds s) { 180 | unsigned char flags = s[-1]; 181 | switch(flags&SDS_TYPE_MASK) { 182 | case SDS_TYPE_5: 183 | return SDS_TYPE_5_LEN(flags); 184 | case SDS_TYPE_8: 185 | return SDS_HDR(8,s)->alloc; 186 | case SDS_TYPE_16: 187 | return SDS_HDR(16,s)->alloc; 188 | case SDS_TYPE_32: 189 | return SDS_HDR(32,s)->alloc; 190 | case SDS_TYPE_64: 191 | return SDS_HDR(64,s)->alloc; 192 | } 193 | return 0; 194 | } 195 | 196 | static inline void sdssetalloc(sds s, size_t newlen) { 197 | unsigned char flags = s[-1]; 198 | switch(flags&SDS_TYPE_MASK) { 199 | case SDS_TYPE_5: 200 | /* Nothing to do, this type has no total allocation info. */ 201 | break; 202 | case SDS_TYPE_8: 203 | SDS_HDR(8,s)->alloc = newlen; 204 | break; 205 | case SDS_TYPE_16: 206 | SDS_HDR(16,s)->alloc = newlen; 207 | break; 208 | case SDS_TYPE_32: 209 | SDS_HDR(32,s)->alloc = newlen; 210 | break; 211 | case SDS_TYPE_64: 212 | SDS_HDR(64,s)->alloc = newlen; 213 | break; 214 | } 215 | } 216 | 217 | sds sdsnewlen(const void *init, size_t initlen); 218 | sds sdsnew(const char *init); 219 | sds sdsempty(void); 220 | sds sdsdup(const sds s); 221 | void sdsfree(sds s); 222 | sds sdsgrowzero(sds s, size_t len); 223 | sds sdscatlen(sds s, const void *t, size_t len); 224 | sds sdscat(sds s, const char *t); 225 | sds sdscatsds(sds s, const sds t); 226 | sds sdscpylen(sds s, const char *t, size_t len); 227 | sds sdscpy(sds s, const char *t); 228 | 229 | sds sdscatvprintf(sds s, const char *fmt, va_list ap); 230 | #ifdef __GNUC__ 231 | sds sdscatprintf(sds s, const char *fmt, ...) 232 | __attribute__((format(printf, 2, 3))); 233 | #else 234 | sds sdscatprintf(sds s, const char *fmt, ...); 235 | #endif 236 | 237 | sds sdscatfmt(sds s, char const *fmt, ...); 238 | sds sdstrim(sds s, const char *cset); 239 | void sdsrange(sds s, int start, int end); 240 | void sdsupdatelen(sds s); 241 | void sdsclear(sds s); 242 | int sdscmp(const sds s1, const sds s2); 243 | sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count); 244 | void sdsfreesplitres(sds *tokens, int count); 245 | void sdstolower(sds s); 246 | void sdstoupper(sds s); 247 | sds sdsfromlonglong(long long value); 248 | sds sdscatrepr(sds s, const char *p, size_t len); 249 | sds *sdssplitargs(const char *line, int *argc); 250 | sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen); 251 | sds sdsjoin(char **argv, int argc, char *sep); 252 | sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen); 253 | 254 | /* Low level functions exposed to the user API */ 255 | sds sdsMakeRoomFor(sds s, size_t addlen); 256 | void sdsIncrLen(sds s, int incr); 257 | sds sdsRemoveFreeSpace(sds s); 258 | size_t sdsAllocSize(sds s); 259 | void *sdsAllocPtr(sds s); 260 | 261 | /* Export the allocator used by SDS to the program using SDS. 262 | * Sometimes the program SDS is linked to, may use a different set of 263 | * allocators, but may want to allocate or free things that SDS will 264 | * respectively free or allocate. */ 265 | void *sds_malloc(size_t size); 266 | void *sds_realloc(void *ptr, size_t size); 267 | void sds_free(void *ptr); 268 | 269 | #ifdef REDIS_TEST 270 | int sdsTest(int argc, char *argv[]); 271 | #endif 272 | 273 | #endif 274 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/sdsalloc.h: -------------------------------------------------------------------------------- 1 | /* SDSLib 2.0 -- A C dynamic strings library 2 | * 3 | * Copyright (c) 2006-2015, Salvatore Sanfilippo 4 | * Copyright (c) 2015, Oran Agra 5 | * Copyright (c) 2015, Redis Labs, Inc 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * * Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * * Neither the name of Redis nor the names of its contributors may be used 17 | * to endorse or promote products derived from this software without 18 | * specific prior written permission. 19 | * 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | * POSSIBILITY OF SUCH DAMAGE. 31 | */ 32 | 33 | /* SDS allocator selection. 34 | * 35 | * This file is used in order to change the SDS allocator at compile time. 36 | * Just define the following defines to what you want to use. Also add 37 | * the include of your alternate allocator if needed (not needed in order 38 | * to use the default libc allocator). */ 39 | 40 | #define s_malloc malloc 41 | #define s_realloc realloc 42 | #define s_free free 43 | -------------------------------------------------------------------------------- /experimental/redisclient/hiredis/win32.h: -------------------------------------------------------------------------------- 1 | #ifndef _WIN32_HELPER_INCLUDE 2 | #define _WIN32_HELPER_INCLUDE 3 | #ifdef _MSC_VER 4 | 5 | #ifndef inline 6 | #define inline __inline 7 | #endif 8 | 9 | #ifndef va_copy 10 | #define va_copy(d,s) ((d) = (s)) 11 | #endif 12 | 13 | #ifndef snprintf 14 | #define snprintf c99_snprintf 15 | 16 | __inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap) 17 | { 18 | int count = -1; 19 | 20 | if (size != 0) 21 | count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); 22 | if (count == -1) 23 | count = _vscprintf(format, ap); 24 | 25 | return count; 26 | } 27 | 28 | __inline int c99_snprintf(char* str, size_t size, const char* format, ...) 29 | { 30 | int count; 31 | va_list ap; 32 | 33 | va_start(ap, format); 34 | count = c99_vsnprintf(str, size, format, ap); 35 | va_end(ap); 36 | 37 | return count; 38 | } 39 | #endif 40 | 41 | #endif 42 | #endif -------------------------------------------------------------------------------- /experimental/redisclient/hiredispool.h: -------------------------------------------------------------------------------- 1 | /* Author: Huanghao 2 | * Date: 2017-2 3 | * Revision: 0.1 4 | * Function: Simple lightweight connection pool for hiredis 5 | * + Connection pooling 6 | * + Auto-reconnect and retry 7 | * + Multiple server endpoints 8 | * Usage: 9 | */ 10 | 11 | #ifndef HIREDISPOOL_H 12 | #define HIREDISPOOL_H 13 | 14 | #include 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | /* Constants */ 22 | #define HIREDISPOOL_MAJOR 0 23 | #define HIREDISPOOL_MINOR 1 24 | #define HIREDISPOOL_PATCH 1 25 | #define HIREDISPOOL_SONAME 0.1 26 | 27 | /* Types */ 28 | typedef struct redis_endpoint { 29 | char host[256]; 30 | int port; 31 | } REDIS_ENDPOINT; 32 | 33 | typedef struct redis_config { 34 | REDIS_ENDPOINT* endpoints; 35 | int num_endpoints; 36 | int connect_timeout; 37 | int net_readwrite_timeout; 38 | int num_redis_socks; 39 | int connect_failure_retry_delay; 40 | } REDIS_CONFIG; 41 | 42 | typedef struct redis_socket { 43 | int id; 44 | int backup; 45 | pthread_mutex_t mutex; 46 | int inuse; 47 | struct redis_socket* next; 48 | enum { sockunconnected, sockconnected } state; 49 | void* conn; 50 | 51 | int err; 52 | char errstr[128]; 53 | char errhost[16]; 54 | int errport; 55 | } REDIS_SOCKET; 56 | 57 | typedef struct redis_instance { 58 | time_t connect_after; 59 | REDIS_SOCKET* redis_pool; 60 | REDIS_SOCKET* last_used; 61 | REDIS_CONFIG* config; 62 | } REDIS_INSTANCE; 63 | 64 | /* Functions */ 65 | int redis_pool_create(const REDIS_CONFIG* config, REDIS_INSTANCE** instance); 66 | int redis_pool_destroy(REDIS_INSTANCE* instance); 67 | 68 | REDIS_SOCKET* redis_get_socket(REDIS_INSTANCE* instance); 69 | int redis_release_socket(REDIS_INSTANCE* instance, REDIS_SOCKET* redisocket); 70 | 71 | void* redis_command(REDIS_SOCKET* redisocket, REDIS_INSTANCE* instance, const char* format, ...); 72 | void* redis_vcommand(REDIS_SOCKET* redisocket, REDIS_INSTANCE* instance, const char* format, va_list ap); 73 | void* redis_command_argv(REDIS_SOCKET* redisocket, REDIS_INSTANCE* instance, int argc, const char **argv, const size_t *argvlen); 74 | 75 | #ifdef __cplusplus 76 | } 77 | #endif 78 | 79 | #endif/*HIREDISPOOL_H*/ 80 | -------------------------------------------------------------------------------- /experimental/redisclient/test_RedisClient.cpp: -------------------------------------------------------------------------------- 1 | #include "RedisClient.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | 9 | int main(int argc, char** argv) 10 | { 11 | (void)argc; 12 | (void)argv; 13 | 14 | REDIS_ENDPOINT endpoints[1] = { 15 | { "127.0.0.1", 6379 }, 16 | //{ "127.0.0.1", 6380 }, 17 | //{ "127.0.0.1", 6381 }, 18 | }; 19 | 20 | REDIS_CONFIG conf = { 21 | (REDIS_ENDPOINT*)&endpoints, 22 | 1, 23 | 10000, 24 | 5000, 25 | 20, 26 | 1, 27 | }; 28 | 29 | RedisClient client(conf); 30 | 31 | { 32 | cout << "Press to continue..." << endl; 33 | cin.get(); 34 | 35 | RedisReplyPtr reply = client.redisCommand("SET %s %s", "key0", "value0"); 36 | if (reply.notNull()) 37 | cout << "SET: " << reply->str << endl; 38 | else 39 | cout << "SET: " << "Something wrong." << endl; 40 | } 41 | 42 | { 43 | cout << "Press to continue..." << endl; 44 | cin.get(); 45 | 46 | RedisReplyPtr reply = client.redisCommand("GET %s", "key0"); 47 | if (reply.notNull()) 48 | if (reply->type == REDIS_REPLY_NIL) 49 | cout << "GET: Key does not exist." << endl; 50 | else 51 | cout << "GET: " << reply->str << endl; 52 | else 53 | cout << "GET: " << "Something wrong." << endl; 54 | } 55 | 56 | { 57 | cout << "Press to continue..." << endl; 58 | cin.get(); 59 | 60 | client.redisCommand("SET count0 0"); 61 | long long count0; 62 | for (long long i = 0; i < 1000; i++) { 63 | count0 = client.redisCommand("INCR count0")->integer; 64 | } 65 | cout << "INCR count0 to " << count0 << endl; 66 | } 67 | 68 | { 69 | cout << "Press to continue..." << endl; 70 | cin.get(); 71 | 72 | RedisReplyPtr reply = client.redisCommand("PING"); 73 | cout << "PING: " << reply->str << endl; 74 | // reply will be freed out of scope. 75 | } 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /experimental/redisclient/test_RedisClient2.cpp: -------------------------------------------------------------------------------- 1 | #include "RedisClient.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | 10 | using namespace std; 11 | 12 | 13 | struct thread_info 14 | { 15 | pthread_t thread; 16 | RedisClient* predis; 17 | long long count; 18 | int id; 19 | }; 20 | 21 | void foo(RedisClient& client, long long c, int id) 22 | { 23 | client.redisCommand("SET ID%d 0", id); 24 | long long count = -1; 25 | for (long long i=0; iinteger; 29 | } 30 | } 31 | cout << "INCR ID" << id << " to " << count << endl; 32 | if (count != c) { 33 | cerr << " *** something error" << endl; 34 | } 35 | } 36 | 37 | void *thread_routine (void * arg) 38 | { 39 | thread_info* pinfo = (thread_info*) arg; 40 | foo(*pinfo->predis, pinfo->count, pinfo->id); 41 | return NULL; 42 | } 43 | 44 | int main(int argc, char** argv) 45 | { 46 | (void)argc; 47 | (void)argv; 48 | 49 | const int num_endpoints = 4; 50 | 51 | REDIS_ENDPOINT endpoints[num_endpoints] = { 52 | { "127.0.0.1", 6379 }, 53 | { "127.0.0.1", 6379 }, 54 | { "127.0.0.1", 6379 }, 55 | { "127.0.0.1", 6379 }, 56 | }; 57 | 58 | REDIS_CONFIG conf = { 59 | (REDIS_ENDPOINT*)&endpoints, 60 | num_endpoints, 61 | 80, 62 | 80, 63 | 25, 64 | 1, 65 | }; 66 | 67 | RedisClient client(conf); 68 | vector threads; 69 | 70 | for (int i=0; i<20; ++i) { 71 | thread_info* pinfo = new thread_info; 72 | 73 | pinfo->predis = &client; 74 | pinfo->count = 5000; 75 | pinfo->id = i; 76 | 77 | if (pthread_create(&pinfo->thread, NULL, thread_routine, pinfo) != 0) 78 | { 79 | cerr << "Can not create thread #" << pinfo->id << ", quit" << endl; 80 | delete pinfo; 81 | break; 82 | } 83 | 84 | threads.push_back(pinfo); 85 | } 86 | 87 | for(vector::const_iterator i=threads.begin(); i!=threads.end(); ++i) { 88 | pthread_t thread = (*i)->thread; 89 | pthread_join(thread, NULL); 90 | delete (*i); 91 | } 92 | 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /experimental/redisclient/test_hiredispool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "hiredispool.h" 6 | #include "logger.h" 7 | #include "hiredis/hiredis.h" 8 | 9 | int main(int argc, char** argv) 10 | { 11 | (void)argc; 12 | (void)argv; 13 | /* 14 | LOG_CONFIG c = { 15 | -9, 16 | LOG_DEST_FILES, 17 | "log/test_hiredispool.log", 18 | "test_hiredispool", 19 | 0, 20 | 1 21 | }; 22 | log_set_config(&c); 23 | */ 24 | REDIS_ENDPOINT endpoints[2] = { 25 | { "127.0.0.1", 6379 }, 26 | { "127.0.0.1", 6380 }, 27 | //{ "127.0.0.1", 6381 }, 28 | }; 29 | 30 | REDIS_CONFIG conf = { 31 | (REDIS_ENDPOINT*)&endpoints, 32 | 2, 33 | 10000, 34 | 5000, 35 | 20, 36 | 1, 37 | }; 38 | 39 | REDIS_INSTANCE* inst; 40 | if (redis_pool_create(&conf, &inst) < 0) 41 | return -1; 42 | 43 | //sleep(5); 44 | 45 | REDIS_SOCKET* sock; 46 | if ((sock = redis_get_socket(inst)) == NULL) { 47 | redis_pool_destroy(inst); 48 | return -1; 49 | } 50 | 51 | //sleep(5); 52 | 53 | redisReply* reply; 54 | if ((reply = (redisReply*)redis_command(sock, inst, "PING")) == NULL) { 55 | redis_release_socket(inst, sock); 56 | redis_pool_destroy(inst); 57 | return -1; 58 | } 59 | logth(Info, "PING: %s", reply->str); 60 | freeReplyObject(reply); 61 | 62 | redis_release_socket(inst, sock); 63 | redis_pool_destroy(inst); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /hiredispool.h: -------------------------------------------------------------------------------- 1 | /* Author: Huanghao 2 | * Date: 2017-2 3 | * Revision: 0.1 4 | * Function: Simple lightweight connection pool for hiredis 5 | * + Connection pooling 6 | * + Auto-reconnect and retry 7 | * + Multiple server endpoints 8 | * Usage: 9 | */ 10 | 11 | #ifndef HIREDISPOOL_H 12 | #define HIREDISPOOL_H 13 | 14 | #include 15 | 16 | #ifdef __cplusplus 17 | extern "C" { 18 | #endif 19 | 20 | 21 | /* Constants */ 22 | #define HIREDISPOOL_MAJOR 0 23 | #define HIREDISPOOL_MINOR 1 24 | #define HIREDISPOOL_PATCH 1 25 | #define HIREDISPOOL_SONAME 0.1 26 | 27 | /* Types */ 28 | typedef struct redis_endpoint { 29 | char host[256]; 30 | int port; 31 | } REDIS_ENDPOINT; 32 | 33 | typedef struct redis_config { 34 | REDIS_ENDPOINT* endpoints; 35 | int num_endpoints; 36 | int connect_timeout; 37 | int net_readwrite_timeout; 38 | int num_redis_socks; 39 | int connect_failure_retry_delay; 40 | } REDIS_CONFIG; 41 | 42 | typedef struct redis_socket { 43 | int id; 44 | int backup; 45 | pthread_mutex_t mutex; 46 | int inuse; 47 | struct redis_socket* next; 48 | enum { sockunconnected, sockconnected } state; 49 | void* conn; 50 | } REDIS_SOCKET; 51 | 52 | typedef struct redis_instance { 53 | time_t connect_after; 54 | REDIS_SOCKET* redis_pool; 55 | REDIS_SOCKET* last_used; 56 | REDIS_CONFIG* config; 57 | } REDIS_INSTANCE; 58 | 59 | /* Functions */ 60 | int redis_pool_create(const REDIS_CONFIG* config, REDIS_INSTANCE** instance); 61 | int redis_pool_destroy(REDIS_INSTANCE* instance); 62 | 63 | REDIS_SOCKET* redis_get_socket(REDIS_INSTANCE* instance); 64 | int redis_release_socket(REDIS_INSTANCE* instance, REDIS_SOCKET* redisocket); 65 | 66 | void* redis_command(REDIS_SOCKET* redisocket, REDIS_INSTANCE* instance, const char* format, ...); 67 | void* redis_vcommand(REDIS_SOCKET* redisocket, REDIS_INSTANCE* instance, const char* format, va_list ap); 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif/*HIREDISPOOL_H*/ 74 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include /* for struct timeval */ 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "log.h" 11 | 12 | 13 | typedef struct log_config_internal { 14 | int verbose; 15 | log_dest_t dest; 16 | char dir[1024]; 17 | char file[1024]; 18 | char progname[256]; 19 | int level_hold; 20 | int print_millisec; 21 | } LOG_CONFIG_INTERNAL; 22 | 23 | static LOG_CONFIG_INTERNAL C = { 24 | 0, 25 | LOG_DEST_STDERR, 26 | "", 27 | "noname.log", 28 | "noname", 29 | L_WARN, 30 | 0 31 | }; 32 | 33 | static _NAME_NUMBER L[] = { 34 | { " TRACE ", L_TRACE }, 35 | { " DEBUG ", L_DEBUG }, 36 | { " INFO ", L_INFO }, 37 | { " WARN ", L_WARN }, 38 | { " ERROR ", L_ERROR }, 39 | { " FATAL ", L_FATAL }, 40 | { NULL, 0 } 41 | }; 42 | 43 | const char * _int2str ( 44 | const _NAME_NUMBER *table, 45 | int number, 46 | const char *def 47 | ) 48 | { 49 | const _NAME_NUMBER *this; 50 | 51 | for (this = table; this->name != NULL; this++) { 52 | if (this->number == number) { 53 | return this->name; 54 | } 55 | } 56 | 57 | return def; 58 | } 59 | 60 | /* 61 | * Control log filename, create directory as needed. 62 | */ 63 | static void _set_logfile(const char* filename) 64 | { 65 | char namebuf[1024]; 66 | char* dirsep; 67 | char* dir = namebuf; 68 | 69 | if(filename == NULL) 70 | return; 71 | 72 | /* Create directory and set log_dir */ 73 | strncpy(namebuf, filename, sizeof(namebuf)); 74 | namebuf[sizeof(namebuf) - 1] = '\0'; 75 | 76 | while((dirsep = strchr(dir, '/')) != NULL) { 77 | *dirsep = '\0'; 78 | mkdir(namebuf, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH); 79 | *dirsep = '/'; 80 | dir = dirsep + 1; 81 | } 82 | 83 | dirsep = strrchr(namebuf, '/'); 84 | if(dirsep != NULL) { 85 | *dirsep = '\0'; 86 | strncpy(C.dir, namebuf, sizeof(C.dir)); 87 | C.dir[sizeof(C.dir) - 1] = '\0'; 88 | *dirsep = '/'; 89 | } 90 | 91 | /* Do set log_file */ 92 | strncpy(C.file, filename, sizeof(C.file)); 93 | C.file[sizeof(C.file) - 1] = '\0'; 94 | } 95 | 96 | static void convert_logfilename(const char* origin, char* converted, size_t namelen) 97 | { 98 | char* p; 99 | int len; 100 | struct tm m; 101 | time_t now; 102 | 103 | len = strlen(origin); 104 | if(namelen < (size_t)len+10) 105 | goto cannot_convert; 106 | 107 | now = time(NULL); 108 | if(now == (time_t)-1) 109 | goto cannot_convert; 110 | 111 | localtime_r(&now, &m); 112 | 113 | p = strrchr(origin, '.'); 114 | if(p == NULL) { 115 | sprintf(converted, "%s.%04d%02d%02d", 116 | origin, m.tm_year+1900, m.tm_mon+1, m.tm_mday); 117 | } else { 118 | len = p - origin; 119 | memcpy(converted, origin, len); 120 | sprintf(converted+len, ".%04d%02d%02d", 121 | m.tm_year+1900, m.tm_mon+1, m.tm_mday); 122 | strcat(converted, p); 123 | } 124 | 125 | return; 126 | 127 | cannot_convert: 128 | strncpy(converted, origin, namelen); 129 | converted[namelen-1] = '\0'; 130 | } 131 | 132 | /* 133 | * Log the message to the logfile. Include the severity and 134 | * a time stamp. 135 | */ 136 | int vlog(int lvl, const char *fmt, va_list ap) 137 | { 138 | FILE *msgfd = NULL; 139 | char *p; 140 | char buffer[8192]; 141 | char namebuf[1024]; 142 | int len, len0; 143 | 144 | /* 145 | * Filter out by level_hold 146 | */ 147 | if(C.level_hold > (lvl & ~L_CONS)) { 148 | return 0; 149 | } 150 | 151 | /* 152 | * NOT debugging, and trying to log debug messages. 153 | * 154 | * Throw the message away. 155 | */ 156 | if ((C.verbose == 0) && ((lvl & ~L_CONS) <= L_DEBUG)) { 157 | return 0; 158 | } 159 | 160 | /* 161 | * If we don't want any messages, then 162 | * throw them away. 163 | */ 164 | if (C.dest == LOG_DEST_NULL) { 165 | return 0; 166 | } 167 | 168 | if (C.dest == LOG_DEST_STDOUT) { 169 | msgfd = stdout; 170 | 171 | } else if (C.dest == LOG_DEST_STDERR) { 172 | msgfd = stderr; 173 | 174 | } else if (C.dest != LOG_DEST_SYSLOG) { 175 | /* 176 | * No log file set. It must go to stdout. 177 | */ 178 | if (C.file[0] == '\0') { 179 | msgfd = stdout; 180 | 181 | /* 182 | * Else try to open the file. 183 | */ 184 | } else { 185 | convert_logfilename(C.file, namebuf, sizeof(namebuf)); 186 | 187 | if ((msgfd = fopen(namebuf, "a+")) == NULL) { 188 | fprintf(stderr, "%s: Couldn't open %s for logging: %s\n", 189 | C.progname, namebuf, strerror(errno)); 190 | 191 | fprintf(stderr, " ("); 192 | vfprintf(stderr, fmt, ap); /* the message that caused the log */ 193 | fprintf(stderr, ")\n"); 194 | return -1; 195 | } 196 | } 197 | } 198 | 199 | if (C.dest == LOG_DEST_SYSLOG) { 200 | *buffer = '\0'; 201 | len0 = 0; 202 | len = 0; 203 | } else 204 | 205 | if(C.print_millisec) 206 | { 207 | const char* s; 208 | struct timeval tv; 209 | struct tm local; 210 | char deflvl[8]; 211 | 212 | gettimeofday(&tv, NULL); 213 | localtime_r(&tv.tv_sec, &local); 214 | 215 | sprintf(buffer, "%04d/%02d/%02d %02d:%02d:%02d,%03d", 216 | local.tm_year+1900, local.tm_mon+1, local.tm_mday, 217 | local.tm_hour, local.tm_min, local.tm_sec, 218 | (int)tv.tv_usec/1000); 219 | 220 | sprintf(deflvl, " L%04X ", (lvl & ~L_CONS)); 221 | s = _int2str(L, (lvl & ~L_CONS), deflvl); 222 | 223 | len0 = strlen(buffer); 224 | strcat(buffer, s); 225 | len = strlen(buffer); 226 | } 227 | else 228 | { 229 | const char *s; 230 | time_t tv; 231 | struct tm local; 232 | char deflvl[8]; 233 | 234 | tv = time(NULL); 235 | localtime_r(&tv, &local); 236 | sprintf(buffer, "%04d/%02d/%02d %02d:%02d:%02d", 237 | local.tm_year+1900, local.tm_mon+1, local.tm_mday, 238 | local.tm_hour, local.tm_min, local.tm_sec); 239 | 240 | sprintf(deflvl, " L%04X ", (lvl & ~L_CONS)); 241 | s = _int2str(L, (lvl & ~L_CONS), deflvl); 242 | 243 | len0 = strlen(buffer); 244 | strcat(buffer, s); 245 | len = strlen(buffer); 246 | } 247 | 248 | vsnprintf(buffer + len, sizeof(buffer) - len - 1, fmt, ap); 249 | buffer[sizeof(buffer) - 2] = '\0'; 250 | 251 | /* 252 | * Filter out characters not in Latin-1. 253 | */ 254 | for (p = buffer; *p != '\0'; p++) { 255 | if (*p == '\r' || *p == '\n') 256 | *p = ' '; 257 | else if ((*p >=0 && *p < 32) || (/**p >= -128 &&*/ *p < 0)) 258 | *p = '?'; 259 | } 260 | strcat(buffer, "\n"); 261 | 262 | /* 263 | * If we're debugging, for small values of debug, then 264 | * we don't do timestamps. 265 | */ 266 | if (C.verbose == 1) { 267 | p = buffer + len0; 268 | 269 | } else { 270 | /* 271 | * No debugging, or lots of debugging. Print 272 | * the time stamps. 273 | */ 274 | p = buffer; 275 | } 276 | 277 | if (C.dest != LOG_DEST_SYSLOG) 278 | { 279 | fputs(p, msgfd); 280 | if (msgfd == stdout) { 281 | fflush(stdout); 282 | } else if (msgfd == stderr) { 283 | fflush(stderr); 284 | } else { 285 | fclose(msgfd); 286 | 287 | if(lvl & L_CONS) { 288 | if((lvl & ~L_CONS) < L_WARN) { 289 | fputs(p, stdout); 290 | fflush(stdout); 291 | } else { 292 | fputs(p, stderr); 293 | fflush(stderr); 294 | } 295 | 296 | /* 297 | * IF debugging, also to console but no flush 298 | */ 299 | } else if(C.verbose) { 300 | if((lvl & ~L_CONS) < L_WARN) { 301 | fputs(p, stdout); 302 | } else { 303 | fputs(p, stderr); 304 | } 305 | } 306 | } 307 | } 308 | else { /* it was syslog */ 309 | lvl = (lvl & ~L_CONS); 310 | 311 | if(lvl > 0 && lvl <= L_DEBUG) { 312 | lvl = LOG_DEBUG; 313 | 314 | } else if(lvl > L_DEBUG && lvl <= L_INFO) { 315 | lvl = LOG_NOTICE; 316 | 317 | } else if(lvl > L_INFO && lvl <= L_WARN) { 318 | lvl = LOG_WARNING; 319 | 320 | } else if(lvl > L_WARN && lvl <= L_ERROR) { 321 | lvl = LOG_ERR; 322 | 323 | } else if(lvl > L_ERROR && lvl <= L_FATAL) { 324 | lvl = LOG_CRIT; 325 | 326 | } else if(lvl > L_FATAL) { 327 | lvl = LOG_ALERT; 328 | 329 | } else { 330 | lvl = LOG_EMERG; 331 | 332 | } 333 | 334 | syslog(lvl, "%s", buffer + len0); /* don't print timestamp */ 335 | } 336 | 337 | return 0; 338 | } 339 | 340 | int log_debug(const char *msg, ...) 341 | { 342 | va_list ap; 343 | int r; 344 | 345 | va_start(ap, msg); 346 | r = vlog(L_DEBUG, msg, ap); 347 | va_end(ap); 348 | 349 | return r; 350 | } 351 | 352 | int log_trace(const char *msg, ...) 353 | { 354 | va_list ap; 355 | int r; 356 | 357 | va_start(ap, msg); 358 | r = vlog(L_TRACE, msg, ap); 359 | va_end(ap); 360 | 361 | return r; 362 | } 363 | 364 | int log_(int lvl, const char *msg, ...) 365 | { 366 | va_list ap; 367 | int r; 368 | 369 | va_start(ap, msg); 370 | r = vlog(lvl, msg, ap); 371 | va_end(ap); 372 | 373 | return r; 374 | } 375 | 376 | void log_set_config(const LOG_CONFIG* config) 377 | { 378 | C.verbose = config->verbose; 379 | C.dest = config->dest; 380 | _set_logfile(config->file); 381 | C.level_hold = config->level_hold; 382 | C.print_millisec = config->print_millisec; 383 | 384 | strncpy(C.progname, config->progname, sizeof(C.progname)); 385 | C.progname[sizeof(C.progname) - 1] = '\0'; 386 | } 387 | 388 | int log_get_verbose() 389 | { 390 | return C.verbose; 391 | } 392 | -------------------------------------------------------------------------------- /log.h: -------------------------------------------------------------------------------- 1 | /* Author: Huanghao 2 | * Date: 2017-2 3 | * Revision: 0.1 4 | * Function: Simple lightweight logging interface 5 | * Usage: 6 | */ 7 | 8 | #ifndef LOG_H 9 | #define LOG_H 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | 16 | /* Constants */ 17 | #define L_TRACE 512 /* 0x00000200 */ 18 | #define L_DEBUG 1024 /* 0x00000400 */ 19 | #define L_INFO 2048 /* 0x00000800 */ 20 | #define L_WARN 4096 /* 0x00001000 */ 21 | #define L_ERROR 8192 /* 0x00002000 */ 22 | #define L_FATAL 16384 /* 0x00004000 */ 23 | #define L_CONS 32768 /* 0x00008000 */ 24 | 25 | /* Types */ 26 | typedef enum _log_dest_t { 27 | LOG_DEST_FILES = 0, 28 | LOG_DEST_SYSLOG, 29 | LOG_DEST_STDOUT, 30 | LOG_DEST_STDERR, 31 | LOG_DEST_NULL 32 | } log_dest_t; 33 | 34 | typedef struct log_config { 35 | int verbose; 36 | log_dest_t dest; 37 | const char* file; 38 | const char* progname; 39 | int level_hold; 40 | int print_millisec; 41 | } LOG_CONFIG; 42 | 43 | typedef struct _name_number { 44 | const char *name; 45 | int number; 46 | } _NAME_NUMBER; 47 | 48 | /* Functions */ 49 | int log_(int lvl, const char *msg, ...); 50 | int log_debug(const char *msg, ...); 51 | int log_trace(const char *msg, ...); 52 | 53 | void log_set_config(const LOG_CONFIG* config); 54 | int log_get_verbose(void); 55 | 56 | #define DEBUG (log_get_verbose() == 0) ? \ 57 | 0 : log_debug 58 | #define DEBUG2 (log_get_verbose() >= 0 && log_get_verbose() <= 1) ? \ 59 | 0 : log_debug 60 | #define DEBUG3 (log_get_verbose() >= 0 && log_get_verbose() <= 2) ? \ 61 | 0 : log_debug 62 | #define DEBUG4 (log_get_verbose() >= 0 && log_get_verbose() <= 3) ? \ 63 | 0 : log_debug 64 | #define DEBUG5 (log_get_verbose() >= 0 && log_get_verbose() <= 4) ? \ 65 | 0 : log_debug 66 | 67 | #define TRACE (log_get_verbose() >= -1) ? \ 68 | 0 : log_trace 69 | #define TRACE2 (log_get_verbose() >= -2) ? \ 70 | 0 : log_trace 71 | #define TRACE3 (log_get_verbose() >= -3) ? \ 72 | 0 : log_trace 73 | #define TRACE4 (log_get_verbose() >= -4) ? \ 74 | 0 : log_trace 75 | #define TRACE5 (log_get_verbose() >= -5) ? \ 76 | 0 : log_trace 77 | 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | 83 | #endif/*LOG_H*/ 84 | -------------------------------------------------------------------------------- /test_RedisClient.cpp: -------------------------------------------------------------------------------- 1 | #include "RedisClient.h" 2 | 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | 9 | int main(int argc, char** argv) 10 | { 11 | (void)argc; 12 | (void)argv; 13 | 14 | REDIS_ENDPOINT endpoints[1] = { 15 | { "127.0.0.1", 6379 }, 16 | //{ "127.0.0.1", 6380 }, 17 | //{ "127.0.0.1", 6381 }, 18 | }; 19 | 20 | REDIS_CONFIG conf = { 21 | (REDIS_ENDPOINT*)&endpoints, 22 | 1, 23 | 10000, 24 | 5000, 25 | 20, 26 | 1, 27 | }; 28 | 29 | RedisClient client(conf); 30 | 31 | { 32 | cout << "Press to continue..." << endl; 33 | cin.get(); 34 | 35 | RedisReplyPtr reply = client.redisCommand("SET %s %s", "key0", "value0"); 36 | if (reply.notNull()) 37 | cout << "SET: " << reply->str << endl; 38 | else 39 | cout << "SET: " << "Something wrong." << endl; 40 | } 41 | 42 | { 43 | cout << "Press to continue..." << endl; 44 | cin.get(); 45 | 46 | RedisReplyPtr reply = client.redisCommand("GET %s", "key0"); 47 | if (reply.notNull()) 48 | if (reply->type == REDIS_REPLY_NIL) 49 | cout << "GET: Key does not exist." << endl; 50 | else 51 | cout << "GET: " << reply->str << endl; 52 | else 53 | cout << "GET: " << "Something wrong." << endl; 54 | } 55 | 56 | { 57 | cout << "Press to continue..." << endl; 58 | cin.get(); 59 | 60 | client.redisCommand("SET count0 0"); 61 | long long count0; 62 | for (long long i = 0; i < 1000; i++) { 63 | count0 = client.redisCommand("INCR count0")->integer; 64 | } 65 | cout << "INCR count0 to " << count0 << endl; 66 | } 67 | 68 | { 69 | cout << "Press to continue..." << endl; 70 | cin.get(); 71 | 72 | RedisReplyPtr reply = client.redisCommand("PING"); 73 | cout << "PING: " << reply->str << endl; 74 | // reply will be freed out of scope. 75 | } 76 | 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /test_RedisClient2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | using namespace std; 10 | 11 | 12 | void foo(RedisClient& client, long long c, int id) 13 | { 14 | client.redisCommand("SET ID%d 0", id); 15 | long long count = -1; 16 | for (long long i=0; iinteger; 20 | } 21 | } 22 | cout << "INCR ID" << id << " to " << count << endl; 23 | } 24 | 25 | int main(int argc, char** argv) 26 | { 27 | (void)argc; 28 | (void)argv; 29 | 30 | REDIS_ENDPOINT endpoints[1] = { 31 | { "127.0.0.1", 6379 }, 32 | //{ "127.0.0.1", 6380 }, 33 | //{ "127.0.0.1", 6381 }, 34 | }; 35 | 36 | REDIS_CONFIG conf = { 37 | (REDIS_ENDPOINT*)&endpoints, 38 | 1, 39 | 500, 40 | 500, 41 | 20, 42 | 1, 43 | }; 44 | 45 | RedisClient client(conf); 46 | vector threads; 47 | 48 | for (int i=0; i<20; ++i) { 49 | threads.emplace_back(thread(foo, ref(client), 1000, i)); 50 | } 51 | 52 | for(auto i=threads.begin(); i!=threads.end(); ++i) { 53 | i->join(); 54 | } 55 | 56 | return 0; 57 | } 58 | 59 | -------------------------------------------------------------------------------- /test_hiredispool.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "hiredispool.h" 6 | #include "log.h" 7 | #include "hiredis/hiredis.h" 8 | 9 | int main(int argc, char** argv) 10 | { 11 | (void)argc; 12 | (void)argv; 13 | 14 | LOG_CONFIG c = { 15 | -9, 16 | LOG_DEST_FILES, 17 | "log/test_hiredispool.log", 18 | "test_hiredispool", 19 | 0, 20 | 1 21 | }; 22 | log_set_config(&c); 23 | 24 | REDIS_ENDPOINT endpoints[4] = { 25 | { "127.0.0.1", 6379 }, 26 | { "127.0.0.1", 6380 }, 27 | { "127.0.0.1", 6381 }, 28 | { "127.0.0.1", 6382 }, 29 | }; 30 | 31 | REDIS_CONFIG conf = { 32 | (REDIS_ENDPOINT*)&endpoints, 33 | 4, 34 | 10000, 35 | 5000, 36 | 20, 37 | 1, 38 | }; 39 | 40 | REDIS_INSTANCE* inst; 41 | if (redis_pool_create(&conf, &inst) < 0) 42 | return -1; 43 | 44 | //sleep(5); 45 | 46 | REDIS_SOCKET* sock; 47 | if ((sock = redis_get_socket(inst)) == NULL) { 48 | redis_pool_destroy(inst); 49 | return -1; 50 | } 51 | 52 | //sleep(5); 53 | 54 | redisReply* reply; 55 | if ((reply = (redisReply*)redis_command(sock, inst, "PING")) == NULL) { 56 | redis_release_socket(inst, sock); 57 | redis_pool_destroy(inst); 58 | return -1; 59 | } 60 | log_(L_INFO|L_CONS, "PING: %s", reply->str); 61 | freeReplyObject(reply); 62 | 63 | redis_release_socket(inst, sock); 64 | redis_pool_destroy(inst); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /test_log.c: -------------------------------------------------------------------------------- 1 | #include "log.h" 2 | 3 | int main(int argc, char** argv) 4 | { 5 | (void)argc; 6 | (void)argv; 7 | 8 | LOG_CONFIG c = { 9 | 9, 10 | LOG_DEST_FILES, 11 | "log/test_log.log", 12 | "test_log", 13 | 0, 14 | 1 15 | }; 16 | log_set_config(&c); 17 | 18 | DEBUG("debug %s!", "me"); 19 | log_(L_DEBUG, "debug %s!", "me2"); 20 | log_(L_INFO|L_CONS, "hello %s!", "me"); 21 | log_(L_WARN, "only in file"); 22 | 23 | return 0; 24 | } 25 | --------------------------------------------------------------------------------