hiredis 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
}
|