hiredis 0.6.1 → 0.6.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/ext/hiredis_ext/connection.c +4 -3
- data/ext/hiredis_ext/reader.c +12 -6
- data/lib/hiredis/version.rb +1 -1
- data/vendor/hiredis/Makefile +53 -34
- data/vendor/hiredis/async.c +40 -9
- data/vendor/hiredis/async.h +1 -0
- data/vendor/hiredis/dict.c +2 -2
- data/vendor/hiredis/fmacros.h +4 -13
- data/vendor/hiredis/hiredis.c +50 -23
- data/vendor/hiredis/hiredis.h +37 -27
- data/vendor/hiredis/net.c +99 -22
- data/vendor/hiredis/net.h +4 -6
- data/vendor/hiredis/read.c +119 -44
- data/vendor/hiredis/read.h +4 -9
- data/vendor/hiredis/sds.c +342 -165
- data/vendor/hiredis/sds.h +184 -13
- data/vendor/hiredis/sdsalloc.h +42 -0
- data/vendor/hiredis/test.c +187 -14
- data/vendor/hiredis/win32.h +42 -0
- metadata +5 -3
data/vendor/hiredis/sds.h
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
-
/*
|
1
|
+
/* SDSLib 2.0 -- A C dynamic strings library
|
2
2
|
*
|
3
|
-
* Copyright (c) 2006-
|
3
|
+
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
4
|
+
* Copyright (c) 2015, Oran Agra
|
5
|
+
* Copyright (c) 2015, Redis Labs, Inc
|
4
6
|
* All rights reserved.
|
5
7
|
*
|
6
8
|
* Redistribution and use in source and binary forms, with or without
|
@@ -35,32 +37,188 @@
|
|
35
37
|
|
36
38
|
#include <sys/types.h>
|
37
39
|
#include <stdarg.h>
|
40
|
+
#include <stdint.h>
|
38
41
|
|
39
42
|
typedef char *sds;
|
40
43
|
|
41
|
-
|
42
|
-
|
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 */
|
44
72
|
char buf[];
|
45
73
|
};
|
46
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
|
+
|
47
86
|
static inline size_t sdslen(const sds s) {
|
48
|
-
|
49
|
-
|
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;
|
50
101
|
}
|
51
102
|
|
52
103
|
static inline size_t sdsavail(const sds s) {
|
53
|
-
|
54
|
-
|
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
|
+
}
|
55
215
|
}
|
56
216
|
|
57
217
|
sds sdsnewlen(const void *init, size_t initlen);
|
58
218
|
sds sdsnew(const char *init);
|
59
219
|
sds sdsempty(void);
|
60
|
-
size_t sdslen(const sds s);
|
61
220
|
sds sdsdup(const sds s);
|
62
221
|
void sdsfree(sds s);
|
63
|
-
size_t sdsavail(const sds s);
|
64
222
|
sds sdsgrowzero(sds s, size_t len);
|
65
223
|
sds sdscatlen(sds s, const void *t, size_t len);
|
66
224
|
sds sdscat(sds s, const char *t);
|
@@ -77,7 +235,7 @@ sds sdscatprintf(sds s, const char *fmt, ...);
|
|
77
235
|
#endif
|
78
236
|
|
79
237
|
sds sdscatfmt(sds s, char const *fmt, ...);
|
80
|
-
|
238
|
+
sds sdstrim(sds s, const char *cset);
|
81
239
|
void sdsrange(sds s, int start, int end);
|
82
240
|
void sdsupdatelen(sds s);
|
83
241
|
void sdsclear(sds s);
|
@@ -90,7 +248,7 @@ sds sdsfromlonglong(long long value);
|
|
90
248
|
sds sdscatrepr(sds s, const char *p, size_t len);
|
91
249
|
sds *sdssplitargs(const char *line, int *argc);
|
92
250
|
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
|
93
|
-
sds sdsjoin(char **argv, int argc, char *sep
|
251
|
+
sds sdsjoin(char **argv, int argc, char *sep);
|
94
252
|
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
|
95
253
|
|
96
254
|
/* Low level functions exposed to the user API */
|
@@ -98,5 +256,18 @@ sds sdsMakeRoomFor(sds s, size_t addlen);
|
|
98
256
|
void sdsIncrLen(sds s, int incr);
|
99
257
|
sds sdsRemoveFreeSpace(sds s);
|
100
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
|
101
272
|
|
102
273
|
#endif
|
@@ -0,0 +1,42 @@
|
|
1
|
+
/* SDSLib 2.0 -- A C dynamic strings library
|
2
|
+
*
|
3
|
+
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
|
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
|
data/vendor/hiredis/test.c
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
#include <limits.h>
|
12
12
|
|
13
13
|
#include "hiredis.h"
|
14
|
+
#include "net.h"
|
14
15
|
|
15
16
|
enum connection_type {
|
16
17
|
CONN_TCP,
|
@@ -29,7 +30,7 @@ struct config {
|
|
29
30
|
|
30
31
|
struct {
|
31
32
|
const char *path;
|
32
|
-
}
|
33
|
+
} unix_sock;
|
33
34
|
};
|
34
35
|
|
35
36
|
/* The following lines make up our testing "framework" :) */
|
@@ -43,6 +44,13 @@ static long long usec(void) {
|
|
43
44
|
return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
|
44
45
|
}
|
45
46
|
|
47
|
+
/* The assert() calls below have side effects, so we need assert()
|
48
|
+
* even if we are compiling without asserts (-DNDEBUG). */
|
49
|
+
#ifdef NDEBUG
|
50
|
+
#undef assert
|
51
|
+
#define assert(e) (void)(e)
|
52
|
+
#endif
|
53
|
+
|
46
54
|
static redisContext *select_database(redisContext *c) {
|
47
55
|
redisReply *reply;
|
48
56
|
|
@@ -89,10 +97,10 @@ static redisContext *connect(struct config config) {
|
|
89
97
|
if (config.type == CONN_TCP) {
|
90
98
|
c = redisConnect(config.tcp.host, config.tcp.port);
|
91
99
|
} else if (config.type == CONN_UNIX) {
|
92
|
-
c = redisConnectUnix(config.
|
100
|
+
c = redisConnectUnix(config.unix_sock.path);
|
93
101
|
} else if (config.type == CONN_FD) {
|
94
102
|
/* Create a dummy connection just to get an fd to inherit */
|
95
|
-
redisContext *dummy_ctx = redisConnectUnix(config.
|
103
|
+
redisContext *dummy_ctx = redisConnectUnix(config.unix_sock.path);
|
96
104
|
if (dummy_ctx) {
|
97
105
|
int fd = disconnect(dummy_ctx, 1);
|
98
106
|
printf("Connecting to inherited fd %d\n", fd);
|
@@ -216,6 +224,22 @@ static void test_format_commands(void) {
|
|
216
224
|
test_cond(strncmp(cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 &&
|
217
225
|
len == 4+4+(3+2)+4+(7+2)+4+(3+2));
|
218
226
|
free(cmd);
|
227
|
+
|
228
|
+
sds sds_cmd;
|
229
|
+
|
230
|
+
sds_cmd = sdsempty();
|
231
|
+
test("Format command into sds by passing argc/argv without lengths: ");
|
232
|
+
len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,NULL);
|
233
|
+
test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n",len) == 0 &&
|
234
|
+
len == 4+4+(3+2)+4+(3+2)+4+(3+2));
|
235
|
+
sdsfree(sds_cmd);
|
236
|
+
|
237
|
+
sds_cmd = sdsempty();
|
238
|
+
test("Format command into sds by passing argc/argv with lengths: ");
|
239
|
+
len = redisFormatSdsCommandArgv(&sds_cmd,argc,argv,lens);
|
240
|
+
test_cond(strncmp(sds_cmd,"*3\r\n$3\r\nSET\r\n$7\r\nfoo\0xxx\r\n$3\r\nbar\r\n",len) == 0 &&
|
241
|
+
len == 4+4+(3+2)+4+(7+2)+4+(3+2));
|
242
|
+
sdsfree(sds_cmd);
|
219
243
|
}
|
220
244
|
|
221
245
|
static void test_append_formatted_commands(struct config config) {
|
@@ -278,6 +302,82 @@ static void test_reply_reader(void) {
|
|
278
302
|
strncasecmp(reader->errstr,"No support for",14) == 0);
|
279
303
|
redisReaderFree(reader);
|
280
304
|
|
305
|
+
test("Correctly parses LLONG_MAX: ");
|
306
|
+
reader = redisReaderCreate();
|
307
|
+
redisReaderFeed(reader, ":9223372036854775807\r\n",22);
|
308
|
+
ret = redisReaderGetReply(reader,&reply);
|
309
|
+
test_cond(ret == REDIS_OK &&
|
310
|
+
((redisReply*)reply)->type == REDIS_REPLY_INTEGER &&
|
311
|
+
((redisReply*)reply)->integer == LLONG_MAX);
|
312
|
+
freeReplyObject(reply);
|
313
|
+
redisReaderFree(reader);
|
314
|
+
|
315
|
+
test("Set error when > LLONG_MAX: ");
|
316
|
+
reader = redisReaderCreate();
|
317
|
+
redisReaderFeed(reader, ":9223372036854775808\r\n",22);
|
318
|
+
ret = redisReaderGetReply(reader,&reply);
|
319
|
+
test_cond(ret == REDIS_ERR &&
|
320
|
+
strcasecmp(reader->errstr,"Bad integer value") == 0);
|
321
|
+
freeReplyObject(reply);
|
322
|
+
redisReaderFree(reader);
|
323
|
+
|
324
|
+
test("Correctly parses LLONG_MIN: ");
|
325
|
+
reader = redisReaderCreate();
|
326
|
+
redisReaderFeed(reader, ":-9223372036854775808\r\n",23);
|
327
|
+
ret = redisReaderGetReply(reader,&reply);
|
328
|
+
test_cond(ret == REDIS_OK &&
|
329
|
+
((redisReply*)reply)->type == REDIS_REPLY_INTEGER &&
|
330
|
+
((redisReply*)reply)->integer == LLONG_MIN);
|
331
|
+
freeReplyObject(reply);
|
332
|
+
redisReaderFree(reader);
|
333
|
+
|
334
|
+
test("Set error when < LLONG_MIN: ");
|
335
|
+
reader = redisReaderCreate();
|
336
|
+
redisReaderFeed(reader, ":-9223372036854775809\r\n",23);
|
337
|
+
ret = redisReaderGetReply(reader,&reply);
|
338
|
+
test_cond(ret == REDIS_ERR &&
|
339
|
+
strcasecmp(reader->errstr,"Bad integer value") == 0);
|
340
|
+
freeReplyObject(reply);
|
341
|
+
redisReaderFree(reader);
|
342
|
+
|
343
|
+
test("Set error when array < -1: ");
|
344
|
+
reader = redisReaderCreate();
|
345
|
+
redisReaderFeed(reader, "*-2\r\n+asdf\r\n",12);
|
346
|
+
ret = redisReaderGetReply(reader,&reply);
|
347
|
+
test_cond(ret == REDIS_ERR &&
|
348
|
+
strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0);
|
349
|
+
freeReplyObject(reply);
|
350
|
+
redisReaderFree(reader);
|
351
|
+
|
352
|
+
test("Set error when bulk < -1: ");
|
353
|
+
reader = redisReaderCreate();
|
354
|
+
redisReaderFeed(reader, "$-2\r\nasdf\r\n",11);
|
355
|
+
ret = redisReaderGetReply(reader,&reply);
|
356
|
+
test_cond(ret == REDIS_ERR &&
|
357
|
+
strcasecmp(reader->errstr,"Bulk string length out of range") == 0);
|
358
|
+
freeReplyObject(reply);
|
359
|
+
redisReaderFree(reader);
|
360
|
+
|
361
|
+
test("Set error when array > INT_MAX: ");
|
362
|
+
reader = redisReaderCreate();
|
363
|
+
redisReaderFeed(reader, "*9223372036854775807\r\n+asdf\r\n",29);
|
364
|
+
ret = redisReaderGetReply(reader,&reply);
|
365
|
+
test_cond(ret == REDIS_ERR &&
|
366
|
+
strcasecmp(reader->errstr,"Multi-bulk length out of range") == 0);
|
367
|
+
freeReplyObject(reply);
|
368
|
+
redisReaderFree(reader);
|
369
|
+
|
370
|
+
#if LLONG_MAX > SIZE_MAX
|
371
|
+
test("Set error when bulk > SIZE_MAX: ");
|
372
|
+
reader = redisReaderCreate();
|
373
|
+
redisReaderFeed(reader, "$9223372036854775807\r\nasdf\r\n",28);
|
374
|
+
ret = redisReaderGetReply(reader,&reply);
|
375
|
+
test_cond(ret == REDIS_ERR &&
|
376
|
+
strcasecmp(reader->errstr,"Bulk string length out of range") == 0);
|
377
|
+
freeReplyObject(reply);
|
378
|
+
redisReaderFree(reader);
|
379
|
+
#endif
|
380
|
+
|
281
381
|
test("Works with NULL functions for reply: ");
|
282
382
|
reader = redisReaderCreate();
|
283
383
|
reader->fn = NULL;
|
@@ -320,12 +420,12 @@ static void test_reply_reader(void) {
|
|
320
420
|
}
|
321
421
|
|
322
422
|
static void test_free_null(void) {
|
323
|
-
void *
|
423
|
+
void *redisCtx = NULL;
|
324
424
|
void *reply = NULL;
|
325
425
|
|
326
426
|
test("Don't fail when redisFree is passed a NULL value: ");
|
327
|
-
redisFree(
|
328
|
-
test_cond(
|
427
|
+
redisFree(redisCtx);
|
428
|
+
test_cond(redisCtx == NULL);
|
329
429
|
|
330
430
|
test("Don't fail when freeReplyObject is passed a NULL value: ");
|
331
431
|
freeReplyObject(reply);
|
@@ -343,6 +443,7 @@ static void test_blocking_connection_errors(void) {
|
|
343
443
|
strcmp(c->errstr,"nodename nor servname provided, or not known") == 0 ||
|
344
444
|
strcmp(c->errstr,"No address associated with hostname") == 0 ||
|
345
445
|
strcmp(c->errstr,"Temporary failure in name resolution") == 0 ||
|
446
|
+
strcmp(c->errstr,"hostname nor servname provided, or not known") == 0 ||
|
346
447
|
strcmp(c->errstr,"no address associated with name") == 0));
|
347
448
|
redisFree(c);
|
348
449
|
|
@@ -352,7 +453,7 @@ static void test_blocking_connection_errors(void) {
|
|
352
453
|
strcmp(c->errstr,"Connection refused") == 0);
|
353
454
|
redisFree(c);
|
354
455
|
|
355
|
-
test("Returns error when the
|
456
|
+
test("Returns error when the unix_sock socket path doesn't accept connections: ");
|
356
457
|
c = redisConnectUnix((char*)"/tmp/idontexist.sock");
|
357
458
|
test_cond(c->err == REDIS_ERR_IO); /* Don't care about the message... */
|
358
459
|
redisFree(c);
|
@@ -436,6 +537,52 @@ static void test_blocking_connection(struct config config) {
|
|
436
537
|
disconnect(c, 0);
|
437
538
|
}
|
438
539
|
|
540
|
+
static void test_blocking_connection_timeouts(struct config config) {
|
541
|
+
redisContext *c;
|
542
|
+
redisReply *reply;
|
543
|
+
ssize_t s;
|
544
|
+
const char *cmd = "DEBUG SLEEP 3\r\n";
|
545
|
+
struct timeval tv;
|
546
|
+
|
547
|
+
c = connect(config);
|
548
|
+
test("Successfully completes a command when the timeout is not exceeded: ");
|
549
|
+
reply = redisCommand(c,"SET foo fast");
|
550
|
+
freeReplyObject(reply);
|
551
|
+
tv.tv_sec = 0;
|
552
|
+
tv.tv_usec = 10000;
|
553
|
+
redisSetTimeout(c, tv);
|
554
|
+
reply = redisCommand(c, "GET foo");
|
555
|
+
test_cond(reply != NULL && reply->type == REDIS_REPLY_STRING && memcmp(reply->str, "fast", 4) == 0);
|
556
|
+
freeReplyObject(reply);
|
557
|
+
disconnect(c, 0);
|
558
|
+
|
559
|
+
c = connect(config);
|
560
|
+
test("Does not return a reply when the command times out: ");
|
561
|
+
s = write(c->fd, cmd, strlen(cmd));
|
562
|
+
tv.tv_sec = 0;
|
563
|
+
tv.tv_usec = 10000;
|
564
|
+
redisSetTimeout(c, tv);
|
565
|
+
reply = redisCommand(c, "GET foo");
|
566
|
+
test_cond(s > 0 && reply == NULL && c->err == REDIS_ERR_IO && strcmp(c->errstr, "Resource temporarily unavailable") == 0);
|
567
|
+
freeReplyObject(reply);
|
568
|
+
|
569
|
+
test("Reconnect properly reconnects after a timeout: ");
|
570
|
+
redisReconnect(c);
|
571
|
+
reply = redisCommand(c, "PING");
|
572
|
+
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0);
|
573
|
+
freeReplyObject(reply);
|
574
|
+
|
575
|
+
test("Reconnect properly uses owned parameters: ");
|
576
|
+
config.tcp.host = "foo";
|
577
|
+
config.unix_sock.path = "foo";
|
578
|
+
redisReconnect(c);
|
579
|
+
reply = redisCommand(c, "PING");
|
580
|
+
test_cond(reply != NULL && reply->type == REDIS_REPLY_STATUS && strcmp(reply->str, "PONG") == 0);
|
581
|
+
freeReplyObject(reply);
|
582
|
+
|
583
|
+
disconnect(c, 0);
|
584
|
+
}
|
585
|
+
|
439
586
|
static void test_blocking_io_errors(struct config config) {
|
440
587
|
redisContext *c;
|
441
588
|
redisReply *reply;
|
@@ -459,7 +606,7 @@ static void test_blocking_io_errors(struct config config) {
|
|
459
606
|
|
460
607
|
test("Returns I/O error when the connection is lost: ");
|
461
608
|
reply = redisCommand(c,"QUIT");
|
462
|
-
if (major
|
609
|
+
if (major > 2 || (major == 2 && minor > 0)) {
|
463
610
|
/* > 2.0 returns OK on QUIT and read() should be issued once more
|
464
611
|
* to know the descriptor is at EOF. */
|
465
612
|
test_cond(strcasecmp(reply->str,"OK") == 0 &&
|
@@ -497,7 +644,7 @@ static void test_invalid_timeout_errors(struct config config) {
|
|
497
644
|
|
498
645
|
c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout);
|
499
646
|
|
500
|
-
test_cond(c->err == REDIS_ERR_IO);
|
647
|
+
test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0);
|
501
648
|
redisFree(c);
|
502
649
|
|
503
650
|
test("Set error when an invalid timeout sec value is given to redisConnectWithTimeout: ");
|
@@ -507,7 +654,7 @@ static void test_invalid_timeout_errors(struct config config) {
|
|
507
654
|
|
508
655
|
c = redisConnectWithTimeout(config.tcp.host, config.tcp.port, config.tcp.timeout);
|
509
656
|
|
510
|
-
test_cond(c->err == REDIS_ERR_IO);
|
657
|
+
test_cond(c->err == REDIS_ERR_IO && strcmp(c->errstr, "Invalid timeout specified") == 0);
|
511
658
|
redisFree(c);
|
512
659
|
}
|
513
660
|
|
@@ -545,6 +692,17 @@ static void test_throughput(struct config config) {
|
|
545
692
|
free(replies);
|
546
693
|
printf("\t(%dx LRANGE with 500 elements: %.3fs)\n", num, (t2-t1)/1000000.0);
|
547
694
|
|
695
|
+
replies = malloc(sizeof(redisReply*)*num);
|
696
|
+
t1 = usec();
|
697
|
+
for (i = 0; i < num; i++) {
|
698
|
+
replies[i] = redisCommand(c, "INCRBY incrkey %d", 1000000);
|
699
|
+
assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_INTEGER);
|
700
|
+
}
|
701
|
+
t2 = usec();
|
702
|
+
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
703
|
+
free(replies);
|
704
|
+
printf("\t(%dx INCRBY: %.3fs)\n", num, (t2-t1)/1000000.0);
|
705
|
+
|
548
706
|
num = 10000;
|
549
707
|
replies = malloc(sizeof(redisReply*)*num);
|
550
708
|
for (i = 0; i < num; i++)
|
@@ -573,6 +731,19 @@ static void test_throughput(struct config config) {
|
|
573
731
|
free(replies);
|
574
732
|
printf("\t(%dx LRANGE with 500 elements (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
|
575
733
|
|
734
|
+
replies = malloc(sizeof(redisReply*)*num);
|
735
|
+
for (i = 0; i < num; i++)
|
736
|
+
redisAppendCommand(c,"INCRBY incrkey %d", 1000000);
|
737
|
+
t1 = usec();
|
738
|
+
for (i = 0; i < num; i++) {
|
739
|
+
assert(redisGetReply(c, (void*)&replies[i]) == REDIS_OK);
|
740
|
+
assert(replies[i] != NULL && replies[i]->type == REDIS_REPLY_INTEGER);
|
741
|
+
}
|
742
|
+
t2 = usec();
|
743
|
+
for (i = 0; i < num; i++) freeReplyObject(replies[i]);
|
744
|
+
free(replies);
|
745
|
+
printf("\t(%dx INCRBY (pipelined): %.3fs)\n", num, (t2-t1)/1000000.0);
|
746
|
+
|
576
747
|
disconnect(c, 0);
|
577
748
|
}
|
578
749
|
|
@@ -681,7 +852,7 @@ int main(int argc, char **argv) {
|
|
681
852
|
.host = "127.0.0.1",
|
682
853
|
.port = 6379
|
683
854
|
},
|
684
|
-
.
|
855
|
+
.unix_sock = {
|
685
856
|
.path = "/tmp/redis.sock"
|
686
857
|
}
|
687
858
|
};
|
@@ -702,7 +873,7 @@ int main(int argc, char **argv) {
|
|
702
873
|
cfg.tcp.port = atoi(argv[0]);
|
703
874
|
} else if (argc >= 2 && !strcmp(argv[0],"-s")) {
|
704
875
|
argv++; argc--;
|
705
|
-
cfg.
|
876
|
+
cfg.unix_sock.path = argv[0];
|
706
877
|
} else if (argc >= 1 && !strcmp(argv[0],"--skip-throughput")) {
|
707
878
|
throughput = 0;
|
708
879
|
} else if (argc >= 1 && !strcmp(argv[0],"--skip-inherit-fd")) {
|
@@ -722,19 +893,21 @@ int main(int argc, char **argv) {
|
|
722
893
|
printf("\nTesting against TCP connection (%s:%d):\n", cfg.tcp.host, cfg.tcp.port);
|
723
894
|
cfg.type = CONN_TCP;
|
724
895
|
test_blocking_connection(cfg);
|
896
|
+
test_blocking_connection_timeouts(cfg);
|
725
897
|
test_blocking_io_errors(cfg);
|
726
898
|
test_invalid_timeout_errors(cfg);
|
727
899
|
test_append_formatted_commands(cfg);
|
728
900
|
if (throughput) test_throughput(cfg);
|
729
901
|
|
730
|
-
printf("\nTesting against Unix socket connection (%s):\n", cfg.
|
902
|
+
printf("\nTesting against Unix socket connection (%s):\n", cfg.unix_sock.path);
|
731
903
|
cfg.type = CONN_UNIX;
|
732
904
|
test_blocking_connection(cfg);
|
905
|
+
test_blocking_connection_timeouts(cfg);
|
733
906
|
test_blocking_io_errors(cfg);
|
734
907
|
if (throughput) test_throughput(cfg);
|
735
908
|
|
736
909
|
if (test_inherit_fd) {
|
737
|
-
printf("\nTesting against inherited fd (%s):\n", cfg.
|
910
|
+
printf("\nTesting against inherited fd (%s):\n", cfg.unix_sock.path);
|
738
911
|
cfg.type = CONN_FD;
|
739
912
|
test_blocking_connection(cfg);
|
740
913
|
}
|