zookeeper 0.4.2 → 0.4.3

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,3 +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.
3
+
1
4
  v0.4.2 Add options to Zookeeper#initialize, silence most Zookeeper logs.
2
5
 
3
6
  v0.4.1 Upgrade to ZooKeeper 3.3.2
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ Echoe.new("zookeeper") do |p|
4
4
  p.author = "Phillip Pearson, Eric Maland, Evan Weaver, Brian Wickman"
5
5
  p.project = "fauna"
6
6
  p.summary = "An interface to the Zookeeper distributed configuration server."
7
- p.url = "http://blog.evanweaver.com/files/doc/fauna/zookeeper/"
7
+ p.url = "https://github.com/twitter/zookeeper"
8
8
  p.docs_host = "blog.evanweaver.com:~/www/bax/public/files/doc/"
9
9
  p.clean_pattern += ["ext/lib", "ext/include", "ext/c", "ext/bin", "ext/conftest.dSYM"]
10
10
  p.rdoc_pattern = /README|TODO|LICENSE|CHANGELOG|BENCH|COMPAT|zookeeper_c.c|zookeeper.rb/
data/ext/extconf.rb CHANGED
@@ -15,10 +15,11 @@ if ENV['DEBUG']
15
15
  puts "Setting debug flags."
16
16
  $CFLAGS << " -O0 -ggdb -DHAVE_DEBUG"
17
17
  $EXTRA_CONF = " --enable-debug"
18
+ $CFLAGS.gsub!(/ -O[^0] /, ' ')
18
19
  end
19
20
 
20
21
  $includes = " -I#{HERE}/include"
21
- $libraries = " -L#{HERE}/lib"
22
+ $libraries = " -L#{HERE}/lib -L#{RbConfig::CONFIG['libdir']}"
22
23
  $CFLAGS = "#{$includes} #{$libraries} #{$CFLAGS}"
23
24
  $LDFLAGS = "#{$libraries} #{$LDFLAGS}"
24
25
  $LIBPATH = ["#{HERE}/lib"]
@@ -33,9 +34,9 @@ Dir.chdir(HERE) do
33
34
  raise "'#{cmd}' failed" unless system(cmd)
34
35
 
35
36
  Dir.chdir(BUNDLE_PATH) do
36
- puts(cmd = "env CFLAGS='-fPIC #{$CFLAGS}' LDFLAGS='-fPIC #{$LDFLAGS}' ./configure --prefix=#{HERE} --without-cppunit --disable-dependency-tracking #{$EXTRA_CONF} 2>&1")
37
+ puts(cmd = "env CC=gcc CXX=g++ CFLAGS='-fPIC #{$CFLAGS}' LDFLAGS='-fPIC #{$LDFLAGS}' ./configure --prefix=#{HERE} --without-cppunit --disable-dependency-tracking #{$EXTRA_CONF} 2>&1")
37
38
  raise "'#{cmd}' failed" unless system(cmd)
38
- puts(cmd = "make CXXFLAGS='#{$CXXFLAGS}' || true 2>&1")
39
+ puts(cmd = "make CXXFLAGS='#{$CXXFLAGS}' CFLAGS='-fPIC #{$CFLAGS}' LDFLAGS='-fPIC #{$LDFLAGS}' || true 2>&1")
39
40
  raise "'#{cmd}' failed" unless system(cmd)
40
41
  puts(cmd = "make install || true 2>&1")
41
42
  raise "'#{cmd}' failed" unless system(cmd)
data/ext/zookeeper_c.c CHANGED
@@ -16,6 +16,7 @@
16
16
  #include <errno.h>
17
17
  #include <stdio.h>
18
18
  #include <stdlib.h>
19
+ #include <unistd.h>
19
20
 
20
21
  #include "zookeeper_lib.h"
21
22
 
@@ -37,21 +38,34 @@ typedef enum {
37
38
  #define IS_SYNC(zkrbcall) ((zkrbcall)==SYNC || (zkrbcall)==SYNC_WATCH)
38
39
  #define IS_ASYNC(zkrbcall) ((zkrbcall)==ASYNC || (zkrbcall)==ASYNC_WATCH)
39
40
 
40
- static void free_zkrb_instance_data(struct zkrb_instance_data* ptr) {
41
- #warning [wickman] TODO: fire off warning if queue is not empty
42
- if (ptr->zh && zoo_state(ptr->zh) == ZOO_CONNECTED_STATE) {
43
- zookeeper_close(ptr->zh);
41
+ static int destroy_zkrb_instance(struct zkrb_instance_data* ptr) {
42
+ int rv = ZOK;
43
+
44
+ if (ptr->zh) {
45
+ const void *ctx = zoo_get_context(ptr->zh);
46
+ /* Note that after zookeeper_close() returns, ZK handle is invalid */
47
+ rv = zookeeper_close(ptr->zh);
48
+ free((void *) ctx);
44
49
  }
50
+
51
+ #warning [wickman] TODO: fire off warning if queue is not empty
45
52
  if (ptr->queue) zkrb_queue_free(ptr->queue);
53
+
54
+ ptr->zh = NULL;
46
55
  ptr->queue = NULL;
56
+ return rv;
57
+ }
58
+
59
+ static void free_zkrb_instance_data(struct zkrb_instance_data* ptr) {
60
+ destroy_zkrb_instance(ptr);
47
61
  }
48
62
 
49
63
  static void print_zkrb_instance_data(struct zkrb_instance_data* ptr) {
50
- fprintf(stderr, "zkrb_instance_data (%x) {\n", ptr);
51
- fprintf(stderr, " zh = %x\n", ptr->zh);
64
+ fprintf(stderr, "zkrb_instance_data (%p) {\n", ptr);
65
+ fprintf(stderr, " zh = %p\n", ptr->zh);
52
66
  fprintf(stderr, " { state = %d }\n", zoo_state(ptr->zh));
53
67
  fprintf(stderr, " id = %llx\n", ptr->myid.client_id);
54
- fprintf(stderr, " q = %x\n", ptr->queue);
68
+ fprintf(stderr, " q = %p\n", ptr->queue);
55
69
  fprintf(stderr, "}\n");
56
70
  }
57
71
 
@@ -78,7 +92,7 @@ static VALUE method_init(int argc, VALUE* argv, VALUE self) {
78
92
  }
79
93
 
80
94
  VALUE data;
81
- struct zkrb_instance_data *zk_local_ctx = NULL;
95
+ struct zkrb_instance_data *zk_local_ctx;
82
96
  data = Data_Make_Struct(Zookeeper,
83
97
  struct zkrb_instance_data,
84
98
  0,
@@ -110,9 +124,11 @@ static VALUE method_init(int argc, VALUE* argv, VALUE self) {
110
124
  return Qnil;
111
125
  }
112
126
 
113
- #define FETCH_DATA_PTR(x, y) \
114
- struct zkrb_instance_data * y; \
115
- Data_Get_Struct(rb_iv_get(x, "@data"), struct zkrb_instance_data, y)
127
+ #define FETCH_DATA_PTR(x, y) \
128
+ struct zkrb_instance_data * y; \
129
+ Data_Get_Struct(rb_iv_get(x, "@data"), struct zkrb_instance_data, y); \
130
+ if ((y)->zh == NULL) \
131
+ rb_raise(rb_eRuntimeError, "zookeeper handle is closed")
116
132
 
117
133
  #define STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, cb_ctx, w_ctx, call_type) \
118
134
  if (TYPE(reqid) != T_FIXNUM && TYPE(reqid) != T_BIGNUM) { \
@@ -122,6 +138,8 @@ static VALUE method_init(int argc, VALUE* argv, VALUE self) {
122
138
  Check_Type(path, T_STRING); \
123
139
  struct zkrb_instance_data * zk; \
124
140
  Data_Get_Struct(rb_iv_get(self, "@data"), struct zkrb_instance_data, zk); \
141
+ if (!zk->zh) \
142
+ rb_raise(rb_eRuntimeError, "zookeeper handle is closed"); \
125
143
  zkrb_calling_context* cb_ctx = \
126
144
  (async != Qfalse && async != Qnil) ? \
127
145
  zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
@@ -206,7 +224,6 @@ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALU
206
224
  VALUE watch = Qfalse;
207
225
  STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
208
226
 
209
- struct Stat stat;
210
227
  if (data != Qnil) Check_Type(data, T_STRING);
211
228
  Check_Type(flags, T_FIXNUM);
212
229
  const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
@@ -220,11 +237,9 @@ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALU
220
237
  switch (call_type) {
221
238
  case SYNC:
222
239
  rc = zoo_create(zk->zh, RSTRING_PTR(path), data_ptr, data_len, aclptr, FIX2INT(flags), realpath, sizeof(realpath));
223
- if (aclptr != NULL) deallocate_ACL_vector(aclptr);
224
240
  break;
225
241
  case ASYNC:
226
242
  rc = zoo_acreate(zk->zh, RSTRING_PTR(path), data_ptr, data_len, aclptr, FIX2INT(flags), zkrb_string_callback, data_ctx);
227
- if (aclptr != NULL) deallocate_ACL_vector(aclptr);
228
243
  break;
229
244
  default:
230
245
  /* TODO(wickman) raise proper argument error */
@@ -232,6 +247,11 @@ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALU
232
247
  break;
233
248
  }
234
249
 
250
+ if (aclptr) {
251
+ deallocate_ACL_vector(aclptr);
252
+ free(aclptr);
253
+ }
254
+
235
255
  VALUE output = rb_ary_new();
236
256
  rb_ary_push(output, INT2FIX(rc));
237
257
  if (IS_SYNC(call_type) && rc == ZOK) {
@@ -295,7 +315,10 @@ static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE
295
315
  VALUE output = rb_ary_new();
296
316
  rb_ary_push(output, INT2FIX(rc));
297
317
  if (IS_SYNC(call_type) && rc == ZOK) {
298
- rb_ary_push(output, rb_str_new(data, data_len));
318
+ if (data_len == -1)
319
+ rb_ary_push(output, Qnil); /* No data associated with path */
320
+ else
321
+ rb_ary_push(output, rb_str_new(data, data_len));
299
322
  rb_ary_push(output, zkrb_stat_to_rarray(&stat));
300
323
  }
301
324
  free(data);
@@ -344,11 +367,9 @@ static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VAL
344
367
  switch (call_type) {
345
368
  case SYNC:
346
369
  rc = zoo_set_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr);
347
- deallocate_ACL_vector(aclptr);
348
370
  break;
349
371
  case ASYNC:
350
372
  rc = zoo_aset_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr, zkrb_void_callback, data_ctx);
351
- deallocate_ACL_vector(aclptr);
352
373
  break;
353
374
  default:
354
375
  /* TODO(wickman) raise proper argument error */
@@ -356,6 +377,9 @@ static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VAL
356
377
  break;
357
378
  }
358
379
 
380
+ deallocate_ACL_vector(aclptr);
381
+ free(aclptr);
382
+
359
383
  return INT2FIX(rc);
360
384
  }
361
385
 
@@ -380,32 +404,57 @@ static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
380
404
  break;
381
405
  }
382
406
 
383
- // do we need to deallocate the strings in the acl vector????
384
407
  VALUE output = rb_ary_new();
385
408
  rb_ary_push(output, INT2FIX(rc));
386
409
  if (IS_SYNC(call_type) && rc == ZOK) {
387
410
  rb_ary_push(output, zkrb_acl_vector_to_ruby(&acls));
388
411
  rb_ary_push(output, zkrb_stat_to_rarray(&stat));
412
+ deallocate_ACL_vector(&acls);
389
413
  }
390
414
  return output;
391
415
  }
392
416
 
393
417
  static VALUE method_get_next_event(VALUE self) {
418
+ char buf[64];
394
419
  FETCH_DATA_PTR(self, zk);
395
- if (zk->queue == NULL) return Qnil;
396
-
397
- zkrb_event_t *event = zkrb_dequeue(zk->queue);
398
- if (event == NULL) return Qnil;
399
420
 
400
- VALUE hash = zkrb_event_to_ruby(event);
401
- zkrb_event_free(event);
402
- return hash;
421
+ for (;;) {
422
+ zkrb_event_t *event = zkrb_dequeue(zk->queue, 1);
423
+
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
+ */
430
+ if (event == NULL) {
431
+ int fd = zk->queue->pipe_read;
432
+ fd_set rset;
433
+
434
+ FD_ZERO(&rset);
435
+ FD_SET(fd, &rset);
436
+
437
+ if (rb_thread_select(fd + 1, &rset, NULL, NULL, NULL) == -1)
438
+ rb_raise(rb_eRuntimeError, "select failed: %d", errno);
439
+
440
+ if (read(fd, buf, sizeof(buf)) == -1)
441
+ rb_raise(rb_eRuntimeError, "read failed: %d", errno);
442
+
443
+ continue;
444
+ }
445
+
446
+ VALUE hash = zkrb_event_to_ruby(event);
447
+ zkrb_event_free(event);
448
+ return hash;
449
+ }
403
450
  }
404
451
 
405
452
  static VALUE method_has_events(VALUE self) {
453
+ VALUE rb_event;
406
454
  FETCH_DATA_PTR(self, zk);
407
- if (zk->queue == NULL) return Qfalse;
408
- return zkrb_peek(zk->queue) != NULL ? Qtrue : Qfalse;
455
+
456
+ rb_event = zkrb_peek(zk->queue) != NULL ? Qtrue : Qfalse;
457
+ return rb_event;
409
458
  }
410
459
 
411
460
  static VALUE method_client_id(VALUE self) {
@@ -416,7 +465,9 @@ static VALUE method_client_id(VALUE self) {
416
465
 
417
466
  static VALUE method_close(VALUE self) {
418
467
  FETCH_DATA_PTR(self, zk);
419
- int rc = zookeeper_close(zk->zh);
468
+
469
+ /* Note that after zookeeper_close() returns, ZK handle is invalid */
470
+ int rc = destroy_zkrb_instance(zk);
420
471
  return INT2FIX(rc);
421
472
  }
422
473
 
@@ -487,7 +538,6 @@ static void zkrb_define_methods(void) {
487
538
  }
488
539
  void Init_zookeeper_c() {
489
540
  ZKRBDebugging = 0;
490
-
491
541
  /* initialize Zookeeper class */
492
542
  Zookeeper = rb_define_class("CZookeeper", rb_cObject);
493
543
  zkrb_define_methods();
data/ext/zookeeper_lib.c CHANGED
@@ -14,58 +14,98 @@ wickman@twitter.com
14
14
  #include <errno.h>
15
15
  #include <stdio.h>
16
16
  #include <stdlib.h>
17
+ #include <pthread.h>
18
+ #include <unistd.h>
17
19
 
18
20
  #define GET_SYM(str) ID2SYM(rb_intern(str))
19
21
 
20
22
  int ZKRBDebugging;
21
23
 
24
+ pthread_mutex_t zkrb_q_mutex = PTHREAD_MUTEX_INITIALIZER;
25
+
22
26
  /* push/pop is a misnomer, this is a queue */
23
- #warning [wickman] TODO enqueue, peek, dequeue => pthread_mutex_lock
24
27
  void zkrb_enqueue(zkrb_queue_t *q, zkrb_event_t *elt) {
28
+ pthread_mutex_lock(&zkrb_q_mutex);
29
+ if (q == NULL || q->tail == NULL) {
30
+ pthread_mutex_unlock(&zkrb_q_mutex);
31
+ return;
32
+ }
25
33
  q->tail->event = elt;
26
34
  q->tail->next = (struct zkrb_event_ll_t *) malloc(sizeof(struct zkrb_event_ll_t));
27
35
  q->tail = q->tail->next;
28
36
  q->tail->event = NULL;
29
37
  q->tail->next = NULL;
38
+ ssize_t ret = write(q->pipe_write, "0", 1); /* Wake up Ruby listener */
39
+ pthread_mutex_unlock(&zkrb_q_mutex);
40
+ if (ret == -1)
41
+ rb_raise(rb_eRuntimeError, "write to pipe failed: %d", errno);
30
42
  }
31
43
 
32
44
  zkrb_event_t * zkrb_peek(zkrb_queue_t *q) {
33
- if (q->head != NULL && q->head->event != NULL)
34
- return q->head->event;
35
- return NULL;
45
+ pthread_mutex_lock(&zkrb_q_mutex);
46
+ zkrb_event_t *event = NULL;
47
+ if (q != NULL && q->head != NULL && q->head->event != NULL) {
48
+ event = q->head->event;
49
+ }
50
+ pthread_mutex_unlock(&zkrb_q_mutex);
51
+ return event;
36
52
  }
37
53
 
38
- zkrb_event_t* zkrb_dequeue(zkrb_queue_t *q) {
39
- if (q->head == NULL || q->head->event == NULL) {
54
+ zkrb_event_t* zkrb_dequeue(zkrb_queue_t *q, int need_lock) {
55
+ if (need_lock)
56
+ pthread_mutex_lock(&zkrb_q_mutex);
57
+ if (q == NULL || q->head == NULL || q->head->event == NULL) {
58
+ if (need_lock)
59
+ pthread_mutex_unlock(&zkrb_q_mutex);
40
60
  return NULL;
41
61
  } else {
42
62
  struct zkrb_event_ll_t *old_root = q->head;
43
63
  q->head = q->head->next;
44
64
  zkrb_event_t *rv = old_root->event;
45
65
  free(old_root);
66
+ if (need_lock)
67
+ pthread_mutex_unlock(&zkrb_q_mutex);
46
68
  return rv;
47
69
  }
48
70
  }
49
71
 
50
72
  zkrb_queue_t *zkrb_queue_alloc(void) {
73
+ int pfd[2];
74
+ if (pipe(pfd) == -1)
75
+ rb_raise(rb_eRuntimeError, "create of pipe failed: %d", errno);
76
+
77
+ pthread_mutex_lock(&zkrb_q_mutex);
51
78
  zkrb_queue_t *rq = malloc(sizeof(zkrb_queue_t));
52
79
  rq->head = malloc(sizeof(struct zkrb_event_ll_t));
53
80
  rq->head->event = NULL; rq->head->next = NULL;
54
81
  rq->tail = rq->head;
82
+ rq->pipe_read = pfd[0];
83
+ rq->pipe_write = pfd[1];
84
+ pthread_mutex_unlock(&zkrb_q_mutex);
85
+
55
86
  return rq;
56
87
  }
57
88
 
58
89
  void zkrb_queue_free(zkrb_queue_t *queue) {
59
- if (queue == NULL) return;
60
- zkrb_event_t *elt = NULL;
61
- while ((elt = zkrb_dequeue(queue)) != NULL) {
90
+ pthread_mutex_lock(&zkrb_q_mutex);
91
+ if (queue == NULL) {
92
+ pthread_mutex_unlock(&zkrb_q_mutex);
93
+ return;
94
+ }
95
+
96
+ zkrb_event_t *elt;
97
+ while ((elt = zkrb_dequeue(queue, 0)) != NULL) {
62
98
  zkrb_event_free(elt);
63
99
  }
100
+ free(queue->head);
101
+ close(queue->pipe_read);
102
+ close(queue->pipe_write);
64
103
  free(queue);
104
+ pthread_mutex_unlock(&zkrb_q_mutex);
65
105
  }
66
106
 
67
107
  zkrb_event_t *zkrb_event_alloc(void) {
68
- zkrb_event_t *rv = (zkrb_event_t *) malloc(sizeof(zkrb_event_t));
108
+ zkrb_event_t *rv = (zkrb_event_t *) malloc(sizeof(zkrb_event_t));
69
109
  return rv;
70
110
  }
71
111
 
@@ -75,16 +115,19 @@ void zkrb_event_free(zkrb_event_t *event) {
75
115
  struct zkrb_data_completion *data_ctx = event->completion.data_completion;
76
116
  free(data_ctx->data);
77
117
  free(data_ctx->stat);
118
+ free(data_ctx);
78
119
  break;
79
120
  }
80
121
  case ZKRB_STAT: {
81
122
  struct zkrb_stat_completion *stat_ctx = event->completion.stat_completion;
82
123
  free(stat_ctx->stat);
124
+ free(stat_ctx);
83
125
  break;
84
126
  }
85
127
  case ZKRB_STRING: {
86
128
  struct zkrb_string_completion *string_ctx = event->completion.string_completion;
87
129
  free(string_ctx->value);
130
+ free(string_ctx);
88
131
  break;
89
132
  }
90
133
  case ZKRB_STRINGS: {
@@ -92,6 +135,7 @@ void zkrb_event_free(zkrb_event_t *event) {
92
135
  int k;
93
136
  for (k = 0; k < strings_ctx->values->count; ++k) free(strings_ctx->values->data[k]);
94
137
  free(strings_ctx->values);
138
+ free(strings_ctx);
95
139
  break;
96
140
  }
97
141
  case ZKRB_STRINGS_STAT: {
@@ -100,6 +144,7 @@ void zkrb_event_free(zkrb_event_t *event) {
100
144
  for (k = 0; k < strings_stat_ctx->values->count; ++k) free(strings_stat_ctx->values->data[k]);
101
145
  free(strings_stat_ctx->values);
102
146
  free(strings_stat_ctx->stat);
147
+ free(strings_stat_ctx);
103
148
  break;
104
149
  }
105
150
  case ZKRB_ACL: {
@@ -109,11 +154,13 @@ void zkrb_event_free(zkrb_event_t *event) {
109
154
  free(acl_ctx->acl);
110
155
  }
111
156
  free(acl_ctx->stat);
157
+ free(acl_ctx);
112
158
  break;
113
159
  }
114
160
  case ZKRB_WATCHER: {
115
161
  struct zkrb_watcher_completion *watcher_ctx = event->completion.watcher_completion;
116
162
  free(watcher_ctx->path);
163
+ free(watcher_ctx);
117
164
  break;
118
165
  }
119
166
  case ZKRB_VOID: {
@@ -214,30 +261,33 @@ zkrb_calling_context *zkrb_calling_context_alloc(int64_t req_id, zkrb_queue_t *q
214
261
  }
215
262
 
216
263
  void zkrb_print_calling_context(zkrb_calling_context *ctx) {
217
- fprintf(stderr, "calling context (%#x){\n", ctx);
264
+ fprintf(stderr, "calling context (%p){\n", ctx);
218
265
  fprintf(stderr, "\treq_id = %lld\n", ctx->req_id);
219
- fprintf(stderr, "\tqueue = 0x%#x\n", ctx->queue);
266
+ fprintf(stderr, "\tqueue = %p\n", ctx->queue);
220
267
  fprintf(stderr, "}\n");
221
268
  }
222
269
 
223
270
  /*
224
271
  process completions that get queued to the watcher queue, translate events
225
272
  to completions that the ruby side dispatches via callbacks.
273
+
274
+ The calling_ctx can be thought of as the outer shell that we discard in
275
+ this macro after pulling out the gooey delicious center.
226
276
  */
227
277
 
228
278
  #define ZKH_SETUP_EVENT(qptr, eptr) \
229
279
  zkrb_calling_context *ctx = (zkrb_calling_context *) calling_ctx; \
230
- zkrb_event_t *eptr = zkrb_event_alloc(); \
280
+ zkrb_event_t *eptr = zkrb_event_alloc(); \
231
281
  eptr->req_id = ctx->req_id; \
232
- if (eptr->req_id != ZKRB_GLOBAL_REQ) free(ctx); \
233
- zkrb_queue_t *qptr = ctx->queue;
282
+ zkrb_queue_t *qptr = ctx->queue; \
283
+ if (eptr->req_id != ZKRB_GLOBAL_REQ) free(ctx)
234
284
 
235
285
  void zkrb_state_callback(
236
286
  zhandle_t *zh, int type, int state, const char *path, void *calling_ctx) {
237
287
  /* logging */
238
288
  if (ZKRBDebugging) {
239
289
  fprintf(stderr, "ZOOKEEPER_C_STATE WATCHER "
240
- "type = %d, state = %d, path = 0x%#x, value = %s\n",
290
+ "type = %d, state = %d, path = %p, value = %s\n",
241
291
  type, state, (void *) path, path ? path : "NULL");
242
292
  }
243
293
 
@@ -245,13 +295,22 @@ void zkrb_state_callback(
245
295
  struct zkrb_watcher_completion *wc = malloc(sizeof(struct zkrb_watcher_completion));
246
296
  wc->type = type;
247
297
  wc->state = state;
248
- wc->path = malloc(strlen(path) + 1);
249
- strcpy(wc->path, path);
298
+ wc->path = strdup(path);
299
+
300
+ // This is unfortunate copy-pasta from ZKH_SETUP_EVENT with one change: we
301
+ // check type instead of the req_id to see if we need to free the ctx.
302
+ zkrb_calling_context *ctx = (zkrb_calling_context *) calling_ctx;
303
+ zkrb_event_t *event = zkrb_event_alloc();
304
+ event->req_id = ctx->req_id;
305
+ zkrb_queue_t *queue = ctx->queue;
306
+ if (type != ZOO_SESSION_EVENT) {
307
+ free(ctx);
308
+ ctx = NULL;
309
+ }
250
310
 
251
- ZKH_SETUP_EVENT(queue, event);
252
311
  event->type = ZKRB_WATCHER;
253
312
  event->completion.watcher_completion = wc;
254
-
313
+
255
314
  zkrb_enqueue(queue, event);
256
315
  }
257
316
 
@@ -267,7 +326,8 @@ void zkrb_data_callback(
267
326
 
268
327
  /* copy data completion */
269
328
  struct zkrb_data_completion *dc = malloc(sizeof(struct zkrb_data_completion));
270
- dc->data = dc->stat = NULL;
329
+ dc->data = NULL;
330
+ dc->stat = NULL;
271
331
  if (value != NULL) { dc->data = malloc(value_len); memcpy(dc->data, value, value_len); }
272
332
  if (stat != NULL) { dc->stat = malloc(sizeof(struct Stat)); memcpy(dc->stat, stat, sizeof(struct Stat)); }
273
333
 
@@ -307,7 +367,8 @@ void zkrb_string_callback(
307
367
 
308
368
  struct zkrb_string_completion *sc = malloc(sizeof(struct zkrb_string_completion));
309
369
  sc->value = NULL;
310
- if (string != NULL) { sc->value = malloc(strlen(string) + 1); strcpy(sc->value, string); }
370
+ if (string)
371
+ sc->value = strdup(string);
311
372
 
312
373
  ZKH_SETUP_EVENT(queue, event);
313
374
  event->rc = rc;
@@ -321,7 +382,7 @@ void zkrb_strings_callback(
321
382
  int rc, const struct String_vector *strings, const void *calling_ctx) {
322
383
  if (ZKRBDebugging) {
323
384
  fprintf(stderr, "ZOOKEEPER_C_STRINGS WATCHER "
324
- "rc = %d (%s), calling_ctx = 0x%#x\n", rc, zerror(rc), calling_ctx);
385
+ "rc = %d (%s), calling_ctx = %p\n", rc, zerror(rc), calling_ctx);
325
386
  }
326
387
 
327
388
  /* copy string vector */
@@ -340,7 +401,7 @@ void zkrb_strings_stat_callback(
340
401
  int rc, const struct String_vector *strings, const struct Stat *stat, const void *calling_ctx) {
341
402
  if (ZKRBDebugging) {
342
403
  fprintf(stderr, "ZOOKEEPER_C_STRINGS_STAT WATCHER "
343
- "rc = %d (%s), calling_ctx = 0x%#x\n", rc, zerror(rc), calling_ctx);
404
+ "rc = %d (%s), calling_ctx = %p\n", rc, zerror(rc), calling_ctx);
344
405
  }
345
406
 
346
407
  struct zkrb_strings_stat_completion *sc = malloc(sizeof(struct zkrb_strings_stat_completion));
@@ -351,7 +412,7 @@ void zkrb_strings_stat_callback(
351
412
  ZKH_SETUP_EVENT(queue, event);
352
413
  event->rc = rc;
353
414
  event->type = ZKRB_STRINGS_STAT;
354
- event->completion.strings_completion = sc;
415
+ event->completion.strings_stat_completion = sc;
355
416
 
356
417
  zkrb_enqueue(queue, event);
357
418
  }
@@ -379,7 +440,8 @@ void zkrb_acl_callback(
379
440
  }
380
441
 
381
442
  struct zkrb_acl_completion *ac = malloc(sizeof(struct zkrb_acl_completion));
382
- ac->acl = ac->stat = NULL;
443
+ ac->acl = NULL;
444
+ ac->stat = NULL;
383
445
  if (acls != NULL) { ac->acl = zkrb_clone_acl_vector(acls); }
384
446
  if (stat != NULL) { ac->stat = malloc(sizeof(struct Stat)); memcpy(ac->stat, stat, sizeof(struct Stat)); }
385
447
 
@@ -450,7 +512,7 @@ struct Id zkrb_ruby_to_id(VALUE rubyid) {
450
512
  }
451
513
 
452
514
  if (ident != Qnil) {
453
- id.id = malloc(RSTRING_LEN(ident) + 1);
515
+ id.id = malloc(RSTRING_LEN(ident) + 1);
454
516
  strncpy(id.id, RSTRING_PTR(ident), RSTRING_LEN(ident));
455
517
  id.id[RSTRING_LEN(ident)] = '\0';
456
518
  } else {
@@ -461,8 +523,8 @@ struct Id zkrb_ruby_to_id(VALUE rubyid) {
461
523
  }
462
524
 
463
525
  VALUE zkrb_acl_vector_to_ruby(struct ACL_vector *acl_vector) {
464
- int i = 0;
465
- VALUE ary = rb_ary_new();
526
+ int i;
527
+ VALUE ary = rb_ary_new2(acl_vector->count);
466
528
  for(i = 0; i < acl_vector->count; i++) {
467
529
  rb_ary_push(ary, zkrb_acl_to_ruby(acl_vector->data+i));
468
530
  }
@@ -470,8 +532,8 @@ VALUE zkrb_acl_vector_to_ruby(struct ACL_vector *acl_vector) {
470
532
  }
471
533
 
472
534
  VALUE zkrb_string_vector_to_ruby(struct String_vector *string_vector) {
473
- int i = 0;
474
- VALUE ary = rb_ary_new();
535
+ int i;
536
+ VALUE ary = rb_ary_new2(string_vector->count);
475
537
  for(i = 0; i < string_vector->count; i++) {
476
538
  rb_ary_push(ary, rb_str_new2(string_vector->data[i]));
477
539
  }
@@ -516,23 +578,20 @@ struct ACL_vector * zkrb_clone_acl_vector(struct ACL_vector * src) {
516
578
  int k;
517
579
  for (k = 0; k < src->count; ++k) {
518
580
  struct ACL * elt = &src->data[k];
519
- dst->data[k].id.scheme = malloc(strlen(elt->id.scheme)+1);
520
- dst->data[k].id.id = malloc(strlen(elt->id.id)+1);
521
- strcpy(dst->data[k].id.scheme, elt->id.scheme);
522
- strcpy(dst->data[k].id.id, elt->id.id);
581
+ dst->data[k].id.scheme = strdup(elt->id.scheme);
582
+ dst->data[k].id.id = strdup(elt->id.id);
523
583
  dst->data[k].perms = elt->perms;
524
584
  }
525
585
  return dst;
526
586
  }
527
587
 
528
588
  #warning [wickman] TODO test zkrb_clone_string_vector
529
- struct String_vector * zkrb_clone_string_vector(struct String_vector * src) {
589
+ struct String_vector * zkrb_clone_string_vector(const struct String_vector * src) {
530
590
  struct String_vector * dst = malloc(sizeof(struct String_vector));
531
591
  allocate_String_vector(dst, src->count);
532
592
  int k;
533
593
  for (k = 0; k < src->count; ++k) {
534
- dst->data[k] = malloc(strlen(src->data[k]) + 1);
535
- strcpy(dst->data[k], src->data[k]);
594
+ dst->data[k] = strdup(src->data[k]);
536
595
  }
537
596
  return dst;
538
597
  }
data/ext/zookeeper_lib.h CHANGED
@@ -22,6 +22,7 @@
22
22
  #endif
23
23
 
24
24
  extern int ZKRBDebugging;
25
+ extern pthread_mutex_t zkrb_q_mutex;
25
26
 
26
27
  struct zkrb_data_completion {
27
28
  char *data;
@@ -94,6 +95,8 @@ struct zkrb_event_ll_t {
94
95
  typedef struct {
95
96
  struct zkrb_event_ll_t *head;
96
97
  struct zkrb_event_ll_t *tail;
98
+ int pipe_read;
99
+ int pipe_write;
97
100
  } zkrb_queue_t;
98
101
 
99
102
  zkrb_queue_t * zkrb_queue_alloc(void);
@@ -104,7 +107,7 @@ void zkrb_event_free(zkrb_event_t *ptr);
104
107
  /* push/pop is a misnomer, this is a queue */
105
108
  void zkrb_enqueue(zkrb_queue_t *queue, zkrb_event_t *elt);
106
109
  zkrb_event_t * zkrb_peek(zkrb_queue_t *queue);
107
- zkrb_event_t * zkrb_dequeue(zkrb_queue_t *queue);
110
+ zkrb_event_t * zkrb_dequeue(zkrb_queue_t *queue, int need_lock);
108
111
 
109
112
  void zkrb_print_stat(const struct Stat *s);
110
113
 
@@ -154,7 +157,7 @@ VALUE zkrb_stat_to_rhash(const struct Stat* stat);
154
157
 
155
158
  struct ACL_vector * zkrb_ruby_to_aclvector(VALUE acl_ary);
156
159
  struct ACL_vector * zkrb_clone_acl_vector(struct ACL_vector * src);
157
- struct String_vector * zkrb_clone_string_vector(struct String_vector * src);
160
+ struct String_vector * zkrb_clone_string_vector(const struct String_vector * src);
158
161
  struct ACL zkrb_ruby_to_acl(VALUE rubyacl);
159
162
  struct Id zkrb_ruby_to_id(VALUE rubyid);
160
163
 
data/lib/zookeeper.rb CHANGED
@@ -156,14 +156,12 @@ private
156
156
  @dispatcher = Thread.new {
157
157
  while true do
158
158
  dispatch_next_callback
159
- sleep 0.1
160
159
  end
161
160
  }
162
161
  end
163
162
 
164
163
  def dispatch_next_callback
165
164
  hash = get_next_event
166
- return nil unless hash
167
165
 
168
166
  is_completion = hash.has_key?(:rc)
169
167
 
data/test/test_basic.rb CHANGED
@@ -1,8 +1,5 @@
1
1
  require 'rubygems'
2
-
3
- HERE = File.expand_path(File.dirname(__FILE__))
4
-
5
- require "#{HERE}/../lib/zookeeper"
2
+ require 'zookeeper'
6
3
 
7
4
  z = Zookeeper.new("localhost:2181")
8
5
 
data/zookeeper.gemspec CHANGED
@@ -2,26 +2,25 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{zookeeper}
5
- s.version = "0.4.2"
5
+ s.version = "0.4.3"
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-01-06}
9
+ s.date = %q{2011-02-09}
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{http://blog.evanweaver.com/files/doc/fauna/zookeeper/}
15
+ s.homepage = %q{https://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
18
  s.rubyforge_project = %q{fauna}
19
- s.rubygems_version = %q{1.3.7}
19
+ s.rubygems_version = %q{1.5.0}
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
 
23
23
  if s.respond_to? :specification_version then
24
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
24
  s.specification_version = 3
26
25
 
27
26
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
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: 11
5
- prerelease: false
4
+ hash: 9
5
+ prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 4
9
- - 2
10
- version: 0.4.2
9
+ - 3
10
+ version: 0.4.3
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-01-06 00:00:00 -08:00
18
+ date: 2011-02-09 00:00:00 -08: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: http://blog.evanweaver.com/files/doc/fauna/zookeeper/
60
+ homepage: https://github.com/twitter/zookeeper
61
61
  licenses: []
62
62
 
63
63
  post_install_message:
@@ -93,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
93
93
  requirements: []
94
94
 
95
95
  rubyforge_project: fauna
96
- rubygems_version: 1.3.7
96
+ rubygems_version: 1.5.0
97
97
  signing_key:
98
98
  specification_version: 3
99
99
  summary: An interface to the Zookeeper distributed configuration server.