zookeeper 0.4.3 → 0.4.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3 -2
- data/Rakefile +2 -4
- data/ext/zookeeper_c.c +37 -27
- data/ext/zookeeper_lib.c +41 -26
- data/ext/zookeeper_lib.h +2 -0
- data/lib/zookeeper.rb +38 -29
- data/zookeeper.gemspec +5 -5
- metadata +7 -7
data/CHANGELOG
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
v0.4.
|
2
|
-
|
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 = "
|
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 ?
|
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
|
-
|
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
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
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
|
-
|
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
|
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.
|
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-
|
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{
|
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{
|
19
|
-
s.rubygems_version = %q{1.
|
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:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 4
|
9
|
-
-
|
10
|
-
version: 0.4.
|
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-
|
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:
|
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:
|
96
|
-
rubygems_version: 1.
|
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.
|