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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 9f5223293433c777928e04bd8c99236f393d6f84
4
- data.tar.gz: 2c915fb52bd73e9816f5acce51dd3c72c16da9cc
2
+ SHA256:
3
+ metadata.gz: 1f07127ae47561dfa27e69e75ec20141aea1ec0f25c9e0a6ebf85d28c0fd0ab5
4
+ data.tar.gz: 71b64366a9ec6eb8eaef1ca8c6dee1aaab91c1608198d2fbc0dd928d31e36cca
5
5
  SHA512:
6
- metadata.gz: 8ee5ef3080b1bd3231ebe60f5d2f76a59bfeee1281c0a642d48cffd6a408b86980f82a7b384288229bb788c2e0332db2f2bd92568c538c3042719d04cf8c2125
7
- data.tar.gz: 81c4474b55f788acded811dbefdc9b125a906eeb3c5008afd94f8663ff62eaae8f9d1939e58f89166624b7961e1433eeb3d971fde9c0ca6304370b325083f8ac
6
+ metadata.gz: e3e5d4387c7e4d625fc81349d1224ac34cc43aae5a6d49c648515462eab5404bd18bb0deae1a166ab42e0ab93f91ef7344dd1a8a0c4ea54fd040bfe97a4a983f
7
+ data.tar.gz: 59504af0292497549b26ae7f970e2495363d0a66b9e15cb8c98b1fdcc748805a11a2c7e800fc9cce41dc81a85dc08273d62558d5481f89b2625f8611bbb50019
@@ -27,9 +27,10 @@ static void parent_context_try_free(redisParentContext *pc) {
27
27
  }
28
28
 
29
29
  static void parent_context_mark(redisParentContext *pc) {
30
- VALUE root;
30
+ // volatile until rb_gc_mark
31
+ volatile VALUE root;
31
32
  if (pc->context && pc->context->reader) {
32
- root = (VALUE)redisReplyReaderGetObject(pc->context->reader);
33
+ root = (VALUE)redisReaderGetObject(pc->context->reader);
33
34
  if (root != 0 && TYPE(root) == T_ARRAY) {
34
35
  rb_gc_mark(root);
35
36
  }
@@ -448,7 +449,7 @@ static int __get_reply(redisParentContext *pc, VALUE *reply) {
448
449
 
449
450
  static VALUE connection_read(VALUE self) {
450
451
  redisParentContext *pc;
451
- VALUE reply;
452
+ volatile VALUE reply;
452
453
 
453
454
  Data_Get_Struct(self,redisParentContext,pc);
454
455
  if (!pc->context)
@@ -10,7 +10,7 @@ static ID str_force_encoding = 0;
10
10
  * Note that the parent should always be of type T_ARRAY. */
11
11
  static void *tryParentize(const redisReadTask *task, VALUE v) {
12
12
  if (task && task->parent != NULL) {
13
- VALUE parent = (VALUE)task->parent->obj;
13
+ volatile VALUE parent = (VALUE)task->parent->obj;
14
14
  assert(TYPE(parent) == T_ARRAY);
15
15
  rb_ary_store(parent,task->idx,v);
16
16
  }
@@ -18,7 +18,7 @@ static void *tryParentize(const redisReadTask *task, VALUE v) {
18
18
  }
19
19
 
20
20
  static void *createStringObject(const redisReadTask *task, char *str, size_t len) {
21
- VALUE v, enc;
21
+ volatile VALUE v, enc;
22
22
  v = rb_str_new(str,len);
23
23
 
24
24
  /* Force default external encoding if possible. */
@@ -35,12 +35,12 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
35
35
  }
36
36
 
37
37
  static void *createArrayObject(const redisReadTask *task, int elements) {
38
- VALUE v = rb_ary_new2(elements);
38
+ volatile VALUE v = rb_ary_new2(elements);
39
39
  return tryParentize(task,v);
40
40
  }
41
41
 
42
42
  static void *createIntegerObject(const redisReadTask *task, long long value) {
43
- VALUE v = LL2NUM(value);
43
+ volatile VALUE v = LL2NUM(value);
44
44
  return tryParentize(task,v);
45
45
  }
46
46
 
@@ -62,7 +62,13 @@ redisReplyObjectFunctions redisExtReplyObjectFunctions = {
62
62
  };
63
63
 
64
64
  static void reader_mark(redisReader *reader) {
65
- VALUE root = (VALUE)reader->reply;
65
+ // volatile until rb_gc_mark
66
+ volatile VALUE root = (VALUE)reader->reply;
67
+ // FIXME - PCO - checking root for 0 is checkign to see if the value is
68
+ // Qfalse. I suspect that is not what is intended here. Checking the
69
+ // redisReader code might clarify. It would be unfortunate if the reply, a
70
+ // void* was using NULL to indicate not set but that may be the nature of
71
+ // the redisReader library. It is worth checking anyway.
66
72
  if (root != 0 && TYPE(root) == T_ARRAY) rb_gc_mark(root);
67
73
  }
68
74
 
@@ -85,7 +91,7 @@ static VALUE reader_feed(VALUE klass, VALUE str) {
85
91
 
86
92
  static VALUE reader_gets(VALUE klass) {
87
93
  redisReader *reader;
88
- VALUE reply;
94
+ volatile VALUE reply;
89
95
 
90
96
  Data_Get_Struct(klass, redisReader, reader);
91
97
  if (redisReaderGetReply(reader,(void**)&reply) != REDIS_OK)
@@ -1,3 +1,3 @@
1
1
  module Hiredis
2
- VERSION = "0.6.1"
2
+ VERSION = "0.6.3"
3
3
  end
@@ -12,15 +12,16 @@ PKGCONFNAME=hiredis.pc
12
12
  HIREDIS_MAJOR=$(shell grep HIREDIS_MAJOR hiredis.h | awk '{print $$3}')
13
13
  HIREDIS_MINOR=$(shell grep HIREDIS_MINOR hiredis.h | awk '{print $$3}')
14
14
  HIREDIS_PATCH=$(shell grep HIREDIS_PATCH hiredis.h | awk '{print $$3}')
15
+ HIREDIS_SONAME=$(shell grep HIREDIS_SONAME hiredis.h | awk '{print $$3}')
15
16
 
16
17
  # Installation related variables and target
17
18
  PREFIX?=/usr/local
18
19
  INCLUDE_PATH?=include/hiredis
19
20
  LIBRARY_PATH?=lib
20
21
  PKGCONF_PATH?=pkgconfig
21
- INSTALL_INCLUDE_PATH= $(PREFIX)/$(INCLUDE_PATH)
22
- INSTALL_LIBRARY_PATH= $(PREFIX)/$(LIBRARY_PATH)
23
- INSTALL_PKGCONF_PATH= $(LIBRARY_PATH)/$(PKGCONF_PATH)
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)
24
25
 
25
26
  # redis-server configuration used for testing
26
27
  REDIS_PORT=56379
@@ -35,16 +36,17 @@ endef
35
36
  export REDIS_TEST_CONFIG
36
37
 
37
38
  # Fallback to gcc when $CC is not in $PATH.
38
- CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
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++')
39
41
  OPTIMIZATION?=-O3
40
42
  WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings
41
- DEBUG?= -g -ggdb
42
- REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH)
43
- REAL_LDFLAGS=$(LDFLAGS) $(ARCH)
43
+ DEBUG_FLAGS?= -g -ggdb
44
+ REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG_FLAGS)
45
+ REAL_LDFLAGS=$(LDFLAGS)
44
46
 
45
47
  DYLIBSUFFIX=so
46
48
  STLIBSUFFIX=a
47
- DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR).$(HIREDIS_MINOR)
49
+ DYLIB_MINOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_SONAME)
48
50
  DYLIB_MAJOR_NAME=$(LIBNAME).$(DYLIBSUFFIX).$(HIREDIS_MAJOR)
49
51
  DYLIBNAME=$(LIBNAME).$(DYLIBSUFFIX)
50
52
  DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
@@ -56,16 +58,14 @@ uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
56
58
  ifeq ($(uname_S),SunOS)
57
59
  REAL_LDFLAGS+= -ldl -lnsl -lsocket
58
60
  DYLIB_MAKE_CMD=$(CC) -G -o $(DYLIBNAME) -h $(DYLIB_MINOR_NAME) $(LDFLAGS)
59
- INSTALL= cp -r
60
61
  endif
61
62
  ifeq ($(uname_S),Darwin)
62
63
  DYLIBSUFFIX=dylib
63
- DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(DYLIBSUFFIX)
64
- DYLIB_MAJOR_NAME=$(LIBNAME).$(HIREDIS_MAJOR).$(DYLIBSUFFIX)
65
- DYLIB_MAKE_CMD=$(CC) -shared -Wl,-install_name,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
64
+ DYLIB_MINOR_NAME=$(LIBNAME).$(HIREDIS_SONAME).$(DYLIBSUFFIX)
65
+ DYLIB_MAKE_CMD=$(CC) -dynamiclib -Wl,-install_name,$(PREFIX)/$(LIBRARY_PATH)/$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
66
66
  endif
67
67
 
68
- all: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
68
+ all: $(DYLIBNAME) $(STLIBNAME) hiredis-test $(PKGCONFNAME)
69
69
 
70
70
  # Deps (use make dep to generate this)
71
71
  async.o: async.c fmacros.h async.h hiredis.h read.h sds.h net.h dict.c dict.h
@@ -93,7 +93,13 @@ hiredis-example-libev: examples/example-libev.c adapters/libev.h $(STLIBNAME)
93
93
  $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -lev $(STLIBNAME)
94
94
 
95
95
  hiredis-example-glib: examples/example-glib.c adapters/glib.h $(STLIBNAME)
96
- $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) $(shell pkg-config --cflags --libs glib-2.0) -I. $< $(STLIBNAME)
96
+ $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< $(shell pkg-config --cflags --libs glib-2.0) $(STLIBNAME)
97
+
98
+ hiredis-example-ivykis: examples/example-ivykis.c adapters/ivykis.h $(STLIBNAME)
99
+ $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -livykis $(STLIBNAME)
100
+
101
+ hiredis-example-macosx: examples/example-macosx.c adapters/macosx.h $(STLIBNAME)
102
+ $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. $< -framework CoreFoundation $(STLIBNAME)
97
103
 
98
104
  ifndef AE_DIR
99
105
  hiredis-example-ae:
@@ -110,7 +116,20 @@ hiredis-example-libuv:
110
116
  @false
111
117
  else
112
118
  hiredis-example-libuv: examples/example-libuv.c adapters/libuv.h $(STLIBNAME)
113
- $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread $(STLIBNAME)
119
+ $(CC) -o examples/$@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(LIBUV_DIR)/include $< $(LIBUV_DIR)/.libs/libuv.a -lpthread -lrt $(STLIBNAME)
120
+ endif
121
+
122
+ ifeq ($(and $(QT_MOC),$(QT_INCLUDE_DIR),$(QT_LIBRARY_DIR)),)
123
+ hiredis-example-qt:
124
+ @echo "Please specify QT_MOC, QT_INCLUDE_DIR AND QT_LIBRARY_DIR"
125
+ @false
126
+ else
127
+ hiredis-example-qt: examples/example-qt.cpp adapters/qt.h $(STLIBNAME)
128
+ $(QT_MOC) adapters/qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \
129
+ $(CXX) -x c++ -o qt-adapter-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore
130
+ $(QT_MOC) examples/example-qt.h -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore | \
131
+ $(CXX) -x c++ -o qt-example-moc.o -c - $(REAL_CFLAGS) -I. -I$(QT_INCLUDE_DIR) -I$(QT_INCLUDE_DIR)/QtCore
132
+ $(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
114
133
  endif
115
134
 
116
135
  hiredis-example: examples/example.c $(STLIBNAME)
@@ -121,7 +140,7 @@ examples: $(EXAMPLES)
121
140
  hiredis-test: test.o $(STLIBNAME)
122
141
 
123
142
  hiredis-%: %.o $(STLIBNAME)
124
- $(CC) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME)
143
+ $(CC) $(REAL_CFLAGS) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME)
125
144
 
126
145
  test: hiredis-test
127
146
  ./hiredis-test
@@ -141,31 +160,27 @@ clean:
141
160
  dep:
142
161
  $(CC) -MM *.c
143
162
 
144
- ifeq ($(uname_S),SunOS)
145
- INSTALL?= cp -r
146
- endif
163
+ INSTALL?= cp -pPR
147
164
 
148
- INSTALL?= cp -a
149
-
150
- $(PKGCONFNAME): $(PKGCONF_SRCNAME)
165
+ $(PKGCONFNAME): hiredis.h
151
166
  @echo "Generating $@ for pkgconfig..."
152
167
  @echo prefix=$(PREFIX) > $@
153
- @echo exec_prefix=$${prefix} >> $@
154
- @echo libdir=$(INSTALL_LIBRARY_PATH) >> $@
155
- @echo includedir=$(INSTALL_INCLUDE_PATH) >> $@
168
+ @echo exec_prefix=\$${prefix} >> $@
169
+ @echo libdir=$(PREFIX)/$(LIBRARY_PATH) >> $@
170
+ @echo includedir=$(PREFIX)/$(INCLUDE_PATH) >> $@
156
171
  @echo >> $@
157
172
  @echo Name: hiredis >> $@
158
- @echo Description: Minimalistic C client library for the Redis database. >> $@
173
+ @echo Description: Minimalistic C client library for Redis. >> $@
159
174
  @echo Version: $(HIREDIS_MAJOR).$(HIREDIS_MINOR).$(HIREDIS_PATCH) >> $@
160
- @echo Libs: -L$${libdir} -lhiredis >> $@
161
- @echo Cflags: -I$${includedir} -D_FILE_OFFSET_BITS=64 >> $@
175
+ @echo Libs: -L\$${libdir} -lhiredis >> $@
176
+ @echo Cflags: -I\$${includedir} -D_FILE_OFFSET_BITS=64 >> $@
162
177
 
163
- install: $(DYLIBNAME) $(STLIBNAME)
164
- mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_LIBRARY_PATH)
165
- $(INSTALL) hiredis.h async.h adapters $(INSTALL_INCLUDE_PATH)
178
+ install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
179
+ mkdir -p $(INSTALL_INCLUDE_PATH) $(INSTALL_INCLUDE_PATH)/adapters $(INSTALL_LIBRARY_PATH)
180
+ $(INSTALL) hiredis.h async.h read.h sds.h $(INSTALL_INCLUDE_PATH)
181
+ $(INSTALL) adapters/*.h $(INSTALL_INCLUDE_PATH)/adapters
166
182
  $(INSTALL) $(DYLIBNAME) $(INSTALL_LIBRARY_PATH)/$(DYLIB_MINOR_NAME)
167
- cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIB_MAJOR_NAME)
168
- cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MAJOR_NAME) $(DYLIBNAME)
183
+ cd $(INSTALL_LIBRARY_PATH) && ln -sf $(DYLIB_MINOR_NAME) $(DYLIBNAME)
169
184
  $(INSTALL) $(STLIBNAME) $(INSTALL_LIBRARY_PATH)
170
185
  mkdir -p $(INSTALL_PKGCONF_PATH)
171
186
  $(INSTALL) $(PKGCONFNAME) $(INSTALL_PKGCONF_PATH)
@@ -176,6 +191,10 @@ install: $(DYLIBNAME) $(STLIBNAME)
176
191
  @echo ""
177
192
  $(MAKE) CFLAGS="-m32" LDFLAGS="-m32"
178
193
 
194
+ 32bit-vars:
195
+ $(eval CFLAGS=-m32)
196
+ $(eval LDFLAGS=-m32)
197
+
179
198
  gprof:
180
199
  $(MAKE) CFLAGS="-pg" LDFLAGS="-pg"
181
200
 
@@ -191,4 +210,4 @@ coverage: gcov
191
210
  noopt:
192
211
  $(MAKE) OPTIMIZATION=""
193
212
 
194
- .PHONY: all test check clean dep install 32bit gprof gcov noopt
213
+ .PHONY: all test check clean dep install 32bit 32bit-vars gprof gcov noopt
@@ -336,7 +336,8 @@ static void __redisAsyncDisconnect(redisAsyncContext *ac) {
336
336
 
337
337
  if (ac->err == 0) {
338
338
  /* For clean disconnects, there should be no pending callbacks. */
339
- assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR);
339
+ int ret = __redisShiftCallback(&ac->replies,NULL);
340
+ assert(ret == REDIS_ERR);
340
341
  } else {
341
342
  /* Disconnection is caused by an error, make sure that pending
342
343
  * callbacks cannot call new commands. */
@@ -364,6 +365,7 @@ void redisAsyncDisconnect(redisAsyncContext *ac) {
364
365
  static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) {
365
366
  redisContext *c = &(ac->c);
366
367
  dict *callbacks;
368
+ redisCallback *cb;
367
369
  dictEntry *de;
368
370
  int pvariant;
369
371
  char *stype;
@@ -387,16 +389,28 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
387
389
  sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len);
388
390
  de = dictFind(callbacks,sname);
389
391
  if (de != NULL) {
390
- memcpy(dstcb,dictGetEntryVal(de),sizeof(*dstcb));
392
+ cb = dictGetEntryVal(de);
393
+
394
+ /* If this is an subscribe reply decrease pending counter. */
395
+ if (strcasecmp(stype+pvariant,"subscribe") == 0) {
396
+ cb->pending_subs -= 1;
397
+ }
398
+
399
+ memcpy(dstcb,cb,sizeof(*dstcb));
391
400
 
392
401
  /* If this is an unsubscribe message, remove it. */
393
402
  if (strcasecmp(stype+pvariant,"unsubscribe") == 0) {
394
- dictDelete(callbacks,sname);
403
+ if (cb->pending_subs == 0)
404
+ dictDelete(callbacks,sname);
395
405
 
396
406
  /* If this was the last unsubscribe message, revert to
397
407
  * non-subscribe mode. */
398
408
  assert(reply->element[2]->type == REDIS_REPLY_INTEGER);
399
- if (reply->element[2]->integer == 0)
409
+
410
+ /* Unset subscribed flag only when no pipelined pending subscribe. */
411
+ if (reply->element[2]->integer == 0
412
+ && dictSize(ac->sub.channels) == 0
413
+ && dictSize(ac->sub.patterns) == 0)
400
414
  c->flags &= ~REDIS_SUBSCRIBED;
401
415
  }
402
416
  }
@@ -410,7 +424,7 @@ static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply,
410
424
 
411
425
  void redisProcessCallbacks(redisAsyncContext *ac) {
412
426
  redisContext *c = &(ac->c);
413
- redisCallback cb = {NULL, NULL, NULL};
427
+ redisCallback cb = {NULL, NULL, 0, NULL};
414
428
  void *reply = NULL;
415
429
  int status;
416
430
 
@@ -418,7 +432,8 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
418
432
  if (reply == NULL) {
419
433
  /* When the connection is being disconnected and there are
420
434
  * no more replies, this is the cue to really disconnect. */
421
- if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0) {
435
+ if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0
436
+ && ac->replies.head == NULL) {
422
437
  __redisAsyncDisconnect(ac);
423
438
  return;
424
439
  }
@@ -454,6 +469,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
454
469
  if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) {
455
470
  c->err = REDIS_ERR_OTHER;
456
471
  snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str);
472
+ c->reader->fn->freeObject(reply);
457
473
  __redisAsyncDisconnect(ac);
458
474
  return;
459
475
  }
@@ -487,7 +503,7 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
487
503
  }
488
504
 
489
505
  /* Internal helper function to detect socket status the first time a read or
490
- * write event fires. When connecting was not succesful, the connect callback
506
+ * write event fires. When connecting was not successful, the connect callback
491
507
  * is called with a REDIS_ERR status and the context is free'd. */
492
508
  static int __redisAsyncHandleConnect(redisAsyncContext *ac) {
493
509
  redisContext *c = &(ac->c);
@@ -581,6 +597,9 @@ static const char *nextArgument(const char *start, const char **str, size_t *len
581
597
  static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) {
582
598
  redisContext *c = &(ac->c);
583
599
  redisCallback cb;
600
+ struct dict *cbdict;
601
+ dictEntry *de;
602
+ redisCallback *existcb;
584
603
  int pvariant, hasnext;
585
604
  const char *cstr, *astr;
586
605
  size_t clen, alen;
@@ -594,6 +613,7 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
594
613
  /* Setup callback */
595
614
  cb.fn = fn;
596
615
  cb.privdata = privdata;
616
+ cb.pending_subs = 1;
597
617
 
598
618
  /* Find out which command will be appended. */
599
619
  p = nextArgument(cmd,&cstr,&clen);
@@ -610,9 +630,18 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
610
630
  while ((p = nextArgument(p,&astr,&alen)) != NULL) {
611
631
  sname = sdsnewlen(astr,alen);
612
632
  if (pvariant)
613
- ret = dictReplace(ac->sub.patterns,sname,&cb);
633
+ cbdict = ac->sub.patterns;
614
634
  else
615
- ret = dictReplace(ac->sub.channels,sname,&cb);
635
+ cbdict = ac->sub.channels;
636
+
637
+ de = dictFind(cbdict,sname);
638
+
639
+ if (de != NULL) {
640
+ existcb = dictGetEntryVal(de);
641
+ cb.pending_subs = existcb->pending_subs + 1;
642
+ }
643
+
644
+ ret = dictReplace(cbdict,sname,&cb);
616
645
 
617
646
  if (ret == 0) sdsfree(sname);
618
647
  }
@@ -674,6 +703,8 @@ int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *priv
674
703
  int len;
675
704
  int status;
676
705
  len = redisFormatSdsCommandArgv(&cmd,argc,argv,argvlen);
706
+ if (len < 0)
707
+ return REDIS_ERR;
677
708
  status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
678
709
  sdsfree(cmd);
679
710
  return status;
@@ -45,6 +45,7 @@ typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
45
45
  typedef struct redisCallback {
46
46
  struct redisCallback *next; /* simple singly linked list */
47
47
  redisCallbackFn *fn;
48
+ int pending_subs;
48
49
  void *privdata;
49
50
  } redisCallback;
50
51
 
@@ -161,7 +161,7 @@ static int dictReplace(dict *ht, void *key, void *val) {
161
161
  dictEntry *entry, auxentry;
162
162
 
163
163
  /* Try to add the element. If the key
164
- * does not exists dictAdd will suceed. */
164
+ * does not exists dictAdd will succeed. */
165
165
  if (dictAdd(ht, key, val) == DICT_OK)
166
166
  return 1;
167
167
  /* It already exists, get the entry */
@@ -293,7 +293,7 @@ static void dictReleaseIterator(dictIterator *iter) {
293
293
 
294
294
  /* Expand the hash table if needed */
295
295
  static int _dictExpandIfNeeded(dict *ht) {
296
- /* If the hash table is empty expand it to the intial size,
296
+ /* If the hash table is empty expand it to the initial size,
297
297
  * if the table is "full" dobule its size. */
298
298
  if (ht->size == 0)
299
299
  return dictExpand(ht, DICT_HT_INITIAL_SIZE);
@@ -1,21 +1,12 @@
1
1
  #ifndef __HIREDIS_FMACRO_H
2
2
  #define __HIREDIS_FMACRO_H
3
3
 
4
- #if defined(__linux__)
5
- #define _BSD_SOURCE
6
- #define _DEFAULT_SOURCE
7
- #endif
8
-
9
- #if defined(__sun__)
10
- #define _POSIX_C_SOURCE 200112L
11
- #elif defined(__linux__) || defined(__OpenBSD__) || defined(__NetBSD__)
12
4
  #define _XOPEN_SOURCE 600
13
- #else
14
- #define _XOPEN_SOURCE
15
- #endif
5
+ #define _POSIX_C_SOURCE 200112L
16
6
 
17
- #if __APPLE__ && __MACH__
18
- #define _OSX
7
+ #if defined(__APPLE__) && defined(__MACH__)
8
+ /* Enable TCP_KEEPALIVE */
9
+ #define _DARWIN_C_SOURCE
19
10
  #endif
20
11
 
21
12
  #endif