zookeeper 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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.