slyphon-zookeeper 0.1.7-java → 0.2.0-java

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  Makefile
7
7
  pkg
8
8
  zookeeper.gemspec
9
+ Gemfile.lock
@@ -16,7 +16,8 @@ class ZookeeperBase < CZookeeper
16
16
  ZOO_LOG_LEVEL_WARN = 2
17
17
  ZOO_LOG_LEVEL_INFO = 3
18
18
  ZOO_LOG_LEVEL_DEBUG = 4
19
-
19
+
20
+
20
21
  def reopen(timeout = 10, watcher=nil)
21
22
  watcher ||= @default_watcher
22
23
 
@@ -26,13 +27,15 @@ class ZookeeperBase < CZookeeper
26
27
  set_default_global_watcher(&watcher)
27
28
  end
28
29
 
29
- init(@host)
30
+ @start_stop_mutex.synchronize do
31
+ init(@host)
30
32
 
31
- if timeout > 0
32
- time_to_stop = Time.now + timeout
33
- until state == Zookeeper::ZOO_CONNECTED_STATE
34
- break if Time.now > time_to_stop
35
- sleep 0.1
33
+ if timeout > 0
34
+ time_to_stop = Time.now + timeout
35
+ until state == Zookeeper::ZOO_CONNECTED_STATE
36
+ break if Time.now > time_to_stop
37
+ sleep 0.1
38
+ end
36
39
  end
37
40
  end
38
41
 
@@ -46,9 +49,12 @@ class ZookeeperBase < CZookeeper
46
49
  @current_req_id = 1
47
50
  @host = host
48
51
 
52
+ @start_stop_mutex = Mutex.new
53
+
49
54
  watcher ||= get_default_global_watcher
50
55
 
51
- @_running = nil # used by the C layer
56
+ @_running = nil # used by the C layer
57
+ @_closed = false # also used by the C layer
52
58
 
53
59
  yield self if block_given?
54
60
 
@@ -76,12 +82,32 @@ class ZookeeperBase < CZookeeper
76
82
  end
77
83
 
78
84
  def close
79
- @_running = false
80
- wake_event_loop!
81
-
82
- @dispatcher.join
85
+ @start_stop_mutex.synchronize do
86
+ @_running = false if @_running
87
+ end
88
+
89
+ if @dispatcher
90
+ wake_event_loop! unless @_closed
91
+ @dispatcher.join
92
+ end
93
+
94
+ @start_stop_mutex.synchronize do
95
+ unless @_closed
96
+ close_handle
97
+
98
+ # this is set up in the C init method, but it's easier to
99
+ # do the teardown here
100
+ begin
101
+ @selectable_io.close if @selectable_io
102
+ rescue IOError
103
+ end
104
+ end
105
+ end
106
+ end
83
107
 
84
- super
108
+ def set_debug_level(int)
109
+ warn "DEPRECATION WARNING: #{self.class.name}#set_debug_level, it has moved to the class level and will be removed in a future release"
110
+ self.class.set_debug_level(int)
85
111
  end
86
112
 
87
113
  # set the watcher object/proc that will receive all global events (such as session/state events)
@@ -92,16 +118,20 @@ class ZookeeperBase < CZookeeper
92
118
  end
93
119
  end
94
120
 
95
- protected
121
+ def closed?
122
+ @start_stop_mutex.synchronize { false|@_closed }
123
+ end
124
+
96
125
  def running?
97
- false|@_running
126
+ @start_stop_mutex.synchronize { false|@_running }
98
127
  end
99
128
 
129
+ protected
100
130
  def setup_dispatch_thread!
101
131
  @dispatcher = Thread.new do
102
132
  while running?
103
133
  begin # calling user code, so protect ourselves
104
- dispatch_next_callback
134
+ dispatch_next_callback
105
135
  rescue Exception => e
106
136
  $stderr.puts "Error in dispatch thread, #{e.class}: #{e.message}\n" << e.backtrace.map{|n| "\t#{n}"}.join("\n")
107
137
  end
data/ext/zookeeper_c.c CHANGED
@@ -17,11 +17,16 @@
17
17
  #include <stdio.h>
18
18
  #include <stdlib.h>
19
19
  #include <unistd.h>
20
+ #include <sys/fcntl.h>
21
+ #include <pthread.h>
20
22
 
21
23
  #include "zookeeper_lib.h"
22
24
 
25
+
23
26
  static VALUE Zookeeper = Qnil;
24
27
 
28
+ // slyphon: possibly add a lock to this for synchronizing during get_next_event
29
+
25
30
  struct zkrb_instance_data {
26
31
  zhandle_t *zh;
27
32
  clientid_t myid;
@@ -69,9 +74,53 @@ static void print_zkrb_instance_data(struct zkrb_instance_data* ptr) {
69
74
  fprintf(stderr, "}\n");
70
75
  }
71
76
 
77
+ // cargo culted from io.c
78
+ static VALUE zkrb_new_instance _((VALUE));
79
+
80
+ static VALUE zkrb_new_instance(VALUE args) {
81
+ return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
82
+ }
83
+
84
+ static int zkrb_dup(int orig) {
85
+ int fd;
86
+
87
+ fd = dup(orig);
88
+ if (fd < 0) {
89
+ if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
90
+ rb_gc();
91
+ fd = dup(orig);
92
+ }
93
+ if (fd < 0) {
94
+ rb_sys_fail(0);
95
+ }
96
+ }
97
+ return fd;
98
+ }
99
+
100
+ static VALUE create_selectable_io(zkrb_queue_t *q) {
101
+ // rb_cIO is the ruby IO class?
102
+
103
+ int pipe, state, read_fd;
104
+ VALUE args[3], reader;
105
+
106
+ read_fd = zkrb_dup(q->pipe_read);
107
+
108
+ args[0] = rb_cIO;
109
+ args[1] = INT2NUM(read_fd);
110
+ args[2] = INT2FIX(O_RDONLY);
111
+ reader = rb_protect(zkrb_new_instance, (VALUE)args, &state);
112
+
113
+ if (state) {
114
+ rb_jump_tag(state);
115
+ }
116
+
117
+ return reader;
118
+ }
119
+
72
120
  static VALUE method_init(int argc, VALUE* argv, VALUE self) {
73
121
  VALUE hostPort;
74
122
  VALUE options;
123
+
75
124
  rb_scan_args(argc, argv, "11", &hostPort, &options);
76
125
 
77
126
  if (NIL_P(options)) {
@@ -121,8 +170,10 @@ static VALUE method_init(int argc, VALUE* argv, VALUE self) {
121
170
  }
122
171
 
123
172
  rb_iv_set(self, "@data", data);
173
+ rb_iv_set(self, "@selectable_io", create_selectable_io(zk_local_ctx->queue));
124
174
  rb_iv_set(self, "@_running", Qtrue);
125
175
 
176
+
126
177
  return Qnil;
127
178
  }
128
179
 
@@ -421,7 +472,10 @@ static int is_running(VALUE self) {
421
472
  return RTEST(rval);
422
473
  }
423
474
 
424
- static VALUE method_get_next_event(VALUE self) {
475
+
476
+ /* slyphon: NEED TO PROTECT THIS AGAINST SHUTDOWN */
477
+
478
+ static VALUE method_get_next_event(VALUE self, VALUE blocking) {
425
479
  char buf[64];
426
480
  FETCH_DATA_PTR(self, zk);
427
481
 
@@ -439,19 +493,35 @@ static VALUE method_get_next_event(VALUE self) {
439
493
 
440
494
  /* Wait for an event using rb_thread_select() on the queue's pipe */
441
495
  if (event == NULL) {
442
- int fd = zk->queue->pipe_read;
443
- fd_set rset;
496
+ if (NIL_P(blocking) || (blocking == Qfalse)) {
497
+ return Qnil; // no event for us
498
+ }
499
+ else {
500
+ int fd = zk->queue->pipe_read;
501
+ ssize_t bytes_read = 0;
502
+
503
+ fd_set rset; // a file descriptor set for use w/ select()
504
+
505
+ FD_ZERO(&rset); // FD_ZERO clears the set
506
+ FD_SET(fd, &rset); // FD_SET adds fd to the rset
444
507
 
445
- FD_ZERO(&rset);
446
- FD_SET(fd, &rset);
508
+ // first arg is nfds: "the highest-numbered file descriptor in any of the three sets, plus 1"
509
+ // why? F*** you, that's why!
447
510
 
448
- if (rb_thread_select(fd + 1, &rset, NULL, NULL, NULL) == -1)
449
- rb_raise(rb_eRuntimeError, "select failed: %d", errno);
511
+ if (rb_thread_select(fd + 1, &rset, NULL, NULL, NULL) == -1)
512
+ rb_raise(rb_eRuntimeError, "select failed: %d", errno);
450
513
 
451
- if (read(fd, buf, sizeof(buf)) == -1)
452
- rb_raise(rb_eRuntimeError, "read failed: %d", errno);
514
+ bytes_read = read(fd, buf, sizeof(buf));
453
515
 
454
- continue;
516
+ if (bytes_read == -1) {
517
+ rb_raise(rb_eRuntimeError, "read failed: %d", errno);
518
+ }
519
+ else if (ZKRBDebugging) {
520
+ fprintf(stderr, "read %d bytes from the queue's pipe\n", bytes_read);
521
+ }
522
+
523
+ continue;
524
+ }
455
525
  }
456
526
 
457
527
  VALUE hash = zkrb_event_to_ruby(event);
@@ -493,11 +563,22 @@ static VALUE method_wake_event_loop_bang(VALUE self) {
493
563
  // return Qnil;
494
564
  // }
495
565
 
496
- static VALUE method_close(VALUE self) {
566
+ static VALUE method_close_handle(VALUE self) {
497
567
  FETCH_DATA_PTR(self, zk);
498
568
 
569
+ if (ZKRBDebugging) {
570
+ fprintf(stderr, "CLOSING ZK INSTANCE:");
571
+ print_zkrb_instance_data(zk);
572
+ }
573
+
574
+ // this is a value on the ruby side we can check to see if destroy_zkrb_instance
575
+ // has been called
576
+ rb_iv_set(self, "@_closed", Qtrue);
577
+
578
+
499
579
  /* Note that after zookeeper_close() returns, ZK handle is invalid */
500
580
  int rc = destroy_zkrb_instance(zk);
581
+
501
582
  return INT2FIX(rc);
502
583
  }
503
584
 
@@ -521,8 +602,7 @@ static VALUE method_recv_timeout(VALUE self) {
521
602
  return INT2NUM(zoo_recv_timeout(zk->zh));
522
603
  }
523
604
 
524
- // how do you make a class method??
525
- static VALUE method_set_debug_level(VALUE self, VALUE level) {
605
+ static VALUE klass_method_set_debug_level(VALUE klass, VALUE level) {
526
606
  Check_Type(level, T_FIXNUM);
527
607
  ZKRBDebugging = (FIX2INT(level) == ZOO_LOG_LEVEL_DEBUG);
528
608
  zoo_set_debug_level(FIX2INT(level));
@@ -549,7 +629,7 @@ static void zkrb_define_methods(void) {
549
629
  DEFINE_METHOD(set_acl, 5);
550
630
  DEFINE_METHOD(get_acl, 3);
551
631
  DEFINE_METHOD(client_id, 0);
552
- DEFINE_METHOD(close, 0);
632
+ DEFINE_METHOD(close_handle, 0);
553
633
  DEFINE_METHOD(deterministic_conn_order, 1);
554
634
  DEFINE_METHOD(is_unrecoverable, 0);
555
635
  DEFINE_METHOD(recv_timeout, 1);
@@ -559,13 +639,16 @@ static void zkrb_define_methods(void) {
559
639
  // DEFINE_METHOD(async, 1);
560
640
 
561
641
  // methods for the ruby-side event manager
562
- DEFINE_METHOD(get_next_event, 0);
642
+ DEFINE_METHOD(get_next_event, 1);
563
643
  DEFINE_METHOD(has_events, 0);
564
644
 
565
645
  // Make these class methods?
566
- DEFINE_METHOD(set_debug_level, 1);
567
646
  DEFINE_METHOD(zerror, 1);
568
647
 
648
+ rb_define_singleton_method(Zookeeper, "set_debug_level", klass_method_set_debug_level, 1);
649
+
650
+ rb_attr(Zookeeper, rb_intern("selectable_io"), 1, 0, Qtrue);
651
+
569
652
  rb_define_method(Zookeeper, "wake_event_loop!", method_wake_event_loop_bang, 0);
570
653
  }
571
654
 
data/ext/zookeeper_lib.c CHANGED
@@ -140,18 +140,26 @@ void zkrb_event_free(zkrb_event_t *event) {
140
140
  }
141
141
  case ZKRB_STRINGS: {
142
142
  struct zkrb_strings_completion *strings_ctx = event->completion.strings_completion;
143
- int k;
144
- for (k = 0; k < strings_ctx->values->count; ++k) free(strings_ctx->values->data[k]);
145
- free(strings_ctx->values);
143
+ if (strings_ctx->values != NULL) {
144
+ int k;
145
+ for (k = 0; k < strings_ctx->values->count; ++k) free(strings_ctx->values->data[k]);
146
+ free(strings_ctx->values);
147
+ }
146
148
  free(strings_ctx);
147
149
  break;
148
150
  }
149
151
  case ZKRB_STRINGS_STAT: {
150
152
  struct zkrb_strings_stat_completion *strings_stat_ctx = event->completion.strings_stat_completion;
151
- int k;
152
- for (k = 0; k < strings_stat_ctx->values->count; ++k) free(strings_stat_ctx->values->data[k]);
153
- free(strings_stat_ctx->values);
154
- free(strings_stat_ctx->stat);
153
+ if (strings_stat_ctx->values != NULL) {
154
+ int k;
155
+ for (k = 0; k < strings_stat_ctx->values->count; ++k) free(strings_stat_ctx->values->data[k]);
156
+ free(strings_stat_ctx->values);
157
+ }
158
+
159
+ if (strings_stat_ctx->stat != NULL) {
160
+ free(strings_stat_ctx->stat);
161
+ }
162
+
155
163
  free(strings_stat_ctx);
156
164
  break;
157
165
  }
@@ -200,33 +208,40 @@ VALUE zkrb_event_to_ruby(zkrb_event_t *event) {
200
208
  break;
201
209
  }
202
210
  case ZKRB_STAT: {
211
+ if (ZKRBDebugging) fprintf(stderr, "zkrb_event_to_ruby ZKRB_STAT\n");
203
212
  struct zkrb_stat_completion *stat_ctx = event->completion.stat_completion;
204
213
  rb_hash_aset(hash, GET_SYM("stat"), stat_ctx->stat ? zkrb_stat_to_rarray(stat_ctx->stat) : Qnil);
205
214
  break;
206
215
  }
207
216
  case ZKRB_STRING: {
217
+ if (ZKRBDebugging) fprintf(stderr, "zkrb_event_to_ruby ZKRB_STRING\n");
208
218
  struct zkrb_string_completion *string_ctx = event->completion.string_completion;
209
219
  rb_hash_aset(hash, GET_SYM("string"), string_ctx->value ? rb_str_new2(string_ctx->value) : Qnil);
210
220
  break;
211
221
  }
212
222
  case ZKRB_STRINGS: {
223
+ if (ZKRBDebugging) fprintf(stderr, "zkrb_event_to_ruby ZKRB_STRINGS\n");
213
224
  struct zkrb_strings_completion *strings_ctx = event->completion.strings_completion;
214
225
  rb_hash_aset(hash, GET_SYM("strings"), strings_ctx->values ? zkrb_string_vector_to_ruby(strings_ctx->values) : Qnil);
215
226
  break;
216
227
  }
217
228
  case ZKRB_STRINGS_STAT: {
229
+ if (ZKRBDebugging) fprintf(stderr, "zkrb_event_to_ruby ZKRB_STRINGS_STAT\n");
218
230
  struct zkrb_strings_stat_completion *strings_stat_ctx = event->completion.strings_stat_completion;
219
231
  rb_hash_aset(hash, GET_SYM("strings"), strings_stat_ctx->values ? zkrb_string_vector_to_ruby(strings_stat_ctx->values) : Qnil);
220
232
  rb_hash_aset(hash, GET_SYM("stat"), strings_stat_ctx->stat ? zkrb_stat_to_rarray(strings_stat_ctx->stat) : Qnil);
221
233
  break;
222
234
  }
223
235
  case ZKRB_ACL: {
236
+ if (ZKRBDebugging) fprintf(stderr, "zkrb_event_to_ruby ZKRB_ACL\n");
224
237
  struct zkrb_acl_completion *acl_ctx = event->completion.acl_completion;
225
238
  rb_hash_aset(hash, GET_SYM("acl"), acl_ctx->acl ? zkrb_acl_vector_to_ruby(acl_ctx->acl) : Qnil);
226
239
  rb_hash_aset(hash, GET_SYM("stat"), acl_ctx->stat ? zkrb_stat_to_rarray(acl_ctx->stat) : Qnil);
227
240
  break;
228
241
  }
229
242
  case ZKRB_WATCHER: {
243
+ if (ZKRBDebugging) fprintf(stderr, "zkrb_event_to_ruby ZKRB_WATCHER\n");
244
+ struct zkrb_acl_completion *acl_ctx = event->completion.acl_completion;
230
245
  struct zkrb_watcher_completion *watcher_ctx = event->completion.watcher_completion;
231
246
  rb_hash_aset(hash, GET_SYM("type"), INT2FIX(watcher_ctx->type));
232
247
  rb_hash_aset(hash, GET_SYM("state"), INT2FIX(watcher_ctx->state));
@@ -422,6 +437,7 @@ void zkrb_strings_stat_callback(
422
437
  struct zkrb_strings_stat_completion *sc = malloc(sizeof(struct zkrb_strings_stat_completion));
423
438
  sc->stat = NULL;
424
439
  if (stat != NULL) { sc->stat = malloc(sizeof(struct Stat)); memcpy(sc->stat, stat, sizeof(struct Stat)); }
440
+
425
441
  sc->values = (strings != NULL) ? zkrb_clone_string_vector(strings) : NULL;
426
442
 
427
443
  ZKH_SETUP_EVENT(queue, event);