zookeeper 0.4.3 → 0.4.4

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/CHANGELOG CHANGED
@@ -1,5 +1,6 @@
1
- v0.4.3 Fix a handful of memory-related bugs, fix SIGSEGV on master change,
2
- reduce latency of event handling, fix compilation on OSX.
1
+ v0.4.4 Fix race condition on close, possible data corruption on async get.
2
+
3
+ v0.4.3 Fix a handful of memory-related bugs, fix SIGSEGV on master change, reduce latency of event handling, fix compilation on OSX.
3
4
 
4
5
  v0.4.2 Add options to Zookeeper#initialize, silence most Zookeeper logs.
5
6
 
data/Rakefile CHANGED
@@ -2,10 +2,8 @@ require 'echoe'
2
2
 
3
3
  Echoe.new("zookeeper") do |p|
4
4
  p.author = "Phillip Pearson, Eric Maland, Evan Weaver, Brian Wickman"
5
- p.project = "fauna"
5
+ p.project = "twitter"
6
6
  p.summary = "An interface to the Zookeeper distributed configuration server."
7
- p.url = "https://github.com/twitter/zookeeper"
8
- p.docs_host = "blog.evanweaver.com:~/www/bax/public/files/doc/"
9
7
  p.clean_pattern += ["ext/lib", "ext/include", "ext/c", "ext/bin", "ext/conftest.dSYM"]
10
8
  p.rdoc_pattern = /README|TODO|LICENSE|CHANGELOG|BENCH|COMPAT|zookeeper_c.c|zookeeper.rb/
11
- end
9
+ end
data/ext/zookeeper_c.c CHANGED
@@ -26,6 +26,7 @@ struct zkrb_instance_data {
26
26
  zhandle_t *zh;
27
27
  clientid_t myid;
28
28
  zkrb_queue_t *queue;
29
+ int pending_close;
29
30
  };
30
31
 
31
32
  typedef enum {
@@ -99,13 +100,14 @@ static VALUE method_init(int argc, VALUE* argv, VALUE self) {
99
100
  free_zkrb_instance_data,
100
101
  zk_local_ctx);
101
102
  zk_local_ctx->queue = zkrb_queue_alloc();
103
+ zk_local_ctx->pending_close = 0;
102
104
 
103
105
  zoo_deterministic_conn_order(0);
104
106
 
105
107
  zkrb_calling_context *ctx =
106
108
  zkrb_calling_context_alloc(ZKRB_GLOBAL_REQ, zk_local_ctx->queue);
107
109
 
108
- zk_local_ctx->zh =
110
+ zk_local_ctx->zh =
109
111
  zookeeper_init(
110
112
  RSTRING_PTR(hostPort),
111
113
  zkrb_state_callback,
@@ -113,7 +115,7 @@ static VALUE method_init(int argc, VALUE* argv, VALUE self) {
113
115
  &zk_local_ctx->myid,
114
116
  ctx,
115
117
  0);
116
-
118
+
117
119
  #warning [wickman] TODO handle this properly on the Ruby side rather than C side
118
120
  if (!zk_local_ctx->zh) {
119
121
  rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
@@ -156,10 +158,10 @@ static VALUE method_init(int argc, VALUE* argv, VALUE self) {
156
158
 
157
159
  static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
158
160
  STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
159
-
161
+
160
162
  struct String_vector strings;
161
163
  struct Stat stat;
162
-
164
+
163
165
  int rc;
164
166
  switch (call_type) {
165
167
  case SYNC:
@@ -169,11 +171,11 @@ static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE asyn
169
171
  case SYNC_WATCH:
170
172
  rc = zoo_wget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &strings, &stat);
171
173
  break;
172
-
174
+
173
175
  case ASYNC:
174
176
  rc = zoo_aget_children2(zk->zh, RSTRING_PTR(path), 0, zkrb_strings_stat_callback, data_ctx);
175
177
  break;
176
-
178
+
177
179
  case ASYNC_WATCH:
178
180
  rc = zoo_awget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_strings_stat_callback, data_ctx);
179
181
  break;
@@ -190,7 +192,7 @@ static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE asyn
190
192
 
191
193
  static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
192
194
  STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
193
-
195
+
194
196
  struct Stat stat;
195
197
 
196
198
  int rc;
@@ -202,11 +204,11 @@ static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VAL
202
204
  case SYNC_WATCH:
203
205
  rc = zoo_wexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &stat);
204
206
  break;
205
-
207
+
206
208
  case ASYNC:
207
209
  rc = zoo_aexists(zk->zh, RSTRING_PTR(path), 0, zkrb_stat_callback, data_ctx);
208
210
  break;
209
-
211
+
210
212
  case ASYNC_WATCH:
211
213
  rc = zoo_awexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_stat_callback, data_ctx);
212
214
  break;
@@ -223,12 +225,12 @@ static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VAL
223
225
  static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE acls, VALUE flags) {
224
226
  VALUE watch = Qfalse;
225
227
  STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
226
-
228
+
227
229
  if (data != Qnil) Check_Type(data, T_STRING);
228
230
  Check_Type(flags, T_FIXNUM);
229
231
  const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
230
232
  size_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
231
-
233
+
232
234
  struct ACL_vector *aclptr = NULL;
233
235
  if (acls != Qnil) { aclptr = zkrb_ruby_to_aclvector(acls); }
234
236
  char realpath[16384];
@@ -261,10 +263,10 @@ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALU
261
263
  }
262
264
 
263
265
  static VALUE method_delete(VALUE self, VALUE reqid, VALUE path, VALUE version, VALUE async) {
264
- VALUE watch = Qfalse;
266
+ VALUE watch = Qfalse;
265
267
  STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
266
268
  Check_Type(version, T_FIXNUM);
267
-
269
+
268
270
  int rc = 0;
269
271
  switch (call_type) {
270
272
  case SYNC:
@@ -293,7 +295,7 @@ static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE
293
295
  struct Stat stat;
294
296
 
295
297
  int rc;
296
-
298
+
297
299
  switch (call_type) {
298
300
  case SYNC:
299
301
  rc = zoo_get(zk->zh, RSTRING_PTR(path), 0, data, &data_len, &stat);
@@ -302,11 +304,11 @@ static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE
302
304
  case SYNC_WATCH:
303
305
  rc = zoo_wget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, data, &data_len, &stat);
304
306
  break;
305
-
307
+
306
308
  case ASYNC:
307
309
  rc = zoo_aget(zk->zh, RSTRING_PTR(path), 0, zkrb_data_callback, data_ctx);
308
310
  break;
309
-
311
+
310
312
  case ASYNC_WATCH:
311
313
  rc = zoo_awget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_data_callback, data_ctx);
312
314
  break;
@@ -329,7 +331,7 @@ static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE
329
331
  static VALUE method_set(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE version) {
330
332
  VALUE watch = Qfalse;
331
333
  STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
332
-
334
+
333
335
  struct Stat stat;
334
336
  if (data != Qnil) Check_Type(data, T_STRING);
335
337
  const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
@@ -389,7 +391,7 @@ static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
389
391
 
390
392
  struct ACL_vector acls;
391
393
  struct Stat stat;
392
-
394
+
393
395
  int rc;
394
396
  switch (call_type) {
395
397
  case SYNC:
@@ -421,12 +423,7 @@ static VALUE method_get_next_event(VALUE self) {
421
423
  for (;;) {
422
424
  zkrb_event_t *event = zkrb_dequeue(zk->queue, 1);
423
425
 
424
- /*
425
- * If no events found, wait for an event by using rb_thread_select() on the
426
- * queue's pipe. Note that the ZK handle might be closed while we're
427
- * waiting; if this happens, the rb_thread_select() will fail, and we can't
428
- * safely touch the "zk" instance handle.
429
- */
426
+ /* Wait for an event using rb_thread_select() on the queue's pipe */
430
427
  if (event == NULL) {
431
428
  int fd = zk->queue->pipe_read;
432
429
  fd_set rset;
@@ -440,6 +437,9 @@ static VALUE method_get_next_event(VALUE self) {
440
437
  if (read(fd, buf, sizeof(buf)) == -1)
441
438
  rb_raise(rb_eRuntimeError, "read failed: %d", errno);
442
439
 
440
+ if (zk->pending_close)
441
+ return Qnil;
442
+
443
443
  continue;
444
444
  }
445
445
 
@@ -463,6 +463,15 @@ static VALUE method_client_id(VALUE self) {
463
463
  return UINT2NUM(id->client_id);
464
464
  }
465
465
 
466
+ static VALUE method_signal_pending_close(VALUE self) {
467
+ FETCH_DATA_PTR(self, zk);
468
+
469
+ zk->pending_close = 1;
470
+ zkrb_signal(zk->queue);
471
+
472
+ return Qnil;
473
+ }
474
+
466
475
  static VALUE method_close(VALUE self) {
467
476
  FETCH_DATA_PTR(self, zk);
468
477
 
@@ -517,8 +526,9 @@ static void zkrb_define_methods(void) {
517
526
  DEFINE_METHOD(get, 4);
518
527
  DEFINE_METHOD(set, 5);
519
528
  DEFINE_METHOD(set_acl, 5);
520
- DEFINE_METHOD(get_acl, 3);
529
+ DEFINE_METHOD(get_acl, 3);
521
530
  DEFINE_METHOD(client_id, 0);
531
+ DEFINE_METHOD(signal_pending_close, 0);
522
532
  DEFINE_METHOD(close, 0);
523
533
  DEFINE_METHOD(deterministic_conn_order, 1);
524
534
  DEFINE_METHOD(is_unrecoverable, 0);
@@ -528,11 +538,11 @@ static void zkrb_define_methods(void) {
528
538
  // DEFINE_METHOD(add_auth, 3);
529
539
  // DEFINE_METHOD(async, 1);
530
540
 
531
- // methods for the ruby-side event manager
541
+ // methods for the ruby-side event manager
532
542
  DEFINE_METHOD(get_next_event, 0);
533
543
  DEFINE_METHOD(has_events, 0);
534
544
 
535
- // Make these class methods?
545
+ // Make these class methods?
536
546
  DEFINE_METHOD(set_debug_level, 1);
537
547
  DEFINE_METHOD(zerror, 1);
538
548
  }
data/ext/zookeeper_lib.c CHANGED
@@ -69,6 +69,14 @@ zkrb_event_t* zkrb_dequeue(zkrb_queue_t *q, int need_lock) {
69
69
  }
70
70
  }
71
71
 
72
+ void zkrb_signal(zkrb_queue_t *q) {
73
+ pthread_mutex_lock(&zkrb_q_mutex);
74
+ ssize_t ret = write(q->pipe_write, "0", 1); /* Wake up Ruby listener */
75
+ pthread_mutex_unlock(&zkrb_q_mutex);
76
+ if (ret == -1)
77
+ rb_raise(rb_eRuntimeError, "write to pipe failed: %d", errno);
78
+ }
79
+
72
80
  zkrb_queue_t *zkrb_queue_alloc(void) {
73
81
  int pfd[2];
74
82
  if (pipe(pfd) == -1)
@@ -187,14 +195,14 @@ VALUE zkrb_event_to_ruby(zkrb_event_t *event) {
187
195
  case ZKRB_DATA: {
188
196
  struct zkrb_data_completion *data_ctx = event->completion.data_completion;
189
197
  if (ZKRBDebugging) zkrb_print_stat(data_ctx->stat);
190
- rb_hash_aset(hash, GET_SYM("data"), data_ctx->data ? rb_str_new2(data_ctx->data) : Qnil);
198
+ rb_hash_aset(hash, GET_SYM("data"), data_ctx->data ? rb_str_new(data_ctx->data, data_ctx->data_len) : Qnil);
191
199
  rb_hash_aset(hash, GET_SYM("stat"), data_ctx->stat ? zkrb_stat_to_rarray(data_ctx->stat) : Qnil);
192
200
  break;
193
201
  }
194
202
  case ZKRB_STAT: {
195
203
  struct zkrb_stat_completion *stat_ctx = event->completion.stat_completion;
196
204
  rb_hash_aset(hash, GET_SYM("stat"), stat_ctx->stat ? zkrb_stat_to_rarray(stat_ctx->stat) : Qnil);
197
- break;
205
+ break;
198
206
  }
199
207
  case ZKRB_STRING: {
200
208
  struct zkrb_string_completion *string_ctx = event->completion.string_completion;
@@ -328,14 +336,21 @@ void zkrb_data_callback(
328
336
  struct zkrb_data_completion *dc = malloc(sizeof(struct zkrb_data_completion));
329
337
  dc->data = NULL;
330
338
  dc->stat = NULL;
331
- if (value != NULL) { dc->data = malloc(value_len); memcpy(dc->data, value, value_len); }
339
+ dc->data_len = 0;
340
+
341
+ if (value != NULL) {
342
+ dc->data = malloc(value_len);
343
+ dc->data_len = value_len;
344
+ memcpy(dc->data, value, value_len);
345
+ }
346
+
332
347
  if (stat != NULL) { dc->stat = malloc(sizeof(struct Stat)); memcpy(dc->stat, stat, sizeof(struct Stat)); }
333
348
 
334
349
  ZKH_SETUP_EVENT(queue, event);
335
350
  event->rc = rc;
336
351
  event->type = ZKRB_DATA;
337
352
  event->completion.data_completion = dc;
338
-
353
+
339
354
  zkrb_enqueue(queue, event);
340
355
  }
341
356
 
@@ -354,7 +369,7 @@ void zkrb_stat_callback(
354
369
  event->rc = rc;
355
370
  event->type = ZKRB_STAT;
356
371
  event->completion.stat_completion = sc;
357
-
372
+
358
373
  zkrb_enqueue(queue, event);
359
374
  }
360
375
 
@@ -374,7 +389,7 @@ void zkrb_string_callback(
374
389
  event->rc = rc;
375
390
  event->type = ZKRB_STRING;
376
391
  event->completion.string_completion = sc;
377
-
392
+
378
393
  zkrb_enqueue(queue, event);
379
394
  }
380
395
 
@@ -393,7 +408,7 @@ void zkrb_strings_callback(
393
408
  event->rc = rc;
394
409
  event->type = ZKRB_STRINGS;
395
410
  event->completion.strings_completion = sc;
396
-
411
+
397
412
  zkrb_enqueue(queue, event);
398
413
  }
399
414
 
@@ -413,7 +428,7 @@ void zkrb_strings_stat_callback(
413
428
  event->rc = rc;
414
429
  event->type = ZKRB_STRINGS_STAT;
415
430
  event->completion.strings_stat_completion = sc;
416
-
431
+
417
432
  zkrb_enqueue(queue, event);
418
433
  }
419
434
 
@@ -428,7 +443,7 @@ void zkrb_void_callback(
428
443
  event->rc = rc;
429
444
  event->type = ZKRB_VOID;
430
445
  event->completion.void_completion = NULL;
431
-
446
+
432
447
  zkrb_enqueue(queue, event);
433
448
  }
434
449
 
@@ -449,7 +464,7 @@ void zkrb_acl_callback(
449
464
  event->rc = rc;
450
465
  event->type = ZKRB_ACL;
451
466
  event->completion.acl_completion = ac;
452
-
467
+
453
468
  /* should be synchronized */
454
469
  zkrb_enqueue(queue, event);
455
470
  }
@@ -487,22 +502,22 @@ struct ACL_vector * zkrb_ruby_to_aclvector(VALUE acl_ary) {
487
502
  #warning [wickman] TODO test zkrb_ruby_to_aclvector
488
503
  struct ACL zkrb_ruby_to_acl(VALUE rubyacl) {
489
504
  struct ACL acl;
490
-
505
+
491
506
  VALUE perms = rb_iv_get(rubyacl, "@perms");
492
507
  VALUE rubyid = rb_iv_get(rubyacl, "@id");
493
508
  acl.perms = NUM2INT(perms);
494
509
  acl.id = zkrb_ruby_to_id(rubyid);
495
-
510
+
496
511
  return acl;
497
512
  }
498
513
 
499
514
  #warning [wickman] TODO zkrb_ruby_to_id error checking? test
500
515
  struct Id zkrb_ruby_to_id(VALUE rubyid) {
501
516
  struct Id id;
502
-
517
+
503
518
  VALUE scheme = rb_iv_get(rubyid, "@scheme");
504
519
  VALUE ident = rb_iv_get(rubyid, "@id");
505
-
520
+
506
521
  if (scheme != Qnil) {
507
522
  id.scheme = malloc(RSTRING_LEN(scheme) + 1);
508
523
  strncpy(id.scheme, RSTRING_PTR(scheme), RSTRING_LEN(scheme));
@@ -518,7 +533,7 @@ struct Id zkrb_ruby_to_id(VALUE rubyid) {
518
533
  } else {
519
534
  id.id = NULL;
520
535
  }
521
-
536
+
522
537
  return id;
523
538
  }
524
539
 
@@ -542,17 +557,17 @@ VALUE zkrb_string_vector_to_ruby(struct String_vector *string_vector) {
542
557
 
543
558
  VALUE zkrb_stat_to_rarray(const struct Stat* stat) {
544
559
  return rb_ary_new3(11,
545
- LL2NUM(stat->czxid),
546
- LL2NUM(stat->mzxid),
547
- LL2NUM(stat->ctime),
548
- LL2NUM(stat->mtime),
549
- INT2NUM(stat->version),
550
- INT2NUM(stat->cversion),
551
- INT2NUM(stat->aversion),
552
- LL2NUM(stat->ephemeralOwner),
553
- INT2NUM(stat->dataLength),
554
- INT2NUM(stat->numChildren),
555
- LL2NUM(stat->pzxid));
560
+ LL2NUM(stat->czxid),
561
+ LL2NUM(stat->mzxid),
562
+ LL2NUM(stat->ctime),
563
+ LL2NUM(stat->mtime),
564
+ INT2NUM(stat->version),
565
+ INT2NUM(stat->cversion),
566
+ INT2NUM(stat->aversion),
567
+ LL2NUM(stat->ephemeralOwner),
568
+ INT2NUM(stat->dataLength),
569
+ INT2NUM(stat->numChildren),
570
+ LL2NUM(stat->pzxid));
556
571
  }
557
572
 
558
573
  VALUE zkrb_stat_to_rhash(const struct Stat *stat) {
data/ext/zookeeper_lib.h CHANGED
@@ -26,6 +26,7 @@ extern pthread_mutex_t zkrb_q_mutex;
26
26
 
27
27
  struct zkrb_data_completion {
28
28
  char *data;
29
+ int data_len;
29
30
  struct Stat *stat;
30
31
  };
31
32
 
@@ -108,6 +109,7 @@ void zkrb_event_free(zkrb_event_t *ptr);
108
109
  void zkrb_enqueue(zkrb_queue_t *queue, zkrb_event_t *elt);
109
110
  zkrb_event_t * zkrb_peek(zkrb_queue_t *queue);
110
111
  zkrb_event_t * zkrb_dequeue(zkrb_queue_t *queue, int need_lock);
112
+ void zkrb_signal(zkrb_queue_t *queue);
111
113
 
112
114
  void zkrb_print_stat(const struct Stat *s);
113
115
 
data/lib/zookeeper.rb CHANGED
@@ -22,7 +22,7 @@ class Zookeeper < CZookeeper
22
22
  ZOO_LOG_LEVEL_WARN = 2
23
23
  ZOO_LOG_LEVEL_INFO = 3
24
24
  ZOO_LOG_LEVEL_DEBUG = 4
25
-
25
+
26
26
  def reopen(timeout = 10)
27
27
  init(@host)
28
28
  if timeout > 0
@@ -34,6 +34,7 @@ class Zookeeper < CZookeeper
34
34
  end
35
35
  # flushes all outstanding watcher reqs.
36
36
  @watcher_reqs = { ZKRB_GLOBAL_CB_REQ => { :watcher => get_default_global_watcher } }
37
+ setup_dispatch_thread!
37
38
  state
38
39
  end
39
40
 
@@ -44,7 +45,6 @@ class Zookeeper < CZookeeper
44
45
  @current_req_id = 1
45
46
  @host = host
46
47
  return nil if reopen(timeout) != Zookeeper::ZOO_CONNECTED_STATE
47
- setup_dispatch_thread!
48
48
  end
49
49
 
50
50
  public
@@ -52,14 +52,14 @@ public
52
52
  assert_open
53
53
  assert_supported_keys(options, [:path, :watcher, :watcher_context, :callback, :callback_context])
54
54
  assert_required_keys(options, [:path])
55
-
55
+
56
56
  req_id = setup_call(options)
57
57
  rc, value, stat = super(req_id, options[:path], options[:callback], options[:watcher])
58
58
 
59
59
  rv = { :req_id => req_id, :rc => rc }
60
60
  options[:callback] ? rv : rv.merge(:data => value, :stat => Stat.new(stat))
61
61
  end
62
-
62
+
63
63
  def set(options = {})
64
64
  assert_open
65
65
  assert_supported_keys(options, [:path, :data, :version, :callback, :callback_context])
@@ -72,7 +72,7 @@ public
72
72
  rv = { :req_id => req_id, :rc => rc }
73
73
  options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
74
74
  end
75
-
75
+
76
76
  def get_children(options = {})
77
77
  assert_open
78
78
  assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
@@ -96,34 +96,34 @@ public
96
96
  rv = { :req_id => req_id, :rc => rc }
97
97
  options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
98
98
  end
99
-
99
+
100
100
  def create(options = {})
101
101
  assert_open
102
102
  assert_supported_keys(options, [:path, :data, :acl, :ephemeral, :sequence, :callback, :callback_context])
103
103
  assert_required_keys(options, [:path])
104
-
104
+
105
105
  flags = 0
106
106
  flags |= ZOO_EPHEMERAL if options[:ephemeral]
107
107
  flags |= ZOO_SEQUENCE if options[:sequence]
108
108
 
109
109
  options[:acl] ||= ZOO_OPEN_ACL_UNSAFE
110
-
110
+
111
111
  req_id = setup_call(options)
112
112
  rc, newpath = super(req_id, options[:path], options[:data], options[:callback], options[:acl], flags)
113
-
113
+
114
114
  rv = { :req_id => req_id, :rc => rc }
115
- options[:callback] ? rv : rv.merge(:path => newpath)
115
+ options[:callback] ? rv : rv.merge(:path => newpath)
116
116
  end
117
-
117
+
118
118
  def delete(options = {})
119
119
  assert_open
120
120
  assert_supported_keys(options, [:path, :version, :callback, :callback_context])
121
121
  assert_required_keys(options, [:path])
122
122
  options[:version] ||= -1
123
-
123
+
124
124
  req_id = setup_call(options)
125
125
  rc = super(req_id, options[:path], options[:version], options[:callback])
126
-
126
+
127
127
  { :req_id => req_id, :rc => rc }
128
128
  end
129
129
 
@@ -132,46 +132,55 @@ public
132
132
  assert_supported_keys(options, [:path, :acl, :version, :callback, :callback_context])
133
133
  assert_required_keys(options, [:path, :acl])
134
134
  options[:version] ||= -1
135
-
135
+
136
136
  req_id = setup_call(options)
137
137
  rc = super(req_id, options[:path], options[:acl], options[:callback], options[:version])
138
-
138
+
139
139
  { :req_id => req_id, :rc => rc }
140
140
  end
141
-
141
+
142
142
  def get_acl(options = {})
143
143
  assert_open
144
144
  assert_supported_keys(options, [:path, :callback, :callback_context])
145
145
  assert_required_keys(options, [:path])
146
-
146
+
147
147
  req_id = setup_call(options)
148
148
  rc, acls, stat = super(req_id, options[:path], options[:callback])
149
-
149
+
150
150
  rv = { :req_id => req_id, :rc => rc }
151
151
  options[:callback] ? rv : rv.merge(:acl => acls, :stat => Stat.new(stat))
152
152
  end
153
153
 
154
+ # To close a Zk handle, first shutdown the dispatcher thread; this is done by
155
+ # signalling the waiting thread that there is a pending close. We then release
156
+ # the C-land Zk state.
157
+ def close
158
+ signal_pending_close
159
+ @dispatcher.join
160
+ super
161
+ end
162
+
154
163
  private
155
164
  def setup_dispatch_thread!
156
165
  @dispatcher = Thread.new {
157
166
  while true do
158
- dispatch_next_callback
167
+ hash = get_next_event
168
+ break if hash.nil? # Pending close => exit dispatcher thread
169
+ dispatch_event(hash)
159
170
  end
160
171
  }
161
172
  end
162
173
 
163
- def dispatch_next_callback
164
- hash = get_next_event
165
-
174
+ def dispatch_event(hash)
166
175
  is_completion = hash.has_key?(:rc)
167
-
176
+
168
177
  hash[:stat] = Stat.new(hash[:stat]) if hash.has_key?(:stat)
169
178
  hash[:acl] = hash[:acl].map { |acl| ACL.new(acl) } if hash[:acl]
170
-
179
+
171
180
  callback_context = is_completion ? get_completion(hash[:req_id]) : get_watcher(hash[:req_id])
172
181
  callback = is_completion ? callback_context[:callback] : callback_context[:watcher]
173
182
  hash[:context] = callback_context[:context]
174
-
183
+
175
184
  # TODO: Eventually enforce derivation from Zookeeper::Callback
176
185
  if callback.respond_to?(:call)
177
186
  callback.call(hash)
@@ -179,7 +188,7 @@ private
179
188
  # puts "dispatch_next_callback found non-callback => #{callback.inspect}"
180
189
  end
181
190
  end
182
-
191
+
183
192
  def setup_call(opts)
184
193
  req_id = nil
185
194
  @req_mutex.synchronize {
@@ -190,7 +199,7 @@ private
190
199
  }
191
200
  req_id
192
201
  end
193
-
202
+
194
203
  def setup_watcher(req_id, call_opts)
195
204
  @watcher_reqs[req_id] = { :watcher => call_opts[:watcher],
196
205
  :context => call_opts[:watcher_context] }
@@ -200,13 +209,13 @@ private
200
209
  @completion_reqs[req_id] = { :callback => call_opts[:callback],
201
210
  :context => call_opts[:callback_context] }
202
211
  end
203
-
212
+
204
213
  def get_watcher(req_id)
205
214
  @req_mutex.synchronize {
206
215
  req_id != ZKRB_GLOBAL_CB_REQ ? @watcher_reqs.delete(req_id) : @watcher_reqs[req_id]
207
216
  }
208
217
  end
209
-
218
+
210
219
  def get_completion(req_id)
211
220
  @req_mutex.synchronize { @completion_reqs.delete(req_id) }
212
221
  end
data/zookeeper.gemspec CHANGED
@@ -2,21 +2,21 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{zookeeper}
5
- s.version = "0.4.3"
5
+ s.version = "0.4.4"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Phillip Pearson, Eric Maland, Evan Weaver, Brian Wickman"]
9
- s.date = %q{2011-02-09}
9
+ s.date = %q{2011-03-30}
10
10
  s.description = %q{An interface to the Zookeeper distributed configuration server.}
11
11
  s.email = %q{}
12
12
  s.extensions = ["ext/extconf.rb"]
13
13
  s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README", "ext/zookeeper_c.c", "lib/zookeeper.rb"]
14
14
  s.files = ["CHANGELOG", "LICENSE", "README", "Rakefile", "examples/cloud_config.rb", "ext/extconf.rb", "ext/zkc-3.3.2.tar.gz", "ext/zookeeper_c.c", "ext/zookeeper_lib.c", "ext/zookeeper_lib.h", "lib/zookeeper.rb", "lib/zookeeper/acls.rb", "lib/zookeeper/callbacks.rb", "lib/zookeeper/constants.rb", "lib/zookeeper/exceptions.rb", "lib/zookeeper/stat.rb", "test/test_basic.rb", "test/test_callback1.rb", "test/test_close.rb", "test/test_esoteric.rb", "test/test_watcher1.rb", "test/test_watcher2.rb", "Manifest", "zookeeper.gemspec"]
15
- s.homepage = %q{https://github.com/twitter/zookeeper}
15
+ s.homepage = %q{http://twitter.github.com/twitter/zookeeper/}
16
16
  s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Zookeeper", "--main", "README"]
17
17
  s.require_paths = ["lib", "ext"]
18
- s.rubyforge_project = %q{fauna}
19
- s.rubygems_version = %q{1.5.0}
18
+ s.rubyforge_project = %q{twitter}
19
+ s.rubygems_version = %q{1.6.1}
20
20
  s.summary = %q{An interface to the Zookeeper distributed configuration server.}
21
21
  s.test_files = ["test/test_basic.rb", "test/test_callback1.rb", "test/test_close.rb", "test/test_esoteric.rb", "test/test_watcher1.rb", "test/test_watcher2.rb"]
22
22
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zookeeper
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 4
9
- - 3
10
- version: 0.4.3
9
+ - 4
10
+ version: 0.4.4
11
11
  platform: ruby
12
12
  authors:
13
13
  - Phillip Pearson, Eric Maland, Evan Weaver, Brian Wickman
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-02-09 00:00:00 -08:00
18
+ date: 2011-03-30 00:00:00 -07:00
19
19
  default_executable:
20
20
  dependencies: []
21
21
 
@@ -57,7 +57,7 @@ files:
57
57
  - Manifest
58
58
  - zookeeper.gemspec
59
59
  has_rdoc: true
60
- homepage: https://github.com/twitter/zookeeper
60
+ homepage: http://twitter.github.com/twitter/zookeeper/
61
61
  licenses: []
62
62
 
63
63
  post_install_message:
@@ -92,8 +92,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
92
92
  version: "1.2"
93
93
  requirements: []
94
94
 
95
- rubyforge_project: fauna
96
- rubygems_version: 1.5.0
95
+ rubyforge_project: twitter
96
+ rubygems_version: 1.6.1
97
97
  signing_key:
98
98
  specification_version: 3
99
99
  summary: An interface to the Zookeeper distributed configuration server.