slyphon-zookeeper 0.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/zookeeper_c.c ADDED
@@ -0,0 +1,571 @@
1
+ /* Ruby wrapper for the Zookeeper C API
2
+ * Phillip Pearson <pp@myelin.co.nz>
3
+ * Eric Maland <eric@twitter.com>
4
+ * Brian Wickman <wickman@twitter.com>
5
+ *
6
+ * This fork is a 90% rewrite of the original. It takes a more evented
7
+ * approach to isolate the ZK state machine from the ruby interpreter via an
8
+ * event queue. It's similar to the ZookeeperFFI version except that it
9
+ * actually works on MRI 1.8.
10
+ */
11
+
12
+ #define THREADED
13
+
14
+ #include "ruby.h"
15
+ #include "c-client-src/zookeeper.h"
16
+ #include <errno.h>
17
+ #include <stdio.h>
18
+ #include <stdlib.h>
19
+ #include <unistd.h>
20
+
21
+ #include "zookeeper_lib.h"
22
+
23
+ static VALUE Zookeeper = Qnil;
24
+
25
+ struct zkrb_instance_data {
26
+ zhandle_t *zh;
27
+ clientid_t myid;
28
+ zkrb_queue_t *queue;
29
+ };
30
+
31
+ typedef enum {
32
+ SYNC = 0,
33
+ ASYNC = 1,
34
+ SYNC_WATCH = 2,
35
+ ASYNC_WATCH = 3
36
+ } zkrb_call_type;
37
+
38
+ #define IS_SYNC(zkrbcall) ((zkrbcall)==SYNC || (zkrbcall)==SYNC_WATCH)
39
+ #define IS_ASYNC(zkrbcall) ((zkrbcall)==ASYNC || (zkrbcall)==ASYNC_WATCH)
40
+
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);
49
+ }
50
+
51
+ #warning [wickman] TODO: fire off warning if queue is not empty
52
+ if (ptr->queue) zkrb_queue_free(ptr->queue);
53
+
54
+ ptr->zh = NULL;
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);
61
+ }
62
+
63
+ static void print_zkrb_instance_data(struct zkrb_instance_data* ptr) {
64
+ fprintf(stderr, "zkrb_instance_data (%p) {\n", ptr);
65
+ fprintf(stderr, " zh = %p\n", ptr->zh);
66
+ fprintf(stderr, " { state = %d }\n", zoo_state(ptr->zh));
67
+ fprintf(stderr, " id = %llx\n", ptr->myid.client_id);
68
+ fprintf(stderr, " q = %p\n", ptr->queue);
69
+ fprintf(stderr, "}\n");
70
+ }
71
+
72
+ static VALUE method_init(int argc, VALUE* argv, VALUE self) {
73
+ VALUE hostPort;
74
+ VALUE options;
75
+ rb_scan_args(argc, argv, "11", &hostPort, &options);
76
+
77
+ if (NIL_P(options)) {
78
+ options = rb_hash_new();
79
+ } else {
80
+ Check_Type(options, T_HASH);
81
+ }
82
+
83
+ Check_Type(hostPort, T_STRING);
84
+
85
+ // Look up :zkc_log_level
86
+ VALUE log_level = rb_hash_aref(options, ID2SYM(rb_intern("zkc_log_level")));
87
+ if (NIL_P(log_level)) {
88
+ zoo_set_debug_level(0); // no log messages
89
+ } else {
90
+ Check_Type(log_level, T_FIXNUM);
91
+ zoo_set_debug_level(log_level);
92
+ }
93
+
94
+
95
+ VALUE data;
96
+ struct zkrb_instance_data *zk_local_ctx;
97
+ data = Data_Make_Struct(Zookeeper,
98
+ struct zkrb_instance_data,
99
+ 0,
100
+ free_zkrb_instance_data,
101
+ zk_local_ctx);
102
+ zk_local_ctx->queue = zkrb_queue_alloc();
103
+
104
+ zoo_deterministic_conn_order(0);
105
+
106
+ zkrb_calling_context *ctx =
107
+ zkrb_calling_context_alloc(ZKRB_GLOBAL_REQ, zk_local_ctx->queue);
108
+
109
+ zk_local_ctx->zh =
110
+ zookeeper_init(
111
+ RSTRING_PTR(hostPort),
112
+ zkrb_state_callback,
113
+ 10000,
114
+ &zk_local_ctx->myid,
115
+ ctx,
116
+ 0);
117
+
118
+ #warning [wickman] TODO handle this properly on the Ruby side rather than C side
119
+ if (!zk_local_ctx->zh) {
120
+ rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
121
+ }
122
+
123
+ rb_iv_set(self, "@data", data);
124
+ rb_iv_set(self, "@_running", Qtrue);
125
+
126
+ return Qnil;
127
+ }
128
+
129
+ #define FETCH_DATA_PTR(x, y) \
130
+ struct zkrb_instance_data * y; \
131
+ Data_Get_Struct(rb_iv_get(x, "@data"), struct zkrb_instance_data, y); \
132
+ if ((y)->zh == NULL) \
133
+ rb_raise(rb_eRuntimeError, "zookeeper handle is closed")
134
+
135
+ #define STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, cb_ctx, w_ctx, call_type) \
136
+ if (TYPE(reqid) != T_FIXNUM && TYPE(reqid) != T_BIGNUM) { \
137
+ rb_raise(rb_eTypeError, "reqid must be Fixnum/Bignum"); \
138
+ return Qnil; \
139
+ } \
140
+ Check_Type(path, T_STRING); \
141
+ struct zkrb_instance_data * zk; \
142
+ Data_Get_Struct(rb_iv_get(self, "@data"), struct zkrb_instance_data, zk); \
143
+ if (!zk->zh) \
144
+ rb_raise(rb_eRuntimeError, "zookeeper handle is closed"); \
145
+ zkrb_calling_context* cb_ctx = \
146
+ (async != Qfalse && async != Qnil) ? \
147
+ zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
148
+ NULL; \
149
+ zkrb_calling_context* w_ctx = \
150
+ (watch != Qfalse && watch != Qnil) ? \
151
+ zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
152
+ NULL; \
153
+ int a = (async != Qfalse && async != Qnil); \
154
+ int w = (watch != Qfalse && watch != Qnil); \
155
+ zkrb_call_type call_type; \
156
+ if (a) { if (w) { call_type = ASYNC_WATCH; } else { call_type = ASYNC; } } \
157
+ else { if (w) { call_type = SYNC_WATCH; } else { call_type = SYNC; } }
158
+
159
+ static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
160
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
161
+
162
+ struct String_vector strings;
163
+ struct Stat stat;
164
+
165
+ int rc;
166
+ switch (call_type) {
167
+ case SYNC:
168
+ rc = zoo_get_children2(zk->zh, RSTRING_PTR(path), 0, &strings, &stat);
169
+ break;
170
+
171
+ case SYNC_WATCH:
172
+ rc = zoo_wget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &strings, &stat);
173
+ break;
174
+
175
+ case ASYNC:
176
+ rc = zoo_aget_children2(zk->zh, RSTRING_PTR(path), 0, zkrb_strings_stat_callback, data_ctx);
177
+ break;
178
+
179
+ case ASYNC_WATCH:
180
+ rc = zoo_awget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_strings_stat_callback, data_ctx);
181
+ break;
182
+ }
183
+
184
+ VALUE output = rb_ary_new();
185
+ rb_ary_push(output, INT2FIX(rc));
186
+ if (IS_SYNC(call_type) && rc == ZOK) {
187
+ rb_ary_push(output, zkrb_string_vector_to_ruby(&strings));
188
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
189
+ }
190
+ return output;
191
+ }
192
+
193
+ static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
194
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
195
+
196
+ struct Stat stat;
197
+
198
+ int rc;
199
+ switch (call_type) {
200
+ case SYNC:
201
+ rc = zoo_exists(zk->zh, RSTRING_PTR(path), 0, &stat);
202
+ break;
203
+
204
+ case SYNC_WATCH:
205
+ rc = zoo_wexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &stat);
206
+ break;
207
+
208
+ case ASYNC:
209
+ rc = zoo_aexists(zk->zh, RSTRING_PTR(path), 0, zkrb_stat_callback, data_ctx);
210
+ break;
211
+
212
+ case ASYNC_WATCH:
213
+ rc = zoo_awexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_stat_callback, data_ctx);
214
+ break;
215
+ }
216
+
217
+ VALUE output = rb_ary_new();
218
+ rb_ary_push(output, INT2FIX(rc));
219
+ if (IS_SYNC(call_type) && rc == ZOK) {
220
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
221
+ }
222
+ return output;
223
+ }
224
+
225
+ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE acls, VALUE flags) {
226
+ VALUE watch = Qfalse;
227
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
228
+
229
+ if (data != Qnil) Check_Type(data, T_STRING);
230
+ Check_Type(flags, T_FIXNUM);
231
+ const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
232
+ size_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
233
+
234
+ struct ACL_vector *aclptr = NULL;
235
+ if (acls != Qnil) { aclptr = zkrb_ruby_to_aclvector(acls); }
236
+ char realpath[16384];
237
+
238
+ int rc;
239
+ switch (call_type) {
240
+ case SYNC:
241
+ rc = zoo_create(zk->zh, RSTRING_PTR(path), data_ptr, data_len, aclptr, FIX2INT(flags), realpath, sizeof(realpath));
242
+ break;
243
+ case ASYNC:
244
+ rc = zoo_acreate(zk->zh, RSTRING_PTR(path), data_ptr, data_len, aclptr, FIX2INT(flags), zkrb_string_callback, data_ctx);
245
+ break;
246
+ default:
247
+ /* TODO(wickman) raise proper argument error */
248
+ return Qnil;
249
+ break;
250
+ }
251
+
252
+ if (aclptr) {
253
+ deallocate_ACL_vector(aclptr);
254
+ free(aclptr);
255
+ }
256
+
257
+ VALUE output = rb_ary_new();
258
+ rb_ary_push(output, INT2FIX(rc));
259
+ if (IS_SYNC(call_type) && rc == ZOK) {
260
+ return rb_ary_push(output, rb_str_new2(realpath));
261
+ }
262
+ return output;
263
+ }
264
+
265
+ static VALUE method_delete(VALUE self, VALUE reqid, VALUE path, VALUE version, VALUE async) {
266
+ VALUE watch = Qfalse;
267
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
268
+ Check_Type(version, T_FIXNUM);
269
+
270
+ int rc = 0;
271
+ switch (call_type) {
272
+ case SYNC:
273
+ rc = zoo_delete(zk->zh, RSTRING_PTR(path), FIX2INT(version));
274
+ break;
275
+ case ASYNC:
276
+ rc = zoo_adelete(zk->zh, RSTRING_PTR(path), FIX2INT(version), zkrb_void_callback, data_ctx);
277
+ break;
278
+ default:
279
+ /* TODO(wickman) raise proper argument error */
280
+ return Qnil;
281
+ break;
282
+ }
283
+
284
+ return INT2FIX(rc);
285
+ }
286
+
287
+ #define MAX_ZNODE_SIZE 1048576
288
+
289
+ static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
290
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
291
+
292
+ /* ugh */
293
+ char * data = malloc(MAX_ZNODE_SIZE);
294
+ int data_len = MAX_ZNODE_SIZE;
295
+ struct Stat stat;
296
+
297
+ int rc;
298
+
299
+ switch (call_type) {
300
+ case SYNC:
301
+ rc = zoo_get(zk->zh, RSTRING_PTR(path), 0, data, &data_len, &stat);
302
+ break;
303
+
304
+ case SYNC_WATCH:
305
+ rc = zoo_wget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, data, &data_len, &stat);
306
+ break;
307
+
308
+ case ASYNC:
309
+ rc = zoo_aget(zk->zh, RSTRING_PTR(path), 0, zkrb_data_callback, data_ctx);
310
+ break;
311
+
312
+ case ASYNC_WATCH:
313
+ rc = zoo_awget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_data_callback, data_ctx);
314
+ break;
315
+ }
316
+
317
+ VALUE output = rb_ary_new();
318
+ rb_ary_push(output, INT2FIX(rc));
319
+ if (IS_SYNC(call_type) && rc == ZOK) {
320
+ if (data_len == -1)
321
+ rb_ary_push(output, Qnil); /* No data associated with path */
322
+ else
323
+ rb_ary_push(output, rb_str_new(data, data_len));
324
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
325
+ }
326
+ free(data);
327
+
328
+ return output;
329
+ }
330
+
331
+ static VALUE method_set(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE version) {
332
+ VALUE watch = Qfalse;
333
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
334
+
335
+ struct Stat stat;
336
+ if (data != Qnil) Check_Type(data, T_STRING);
337
+ const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
338
+ size_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
339
+
340
+ int rc;
341
+ switch (call_type) {
342
+ case SYNC:
343
+ rc = zoo_set2(zk->zh, RSTRING_PTR(path), data_ptr, data_len, FIX2INT(version), &stat);
344
+ break;
345
+ case ASYNC:
346
+ rc = zoo_aset(zk->zh, RSTRING_PTR(path), data_ptr, data_len, FIX2INT(version),
347
+ zkrb_stat_callback, data_ctx);
348
+ break;
349
+ default:
350
+ /* TODO(wickman) raise proper argument error */
351
+ return Qnil;
352
+ break;
353
+ }
354
+
355
+ VALUE output = rb_ary_new();
356
+ rb_ary_push(output, INT2FIX(rc));
357
+ if (IS_SYNC(call_type) && rc == ZOK) {
358
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
359
+ }
360
+ return output;
361
+ }
362
+
363
+ static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VALUE async, VALUE version) {
364
+ VALUE watch = Qfalse;
365
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
366
+ struct ACL_vector * aclptr = zkrb_ruby_to_aclvector(acls);
367
+
368
+ int rc;
369
+ switch (call_type) {
370
+ case SYNC:
371
+ rc = zoo_set_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr);
372
+ break;
373
+ case ASYNC:
374
+ rc = zoo_aset_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr, zkrb_void_callback, data_ctx);
375
+ break;
376
+ default:
377
+ /* TODO(wickman) raise proper argument error */
378
+ return Qnil;
379
+ break;
380
+ }
381
+
382
+ deallocate_ACL_vector(aclptr);
383
+ free(aclptr);
384
+
385
+ return INT2FIX(rc);
386
+ }
387
+
388
+ static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
389
+ VALUE watch = Qfalse;
390
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
391
+
392
+ struct ACL_vector acls;
393
+ struct Stat stat;
394
+
395
+ int rc;
396
+ switch (call_type) {
397
+ case SYNC:
398
+ rc = zoo_get_acl(zk->zh, RSTRING_PTR(path), &acls, &stat);
399
+ break;
400
+ case ASYNC:
401
+ rc = zoo_aget_acl(zk->zh, RSTRING_PTR(path), zkrb_acl_callback, data_ctx);
402
+ break;
403
+ default:
404
+ /* TODO(wickman) raise proper argument error */
405
+ return Qnil;
406
+ break;
407
+ }
408
+
409
+ VALUE output = rb_ary_new();
410
+ rb_ary_push(output, INT2FIX(rc));
411
+ if (IS_SYNC(call_type) && rc == ZOK) {
412
+ rb_ary_push(output, zkrb_acl_vector_to_ruby(&acls));
413
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
414
+ deallocate_ACL_vector(&acls);
415
+ }
416
+ return output;
417
+ }
418
+
419
+ static int is_running(VALUE self) {
420
+ VALUE rval = rb_iv_get(self, "@_running");
421
+ return RTEST(rval);
422
+ }
423
+
424
+ static VALUE method_get_next_event(VALUE self) {
425
+ char buf[64];
426
+ FETCH_DATA_PTR(self, zk);
427
+
428
+ for (;;) {
429
+ if (!is_running(self)) {
430
+ /* fprintf(stderr, "method_get_next_event: running is false, returning nil\n");*/
431
+ return Qnil; // this case for shutdown
432
+ }
433
+
434
+ zkrb_event_t *event = zkrb_dequeue(zk->queue, 1);
435
+
436
+ /*
437
+ * If no events found, wait for an event by using rb_thread_select() on the
438
+ * queue's pipe. Note that the ZK handle might be closed while we're
439
+ * waiting; if this happens, the rb_thread_select() will fail, and we can't
440
+ * safely touch the "zk" instance handle.
441
+ */
442
+ if (event == NULL) {
443
+ int fd = zk->queue->pipe_read;
444
+ fd_set rset;
445
+
446
+ FD_ZERO(&rset);
447
+ FD_SET(fd, &rset);
448
+
449
+ if (rb_thread_select(fd + 1, &rset, NULL, NULL, NULL) == -1)
450
+ rb_raise(rb_eRuntimeError, "select failed: %d", errno);
451
+
452
+ if (read(fd, buf, sizeof(buf)) == -1)
453
+ rb_raise(rb_eRuntimeError, "read failed: %d", errno);
454
+
455
+ continue;
456
+ }
457
+
458
+ VALUE hash = zkrb_event_to_ruby(event);
459
+ zkrb_event_free(event);
460
+ return hash;
461
+ }
462
+ }
463
+
464
+ static VALUE method_has_events(VALUE self) {
465
+ VALUE rb_event;
466
+ FETCH_DATA_PTR(self, zk);
467
+
468
+ rb_event = zkrb_peek(zk->queue) != NULL ? Qtrue : Qfalse;
469
+ return rb_event;
470
+ }
471
+
472
+ static VALUE method_client_id(VALUE self) {
473
+ FETCH_DATA_PTR(self, zk);
474
+ const clientid_t *id = zoo_client_id(zk->zh);
475
+ return UINT2NUM(id->client_id);
476
+ }
477
+
478
+ // wake up the event loop, used when shutting down
479
+ static VALUE method_wake_event_loop_bang(VALUE self) {
480
+ FETCH_DATA_PTR(self, zk);
481
+
482
+ ssize_t ret = write(zk->queue->pipe_write, "0", 1); /* Wake up Ruby listener */
483
+
484
+ if (ret == -1)
485
+ rb_raise(rb_eRuntimeError, "write to pipe failed: %d", errno);
486
+
487
+ return Qnil;
488
+ };
489
+
490
+ static VALUE method_close(VALUE self) {
491
+ FETCH_DATA_PTR(self, zk);
492
+
493
+ /* Note that after zookeeper_close() returns, ZK handle is invalid */
494
+ int rc = destroy_zkrb_instance(zk);
495
+ return INT2FIX(rc);
496
+ }
497
+
498
+ static VALUE method_deterministic_conn_order(VALUE self, VALUE yn) {
499
+ zoo_deterministic_conn_order(yn == Qtrue);
500
+ return Qnil;
501
+ }
502
+
503
+ static VALUE method_is_unrecoverable(VALUE self) {
504
+ FETCH_DATA_PTR(self, zk);
505
+ return is_unrecoverable(zk->zh) == ZINVALIDSTATE ? Qtrue : Qfalse;
506
+ }
507
+
508
+ static VALUE method_state(VALUE self) {
509
+ FETCH_DATA_PTR(self, zk);
510
+ return INT2NUM(zoo_state(zk->zh));
511
+ }
512
+
513
+ static VALUE method_recv_timeout(VALUE self) {
514
+ FETCH_DATA_PTR(self, zk);
515
+ return INT2NUM(zoo_recv_timeout(zk->zh));
516
+ }
517
+
518
+ // how do you make a class method??
519
+ static VALUE method_set_debug_level(VALUE self, VALUE level) {
520
+ Check_Type(level, T_FIXNUM);
521
+ ZKRBDebugging = (FIX2INT(level) == ZOO_LOG_LEVEL_DEBUG);
522
+ zoo_set_debug_level(FIX2INT(level));
523
+ return Qnil;
524
+ }
525
+
526
+ static VALUE method_zerror(VALUE self, VALUE errc) {
527
+ return rb_str_new2(zerror(FIX2INT(errc)));
528
+ }
529
+
530
+ static void zkrb_define_methods(void) {
531
+ #define DEFINE_METHOD(method, args) { \
532
+ rb_define_method(Zookeeper, #method, method_ ## method, args); }
533
+ #define DEFINE_CLASS_METHOD(method, args) { \
534
+ rb_define_singleton_method(Zookeeper, #method, method_ ## method, args); }
535
+
536
+ DEFINE_METHOD(init, -1);
537
+ DEFINE_METHOD(get_children, 4);
538
+ DEFINE_METHOD(exists, 4);
539
+ DEFINE_METHOD(create, 6);
540
+ DEFINE_METHOD(delete, 4);
541
+ DEFINE_METHOD(get, 4);
542
+ DEFINE_METHOD(set, 5);
543
+ DEFINE_METHOD(set_acl, 5);
544
+ DEFINE_METHOD(get_acl, 3);
545
+ DEFINE_METHOD(client_id, 0);
546
+ DEFINE_METHOD(close, 0);
547
+ DEFINE_METHOD(deterministic_conn_order, 1);
548
+ DEFINE_METHOD(is_unrecoverable, 0);
549
+ DEFINE_METHOD(recv_timeout, 1);
550
+ DEFINE_METHOD(state, 0);
551
+ // TODO
552
+ // DEFINE_METHOD(add_auth, 3);
553
+ // DEFINE_METHOD(async, 1);
554
+
555
+ // methods for the ruby-side event manager
556
+ DEFINE_METHOD(get_next_event, 0);
557
+ DEFINE_METHOD(has_events, 0);
558
+
559
+ // Make these class methods?
560
+ DEFINE_METHOD(set_debug_level, 1);
561
+ DEFINE_METHOD(zerror, 1);
562
+
563
+ rb_define_method(Zookeeper, "wake_event_loop!", method_wake_event_loop_bang, 0);
564
+ }
565
+
566
+ void Init_zookeeper_c() {
567
+ ZKRBDebugging = 0;
568
+ /* initialize Zookeeper class */
569
+ Zookeeper = rb_define_class("CZookeeper", rb_cObject);
570
+ zkrb_define_methods();
571
+ }