zookeeper 0.9.3-java

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