hiredis 0.2.0 → 0.3.0
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.
- 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
|
-
|