hiredis 0.4.5 → 0.5.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d434e6b09126833f2a6dcf82385105de08f629dd
4
+ data.tar.gz: 2d668be20b90a469f8f905f5915868e143cf5ae4
5
+ SHA512:
6
+ metadata.gz: 637b4bc535ceca4c61aff1f3a1d7456819dc9abdfc934618eac3f8c66b2d791a8106197c552ee6a8635611bcb8588cebb4d183a0de60e21ad4b8b10a29f494eb
7
+ data.tar.gz: 5170e3ae0d95f728b2ca8566717de256aba4a4e3f804618a968ce81bbe8e3fca5b57942fe3d050441c10fe44aaf3f3c140ed7d8c99bc45e153033cb34884ad99
data/Rakefile CHANGED
@@ -1,6 +1,7 @@
1
1
  require "bundler"
2
2
  Bundler::GemHelper.install_tasks
3
3
 
4
+ require "rbconfig"
4
5
  require "rake/testtask"
5
6
  require "rake/extensiontask"
6
7
 
@@ -18,7 +19,12 @@ unless defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
18
19
  if !File.directory?("vendor/hiredis/.git")
19
20
  system("git submodule update --init")
20
21
  end
21
- system("cd vendor/hiredis && make clean")
22
+ RbConfig::CONFIG['configure_args'] =~ /with-make-prog\=(\w+)/
23
+ make_program = $1 || ENV['make']
24
+ unless make_program then
25
+ make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
26
+ end
27
+ system("cd vendor/hiredis && #{make_program} clean")
22
28
  end
23
29
  end
24
30
 
@@ -72,24 +72,58 @@ static VALUE connection_parent_context_alloc(VALUE klass) {
72
72
  return Data_Wrap_Struct(klass, parent_context_mark, parent_context_free, pc);
73
73
  }
74
74
 
75
+
76
+ /*
77
+ * The rb_fdset_t API was introduced in Ruby 1.9.1. The rb_fd_thread_select
78
+ * function was introduced in a later version. Therefore, there are one more
79
+ * versions where we cannot simply test HAVE_RB_FD_INIT and be done, we have to
80
+ * explicitly test for HAVE_RB_THREAD_FD_SELECT (also see extconf.rb).
81
+ */
82
+ #ifdef HAVE_RB_THREAD_FD_SELECT
83
+ typedef rb_fdset_t _fdset_t;
84
+ #define _fd_zero(f) rb_fd_zero(f)
85
+ #define _fd_set(n, f) rb_fd_set(n, f)
86
+ #define _fd_clr(n, f) rb_fd_clr(n, f)
87
+ #define _fd_isset(n, f) rb_fd_isset(n, f)
88
+ #define _fd_copy(d, s, n) rb_fd_copy(d, s, n)
89
+ #define _fd_ptr(f) rb_fd_ptr(f)
90
+ #define _fd_init(f) rb_fd_init(f)
91
+ #define _fd_term(f) rb_fd_term(f)
92
+ #define _fd_max(f) rb_fd_max(f)
93
+ #define _thread_fd_select(n, r, w, e, t) rb_thread_fd_select(n, r, w, e, t)
94
+ #else
95
+ typedef fd_set _fdset_t;
96
+ #define _fd_zero(f) FD_ZERO(f)
97
+ #define _fd_set(n, f) FD_SET(n, f)
98
+ #define _fd_clr(n, f) FD_CLR(n, f)
99
+ #define _fd_isset(n, f) FD_ISSET(n, f)
100
+ #define _fd_copy(d, s, n) (*(d) = *(s))
101
+ #define _fd_ptr(f) (f)
102
+ #define _fd_init(f) FD_ZERO(f)
103
+ #define _fd_term(f) (void)(f)
104
+ #define _fd_max(f) FD_SETSIZE
105
+ #define _thread_fd_select(n, r, w, e, t) rb_thread_select(n, r, w, e, t)
106
+ #endif
107
+
75
108
  static int __wait_readable(int fd, const struct timeval *timeout, int *isset) {
76
109
  struct timeval to;
77
110
  struct timeval *toptr = NULL;
78
- fd_set fds;
79
- FD_ZERO(&fds);
80
- FD_SET(fd, &fds);
81
111
 
82
- /* rb_thread_select modifies the passed timeval, so we pass a copy */
112
+ _fdset_t fds;
113
+ _fd_init(&fds);
114
+ _fd_set(fd, &fds);
115
+
116
+ /* rb_fd_select modifies the passed timeval, so we pass a copy */
83
117
  if (timeout != NULL) {
84
118
  memcpy(&to, timeout, sizeof(to));
85
119
  toptr = &to;
86
120
  }
87
121
 
88
- if (rb_thread_select(fd + 1, &fds, NULL, NULL, toptr) < 0) {
122
+ if (_thread_fd_select(fd + 1, &fds, NULL, NULL, toptr) < 0) {
89
123
  return -1;
90
124
  }
91
125
 
92
- if (FD_ISSET(fd, &fds) && isset) {
126
+ if (_fd_isset(fd, &fds) && isset) {
93
127
  *isset = 1;
94
128
  }
95
129
 
@@ -99,21 +133,22 @@ static int __wait_readable(int fd, const struct timeval *timeout, int *isset) {
99
133
  static int __wait_writable(int fd, const struct timeval *timeout, int *isset) {
100
134
  struct timeval to;
101
135
  struct timeval *toptr = NULL;
102
- fd_set fds;
103
- FD_ZERO(&fds);
104
- FD_SET(fd, &fds);
105
136
 
106
- /* rb_thread_select modifies the passed timeval, so we pass a copy */
137
+ _fdset_t fds;
138
+ _fd_init(&fds);
139
+ _fd_set(fd, &fds);
140
+
141
+ /* rb_fd_select modifies the passed timeval, so we pass a copy */
107
142
  if (timeout != NULL) {
108
143
  memcpy(&to, timeout, sizeof(to));
109
144
  toptr = &to;
110
145
  }
111
146
 
112
- if (rb_thread_select(fd + 1, NULL, &fds, NULL, toptr) < 0) {
147
+ if (_thread_fd_select(fd + 1, NULL, &fds, NULL, toptr) < 0) {
113
148
  return -1;
114
149
  }
115
150
 
116
- if (FD_ISSET(fd, &fds) && isset) {
151
+ if (_fd_isset(fd, &fds) && isset) {
117
152
  *isset = 1;
118
153
  }
119
154
 
@@ -124,6 +159,9 @@ static VALUE connection_generic_connect(VALUE self, redisContext *c, VALUE arg_t
124
159
  redisParentContext *pc;
125
160
  struct timeval tv;
126
161
  struct timeval *timeout = NULL;
162
+ int writable = 0;
163
+ int optval = 0;
164
+ socklen_t optlen = sizeof(optval);
127
165
 
128
166
  Data_Get_Struct(self,redisParentContext,pc);
129
167
 
@@ -158,7 +196,6 @@ static VALUE connection_generic_connect(VALUE self, redisContext *c, VALUE arg_t
158
196
  }
159
197
 
160
198
  /* Wait for socket to become writable */
161
- int writable = 0;
162
199
  if (__wait_writable(c->fd, timeout, &writable) < 0) {
163
200
  goto sys_fail;
164
201
  }
@@ -169,8 +206,6 @@ static VALUE connection_generic_connect(VALUE self, redisContext *c, VALUE arg_t
169
206
  }
170
207
 
171
208
  /* Check for socket error */
172
- int optval = 0;
173
- socklen_t optlen = sizeof(optval);
174
209
  if (getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) {
175
210
  goto sys_fail;
176
211
  }
@@ -191,7 +226,6 @@ sys_fail:
191
226
  }
192
227
 
193
228
  static VALUE connection_connect(int argc, VALUE *argv, VALUE self) {
194
- redisParentContext *pc;
195
229
  redisContext *c;
196
230
  VALUE arg_host = Qnil;
197
231
  VALUE arg_port = Qnil;
@@ -213,13 +247,11 @@ static VALUE connection_connect(int argc, VALUE *argv, VALUE self) {
213
247
  rb_raise(rb_eArgError, "invalid number of arguments");
214
248
  }
215
249
 
216
- Data_Get_Struct(self,redisParentContext,pc);
217
250
  c = redisConnectNonBlock(StringValuePtr(arg_host), NUM2INT(arg_port));
218
251
  return connection_generic_connect(self,c,arg_timeout);
219
252
  }
220
253
 
221
254
  static VALUE connection_connect_unix(int argc, VALUE *argv, VALUE self) {
222
- redisParentContext *pc;
223
255
  redisContext *c;
224
256
  VALUE arg_path = Qnil;
225
257
  VALUE arg_timeout = Qnil;
@@ -239,7 +271,6 @@ static VALUE connection_connect_unix(int argc, VALUE *argv, VALUE self) {
239
271
  rb_raise(rb_eArgError, "invalid number of arguments");
240
272
  }
241
273
 
242
- Data_Get_Struct(self,redisParentContext,pc);
243
274
  c = redisConnectUnixNonBlock(StringValuePtr(arg_path));
244
275
  return connection_generic_connect(self,c,arg_timeout);
245
276
  }
@@ -265,7 +296,6 @@ static VALUE connection_disconnect(VALUE self) {
265
296
  static VALUE connection_write(VALUE self, VALUE command) {
266
297
  redisParentContext *pc;
267
298
  int argc;
268
- VALUE *args;
269
299
  char **argv = NULL;
270
300
  size_t *alen = NULL;
271
301
  int i;
@@ -280,15 +310,15 @@ static VALUE connection_write(VALUE self, VALUE command) {
280
310
  rb_raise(rb_eRuntimeError,"%s","not connected");
281
311
 
282
312
  argc = (int)RARRAY_LEN(command);
283
- args = RARRAY_PTR(command);
284
313
  argv = malloc(argc*sizeof(char*));
285
314
  alen = malloc(argc*sizeof(size_t));
286
315
  for (i = 0; i < argc; i++) {
287
316
  /* Replace arguments in the arguments array to prevent their string
288
317
  * equivalents to be garbage collected before this loop is done. */
289
- args[i] = rb_obj_as_string(args[i]);
290
- argv[i] = RSTRING_PTR(args[i]);
291
- alen[i] = RSTRING_LEN(args[i]);
318
+ VALUE entry = rb_obj_as_string(rb_ary_entry(command, i));
319
+ rb_ary_store(command, i, entry);
320
+ argv[i] = RSTRING_PTR(entry);
321
+ alen[i] = RSTRING_LEN(entry);
292
322
  }
293
323
  redisAppendCommandArgv(pc->context,argc,(const char**)argv,alen);
294
324
  free(argv);
@@ -459,6 +489,7 @@ static VALUE connection_fileno(VALUE self) {
459
489
  VALUE klass_connection;
460
490
  void InitConnection(VALUE mod) {
461
491
  klass_connection = rb_define_class_under(mod, "Connection", rb_cObject);
492
+ rb_global_variable(&klass_connection);
462
493
  rb_define_alloc_func(klass_connection, connection_parent_context_alloc);
463
494
  rb_define_method(klass_connection, "connect", connection_connect, -1);
464
495
  rb_define_method(klass_connection, "connect_unix", connection_connect_unix, -1);
@@ -2,16 +2,27 @@ require 'mkmf'
2
2
 
3
3
  RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
4
4
 
5
- hiredis_dir = File.expand_path(File.join(File.dirname(__FILE__), %w{.. .. vendor hiredis}))
5
+ hiredis_dir = File.join(File.dirname(__FILE__), %w{.. .. vendor hiredis})
6
6
  unless File.directory?(hiredis_dir)
7
7
  STDERR.puts "vendor/hiredis missing, please checkout its submodule..."
8
8
  exit 1
9
9
  end
10
10
 
11
+ RbConfig::CONFIG['configure_args'] =~ /with-make-prog\=(\w+)/
12
+ make_program = $1 || ENV['make']
13
+ unless make_program then
14
+ make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
15
+ end
16
+
11
17
  # Make sure hiredis is built...
12
- system("cd #{hiredis_dir} && make static")
18
+ Dir.chdir(hiredis_dir) do
19
+ success = system("#{make_program} static")
20
+ raise "Building hiredis failed" if !success
21
+ end
13
22
 
14
23
  # Statically link to hiredis (mkmf can't do this for us)
15
24
  $CFLAGS << " -I#{hiredis_dir}"
16
25
  $LDFLAGS << " #{hiredis_dir}/libhiredis.a"
26
+
27
+ have_func("rb_thread_fd_select")
17
28
  create_makefile('hiredis/ext/hiredis_ext')
@@ -8,6 +8,8 @@ VALUE mod_ext;
8
8
  void Init_hiredis_ext() {
9
9
  mod_hiredis = rb_define_module("Hiredis");
10
10
  mod_ext = rb_define_module_under(mod_hiredis,"Ext");
11
+ rb_global_variable(&mod_hiredis);
12
+ rb_global_variable(&mod_ext);
11
13
  InitReader(mod_ext);
12
14
  InitConnection(mod_ext);
13
15
  }
@@ -1,6 +1,13 @@
1
1
  #ifndef __HIREDIS_EXT_H
2
2
  #define __HIREDIS_EXT_H
3
3
 
4
+ /* Defined for Rubinius. This indicates a char* obtained
5
+ * through RSTRING_PTR is never modified in place. With this
6
+ * define Rubinius can disable the slow copy back mechanisms
7
+ * to make sure strings are updated at the Ruby side.
8
+ */
9
+ #define RSTRING_NOT_MODIFIED
10
+
4
11
  #include "hiredis.h"
5
12
  #include "ruby.h"
6
13
 
@@ -97,6 +97,7 @@ static VALUE reader_gets(VALUE klass) {
97
97
  VALUE klass_reader;
98
98
  void InitReader(VALUE mod) {
99
99
  klass_reader = rb_define_class_under(mod, "Reader", rb_cObject);
100
+ rb_global_variable(&klass_reader);
100
101
  rb_define_alloc_func(klass_reader, reader_allocate);
101
102
  rb_define_method(klass_reader, "feed", reader_feed, 1);
102
103
  rb_define_method(klass_reader, "gets", reader_gets, 0);
@@ -108,6 +109,7 @@ void InitReader(VALUE mod) {
108
109
  enc_klass = rb_const_get(rb_cObject, rb_intern("Encoding"));
109
110
  enc_default_external = rb_intern("default_external");
110
111
  str_force_encoding = rb_intern("force_encoding");
112
+ rb_global_variable(&enc_klass);
111
113
  } else {
112
114
  enc_default_external = 0;
113
115
  }
@@ -1,3 +1,3 @@
1
1
  module Hiredis
2
- VERSION = "0.4.5"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -15,8 +15,8 @@ CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
15
15
  OPTIMIZATION?=-O3
16
16
  WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings
17
17
  DEBUG?= -g -ggdb
18
- REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG)
19
- REAL_LDFLAGS=$(LDFLAGS)
18
+ REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH)
19
+ REAL_LDFLAGS=$(LDFLAGS) $(ARCH)
20
20
 
21
21
  DYLIBSUFFIX=so
22
22
  STLIBSUFFIX=a
@@ -372,6 +372,11 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
372
372
  __redisAsyncDisconnect(ac);
373
373
  return;
374
374
  }
375
+
376
+ /* If monitor mode, repush callback */
377
+ if(c->flags & REDIS_MONITORING) {
378
+ __redisPushCallback(&ac->replies,&cb);
379
+ }
375
380
 
376
381
  /* When the connection is not being disconnected, simply stop
377
382
  * trying to get replies and wait for the next loop tick. */
@@ -381,22 +386,31 @@ void redisProcessCallbacks(redisAsyncContext *ac) {
381
386
  /* Even if the context is subscribed, pending regular callbacks will
382
387
  * get a reply before pub/sub messages arrive. */
383
388
  if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) {
384
- /* A spontaneous reply in a not-subscribed context can only be the
385
- * error reply that is sent when a new connection exceeds the
386
- * maximum number of allowed connections on the server side. This
387
- * is seen as an error instead of a regular reply because the
388
- * server closes the connection after sending it. To prevent the
389
- * error from being overwritten by an EOF error the connection is
390
- * closed here. See issue #43. */
391
- if ( !(c->flags & REDIS_SUBSCRIBED) && ((redisReply*)reply)->type == REDIS_REPLY_ERROR ) {
389
+ /*
390
+ * A spontaneous reply in a not-subscribed context can be the error
391
+ * reply that is sent when a new connection exceeds the maximum
392
+ * number of allowed connections on the server side.
393
+ *
394
+ * This is seen as an error instead of a regular reply because the
395
+ * server closes the connection after sending it.
396
+ *
397
+ * To prevent the error from being overwritten by an EOF error the
398
+ * connection is closed here. See issue #43.
399
+ *
400
+ * Another possibility is that the server is loading its dataset.
401
+ * In this case we also want to close the connection, and have the
402
+ * user wait until the server is ready to take our request.
403
+ */
404
+ if (((redisReply*)reply)->type == REDIS_REPLY_ERROR) {
392
405
  c->err = REDIS_ERR_OTHER;
393
406
  snprintf(c->errstr,sizeof(c->errstr),"%s",((redisReply*)reply)->str);
394
407
  __redisAsyncDisconnect(ac);
395
408
  return;
396
409
  }
397
- /* No more regular callbacks and no errors, the context *must* be subscribed. */
398
- assert(c->flags & REDIS_SUBSCRIBED);
399
- __redisGetSubscribeCallback(ac,reply,&cb);
410
+ /* No more regular callbacks and no errors, the context *must* be subscribed or monitoring. */
411
+ assert((c->flags & REDIS_SUBSCRIBED || c->flags & REDIS_MONITORING));
412
+ if(c->flags & REDIS_SUBSCRIBED)
413
+ __redisGetSubscribeCallback(ac,reply,&cb);
400
414
  }
401
415
 
402
416
  if (cb.fn != NULL) {
@@ -557,6 +571,10 @@ static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void
557
571
  /* (P)UNSUBSCRIBE does not have its own response: every channel or
558
572
  * pattern that is unsubscribed will receive a message. This means we
559
573
  * should not append a callback function for this command. */
574
+ } else if(strncasecmp(cstr,"monitor\r\n",9) == 0) {
575
+ /* Set monitor flag and push callback */
576
+ c->flags |= REDIS_MONITORING;
577
+ __redisPushCallback(&ac->replies,&cb);
560
578
  } else {
561
579
  if (c->flags & REDIS_SUBSCRIBED)
562
580
  /* This will likely result in an error reply, but it needs to be
@@ -446,10 +446,10 @@ static int processMultiBulkItem(redisReader *r) {
446
446
  long elements;
447
447
  int root = 0;
448
448
 
449
- /* Set error for nested multi bulks with depth > 2 */
450
- if (r->ridx == 3) {
449
+ /* Set error for nested multi bulks with depth > 7 */
450
+ if (r->ridx == 8) {
451
451
  __redisReaderSetError(r,REDIS_ERR_PROTOCOL,
452
- "No support for nested multi bulk replies with depth > 2");
452
+ "No support for nested multi bulk replies with depth > 7");
453
453
  return REDIS_ERR;
454
454
  }
455
455
 
@@ -564,6 +564,7 @@ redisReader *redisReaderCreate(void) {
564
564
  r->errstr[0] = '\0';
565
565
  r->fn = &defaultFunctions;
566
566
  r->buf = sdsempty();
567
+ r->maxbuf = REDIS_READER_MAX_BUF;
567
568
  if (r->buf == NULL) {
568
569
  free(r);
569
570
  return NULL;
@@ -591,7 +592,7 @@ int redisReaderFeed(redisReader *r, const char *buf, size_t len) {
591
592
  /* Copy the provided buffer. */
592
593
  if (buf != NULL && len >= 1) {
593
594
  /* Destroy internal buffer when it is empty and is quite large. */
594
- if (r->len == 0 && sdsavail(r->buf) > 16*1024) {
595
+ if (r->len == 0 && r->maxbuf != 0 && sdsavail(r->buf) > r->maxbuf) {
595
596
  sdsfree(r->buf);
596
597
  r->buf = sdsempty();
597
598
  r->pos = 0;
@@ -749,6 +750,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
749
750
  default:
750
751
  /* Try to detect printf format */
751
752
  {
753
+ static const char intfmts[] = "diouxX";
752
754
  char _format[16];
753
755
  const char *_p = c+1;
754
756
  size_t _l = 0;
@@ -774,7 +776,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
774
776
  va_copy(_cpy,ap);
775
777
 
776
778
  /* Integer conversion (without modifiers) */
777
- if (strchr("diouxX",*_p) != NULL) {
779
+ if (strchr(intfmts,*_p) != NULL) {
778
780
  va_arg(ap,int);
779
781
  goto fmt_valid;
780
782
  }
@@ -788,7 +790,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
788
790
  /* Size: char */
789
791
  if (_p[0] == 'h' && _p[1] == 'h') {
790
792
  _p += 2;
791
- if (*_p != '\0' && strchr("diouxX",*_p) != NULL) {
793
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
792
794
  va_arg(ap,int); /* char gets promoted to int */
793
795
  goto fmt_valid;
794
796
  }
@@ -798,7 +800,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
798
800
  /* Size: short */
799
801
  if (_p[0] == 'h') {
800
802
  _p += 1;
801
- if (*_p != '\0' && strchr("diouxX",*_p) != NULL) {
803
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
802
804
  va_arg(ap,int); /* short gets promoted to int */
803
805
  goto fmt_valid;
804
806
  }
@@ -808,7 +810,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
808
810
  /* Size: long long */
809
811
  if (_p[0] == 'l' && _p[1] == 'l') {
810
812
  _p += 2;
811
- if (*_p != '\0' && strchr("diouxX",*_p) != NULL) {
813
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
812
814
  va_arg(ap,long long);
813
815
  goto fmt_valid;
814
816
  }
@@ -818,7 +820,7 @@ int redisvFormatCommand(char **target, const char *format, va_list ap) {
818
820
  /* Size: long */
819
821
  if (_p[0] == 'l') {
820
822
  _p += 1;
821
- if (*_p != '\0' && strchr("diouxX",*_p) != NULL) {
823
+ if (*_p != '\0' && strchr(intfmts,*_p) != NULL) {
822
824
  va_arg(ap,long);
823
825
  goto fmt_valid;
824
826
  }
@@ -1066,7 +1068,7 @@ int redisSetTimeout(redisContext *c, struct timeval tv) {
1066
1068
  * After this function is called, you may use redisContextReadReply to
1067
1069
  * see if there is a reply available. */
1068
1070
  int redisBufferRead(redisContext *c) {
1069
- char buf[2048];
1071
+ char buf[1024*16];
1070
1072
  int nread;
1071
1073
 
1072
1074
  /* Return early when the context has seen an error. */
@@ -36,8 +36,8 @@
36
36
  #include <sys/time.h> /* for struct timeval */
37
37
 
38
38
  #define HIREDIS_MAJOR 0
39
- #define HIREDIS_MINOR 10
40
- #define HIREDIS_PATCH 1
39
+ #define HIREDIS_MINOR 11
40
+ #define HIREDIS_PATCH 0
41
41
 
42
42
  #define REDIS_ERR -1
43
43
  #define REDIS_OK 0
@@ -76,6 +76,9 @@
76
76
  /* Flag that is set when the async context has one or more subscriptions. */
77
77
  #define REDIS_SUBSCRIBED 0x20
78
78
 
79
+ /* Flag that is set when monitor mode is active */
80
+ #define REDIS_MONITORING 0x40
81
+
79
82
  #define REDIS_REPLY_STRING 1
80
83
  #define REDIS_REPLY_ARRAY 2
81
84
  #define REDIS_REPLY_INTEGER 3
@@ -83,6 +86,8 @@
83
86
  #define REDIS_REPLY_STATUS 5
84
87
  #define REDIS_REPLY_ERROR 6
85
88
 
89
+ #define REDIS_READER_MAX_BUF (1024*16) /* Default max unused reader buffer. */
90
+
86
91
  #ifdef __cplusplus
87
92
  extern "C" {
88
93
  #endif
@@ -122,8 +127,9 @@ typedef struct redisReader {
122
127
  char *buf; /* Read buffer */
123
128
  size_t pos; /* Buffer cursor */
124
129
  size_t len; /* Buffer length */
130
+ size_t maxbuf; /* Max length of unused buffer */
125
131
 
126
- redisReadTask rstack[4];
132
+ redisReadTask rstack[9];
127
133
  int ridx; /* Index of current read task */
128
134
  void *reply; /* Temporary reply pointer */
129
135
 
@@ -45,6 +45,8 @@
45
45
  #include <errno.h>
46
46
  #include <stdarg.h>
47
47
  #include <stdio.h>
48
+ #include <poll.h>
49
+ #include <limits.h>
48
50
 
49
51
  #include "net.h"
50
52
  #include "sds.h"
@@ -121,28 +123,38 @@ static int redisSetTcpNoDelay(redisContext *c, int fd) {
121
123
  return REDIS_OK;
122
124
  }
123
125
 
126
+ #define __MAX_MSEC (((LONG_MAX) - 999) / 1000)
127
+
124
128
  static int redisContextWaitReady(redisContext *c, int fd, const struct timeval *timeout) {
125
- struct timeval to;
126
- struct timeval *toptr = NULL;
127
- fd_set wfd;
129
+ struct pollfd wfd[1];
130
+ long msec;
131
+
132
+ msec = -1;
133
+ wfd[0].fd = fd;
134
+ wfd[0].events = POLLOUT;
128
135
 
129
136
  /* Only use timeout when not NULL. */
130
137
  if (timeout != NULL) {
131
- to = *timeout;
132
- toptr = &to;
138
+ if (timeout->tv_usec > 1000000 || timeout->tv_sec > __MAX_MSEC) {
139
+ close(fd);
140
+ return REDIS_ERR;
141
+ }
142
+
143
+ msec = (timeout->tv_sec * 1000) + ((timeout->tv_usec + 999) / 1000);
144
+
145
+ if (msec < 0 || msec > INT_MAX) {
146
+ msec = INT_MAX;
147
+ }
133
148
  }
134
149
 
135
150
  if (errno == EINPROGRESS) {
136
- FD_ZERO(&wfd);
137
- FD_SET(fd, &wfd);
151
+ int res;
138
152
 
139
- if (select(FD_SETSIZE, NULL, &wfd, NULL, toptr) == -1) {
140
- __redisSetErrorFromErrno(c,REDIS_ERR_IO,"select(2)");
153
+ if ((res = poll(wfd, 1, msec)) == -1) {
154
+ __redisSetErrorFromErrno(c, REDIS_ERR_IO, "poll(2)");
141
155
  close(fd);
142
156
  return REDIS_ERR;
143
- }
144
-
145
- if (!FD_ISSET(fd, &wfd)) {
157
+ } else if (res == 0) {
146
158
  errno = ETIMEDOUT;
147
159
  __redisSetErrorFromErrno(c,REDIS_ERR_IO,NULL);
148
160
  close(fd);
@@ -177,7 +177,7 @@ static void test_format_commands(void) {
177
177
  FLOAT_WIDTH_TEST(double);
178
178
 
179
179
  test("Format command with invalid printf format: ");
180
- len = redisFormatCommand(&cmd,"key:%08p %b",1234,"foo",3);
180
+ len = redisFormatCommand(&cmd,"key:%08p %b",(void*)1234,"foo",3);
181
181
  test_cond(len == -1);
182
182
 
183
183
  const char *argv[3];
@@ -204,6 +204,7 @@ static void test_reply_reader(void) {
204
204
  redisReader *reader;
205
205
  void *reply;
206
206
  int ret;
207
+ int i;
207
208
 
208
209
  test("Error handling in reply parser: ");
209
210
  reader = redisReaderCreate();
@@ -225,12 +226,13 @@ static void test_reply_reader(void) {
225
226
  strcasecmp(reader->errstr,"Protocol error, got \"@\" as reply type byte") == 0);
226
227
  redisReaderFree(reader);
227
228
 
228
- test("Set error on nested multi bulks with depth > 2: ");
229
+ test("Set error on nested multi bulks with depth > 7: ");
229
230
  reader = redisReaderCreate();
230
- redisReaderFeed(reader,(char*)"*1\r\n",4);
231
- redisReaderFeed(reader,(char*)"*1\r\n",4);
232
- redisReaderFeed(reader,(char*)"*1\r\n",4);
233
- redisReaderFeed(reader,(char*)"*1\r\n",4);
231
+
232
+ for (i = 0; i < 9; i++) {
233
+ redisReaderFeed(reader,(char*)"*1\r\n",4);
234
+ }
235
+
234
236
  ret = redisReaderGetReply(reader,NULL);
235
237
  test_cond(ret == REDIS_ERR &&
236
238
  strncasecmp(reader->errstr,"No support for",14) == 0);
@@ -283,7 +285,8 @@ static void test_blocking_connection_errors(void) {
283
285
  test("Returns error when host cannot be resolved: ");
284
286
  c = redisConnect((char*)"idontexist.local", 6379);
285
287
  test_cond(c->err == REDIS_ERR_OTHER &&
286
- strcmp(c->errstr,"Can't resolve: idontexist.local") == 0);
288
+ (strcmp(c->errstr,"Name or service not known") == 0 ||
289
+ strcmp(c->errstr,"Can't resolve: idontexist.local") == 0));
287
290
  redisFree(c);
288
291
 
289
292
  test("Returns error when the port is not open: ");
metadata CHANGED
@@ -1,28 +1,45 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiredis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.5
5
- prerelease:
4
+ version: 0.5.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Pieter Noordhuis
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-03-19 00:00:00.000000000 Z
11
+ date: 2014-03-27 00:00:00.000000000 Z
13
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: '10.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: '10.0'
14
27
  - !ruby/object:Gem::Dependency
15
28
  name: rake-compiler
16
- requirement: &70232656303880 !ruby/object:Gem::Requirement
17
- none: false
29
+ requirement: !ruby/object:Gem::Requirement
18
30
  requirements:
19
31
  - - ~>
20
32
  - !ruby/object:Gem::Version
21
33
  version: 0.7.1
22
34
  type: :development
23
35
  prerelease: false
24
- version_requirements: *70232656303880
25
- description: Ruby extension that wraps Hiredis (blocking connection and reply parsing)
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 0.7.1
41
+ description: Ruby wrapper for hiredis (protocol serialization/deserialization and
42
+ blocking I/O)
26
43
  email:
27
44
  - pcnoordhuis@gmail.com
28
45
  executables: []
@@ -31,57 +48,56 @@ extensions:
31
48
  extra_rdoc_files: []
32
49
  files:
33
50
  - ext/hiredis_ext/extconf.rb
34
- - ext/hiredis_ext/connection.c
35
51
  - ext/hiredis_ext/hiredis_ext.c
36
52
  - ext/hiredis_ext/reader.c
53
+ - ext/hiredis_ext/connection.c
37
54
  - ext/hiredis_ext/hiredis_ext.h
38
55
  - vendor/hiredis/async.c
39
- - vendor/hiredis/dict.c
40
56
  - vendor/hiredis/hiredis.c
57
+ - vendor/hiredis/test.c
58
+ - vendor/hiredis/dict.c
41
59
  - vendor/hiredis/net.c
42
60
  - vendor/hiredis/sds.c
43
- - vendor/hiredis/test.c
44
- - vendor/hiredis/async.h
45
- - vendor/hiredis/dict.h
46
61
  - vendor/hiredis/fmacros.h
47
- - vendor/hiredis/hiredis.h
48
- - vendor/hiredis/net.h
49
62
  - vendor/hiredis/sds.h
63
+ - vendor/hiredis/dict.h
64
+ - vendor/hiredis/async.h
65
+ - vendor/hiredis/net.h
66
+ - vendor/hiredis/hiredis.h
50
67
  - vendor/hiredis/COPYING
51
68
  - vendor/hiredis/Makefile
52
- - lib/hiredis/connection.rb
53
- - lib/hiredis/errors.rb
54
- - lib/hiredis/ext/connection.rb
55
- - lib/hiredis/ext/reader.rb
56
69
  - lib/hiredis/reader.rb
57
- - lib/hiredis/ruby/connection.rb
58
- - lib/hiredis/ruby/reader.rb
59
70
  - lib/hiredis/version.rb
71
+ - lib/hiredis/ruby/reader.rb
72
+ - lib/hiredis/ruby/connection.rb
73
+ - lib/hiredis/ext/reader.rb
74
+ - lib/hiredis/ext/connection.rb
75
+ - lib/hiredis/connection.rb
60
76
  - lib/hiredis.rb
61
77
  - COPYING
62
78
  - Rakefile
63
- homepage: http://github.com/pietern/hiredis-rb
79
+ homepage: http://github.com/redis/hiredis-rb
64
80
  licenses: []
81
+ metadata: {}
65
82
  post_install_message:
66
83
  rdoc_options: []
67
84
  require_paths:
68
85
  - lib
69
86
  required_ruby_version: !ruby/object:Gem::Requirement
70
- none: false
71
87
  requirements:
72
- - - ! '>='
88
+ - - '>='
73
89
  - !ruby/object:Gem::Version
74
90
  version: '0'
75
91
  required_rubygems_version: !ruby/object:Gem::Requirement
76
- none: false
77
92
  requirements:
78
- - - ! '>='
93
+ - - '>='
79
94
  - !ruby/object:Gem::Version
80
95
  version: '0'
81
96
  requirements: []
82
97
  rubyforge_project:
83
- rubygems_version: 1.8.11
98
+ rubygems_version: 2.0.14
84
99
  signing_key:
85
- specification_version: 3
86
- summary: Ruby extension that wraps Hiredis (blocking connection and reply parsing)
100
+ specification_version: 4
101
+ summary: Ruby wrapper for hiredis (protocol serialization/deserialization and blocking
102
+ I/O)
87
103
  test_files: []
@@ -1,5 +0,0 @@
1
- module Hiredis
2
- class Error < StandardError; end
3
- class ProtocolError < Error; end
4
- class ReplyError < Error; end
5
- end