hiredis 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -47
- data/ext/hiredis_ext/connection.c +104 -35
- data/ext/hiredis_ext/extconf.rb +1 -1
- data/ext/hiredis_ext/hiredis_ext.c +4 -2
- data/ext/hiredis_ext/hiredis_ext.h +0 -1
- data/ext/hiredis_ext/reader.c +0 -20
- data/lib/hiredis.rb +2 -10
- data/lib/hiredis/connection.rb +7 -14
- data/lib/hiredis/ext/connection.rb +16 -0
- data/lib/hiredis/ext/reader.rb +2 -0
- data/lib/hiredis/reader.rb +10 -1
- data/lib/hiredis/ruby/connection.rb +113 -0
- data/lib/hiredis/ruby/reader.rb +164 -0
- data/lib/hiredis/version.rb +1 -1
- data/vendor/hiredis/Makefile +4 -5
- data/vendor/hiredis/async.c +2 -0
- data/vendor/hiredis/async.h +3 -3
- data/vendor/hiredis/dict.c +27 -77
- data/vendor/hiredis/dict.h +12 -16
- data/vendor/hiredis/hiredis.c +26 -17
- data/vendor/hiredis/hiredis.h +4 -2
- data/vendor/hiredis/net.c +85 -18
- data/vendor/hiredis/net.h +2 -2
- data/vendor/hiredis/sds.c +129 -4
- data/vendor/hiredis/sds.h +2 -1
- data/vendor/hiredis/test.c +14 -5
- metadata +15 -29
- data/lib/hiredis/em.rb +0 -1
- data/lib/hiredis/em/base.rb +0 -36
- data/lib/hiredis/em/connection.rb +0 -25
@@ -0,0 +1,164 @@
|
|
1
|
+
require "hiredis/version"
|
2
|
+
|
3
|
+
module Hiredis
|
4
|
+
module Ruby
|
5
|
+
class Reader
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@buffer = Buffer.new
|
9
|
+
@task = Task.new(@buffer)
|
10
|
+
end
|
11
|
+
|
12
|
+
def feed(data)
|
13
|
+
@buffer << data
|
14
|
+
end
|
15
|
+
|
16
|
+
def gets
|
17
|
+
reply = @task.process
|
18
|
+
@buffer.discard!
|
19
|
+
reply
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
class Task
|
25
|
+
|
26
|
+
# Use lookup table to map reply types to methods
|
27
|
+
method_index = {}
|
28
|
+
method_index[?-] = :process_error_reply
|
29
|
+
method_index[?+] = :process_status_reply
|
30
|
+
method_index[?:] = :process_integer_reply
|
31
|
+
method_index[?$] = :process_bulk_reply
|
32
|
+
method_index[?*] = :process_multi_bulk_reply
|
33
|
+
METHOD_INDEX = method_index.freeze
|
34
|
+
|
35
|
+
attr_accessor :parent, :child
|
36
|
+
attr_accessor :multi_bulk
|
37
|
+
|
38
|
+
def initialize(buffer, parent = nil, depth = 0)
|
39
|
+
@buffer, @parent = buffer, parent
|
40
|
+
|
41
|
+
# Require 3 nested tasks
|
42
|
+
@child = Task.new(@buffer, self, depth + 1) if depth < 2
|
43
|
+
end
|
44
|
+
|
45
|
+
def root
|
46
|
+
parent ? parent.root : self
|
47
|
+
end
|
48
|
+
|
49
|
+
def reset!
|
50
|
+
@line = @type = @multi_bulk = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def process_error_reply
|
54
|
+
RuntimeError.new(@line)
|
55
|
+
end
|
56
|
+
|
57
|
+
def process_status_reply
|
58
|
+
@line
|
59
|
+
end
|
60
|
+
|
61
|
+
def process_integer_reply
|
62
|
+
@line.to_i
|
63
|
+
end
|
64
|
+
|
65
|
+
def process_bulk_reply
|
66
|
+
bulk_length = @line.to_i
|
67
|
+
return nil if bulk_length < 0
|
68
|
+
|
69
|
+
# Caught by caller function when false
|
70
|
+
@buffer.read(bulk_length, 2)
|
71
|
+
end
|
72
|
+
|
73
|
+
def process_multi_bulk_reply
|
74
|
+
multi_bulk_length = @line.to_i
|
75
|
+
|
76
|
+
if multi_bulk_length > 0
|
77
|
+
@multi_bulk ||= []
|
78
|
+
|
79
|
+
# We know the multi bulk is not complete when this path is taken.
|
80
|
+
while (element = child.process) != false
|
81
|
+
@multi_bulk << element
|
82
|
+
return @multi_bulk if @multi_bulk.length == multi_bulk_length
|
83
|
+
end
|
84
|
+
|
85
|
+
false
|
86
|
+
elsif multi_bulk_length == 0
|
87
|
+
[]
|
88
|
+
else
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def process_protocol_error
|
94
|
+
raise "Protocol error"
|
95
|
+
end
|
96
|
+
|
97
|
+
def process
|
98
|
+
@line ||= @buffer.read_line
|
99
|
+
return false if @line == false
|
100
|
+
|
101
|
+
@type ||= @line.slice!(0)
|
102
|
+
reply = send(METHOD_INDEX[@type] || :process_protocol_error)
|
103
|
+
|
104
|
+
reset! if reply != false
|
105
|
+
reply
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
class Buffer
|
110
|
+
|
111
|
+
CRLF = "\r\n".freeze
|
112
|
+
|
113
|
+
def initialize
|
114
|
+
@buffer = ""
|
115
|
+
@length = @pos = 0
|
116
|
+
end
|
117
|
+
|
118
|
+
def <<(data)
|
119
|
+
@length += data.length
|
120
|
+
@buffer << data
|
121
|
+
end
|
122
|
+
|
123
|
+
def length
|
124
|
+
@length
|
125
|
+
end
|
126
|
+
|
127
|
+
def empty?
|
128
|
+
@length == 0
|
129
|
+
end
|
130
|
+
|
131
|
+
def discard!
|
132
|
+
if @length == 0
|
133
|
+
@buffer = ""
|
134
|
+
@length = @pos = 0
|
135
|
+
else
|
136
|
+
if @pos >= 1024
|
137
|
+
@buffer.slice!(0, @pos)
|
138
|
+
@length -= @pos
|
139
|
+
@pos = 0
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def read(bytes, skip = 0)
|
145
|
+
start = @pos
|
146
|
+
stop = start + bytes + skip
|
147
|
+
return false if @length < stop
|
148
|
+
|
149
|
+
@pos = stop
|
150
|
+
@buffer[start, bytes]
|
151
|
+
end
|
152
|
+
|
153
|
+
def read_line
|
154
|
+
start = @pos
|
155
|
+
stop = @buffer.index(CRLF, @pos)
|
156
|
+
return false unless stop
|
157
|
+
|
158
|
+
@pos = stop + 2 # include CRLF
|
159
|
+
@buffer[start, stop - start]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
data/lib/hiredis/version.rb
CHANGED
data/vendor/hiredis/Makefile
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
# Copyright (C) 2010 Salvatore Sanfilippo <antirez at gmail dot com>
|
3
3
|
# This file is released under the BSD license, see the COPYING file
|
4
4
|
|
5
|
-
OBJ = net.o hiredis.o sds.o async.o
|
5
|
+
OBJ = net.o hiredis.o sds.o async.o
|
6
6
|
BINS = hiredis-example hiredis-test
|
7
7
|
|
8
8
|
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
@@ -16,7 +16,7 @@ ifeq ($(uname_S),SunOS)
|
|
16
16
|
STLIBNAME?=libhiredis.a
|
17
17
|
STLIB_MAKE_CMD?=ar rcs ${STLIBNAME} ${OBJ}
|
18
18
|
else ifeq ($(uname_S),Darwin)
|
19
|
-
CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wwrite-strings $(ARCH) $(PROF)
|
19
|
+
CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings $(ARCH) $(PROF)
|
20
20
|
CCLINK?=-lm -pthread
|
21
21
|
LDFLAGS?=-L. -Wl,-rpath,.
|
22
22
|
OBJARCH?=-arch i386 -arch x86_64
|
@@ -25,7 +25,7 @@ else ifeq ($(uname_S),Darwin)
|
|
25
25
|
STLIBNAME?=libhiredis.a
|
26
26
|
STLIB_MAKE_CMD?=libtool -static -o ${STLIBNAME} - ${OBJ}
|
27
27
|
else
|
28
|
-
CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wwrite-strings $(ARCH) $(PROF)
|
28
|
+
CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings $(ARCH) $(PROF)
|
29
29
|
CCLINK?=-lm -pthread
|
30
30
|
LDFLAGS?=-L. -Wl,-rpath,.
|
31
31
|
DYLIBNAME?=libhiredis.so
|
@@ -45,11 +45,10 @@ all: ${DYLIBNAME} ${BINS}
|
|
45
45
|
|
46
46
|
# Deps (use make dep to generate this)
|
47
47
|
net.o: net.c fmacros.h net.h
|
48
|
-
async.o: async.c async.h hiredis.h sds.h util.h
|
48
|
+
async.o: async.c async.h hiredis.h sds.h util.h dict.c dict.h
|
49
49
|
example.o: example.c hiredis.h
|
50
50
|
hiredis.o: hiredis.c hiredis.h net.h sds.h util.h
|
51
51
|
sds.o: sds.c sds.h
|
52
|
-
dict.o: dict.c dict.h
|
53
52
|
test.o: test.c hiredis.h
|
54
53
|
|
55
54
|
${DYLIBNAME}: ${OBJ}
|
data/vendor/hiredis/async.c
CHANGED
data/vendor/hiredis/async.h
CHANGED
@@ -32,13 +32,13 @@
|
|
32
32
|
#ifndef __HIREDIS_ASYNC_H
|
33
33
|
#define __HIREDIS_ASYNC_H
|
34
34
|
#include "hiredis.h"
|
35
|
-
#include "dict.h"
|
36
35
|
|
37
36
|
#ifdef __cplusplus
|
38
37
|
extern "C" {
|
39
38
|
#endif
|
40
39
|
|
41
40
|
struct redisAsyncContext; /* need forward declaration of redisAsyncContext */
|
41
|
+
struct dict; /* dictionary header is included in async.c */
|
42
42
|
|
43
43
|
/* Reply callback prototype and container */
|
44
44
|
typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
|
@@ -95,8 +95,8 @@ typedef struct redisAsyncContext {
|
|
95
95
|
/* Subscription callbacks */
|
96
96
|
struct {
|
97
97
|
redisCallbackList invalid;
|
98
|
-
dict *channels;
|
99
|
-
dict *patterns;
|
98
|
+
struct dict *channels;
|
99
|
+
struct dict *patterns;
|
100
100
|
} sub;
|
101
101
|
} redisAsyncContext;
|
102
102
|
|
data/vendor/hiredis/dict.c
CHANGED
@@ -50,7 +50,7 @@ static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
|
|
50
50
|
|
51
51
|
/* Generic hash function (a popular one from Bernstein).
|
52
52
|
* I tested a few and this was the best. */
|
53
|
-
unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
|
53
|
+
static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
|
54
54
|
unsigned int hash = 5381;
|
55
55
|
|
56
56
|
while (len--)
|
@@ -70,31 +70,22 @@ static void _dictReset(dict *ht) {
|
|
70
70
|
}
|
71
71
|
|
72
72
|
/* Create a new hash table */
|
73
|
-
dict *dictCreate(dictType *type, void *privDataPtr) {
|
73
|
+
static dict *dictCreate(dictType *type, void *privDataPtr) {
|
74
74
|
dict *ht = malloc(sizeof(*ht));
|
75
75
|
_dictInit(ht,type,privDataPtr);
|
76
76
|
return ht;
|
77
77
|
}
|
78
78
|
|
79
79
|
/* Initialize the hash table */
|
80
|
-
int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
|
80
|
+
static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
|
81
81
|
_dictReset(ht);
|
82
82
|
ht->type = type;
|
83
83
|
ht->privdata = privDataPtr;
|
84
84
|
return DICT_OK;
|
85
85
|
}
|
86
86
|
|
87
|
-
/* Resize the table to the minimal size that contains all the elements,
|
88
|
-
* but with the invariant of a USER/BUCKETS ration near to <= 1 */
|
89
|
-
int dictResize(dict *ht) {
|
90
|
-
int minimal = ht->used;
|
91
|
-
if (minimal < DICT_HT_INITIAL_SIZE)
|
92
|
-
minimal = DICT_HT_INITIAL_SIZE;
|
93
|
-
return dictExpand(ht, minimal);
|
94
|
-
}
|
95
|
-
|
96
87
|
/* Expand or create the hashtable */
|
97
|
-
int dictExpand(dict *ht, unsigned long size) {
|
88
|
+
static int dictExpand(dict *ht, unsigned long size) {
|
98
89
|
dict n; /* the new hashtable */
|
99
90
|
unsigned long realsize = _dictNextPower(size), i;
|
100
91
|
|
@@ -141,7 +132,7 @@ int dictExpand(dict *ht, unsigned long size) {
|
|
141
132
|
}
|
142
133
|
|
143
134
|
/* Add an element to the target hash table */
|
144
|
-
int dictAdd(dict *ht, void *key, void *val) {
|
135
|
+
static int dictAdd(dict *ht, void *key, void *val) {
|
145
136
|
int index;
|
146
137
|
dictEntry *entry;
|
147
138
|
|
@@ -166,7 +157,7 @@ int dictAdd(dict *ht, void *key, void *val) {
|
|
166
157
|
* Return 1 if the key was added from scratch, 0 if there was already an
|
167
158
|
* element with such key and dictReplace() just performed a value update
|
168
159
|
* operation. */
|
169
|
-
int dictReplace(dict *ht, void *key, void *val) {
|
160
|
+
static int dictReplace(dict *ht, void *key, void *val) {
|
170
161
|
dictEntry *entry, auxentry;
|
171
162
|
|
172
163
|
/* Try to add the element. If the key
|
@@ -188,47 +179,38 @@ int dictReplace(dict *ht, void *key, void *val) {
|
|
188
179
|
}
|
189
180
|
|
190
181
|
/* Search and remove an element */
|
191
|
-
static int
|
182
|
+
static int dictDelete(dict *ht, const void *key) {
|
192
183
|
unsigned int h;
|
193
|
-
dictEntry *
|
184
|
+
dictEntry *de, *prevde;
|
194
185
|
|
195
186
|
if (ht->size == 0)
|
196
187
|
return DICT_ERR;
|
197
188
|
h = dictHashKey(ht, key) & ht->sizemask;
|
198
|
-
|
189
|
+
de = ht->table[h];
|
199
190
|
|
200
|
-
|
201
|
-
while(
|
202
|
-
if (dictCompareHashKeys(ht,
|
191
|
+
prevde = NULL;
|
192
|
+
while(de) {
|
193
|
+
if (dictCompareHashKeys(ht,key,de->key)) {
|
203
194
|
/* Unlink the element from the list */
|
204
|
-
if (
|
205
|
-
|
195
|
+
if (prevde)
|
196
|
+
prevde->next = de->next;
|
206
197
|
else
|
207
|
-
ht->table[h] =
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
free(he);
|
198
|
+
ht->table[h] = de->next;
|
199
|
+
|
200
|
+
dictFreeEntryKey(ht,de);
|
201
|
+
dictFreeEntryVal(ht,de);
|
202
|
+
free(de);
|
213
203
|
ht->used--;
|
214
204
|
return DICT_OK;
|
215
205
|
}
|
216
|
-
|
217
|
-
|
206
|
+
prevde = de;
|
207
|
+
de = de->next;
|
218
208
|
}
|
219
209
|
return DICT_ERR; /* not found */
|
220
210
|
}
|
221
211
|
|
222
|
-
int dictDelete(dict *ht, const void *key) {
|
223
|
-
return dictGenericDelete(ht,key,0);
|
224
|
-
}
|
225
|
-
|
226
|
-
int dictDeleteNoFree(dict *ht, const void *key) {
|
227
|
-
return dictGenericDelete(ht,key,1);
|
228
|
-
}
|
229
|
-
|
230
212
|
/* Destroy an entire hash table */
|
231
|
-
int _dictClear(dict *ht) {
|
213
|
+
static int _dictClear(dict *ht) {
|
232
214
|
unsigned long i;
|
233
215
|
|
234
216
|
/* Free all the elements */
|
@@ -253,12 +235,12 @@ int _dictClear(dict *ht) {
|
|
253
235
|
}
|
254
236
|
|
255
237
|
/* Clear & Release the hash table */
|
256
|
-
void dictRelease(dict *ht) {
|
238
|
+
static void dictRelease(dict *ht) {
|
257
239
|
_dictClear(ht);
|
258
240
|
free(ht);
|
259
241
|
}
|
260
242
|
|
261
|
-
dictEntry *dictFind(dict *ht, const void *key) {
|
243
|
+
static dictEntry *dictFind(dict *ht, const void *key) {
|
262
244
|
dictEntry *he;
|
263
245
|
unsigned int h;
|
264
246
|
|
@@ -273,7 +255,7 @@ dictEntry *dictFind(dict *ht, const void *key) {
|
|
273
255
|
return NULL;
|
274
256
|
}
|
275
257
|
|
276
|
-
dictIterator *dictGetIterator(dict *ht) {
|
258
|
+
static dictIterator *dictGetIterator(dict *ht) {
|
277
259
|
dictIterator *iter = malloc(sizeof(*iter));
|
278
260
|
|
279
261
|
iter->ht = ht;
|
@@ -283,7 +265,7 @@ dictIterator *dictGetIterator(dict *ht) {
|
|
283
265
|
return iter;
|
284
266
|
}
|
285
267
|
|
286
|
-
dictEntry *dictNext(dictIterator *iter) {
|
268
|
+
static dictEntry *dictNext(dictIterator *iter) {
|
287
269
|
while (1) {
|
288
270
|
if (iter->entry == NULL) {
|
289
271
|
iter->index++;
|
@@ -303,38 +285,10 @@ dictEntry *dictNext(dictIterator *iter) {
|
|
303
285
|
return NULL;
|
304
286
|
}
|
305
287
|
|
306
|
-
void dictReleaseIterator(dictIterator *iter) {
|
288
|
+
static void dictReleaseIterator(dictIterator *iter) {
|
307
289
|
free(iter);
|
308
290
|
}
|
309
291
|
|
310
|
-
/* Return a random entry from the hash table. Useful to
|
311
|
-
* implement randomized algorithms */
|
312
|
-
dictEntry *dictGetRandomKey(dict *ht) {
|
313
|
-
dictEntry *he;
|
314
|
-
unsigned int h;
|
315
|
-
int listlen, listele;
|
316
|
-
|
317
|
-
if (ht->used == 0) return NULL;
|
318
|
-
do {
|
319
|
-
h = random() & ht->sizemask;
|
320
|
-
he = ht->table[h];
|
321
|
-
} while(he == NULL);
|
322
|
-
|
323
|
-
/* Now we found a non empty bucket, but it is a linked
|
324
|
-
* list and we need to get a random element from the list.
|
325
|
-
* The only sane way to do so is to count the element and
|
326
|
-
* select a random index. */
|
327
|
-
listlen = 0;
|
328
|
-
while(he) {
|
329
|
-
he = he->next;
|
330
|
-
listlen++;
|
331
|
-
}
|
332
|
-
listele = random() % listlen;
|
333
|
-
he = ht->table[h];
|
334
|
-
while(listele--) he = he->next;
|
335
|
-
return he;
|
336
|
-
}
|
337
|
-
|
338
292
|
/* ------------------------- private functions ------------------------------ */
|
339
293
|
|
340
294
|
/* Expand the hash table if needed */
|
@@ -382,7 +336,3 @@ static int _dictKeyIndex(dict *ht, const void *key) {
|
|
382
336
|
return h;
|
383
337
|
}
|
384
338
|
|
385
|
-
void dictEmpty(dict *ht) {
|
386
|
-
_dictClear(ht);
|
387
|
-
}
|
388
|
-
|