zookeeper 0.9.3-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.
Files changed (53) hide show
  1. data/.gitignore +10 -0
  2. data/CHANGELOG +119 -0
  3. data/Gemfile +17 -0
  4. data/LICENSE +23 -0
  5. data/Manifest +29 -0
  6. data/README.markdown +59 -0
  7. data/Rakefile +139 -0
  8. data/examples/cloud_config.rb +125 -0
  9. data/ext/.gitignore +6 -0
  10. data/ext/Rakefile +51 -0
  11. data/ext/c_zookeeper.rb +212 -0
  12. data/ext/dbg.h +53 -0
  13. data/ext/depend +5 -0
  14. data/ext/extconf.rb +85 -0
  15. data/ext/generate_gvl_code.rb +316 -0
  16. data/ext/zkc-3.3.5.tar.gz +0 -0
  17. data/ext/zkrb_wrapper.c +731 -0
  18. data/ext/zkrb_wrapper.h +330 -0
  19. data/ext/zkrb_wrapper_compat.c +15 -0
  20. data/ext/zkrb_wrapper_compat.h +11 -0
  21. data/ext/zookeeper_base.rb +211 -0
  22. data/ext/zookeeper_c.c +725 -0
  23. data/ext/zookeeper_lib.c +677 -0
  24. data/ext/zookeeper_lib.h +172 -0
  25. data/java/zookeeper_base.rb +477 -0
  26. data/lib/zookeeper.rb +297 -0
  27. data/lib/zookeeper/acls.rb +40 -0
  28. data/lib/zookeeper/callbacks.rb +91 -0
  29. data/lib/zookeeper/common.rb +174 -0
  30. data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
  31. data/lib/zookeeper/constants.rb +57 -0
  32. data/lib/zookeeper/em_client.rb +55 -0
  33. data/lib/zookeeper/exceptions.rb +100 -0
  34. data/lib/zookeeper/stat.rb +21 -0
  35. data/lib/zookeeper/version.rb +6 -0
  36. data/notes.txt +14 -0
  37. data/spec/c_zookeeper_spec.rb +50 -0
  38. data/spec/chrooted_connection_spec.rb +81 -0
  39. data/spec/default_watcher_spec.rb +41 -0
  40. data/spec/em_spec.rb +51 -0
  41. data/spec/log4j.properties +17 -0
  42. data/spec/shared/all_success_return_values.rb +10 -0
  43. data/spec/shared/connection_examples.rb +1018 -0
  44. data/spec/spec_helper.rb +119 -0
  45. data/spec/support/progress_formatter.rb +15 -0
  46. data/spec/zookeeper_spec.rb +24 -0
  47. data/test/test_basic.rb +37 -0
  48. data/test/test_callback1.rb +36 -0
  49. data/test/test_close.rb +16 -0
  50. data/test/test_esoteric.rb +7 -0
  51. data/test/test_watcher1.rb +56 -0
  52. data/test/test_watcher2.rb +52 -0
  53. metadata +181 -0
data/ext/zookeeper_c.c ADDED
@@ -0,0 +1,725 @@
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
+ * Jonathan D. Simms <slyphon@gmail.com>
6
+ *
7
+ * This fork is a 90% rewrite of the original. It takes a more evented
8
+ * approach to isolate the ZK state machine from the ruby interpreter via an
9
+ * event queue. It's similar to the ZookeeperFFI version except that it
10
+ * actually works on MRI 1.8.
11
+ */
12
+
13
+ #define THREADED
14
+
15
+ #include "ruby.h"
16
+ #include "c-client-src/zookeeper.h"
17
+ #include <errno.h>
18
+ #include <stdio.h>
19
+ #include <stdlib.h>
20
+ #include <unistd.h>
21
+ #include <sys/fcntl.h>
22
+ #include <pthread.h>
23
+ #include <inttypes.h>
24
+
25
+ #include "zookeeper_lib.h"
26
+ #include "zkrb_wrapper.h"
27
+ #include "dbg.h"
28
+
29
+ static VALUE Zookeeper = Qnil;
30
+ static VALUE ZookeeperClientId = Qnil;
31
+
32
+ // slyphon: possibly add a lock to this for synchronizing during get_next_event
33
+
34
+ struct zkrb_instance_data {
35
+ zhandle_t *zh;
36
+ clientid_t myid;
37
+ zkrb_queue_t *queue;
38
+ long object_id; // the ruby object this instance data is associated with
39
+ };
40
+
41
+ typedef enum {
42
+ SYNC = 0,
43
+ ASYNC = 1,
44
+ SYNC_WATCH = 2,
45
+ ASYNC_WATCH = 3
46
+ } zkrb_call_type;
47
+
48
+ #define IS_SYNC(zkrbcall) ((zkrbcall)==SYNC || (zkrbcall)==SYNC_WATCH)
49
+ #define IS_ASYNC(zkrbcall) ((zkrbcall)==ASYNC || (zkrbcall)==ASYNC_WATCH)
50
+
51
+
52
+ static int destroy_zkrb_instance(struct zkrb_instance_data* ptr) {
53
+ int rv = ZOK;
54
+
55
+ if (ptr->zh) {
56
+ const void *ctx = zoo_get_context(ptr->zh);
57
+ /* Note that after zookeeper_close() returns, ZK handle is invalid */
58
+ zkrb_debug("obj_id: %lx, calling zookeeper_close", ptr->object_id);
59
+ rv = zookeeper_close(ptr->zh);
60
+ zkrb_debug("obj_id: %lx, zookeeper_close returned %d", ptr->object_id, rv);
61
+ free((void *) ctx);
62
+ }
63
+
64
+ #warning [wickman] TODO: fire off warning if queue is not empty
65
+ if (ptr->queue) {
66
+ zkrb_debug("obj_id: %lx, freeing queue pointer: %p", ptr->object_id, ptr->queue);
67
+ zkrb_queue_free(ptr->queue);
68
+ }
69
+
70
+ ptr->zh = NULL;
71
+ ptr->queue = NULL;
72
+
73
+ return rv;
74
+ }
75
+
76
+ static void free_zkrb_instance_data(struct zkrb_instance_data* ptr) {
77
+ destroy_zkrb_instance(ptr);
78
+ }
79
+
80
+ static void print_zkrb_instance_data(struct zkrb_instance_data* ptr) {
81
+ fprintf(stderr, "zkrb_instance_data (%p) {\n", ptr);
82
+ fprintf(stderr, " zh = %p\n", ptr->zh);
83
+ fprintf(stderr, " { state = %d }\n", zoo_state(ptr->zh));
84
+ fprintf(stderr, " id = %"PRId64"\n", ptr->myid.client_id); // PRId64 defined in inttypes.h
85
+ fprintf(stderr, " q = %p\n", ptr->queue);
86
+ fprintf(stderr, " obj_id = %lx\n", ptr->object_id);
87
+ fprintf(stderr, "}\n");
88
+ }
89
+
90
+ // cargo culted from io.c
91
+ static VALUE zkrb_new_instance _((VALUE));
92
+
93
+ static VALUE zkrb_new_instance(VALUE args) {
94
+ return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
95
+ }
96
+
97
+ static int zkrb_dup(int orig) {
98
+ int fd;
99
+
100
+ fd = dup(orig);
101
+ if (fd < 0) {
102
+ if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
103
+ rb_gc();
104
+ fd = dup(orig);
105
+ }
106
+ if (fd < 0) {
107
+ rb_sys_fail(0);
108
+ }
109
+ }
110
+ return fd;
111
+ }
112
+
113
+ #if 0
114
+ static VALUE create_selectable_io(zkrb_queue_t *q) {
115
+ // rb_cIO is the ruby IO class?
116
+
117
+ int pipe, state, read_fd;
118
+ VALUE args[3], reader;
119
+
120
+ read_fd = zkrb_dup(q->pipe_read);
121
+
122
+ args[0] = rb_cIO;
123
+ args[1] = INT2NUM(read_fd);
124
+ args[2] = INT2FIX(O_RDONLY);
125
+ reader = rb_protect(zkrb_new_instance, (VALUE)args, &state);
126
+
127
+ if (state) {
128
+ rb_jump_tag(state);
129
+ }
130
+
131
+ return reader;
132
+ }
133
+ #endif
134
+
135
+ #define session_timeout_msec(self) rb_iv_get(self, "@_session_timeout_msec")
136
+
137
+ static VALUE method_zkrb_init(int argc, VALUE* argv, VALUE self) {
138
+ VALUE hostPort;
139
+ VALUE options;
140
+
141
+ rb_scan_args(argc, argv, "11", &hostPort, &options);
142
+
143
+ if (NIL_P(options)) {
144
+ options = rb_hash_new();
145
+ } else {
146
+ Check_Type(options, T_HASH);
147
+ }
148
+
149
+ Check_Type(hostPort, T_STRING);
150
+
151
+ // Look up :zkc_log_level
152
+ VALUE log_level = rb_hash_aref(options, ID2SYM(rb_intern("zkc_log_level")));
153
+ if (NIL_P(log_level)) {
154
+ zoo_set_debug_level(0); // no log messages
155
+ } else {
156
+ Check_Type(log_level, T_FIXNUM);
157
+ zoo_set_debug_level((int)log_level);
158
+ }
159
+
160
+
161
+ VALUE data;
162
+ struct zkrb_instance_data *zk_local_ctx;
163
+ data = Data_Make_Struct(Zookeeper, struct zkrb_instance_data, 0, free_zkrb_instance_data, zk_local_ctx);
164
+ zk_local_ctx->queue = zkrb_queue_alloc();
165
+
166
+ if (zk_local_ctx->queue == NULL)
167
+ rb_raise(rb_eRuntimeError, "could not allocate zkrb queue!");
168
+
169
+ zoo_deterministic_conn_order(0);
170
+
171
+ zkrb_calling_context *ctx =
172
+ zkrb_calling_context_alloc(ZKRB_GLOBAL_REQ, zk_local_ctx->queue);
173
+
174
+ zk_local_ctx->object_id = FIX2LONG(rb_obj_id(self));
175
+
176
+ zk_local_ctx->zh =
177
+ zookeeper_init(
178
+ RSTRING_PTR(hostPort),
179
+ zkrb_state_callback,
180
+ session_timeout_msec(self),
181
+ &zk_local_ctx->myid,
182
+ ctx,
183
+ 0);
184
+
185
+ #warning [wickman] TODO handle this properly on the Ruby side rather than C side
186
+ if (!zk_local_ctx->zh) {
187
+ rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
188
+ }
189
+
190
+ rb_iv_set(self, "@_data", data);
191
+ rb_funcall(self, rb_intern("zkc_set_running_and_notify!"), 0);
192
+
193
+ error:
194
+ return Qnil;
195
+ }
196
+
197
+ #define FETCH_DATA_PTR(X, Y) \
198
+ struct zkrb_instance_data * Y; \
199
+ Data_Get_Struct(rb_iv_get(X, "@_data"), struct zkrb_instance_data, Y); \
200
+ if ((Y)->zh == NULL) \
201
+ rb_raise(rb_eRuntimeError, "zookeeper handle is closed")
202
+
203
+ #define STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, cb_ctx, w_ctx, call_type) \
204
+ if (TYPE(reqid) != T_FIXNUM && TYPE(reqid) != T_BIGNUM) { \
205
+ rb_raise(rb_eTypeError, "reqid must be Fixnum/Bignum"); \
206
+ return Qnil; \
207
+ } \
208
+ Check_Type(path, T_STRING); \
209
+ struct zkrb_instance_data * zk; \
210
+ Data_Get_Struct(rb_iv_get(self, "@_data"), struct zkrb_instance_data, zk); \
211
+ if (!zk->zh) \
212
+ rb_raise(rb_eRuntimeError, "zookeeper handle is closed"); \
213
+ zkrb_calling_context* cb_ctx = \
214
+ (async != Qfalse && async != Qnil) ? \
215
+ zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
216
+ NULL; \
217
+ zkrb_calling_context* w_ctx = \
218
+ (watch != Qfalse && watch != Qnil) ? \
219
+ zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
220
+ NULL; \
221
+ int a_ = (async != Qfalse && async != Qnil); \
222
+ int w_ = (watch != Qfalse && watch != Qnil); \
223
+ zkrb_call_type call_type; \
224
+ if (a_) { if (w_) { call_type = ASYNC_WATCH; } else { call_type = ASYNC; } } \
225
+ else { if (w_) { call_type = SYNC_WATCH; } else { call_type = SYNC; } }
226
+
227
+ static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
228
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
229
+
230
+ struct String_vector strings;
231
+ struct Stat stat;
232
+
233
+ int rc;
234
+ switch (call_type) {
235
+ case SYNC:
236
+ rc = zkrb_call_zoo_get_children2(zk->zh, RSTRING_PTR(path), 0, &strings, &stat);
237
+ break;
238
+
239
+ case SYNC_WATCH:
240
+ rc = zkrb_call_zoo_wget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &strings, &stat);
241
+ break;
242
+
243
+ case ASYNC:
244
+ rc = zkrb_call_zoo_aget_children2(zk->zh, RSTRING_PTR(path), 0, zkrb_strings_stat_callback, data_ctx);
245
+ break;
246
+
247
+ case ASYNC_WATCH:
248
+ rc = zkrb_call_zoo_awget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_strings_stat_callback, data_ctx);
249
+ break;
250
+ }
251
+
252
+ VALUE output = rb_ary_new();
253
+ rb_ary_push(output, INT2FIX(rc));
254
+ if (IS_SYNC(call_type) && rc == ZOK) {
255
+ rb_ary_push(output, zkrb_string_vector_to_ruby(&strings));
256
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
257
+ }
258
+ return output;
259
+ }
260
+
261
+ static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
262
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
263
+
264
+ struct Stat stat;
265
+
266
+ int rc;
267
+ switch (call_type) {
268
+ case SYNC:
269
+ rc = zkrb_call_zoo_exists(zk->zh, RSTRING_PTR(path), 0, &stat);
270
+ break;
271
+
272
+ case SYNC_WATCH:
273
+ rc = zkrb_call_zoo_wexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &stat);
274
+ break;
275
+
276
+ case ASYNC:
277
+ rc = zkrb_call_zoo_aexists(zk->zh, RSTRING_PTR(path), 0, zkrb_stat_callback, data_ctx);
278
+ break;
279
+
280
+ case ASYNC_WATCH:
281
+ rc = zkrb_call_zoo_awexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_stat_callback, data_ctx);
282
+ break;
283
+ }
284
+
285
+ VALUE output = rb_ary_new();
286
+ rb_ary_push(output, INT2FIX(rc));
287
+ if (IS_SYNC(call_type) && rc == ZOK) {
288
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
289
+ }
290
+ return output;
291
+ }
292
+
293
+ // this method is *only* called asynchronously
294
+ static VALUE method_sync(VALUE self, VALUE reqid, VALUE path) {
295
+ VALUE async = Qtrue;
296
+ VALUE watch = Qfalse;
297
+ int rc;
298
+
299
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
300
+
301
+ rc = zkrb_call_zoo_async(zk->zh, RSTRING_PTR(path), zkrb_string_callback, data_ctx);
302
+
303
+ return INT2FIX(rc);
304
+ }
305
+
306
+ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE acls, VALUE flags) {
307
+ VALUE watch = Qfalse;
308
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
309
+
310
+ if (data != Qnil) Check_Type(data, T_STRING);
311
+ Check_Type(flags, T_FIXNUM);
312
+ const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
313
+ size_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
314
+
315
+ struct ACL_vector *aclptr = NULL;
316
+ if (acls != Qnil) { aclptr = zkrb_ruby_to_aclvector(acls); }
317
+ char realpath[16384];
318
+
319
+ int rc;
320
+ switch (call_type) {
321
+ case SYNC:
322
+ // casting data_len to int is OK as you can only store 1MB in zookeeper
323
+ rc = zkrb_call_zoo_create(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, aclptr, FIX2INT(flags), realpath, sizeof(realpath));
324
+
325
+ break;
326
+ case ASYNC:
327
+ rc = zkrb_call_zoo_acreate(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, aclptr, FIX2INT(flags), zkrb_string_callback, data_ctx);
328
+
329
+ break;
330
+ default:
331
+ /* TODO(wickman) raise proper argument error */
332
+ return Qnil;
333
+ break;
334
+ }
335
+
336
+
337
+ if (aclptr) {
338
+ deallocate_ACL_vector(aclptr);
339
+ free(aclptr);
340
+ }
341
+
342
+ VALUE output = rb_ary_new();
343
+ rb_ary_push(output, INT2FIX(rc));
344
+ if (IS_SYNC(call_type) && rc == ZOK) {
345
+ return rb_ary_push(output, rb_str_new2(realpath));
346
+ }
347
+ return output;
348
+ }
349
+
350
+ static VALUE method_delete(VALUE self, VALUE reqid, VALUE path, VALUE version, VALUE async) {
351
+ VALUE watch = Qfalse;
352
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
353
+ Check_Type(version, T_FIXNUM);
354
+
355
+ int rc = 0;
356
+ switch (call_type) {
357
+ case SYNC:
358
+ rc = zkrb_call_zoo_delete(zk->zh, RSTRING_PTR(path), FIX2INT(version));
359
+ break;
360
+ case ASYNC:
361
+ rc = zkrb_call_zoo_adelete(zk->zh, RSTRING_PTR(path), FIX2INT(version), zkrb_void_callback, data_ctx);
362
+ break;
363
+ default:
364
+ /* TODO(wickman) raise proper argument error */
365
+ return Qnil;
366
+ break;
367
+ }
368
+
369
+ return INT2FIX(rc);
370
+ }
371
+
372
+ #define MAX_ZNODE_SIZE 1048576
373
+
374
+ static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
375
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
376
+
377
+ /* ugh */
378
+ char * data = malloc(MAX_ZNODE_SIZE);
379
+ int data_len = MAX_ZNODE_SIZE;
380
+ struct Stat stat;
381
+
382
+ int rc;
383
+
384
+ switch (call_type) {
385
+ case SYNC:
386
+ rc = zkrb_call_zoo_get(zk->zh, RSTRING_PTR(path), 0, data, &data_len, &stat);
387
+ break;
388
+
389
+ case SYNC_WATCH:
390
+ rc = zkrb_call_zoo_wget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, data, &data_len, &stat);
391
+ break;
392
+
393
+ case ASYNC:
394
+ rc = zkrb_call_zoo_aget(zk->zh, RSTRING_PTR(path), 0, zkrb_data_callback, data_ctx);
395
+ break;
396
+
397
+ case ASYNC_WATCH:
398
+ rc = zkrb_call_zoo_awget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_data_callback, data_ctx);
399
+ break;
400
+ }
401
+
402
+ VALUE output = rb_ary_new();
403
+ rb_ary_push(output, INT2FIX(rc));
404
+ if (IS_SYNC(call_type) && rc == ZOK) {
405
+ if (data_len == -1)
406
+ rb_ary_push(output, Qnil); /* No data associated with path */
407
+ else
408
+ rb_ary_push(output, rb_str_new(data, data_len));
409
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
410
+ }
411
+ free(data);
412
+
413
+ return output;
414
+ }
415
+
416
+ static VALUE method_set(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE version) {
417
+ VALUE watch = Qfalse;
418
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
419
+
420
+ struct Stat stat;
421
+ if (data != Qnil) Check_Type(data, T_STRING);
422
+ const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
423
+ size_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
424
+
425
+ int rc;
426
+ switch (call_type) {
427
+ case SYNC:
428
+ rc = zkrb_call_zoo_set2(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version), &stat);
429
+ break;
430
+ case ASYNC:
431
+ rc = zkrb_call_zoo_aset(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version),
432
+ zkrb_stat_callback, data_ctx);
433
+ break;
434
+ default:
435
+ /* TODO(wickman) raise proper argument error */
436
+ return Qnil;
437
+ break;
438
+ }
439
+
440
+ VALUE output = rb_ary_new();
441
+ rb_ary_push(output, INT2FIX(rc));
442
+ if (IS_SYNC(call_type) && rc == ZOK) {
443
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
444
+ }
445
+ return output;
446
+ }
447
+
448
+ static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VALUE async, VALUE version) {
449
+ VALUE watch = Qfalse;
450
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
451
+ struct ACL_vector * aclptr = zkrb_ruby_to_aclvector(acls);
452
+
453
+ int rc;
454
+ switch (call_type) {
455
+ case SYNC:
456
+ rc = zkrb_call_zoo_set_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr);
457
+ break;
458
+ case ASYNC:
459
+ rc = zkrb_call_zoo_aset_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr, zkrb_void_callback, data_ctx);
460
+ break;
461
+ default:
462
+ /* TODO(wickman) raise proper argument error */
463
+ return Qnil;
464
+ break;
465
+ }
466
+
467
+ deallocate_ACL_vector(aclptr);
468
+ free(aclptr);
469
+
470
+ return INT2FIX(rc);
471
+ }
472
+
473
+ static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
474
+ VALUE watch = Qfalse;
475
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
476
+
477
+ struct ACL_vector acls;
478
+ struct Stat stat;
479
+
480
+ int rc;
481
+ switch (call_type) {
482
+ case SYNC:
483
+ rc = zkrb_call_zoo_get_acl(zk->zh, RSTRING_PTR(path), &acls, &stat);
484
+ break;
485
+ case ASYNC:
486
+ rc = zkrb_call_zoo_aget_acl(zk->zh, RSTRING_PTR(path), zkrb_acl_callback, data_ctx);
487
+ break;
488
+ default:
489
+ /* TODO(wickman) raise proper argument error */
490
+ return Qnil;
491
+ break;
492
+ }
493
+
494
+ VALUE output = rb_ary_new();
495
+ rb_ary_push(output, INT2FIX(rc));
496
+ if (IS_SYNC(call_type) && rc == ZOK) {
497
+ rb_ary_push(output, zkrb_acl_vector_to_ruby(&acls));
498
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
499
+ deallocate_ACL_vector(&acls);
500
+ }
501
+ return output;
502
+ }
503
+
504
+ #define is_running(self) RTEST(rb_iv_get(self, "@_running"))
505
+ #define is_closed(self) RTEST(rb_iv_get(self, "@_closed"))
506
+ #define is_shutting_down(self) RTEST(rb_iv_get(self, "@_shutting_down"))
507
+
508
+ static VALUE method_get_next_event(VALUE self, VALUE blocking) {
509
+ // dbg.h
510
+ check_debug(!is_closed(self), "we are closed, not trying to get event");
511
+
512
+ char buf[64];
513
+ FETCH_DATA_PTR(self, zk);
514
+
515
+ for (;;) {
516
+ check_debug(!is_closed(self), "we're closed in the middle of method_get_next_event, bailing");
517
+
518
+ zkrb_event_t *event = zkrb_dequeue(zk->queue, 1);
519
+
520
+ /* Wait for an event using rb_thread_select() on the queue's pipe */
521
+ if (event == NULL) {
522
+ if (NIL_P(blocking) || (blocking == Qfalse)) {
523
+ goto error;
524
+ }
525
+ else {
526
+ // if we're shutting down, don't enter this section, we don't want to block
527
+ check_debug(!is_shutting_down(self), "method_get_next_event, we're shutting down, don't enter blocking section");
528
+
529
+ int fd = zk->queue->pipe_read;
530
+ ssize_t bytes_read = 0;
531
+
532
+ // wait for an fd to become readable, opposite of rb_thread_fd_writable
533
+ rb_thread_wait_fd(fd);
534
+
535
+ // clear all bytes here, we'll catch all the events on subsequent calls
536
+ // (until we run out of events)
537
+ bytes_read = read(fd, buf, sizeof(buf));
538
+
539
+ if (bytes_read == -1) {
540
+ rb_raise(rb_eRuntimeError, "read failed: %d", errno);
541
+ }
542
+
543
+ zkrb_debug_inst(self, "read %zd bytes from the queue (%p)'s pipe", bytes_read, zk->queue);
544
+
545
+ continue;
546
+ }
547
+ }
548
+
549
+ VALUE hash = zkrb_event_to_ruby(event);
550
+ zkrb_event_free(event);
551
+ return hash;
552
+ }
553
+
554
+ error:
555
+ return Qnil;
556
+ }
557
+
558
+ static VALUE method_has_events(VALUE self) {
559
+ VALUE rb_event;
560
+ FETCH_DATA_PTR(self, zk);
561
+
562
+ rb_event = zkrb_peek(zk->queue) != NULL ? Qtrue : Qfalse;
563
+ return rb_event;
564
+ }
565
+
566
+
567
+ // wake up the event loop, used when shutting down
568
+ static VALUE method_wake_event_loop_bang(VALUE self) {
569
+ FETCH_DATA_PTR(self, zk);
570
+
571
+ zkrb_debug_inst(self, "Waking event loop: %p", zk->queue);
572
+ zkrb_signal(zk->queue);
573
+
574
+ return Qnil;
575
+ };
576
+
577
+ static VALUE method_close_handle(VALUE self) {
578
+ FETCH_DATA_PTR(self, zk);
579
+
580
+ if (ZKRBDebugging) {
581
+ /* fprintf(stderr, "CLOSING ZK INSTANCE: obj_id %lx", FIX2LONG(rb_obj_id(self)));*/
582
+ zkrb_debug_inst(self, "CLOSING_ZK_INSTANCE");
583
+ print_zkrb_instance_data(zk);
584
+ }
585
+
586
+ // this is a value on the ruby side we can check to see if destroy_zkrb_instance
587
+ // has been called
588
+ rb_iv_set(self, "@_closed", Qtrue);
589
+
590
+ zkrb_debug_inst(self, "calling destroy_zkrb_instance");
591
+
592
+ /* Note that after zookeeper_close() returns, ZK handle is invalid */
593
+ int rc = destroy_zkrb_instance(zk);
594
+
595
+ zkrb_debug("destroy_zkrb_instance returned: %d", rc);
596
+
597
+ return Qnil;
598
+ /* return INT2FIX(rc);*/
599
+ }
600
+
601
+ static VALUE method_deterministic_conn_order(VALUE self, VALUE yn) {
602
+ zoo_deterministic_conn_order(yn == Qtrue);
603
+ return Qnil;
604
+ }
605
+
606
+ static VALUE method_is_unrecoverable(VALUE self) {
607
+ FETCH_DATA_PTR(self, zk);
608
+ return is_unrecoverable(zk->zh) == ZINVALIDSTATE ? Qtrue : Qfalse;
609
+ }
610
+
611
+ static VALUE method_zkrb_state(VALUE self) {
612
+ FETCH_DATA_PTR(self, zk);
613
+ return INT2NUM(zoo_state(zk->zh));
614
+ }
615
+
616
+ static VALUE method_recv_timeout(VALUE self) {
617
+ FETCH_DATA_PTR(self, zk);
618
+ return INT2NUM(zoo_recv_timeout(zk->zh));
619
+ }
620
+
621
+ /*static VALUE method_client_id(VALUE self) {*/
622
+ /* FETCH_DATA_PTR(self, zk);*/
623
+ /* const clientid_t *id = zoo_client_id(zk->zh);*/
624
+ /* return UINT2NUM(id->client_id);*/
625
+ /*}*/
626
+
627
+
628
+ // returns a CZookeeper::ClientId object with the values set for session_id and passwd
629
+ static VALUE method_client_id(VALUE self) {
630
+ FETCH_DATA_PTR(self, zk);
631
+ const clientid_t *cid = zoo_client_id(zk->zh);
632
+
633
+ VALUE session_id = LL2NUM(cid->client_id);
634
+ VALUE passwd = rb_str_new2(cid->passwd);
635
+
636
+ VALUE client_id_obj = rb_class_new_instance(0, RARRAY_PTR(rb_ary_new()), ZookeeperClientId);
637
+
638
+ rb_funcall(client_id_obj, rb_intern("session_id="), 1, session_id);
639
+ rb_funcall(client_id_obj, rb_intern("passwd="), 1, passwd);
640
+
641
+ return client_id_obj;
642
+ }
643
+
644
+ static VALUE klass_method_zkrb_set_debug_level(VALUE klass, VALUE level) {
645
+ Check_Type(level, T_FIXNUM);
646
+ ZKRBDebugging = (FIX2INT(level) == ZOO_LOG_LEVEL_DEBUG);
647
+ zoo_set_debug_level(FIX2INT(level));
648
+ return Qnil;
649
+ }
650
+
651
+ static VALUE method_zerror(VALUE self, VALUE errc) {
652
+ return rb_str_new2(zerror(FIX2INT(errc)));
653
+ }
654
+
655
+ static void zkrb_define_methods(void) {
656
+ #define DEFINE_METHOD(method, args) { \
657
+ rb_define_method(Zookeeper, #method, method_ ## method, args); }
658
+ #define DEFINE_CLASS_METHOD(method, args) { \
659
+ rb_define_singleton_method(Zookeeper, #method, method_ ## method, args); }
660
+
661
+ // the number after the method name should be actual arity of C function - 1
662
+ DEFINE_METHOD(zkrb_init, -1);
663
+ DEFINE_METHOD(get_children, 4);
664
+ DEFINE_METHOD(exists, 4);
665
+ DEFINE_METHOD(create, 6);
666
+ DEFINE_METHOD(delete, 4);
667
+ DEFINE_METHOD(get, 4);
668
+ DEFINE_METHOD(set, 5);
669
+ DEFINE_METHOD(set_acl, 5);
670
+ DEFINE_METHOD(get_acl, 3);
671
+ DEFINE_METHOD(client_id, 0);
672
+ DEFINE_METHOD(close_handle, 0);
673
+ DEFINE_METHOD(deterministic_conn_order, 1);
674
+ DEFINE_METHOD(is_unrecoverable, 0);
675
+ DEFINE_METHOD(recv_timeout, 1);
676
+ DEFINE_METHOD(zkrb_state, 0);
677
+ DEFINE_METHOD(sync, 2);
678
+
679
+ // TODO
680
+ // DEFINE_METHOD(add_auth, 3);
681
+
682
+ // methods for the ruby-side event manager
683
+ DEFINE_METHOD(get_next_event, 1);
684
+ DEFINE_METHOD(has_events, 0);
685
+
686
+ // Make these class methods?
687
+ DEFINE_METHOD(zerror, 1);
688
+
689
+ rb_define_singleton_method(Zookeeper, "set_zkrb_debug_level", klass_method_zkrb_set_debug_level, 1);
690
+
691
+ rb_attr(Zookeeper, rb_intern("selectable_io"), 1, 0, Qtrue);
692
+ rb_define_method(Zookeeper, "wake_event_loop!", method_wake_event_loop_bang, 0);
693
+
694
+ }
695
+
696
+ // class CZookeeper::ClientId
697
+ // attr_accessor :session_id, :passwd
698
+ //
699
+ // def initialize(session_id, passwd)
700
+ // @session_id = session_id
701
+ // @passwd = passwd
702
+ // end
703
+ // end
704
+
705
+ static VALUE zkrb_client_id_method_initialize(VALUE self) {
706
+ rb_iv_set(self, "@session_id", Qnil);
707
+ rb_iv_set(self, "@passwd", Qnil);
708
+ return Qnil;
709
+ }
710
+
711
+
712
+ void Init_zookeeper_c() {
713
+ ZKRBDebugging = 0;
714
+
715
+ /* initialize Zookeeper class */
716
+ Zookeeper = rb_define_class("CZookeeper", rb_cObject);
717
+ zkrb_define_methods();
718
+
719
+ ZookeeperClientId = rb_define_class_under(Zookeeper, "ClientId", rb_cObject);
720
+ rb_define_method(ZookeeperClientId, "initialize", zkrb_client_id_method_initialize, 0);
721
+ rb_define_attr(ZookeeperClientId, "session_id", 1, 1);
722
+ rb_define_attr(ZookeeperClientId, "passwd", 1, 1);
723
+ }
724
+
725
+ // vim:ts=2:sw=2:sts=2:et