slyphon-zookeeper 0.1.7-java → 0.2.0-java

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.
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);