hiredis 0.4.5 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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