hiredis-client 0.5.1 → 0.6.2

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
2
  SHA256:
3
- metadata.gz: ba2a16ce75c627a3bdf88b08b484718e32d352c03a21c5d3d7c96201453952b8
4
- data.tar.gz: 4d75701dadbf783d8426bd0225e35e3388845c4303a61e1b28122aac664c4f47
3
+ metadata.gz: 4a1e6c581e8cdaf2e39e684939f9747503d80f2573065d18a43b9002a83005f3
4
+ data.tar.gz: d3a82df8aa27552818f25757fadc2e9789cecd2e149051a05379f6361f618bab
5
5
  SHA512:
6
- metadata.gz: 92aa71bb1f4b460b06278fb026b0b12edfbc8bb8f2edb4a8a7e006d1afdfbd9f34e665c8592b0245b2355742b4922c37ea42412adbf0ee36b188c0a7817f07f4
7
- data.tar.gz: f8af4f856b5e48bc75ef12520a62c0010e02976ea6961cdb9d50087cdf7b654f8b7c58b267aef4d1fa3535c0449c08f17fcf163c6abcdfdf8fad9f81086d8092
6
+ metadata.gz: b06e2e1ace5bac902ce44d25e1739f4597ef2b22604c34ba769b79c261fb0e72f31b6e94fe7c7dbd7d950f3bed692bac113cf60bdb7fc11f21c8ac28ae2a8a0f
7
+ data.tar.gz: 714b5eb43dfd5236ace702d9ed47301720c422db22ee501678e30ad143d1d1a9d187d66d2e555b31442bb4e3dbbdc4dbae03faca6a6277e9e84315e6869b9a3c
@@ -31,6 +31,7 @@
31
31
  // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
32
 
33
33
  #include "ruby.h"
34
+ #include "ruby/thread.h"
34
35
  #include "ruby/encoding.h"
35
36
  #include <errno.h>
36
37
  #include <sys/socket.h>
@@ -45,15 +46,15 @@ static inline VALUE rb_hash_new_capa(long capa)
45
46
  }
46
47
  #endif
47
48
 
48
- static VALUE rb_cSet, rb_eRedisClientCommandError, rb_eRedisClientConnectionError;
49
- static VALUE rb_eRedisClientConnectTimeoutError, rb_eRedisClientReadTimeoutError, rb_eRedisClientWriteTimeoutError;
50
- static ID id_parse, id_add, id_new;
49
+ static VALUE rb_eRedisClientCommandError, rb_eRedisClientConnectionError, rb_eRedisClientCannotConnectError, rb_eRedisClientProtocolError;
50
+ static VALUE rb_eRedisClientReadTimeoutError, rb_eRedisClientWriteTimeoutError;
51
+ static ID id_parse;
51
52
 
52
53
  typedef struct {
53
54
  redisSSLContext *context;
54
55
  } hiredis_ssl_context_t;
55
56
 
56
- #define ENSURE_CONNECTED(connection) if (!connection->context) rb_raise(rb_eRuntimeError, "[BUG] not connected");
57
+ #define ENSURE_CONNECTED(connection) if (!connection->context) rb_raise(rb_eRedisClientConnectionError, "Not connected");
57
58
 
58
59
  #define SSL_CONTEXT(from, name) \
59
60
  hiredis_ssl_context_t *name = NULL; \
@@ -126,6 +127,7 @@ static void *reply_append(const redisReadTask *task, VALUE value) {
126
127
 
127
128
  switch (task->parent->type) {
128
129
  case REDIS_REPLY_ARRAY:
130
+ case REDIS_REPLY_SET:
129
131
  case REDIS_REPLY_PUSH:
130
132
  rb_ary_store(parent, task->idx, value);
131
133
  break;
@@ -138,9 +140,6 @@ static void *reply_append(const redisReadTask *task, VALUE value) {
138
140
  task->parent->privdata = (void*)value;
139
141
  }
140
142
  break;
141
- case REDIS_REPLY_SET:
142
- rb_funcall(parent, id_add, 1, value);
143
- break;
144
143
  default:
145
144
  rb_bug("[hiredis] Unexpected task parent type %d", task->parent->type);
146
145
  break;
@@ -150,6 +149,12 @@ static void *reply_append(const redisReadTask *task, VALUE value) {
150
149
  }
151
150
 
152
151
  static void *reply_create_string(const redisReadTask *task, char *cstr, size_t len) {
152
+ if (len >= 4 && task->type == REDIS_REPLY_VERB) {
153
+ // Skip 4 bytes of verbatim type header.
154
+ cstr += 4;
155
+ len -= 4;
156
+ }
157
+
153
158
  VALUE string = rb_external_str_new(cstr, len);
154
159
  if (rb_enc_str_coderange(string) == ENC_CODERANGE_BROKEN) {
155
160
  rb_enc_associate(string, rb_ascii8bit_encoding());
@@ -170,14 +175,12 @@ static void *reply_create_array(const redisReadTask *task, size_t elements) {
170
175
  switch (task->type) {
171
176
  case REDIS_REPLY_PUSH:
172
177
  case REDIS_REPLY_ARRAY:
178
+ case REDIS_REPLY_SET:
173
179
  value = rb_ary_new_capa(elements);
174
180
  break;
175
181
  case REDIS_REPLY_MAP:
176
182
  value = rb_hash_new_capa(elements / 2);
177
183
  break;
178
- case REDIS_REPLY_SET:
179
- value = rb_funcallv(rb_cSet, id_new, 0, NULL);
180
- break;
181
184
  default:
182
185
  rb_bug("[hiredis] Unexpected create array type %d", task->parent->type);
183
186
  break;
@@ -325,6 +328,8 @@ static inline void redis_raise_error_and_disconnect(redisContext *context, VALUE
325
328
  case REDIS_ERR_IO:
326
329
  rb_sys_fail(0);
327
330
  break;
331
+ case REDIS_ERR_PROTOCOL:
332
+ rb_raise(rb_eRedisClientProtocolError, "%s", errstr);
328
333
  default:
329
334
  /* Raise something else */
330
335
  rb_raise(rb_eRedisClientConnectionError, "%s", errstr);
@@ -420,7 +425,7 @@ static int hiredis_wait_writable(int fd, const struct timeval *timeout, int *iss
420
425
 
421
426
  static VALUE hiredis_connect_finish(hiredis_connection_t *connection, redisContext *context) {
422
427
  if (context->err) {
423
- redis_raise_error_and_disconnect(context, rb_eRedisClientConnectTimeoutError);
428
+ redis_raise_error_and_disconnect(context, rb_eRedisClientCannotConnectError);
424
429
  }
425
430
 
426
431
  int writable = 0;
@@ -429,23 +434,23 @@ static VALUE hiredis_connect_finish(hiredis_connection_t *connection, redisConte
429
434
 
430
435
  /* Wait for socket to become writable */
431
436
  if (hiredis_wait_writable(context->fd, &connection->connect_timeout, &writable) < 0) {
432
- redis_raise_error_and_disconnect(context, rb_eRedisClientConnectTimeoutError);
437
+ redis_raise_error_and_disconnect(context, rb_eRedisClientCannotConnectError);
433
438
  }
434
439
 
435
440
  if (!writable) {
436
441
  errno = ETIMEDOUT;
437
- redis_raise_error_and_disconnect(context, rb_eRedisClientConnectTimeoutError);
442
+ redis_raise_error_and_disconnect(context, rb_eRedisClientCannotConnectError);
438
443
  }
439
444
 
440
445
  /* Check for socket error */
441
446
  if (getsockopt(context->fd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) {
442
447
  context->err = REDIS_ERR_IO;
443
- redis_raise_error_and_disconnect(context, rb_eRedisClientConnectTimeoutError);
448
+ redis_raise_error_and_disconnect(context, rb_eRedisClientCannotConnectError);
444
449
  }
445
450
 
446
451
  if (optval) {
447
452
  errno = optval;
448
- redis_raise_error_and_disconnect(context, rb_eRedisClientConnectTimeoutError);
453
+ redis_raise_error_and_disconnect(context, rb_eRedisClientCannotConnectError);
449
454
  }
450
455
 
451
456
  context->reader->fn = &reply_functions;
@@ -477,7 +482,7 @@ static VALUE hiredis_init_ssl(VALUE self, VALUE ssl_param) {
477
482
  SSL_CONTEXT(ssl_param, ssl_context)
478
483
 
479
484
  if (redisInitiateSSLWithContext(connection->context, ssl_context->context) != REDIS_OK) {
480
- hiredis_raise_error_and_disconnect(connection, rb_eRedisClientConnectTimeoutError);
485
+ hiredis_raise_error_and_disconnect(connection, rb_eRedisClientCannotConnectError);
481
486
  }
482
487
 
483
488
  redisSSL *redis_ssl = redisGetSSLSocket(connection->context);
@@ -485,15 +490,15 @@ static VALUE hiredis_init_ssl(VALUE self, VALUE ssl_param) {
485
490
  if (redis_ssl->wantRead) {
486
491
  int readable = 0;
487
492
  if (hiredis_wait_readable(connection->context->fd, &connection->connect_timeout, &readable) < 0) {
488
- hiredis_raise_error_and_disconnect(connection, rb_eRedisClientConnectTimeoutError);
493
+ hiredis_raise_error_and_disconnect(connection, rb_eRedisClientCannotConnectError);
489
494
  }
490
495
  if (!readable) {
491
496
  errno = EAGAIN;
492
- hiredis_raise_error_and_disconnect(connection, rb_eRedisClientConnectTimeoutError);
497
+ hiredis_raise_error_and_disconnect(connection, rb_eRedisClientCannotConnectError);
493
498
  }
494
499
 
495
500
  if (redisInitiateSSLContinue(connection->context) != REDIS_OK) {
496
- hiredis_raise_error_and_disconnect(connection, rb_eRedisClientConnectTimeoutError);
501
+ hiredis_raise_error_and_disconnect(connection, rb_eRedisClientCannotConnectError);
497
502
  };
498
503
  }
499
504
 
@@ -530,6 +535,44 @@ static VALUE hiredis_write(VALUE self, VALUE command) {
530
535
  return Qnil;
531
536
  }
532
537
 
538
+ typedef struct {
539
+ redisContext *context;
540
+ int return_value;
541
+ } hiredis_buffer_read_args_t;
542
+
543
+ void *hiredis_buffer_read_safe(void *_args) {
544
+ hiredis_buffer_read_args_t *args = _args;
545
+ args->return_value = redisBufferRead(args->context);
546
+ return NULL;
547
+ }
548
+ int hiredis_buffer_read_nogvl(redisContext *context) {
549
+ hiredis_buffer_read_args_t args = {
550
+ .context = context,
551
+ };
552
+ rb_thread_call_without_gvl(hiredis_buffer_read_safe, &args, RUBY_UBF_IO, 0);
553
+ return args.return_value;
554
+ }
555
+
556
+ typedef struct {
557
+ redisContext *context;
558
+ int *done;
559
+ int return_value;
560
+ } hiredis_buffer_write_args_t;
561
+
562
+ void *hiredis_buffer_write_safe(void *_args) {
563
+ hiredis_buffer_write_args_t *args = _args;
564
+ args->return_value = redisBufferWrite(args->context, args->done);
565
+ return NULL;
566
+ }
567
+ int hiredis_buffer_write_nogvl(redisContext *context, int *done) {
568
+ hiredis_buffer_write_args_t args = {
569
+ .context = context,
570
+ .done = done,
571
+ };
572
+ rb_thread_call_without_gvl(hiredis_buffer_write_safe, &args, RUBY_UBF_IO, 0);
573
+ return args.return_value;
574
+ }
575
+
533
576
  static VALUE hiredis_flush(VALUE self) {
534
577
  CONNECTION(self, connection);
535
578
  ENSURE_CONNECTED(connection);
@@ -537,7 +580,7 @@ static VALUE hiredis_flush(VALUE self) {
537
580
  int wdone = 0;
538
581
  while (!wdone) {
539
582
  errno = 0;
540
- if (redisBufferWrite(connection->context, &wdone) == REDIS_ERR) {
583
+ if (hiredis_buffer_write_nogvl(connection->context, &wdone) == REDIS_ERR) {
541
584
  if (errno == EAGAIN) {
542
585
  int writable = 0;
543
586
 
@@ -573,7 +616,7 @@ static int hiredis_read_internal(hiredis_connection_t *connection, VALUE *reply)
573
616
  while (!wdone) {
574
617
  errno = 0;
575
618
 
576
- if (redisBufferWrite(connection->context, &wdone) == REDIS_ERR) {
619
+ if (hiredis_buffer_write_nogvl(connection->context, &wdone) == REDIS_ERR) {
577
620
  /* Socket error */
578
621
  return -1;
579
622
  }
@@ -596,7 +639,7 @@ static int hiredis_read_internal(hiredis_connection_t *connection, VALUE *reply)
596
639
  while (redis_reply == NULL) {
597
640
  errno = 0;
598
641
 
599
- if (redisBufferRead(connection->context) == REDIS_ERR) {
642
+ if (hiredis_buffer_read_nogvl(connection->context) == REDIS_ERR) {
600
643
  /* Socket error */
601
644
  return -1;
602
645
  }
@@ -662,11 +705,6 @@ void Init_hiredis_connection(void) {
662
705
  redisInitOpenSSL();
663
706
 
664
707
  id_parse = rb_intern("parse");
665
- id_add = rb_intern("add");
666
- id_new = rb_intern("new");
667
-
668
- rb_cSet = rb_const_get(rb_cObject, rb_intern("Set"));
669
- rb_global_variable(&rb_cSet);
670
708
 
671
709
  VALUE rb_cRedisClient = rb_const_get(rb_cObject, rb_intern("RedisClient"));
672
710
 
@@ -676,8 +714,11 @@ void Init_hiredis_connection(void) {
676
714
  rb_eRedisClientConnectionError = rb_const_get(rb_cRedisClient, rb_intern("ConnectionError"));
677
715
  rb_global_variable(&rb_eRedisClientConnectionError);
678
716
 
679
- rb_eRedisClientConnectTimeoutError = rb_const_get(rb_cRedisClient, rb_intern("ConnectTimeoutError"));
680
- rb_global_variable(&rb_eRedisClientConnectTimeoutError);
717
+ rb_eRedisClientCannotConnectError = rb_const_get(rb_cRedisClient, rb_intern("CannotConnectError"));
718
+ rb_global_variable(&rb_eRedisClientCannotConnectError);
719
+
720
+ rb_eRedisClientProtocolError = rb_const_get(rb_cRedisClient, rb_intern("ProtocolError"));
721
+ rb_global_variable(&rb_eRedisClientProtocolError);
681
722
 
682
723
  rb_eRedisClientReadTimeoutError = rb_const_get(rb_cRedisClient, rb_intern("ReadTimeoutError"));
683
724
  rb_global_variable(&rb_eRedisClientReadTimeoutError);
@@ -34,7 +34,11 @@ class RedisClient
34
34
  self.write_timeout = write_timeout
35
35
 
36
36
  if config.path
37
- connect_unix(config.path)
37
+ begin
38
+ connect_unix(config.path)
39
+ rescue SystemCallError => error
40
+ raise CannotConnectError, error.message, error.backtrace
41
+ end
38
42
  else
39
43
  connect_tcp(config.host, config.port)
40
44
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hiredis-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean Boussier
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-02 00:00:00.000000000 Z
11
+ date: 2022-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis-client
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.5.1
19
+ version: 0.6.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.5.1
26
+ version: 0.6.2
27
27
  description:
28
28
  email:
29
29
  - jean.boussier@gmail.com