zookeeper-ng 1.5.2.1-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 (86) hide show
  1. checksums.yaml +7 -0
  2. data/.ctags_paths +1 -0
  3. data/.dotfiles/ruby-gemset +1 -0
  4. data/.dotfiles/ruby-version +1 -0
  5. data/.dotfiles/rvmrc +2 -0
  6. data/.github/workflows/build.yml +57 -0
  7. data/.gitignore +19 -0
  8. data/.gitmodules +3 -0
  9. data/CHANGELOG +408 -0
  10. data/Gemfile +30 -0
  11. data/Guardfile +8 -0
  12. data/LICENSE +23 -0
  13. data/Manifest +29 -0
  14. data/README.markdown +62 -0
  15. data/Rakefile +121 -0
  16. data/cause-abort.rb +117 -0
  17. data/ext/.gitignore +6 -0
  18. data/ext/Rakefile +41 -0
  19. data/ext/c_zookeeper.rb +398 -0
  20. data/ext/common.h +17 -0
  21. data/ext/dbg.h +53 -0
  22. data/ext/depend +5 -0
  23. data/ext/event_lib.c +740 -0
  24. data/ext/event_lib.h +175 -0
  25. data/ext/extconf.rb +103 -0
  26. data/ext/generate_gvl_code.rb +321 -0
  27. data/ext/patches/zkc-3.3.5-network.patch +24 -0
  28. data/ext/patches/zkc-3.4.5-buffer-overflow.patch +11 -0
  29. data/ext/patches/zkc-3.4.5-config.patch +5454 -0
  30. data/ext/patches/zkc-3.4.5-fetch-and-add.patch +16 -0
  31. data/ext/patches/zkc-3.4.5-logging.patch +41 -0
  32. data/ext/patches/zkc-3.4.5-out-of-order-ping.patch +163 -0
  33. data/ext/patches/zkc-3.4.5-yosemite-htonl-fix.patch +102 -0
  34. data/ext/zkc-3.4.5.tar.gz +0 -0
  35. data/ext/zkrb.c +1080 -0
  36. data/ext/zkrb_wrapper.c +775 -0
  37. data/ext/zkrb_wrapper.h +350 -0
  38. data/ext/zkrb_wrapper_compat.c +15 -0
  39. data/ext/zkrb_wrapper_compat.h +11 -0
  40. data/ext/zookeeper_base.rb +256 -0
  41. data/java/java_base.rb +501 -0
  42. data/lib/zookeeper/acls.rb +44 -0
  43. data/lib/zookeeper/callbacks.rb +108 -0
  44. data/lib/zookeeper/client.rb +30 -0
  45. data/lib/zookeeper/client_methods.rb +282 -0
  46. data/lib/zookeeper/common/queue_with_pipe.rb +110 -0
  47. data/lib/zookeeper/common.rb +122 -0
  48. data/lib/zookeeper/compatibility.rb +138 -0
  49. data/lib/zookeeper/constants.rb +97 -0
  50. data/lib/zookeeper/continuation.rb +223 -0
  51. data/lib/zookeeper/core_ext.rb +58 -0
  52. data/lib/zookeeper/em_client.rb +55 -0
  53. data/lib/zookeeper/exceptions.rb +135 -0
  54. data/lib/zookeeper/forked.rb +19 -0
  55. data/lib/zookeeper/latch.rb +34 -0
  56. data/lib/zookeeper/logger/forwarding_logger.rb +84 -0
  57. data/lib/zookeeper/logger.rb +39 -0
  58. data/lib/zookeeper/monitor.rb +19 -0
  59. data/lib/zookeeper/rake_tasks.rb +165 -0
  60. data/lib/zookeeper/request_registry.rb +153 -0
  61. data/lib/zookeeper/stat.rb +21 -0
  62. data/lib/zookeeper/version.rb +4 -0
  63. data/lib/zookeeper.rb +115 -0
  64. data/notes.txt +14 -0
  65. data/scripts/upgrade-1.0-sed-alike.rb +46 -0
  66. data/spec/c_zookeeper_spec.rb +51 -0
  67. data/spec/chrooted_connection_spec.rb +83 -0
  68. data/spec/compatibilty_spec.rb +8 -0
  69. data/spec/default_watcher_spec.rb +41 -0
  70. data/spec/em_spec.rb +51 -0
  71. data/spec/ext/zookeeper_base_spec.rb +19 -0
  72. data/spec/forked_connection_spec.rb +122 -0
  73. data/spec/latch_spec.rb +24 -0
  74. data/spec/log4j.properties +17 -0
  75. data/spec/shared/all_success_return_values.rb +10 -0
  76. data/spec/shared/connection_examples.rb +1081 -0
  77. data/spec/spec_helper.rb +61 -0
  78. data/spec/support/00_logging.rb +38 -0
  79. data/spec/support/10_spawn_zookeeper.rb +20 -0
  80. data/spec/support/progress_formatter.rb +15 -0
  81. data/spec/support/zookeeper_spec_helpers.rb +96 -0
  82. data/spec/zookeeper_spec.rb +24 -0
  83. data/zookeeper.gemspec +46 -0
  84. data/zoomonkey/duplicates +3 -0
  85. data/zoomonkey/zoomonkey.rb +194 -0
  86. metadata +185 -0
data/ext/zkrb.c ADDED
@@ -0,0 +1,1080 @@
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
+ * (slyphon)
14
+ *
15
+ * Wickman's implementation was linked against the 'mt' version of the zookeeper
16
+ * library, which is multithreaded at the zookeeper level and is subsequently
17
+ * much more difficult to get to behave properly with the ruby runtime (which
18
+ * he did, and I could never have written).
19
+ *
20
+ * The current implementation has been converted to use the 'st' version of the
21
+ * zookeeper library, which is single threaded and requires a ruby-side event
22
+ * loop. This is essentially a ruby port of the code running in the 'mt'
23
+ * library, with one important difference: It's running in ruby-land. The
24
+ * reason this change is so important is that it's virtually impossible to
25
+ * provide a fork-safe library when you have native threads you don't own
26
+ * running around. If you fork when a thread holds a mutex, and that thread
27
+ * is not the fork-caller, that mutex can never be unlocked, and is therefore
28
+ * a ticking time-bomb in the child. The only way to guarantee safety is to
29
+ * either replace all of your mutexes and conditions and such after a fork
30
+ * (which is what we do on the ruby side), or avoid the problem altogether
31
+ * and not use a multithreaded library on the backend. Since we can't replace
32
+ * mutexes in the zookeeper code, we opt for the latter solution.
33
+ *
34
+ * The ruby code runs the event loop in a thread that will never cause a fork()
35
+ * to occur. This way, when fork() is called, the event thread will be dead
36
+ * in the child, guaranteeing that the child can safely be cleaned up.
37
+ *
38
+ * In that cleanup, there is a nasty (and brutishly effective) hack that makes
39
+ * the fork case work. We keep track of the pid that allocated the
40
+ * zkrb_instance_data_t, and if at destruction time we see that a fork has
41
+ * happened, we reach inside the zookeeper handle (zk->zh), and close the
42
+ * open socket it's got before calling zookeeper_close. This prevents
43
+ * corruption of the client/server state. Without this code, zookeeper_close
44
+ * in the child would actually send an "Ok, we're closing" message with the
45
+ * parent's session id, causing the parent to hit an assert() case in
46
+ * zookeeper_process, and cause a SIGABRT. With this code in place, we get back
47
+ * a ZCONNECTIONLOSS from zookeeper_close in the child (which we ignore), and
48
+ * the parent continues on.
49
+ *
50
+ * You will notice below we undef 'THREADED', which would be set if we were
51
+ * using the 'mt' library. We also conditionally include additional cases
52
+ * ('SYNC', 'SYNC_WATCH') inside of some of the methods defined here. These
53
+ * would be valid when running the 'mt' library, but since we have a ruby layer
54
+ * to provide a sync front-end to an async backend, these cases should never be
55
+ * hit, and instead will raise exceptions.
56
+ *
57
+ * NOTE: This file depends on exception classes defined in lib/zookeeper/exceptions.rb
58
+ *
59
+ * -------
60
+ *
61
+ * @rectalogic: any time you create a ruby value in C, and so there are no
62
+ * references to it in the VM except for your variable, and you then call into
63
+ * the VM (allowing a GC), and your reference is on the stack, then it needs to
64
+ * be volatile
65
+ *
66
+ */
67
+
68
+ #include "ruby.h"
69
+
70
+ #ifdef ZKRB_RUBY_187
71
+ #include "rubyio.h"
72
+ #else
73
+ #include "ruby/io.h"
74
+ #endif
75
+
76
+ #ifndef HAVE_RB_THREAD_FD_SELECT
77
+ #define rb_fdset_t fd_set
78
+ #define rb_fd_isset(n, f) FD_ISSET(n, f)
79
+ #define rb_fd_init(f) FD_ZERO(f)
80
+ #define rb_fd_zero(f) FD_ZERO(f)
81
+ #define rb_fd_set(n, f) FD_SET(n, f)
82
+ #define rb_fd_clr(n, f) FD_CLR(n, f)
83
+ #define rb_fd_term(f)
84
+ #define rb_thread_fd_select rb_thread_select
85
+ #endif
86
+
87
+ #include "zookeeper/zookeeper.h"
88
+ #include <errno.h>
89
+ #include <stdio.h>
90
+ #include <stdlib.h>
91
+ #include <unistd.h>
92
+ #include <sys/fcntl.h>
93
+ #include <pthread.h>
94
+ #include <inttypes.h>
95
+ #include <time.h>
96
+ #include <arpa/inet.h>
97
+ #include <netinet/in.h>
98
+
99
+ #include "common.h"
100
+ #include "event_lib.h"
101
+ #include "zkrb_wrapper.h"
102
+ #include "dbg.h"
103
+
104
+ static VALUE mZookeeper = Qnil; // the Zookeeper module
105
+ static VALUE CZookeeper = Qnil; // the Zookeeper::CZookeeper class
106
+ static VALUE ZookeeperClientId = Qnil;
107
+ static VALUE mZookeeperExceptions = Qnil; // the Zookeeper::Exceptions module
108
+ static VALUE eHandleClosedException = Qnil; // raised when we don't have a valid handle in FETCH_DATA_PTR
109
+
110
+ // slyphon: possibly add a lock to this for synchronizing during get_next_event
111
+
112
+ struct zkrb_instance_data {
113
+ zhandle_t *zh;
114
+ clientid_t myid;
115
+ zkrb_queue_t *queue;
116
+ long object_id; // the ruby object this instance data is associated with
117
+ pid_t orig_pid;
118
+ };
119
+
120
+ typedef struct zkrb_instance_data zkrb_instance_data_t;
121
+
122
+ typedef enum {
123
+ SYNC = 0,
124
+ ASYNC = 1,
125
+ SYNC_WATCH = 2,
126
+ ASYNC_WATCH = 3
127
+ } zkrb_call_type;
128
+
129
+ inline static const char* call_type_to_str(zkrb_call_type ct) {
130
+ const char *rv = NULL;
131
+ switch (ct) {
132
+ case SYNC:
133
+ rv="SYNC";
134
+ break;
135
+ case ASYNC:
136
+ rv="ASYNC";
137
+ break;
138
+ case SYNC_WATCH:
139
+ rv="SYNC_WATCH";
140
+ break;
141
+ case ASYNC_WATCH:
142
+ rv="ASYNC_WATCH";
143
+ break;
144
+ }
145
+ return rv;
146
+ }
147
+
148
+ inline static void assert_valid_params(VALUE reqid, VALUE path) {
149
+ switch (TYPE(reqid)) {
150
+ case T_FIXNUM:
151
+ case T_BIGNUM:
152
+ break;
153
+ default:
154
+ rb_raise(rb_eTypeError, "reqid must be Fixnum/Bignum");
155
+ }
156
+
157
+ Check_Type(path, T_STRING);
158
+ }
159
+
160
+ inline static zkrb_call_type get_call_type(VALUE async, VALUE watch) {
161
+ if (RTEST(async)) {
162
+ return RTEST(watch) ? ASYNC_WATCH : ASYNC;
163
+ } else {
164
+ return RTEST(watch) ? SYNC_WATCH : SYNC;
165
+ }
166
+ }
167
+
168
+ inline static void raise_invalid_call_type_err(zkrb_call_type call_type) {
169
+ rb_raise(rb_eRuntimeError, "hit the default case, call_type: %s", call_type_to_str(call_type));
170
+ }
171
+
172
+ #define IS_SYNC(zkrbcall) ((zkrbcall)==SYNC || (zkrbcall)==SYNC_WATCH)
173
+ #define IS_ASYNC(zkrbcall) ((zkrbcall)==ASYNC || (zkrbcall)==ASYNC_WATCH)
174
+
175
+ #define FETCH_DATA_PTR(SELF, ZK) \
176
+ zkrb_instance_data_t * ZK; \
177
+ Data_Get_Struct(rb_iv_get(SELF, "@_data"), zkrb_instance_data_t, ZK); \
178
+ if ((ZK)->zh == NULL) \
179
+ rb_raise(eHandleClosedException, "zookeeper handle is closed")
180
+
181
+ #define STANDARD_PREAMBLE(SELF, ZK, REQID, PATH, ASYNC, WATCH, CALL_TYPE) \
182
+ assert_valid_params(REQID, PATH); \
183
+ FETCH_DATA_PTR(SELF, ZK); \
184
+ zkrb_call_type CALL_TYPE = get_call_type(ASYNC, WATCH); \
185
+
186
+ #define CTX_ALLOC(ZK,REQID) zkrb_calling_context_alloc(NUM2LL(REQID), ZK->queue)
187
+
188
+ static void hexbufify(char *dest, const char *src, int len) {
189
+ int i=0;
190
+
191
+ for (i=0; i < len; i++) {
192
+ sprintf(&dest[i*2], "%x", src[i]);
193
+ }
194
+ }
195
+
196
+ inline static int we_are_forked(zkrb_instance_data_t *zk) {
197
+ int rv=0;
198
+
199
+ if ((!!zk) && (zk->orig_pid != getpid())) {
200
+ rv=1;
201
+ }
202
+
203
+ return rv;
204
+ }
205
+
206
+ static int destroy_zkrb_instance(zkrb_instance_data_t* zk) {
207
+ int rv = ZOK;
208
+
209
+ zkrb_debug("destroy_zkrb_instance, zk_local_ctx: %p, zh: %p, queue: %p", zk, zk->zh, zk->queue);
210
+
211
+ if (zk->zh) {
212
+ const void *ctx = zoo_get_context(zk->zh);
213
+ /* Note that after zookeeper_close() returns, ZK handle is invalid */
214
+ zkrb_debug("obj_id: %lx, calling zookeeper_close", zk->object_id);
215
+
216
+ if (we_are_forked(zk)) {
217
+ zkrb_debug("FORK DETECTED! orig_pid: %d, current pid: %d, "
218
+ "using socket-closing hack before zookeeper_close", zk->orig_pid, getpid());
219
+
220
+ int fd = ((int *)zk->zh)[0]; // nasty, brutish, and wonderfully effective hack (see above)
221
+ close(fd);
222
+
223
+ }
224
+
225
+ rv = zookeeper_close(zk->zh);
226
+
227
+ zkrb_debug("obj_id: %lx, zookeeper_close returned %d, calling context: %p", zk->object_id, rv, ctx);
228
+ zkrb_calling_context_free((zkrb_calling_context *) ctx);
229
+ }
230
+
231
+ zk->zh = NULL;
232
+
233
+ if (zk->queue) {
234
+ zkrb_debug("obj_id: %lx, freeing queue pointer: %p", zk->object_id, zk->queue);
235
+ zkrb_queue_free(zk->queue);
236
+ }
237
+
238
+ zk->queue = NULL;
239
+
240
+ return rv;
241
+ }
242
+
243
+ static void free_zkrb_instance_data(zkrb_instance_data_t* ptr) {
244
+ destroy_zkrb_instance(ptr);
245
+ }
246
+
247
+ VALUE alloc_zkrb_instance(VALUE klass) {
248
+ zkrb_instance_data_t* zk = ZALLOC_N(zkrb_instance_data_t, 1);
249
+ return Data_Wrap_Struct(klass, NULL, free_zkrb_instance_data, zk);
250
+ }
251
+
252
+ static void print_zkrb_instance_data(zkrb_instance_data_t* ptr) {
253
+ fprintf(stderr, "zkrb_instance_data (%p) {\n", ptr);
254
+ fprintf(stderr, " zh = %p\n", ptr->zh);
255
+ fprintf(stderr, " { state = %d }\n", zoo_state(ptr->zh));
256
+ fprintf(stderr, " id = %"PRId64"\n", ptr->myid.client_id); // PRId64 defined in inttypes.h
257
+ fprintf(stderr, " q = %p\n", ptr->queue);
258
+ fprintf(stderr, " obj_id = %lx\n", ptr->object_id);
259
+ fprintf(stderr, "}\n");
260
+ }
261
+
262
+ #define receive_timeout_msec(self) rb_iv_get(self, "@_receive_timeout_msec")
263
+
264
+ inline static void zkrb_debug_clientid_t(const clientid_t *cid) {
265
+ int pass_len = sizeof(cid->passwd);
266
+ int hex_len = 2 * pass_len + 1;
267
+ char buf[hex_len];
268
+ hexbufify(buf, cid->passwd, pass_len);
269
+
270
+ zkrb_debug("myid, client_id: %"PRId64", passwd: %*s", cid->client_id, hex_len, buf);
271
+ }
272
+
273
+ static VALUE method_zkrb_init(int argc, VALUE* argv, VALUE self) {
274
+ VALUE hostPort=Qnil;
275
+ VALUE options=Qnil;
276
+
277
+ rb_scan_args(argc, argv, "11", &hostPort, &options);
278
+
279
+ if (NIL_P(options)) {
280
+ options = rb_hash_new();
281
+ } else {
282
+ Check_Type(options, T_HASH);
283
+ }
284
+
285
+ Check_Type(hostPort, T_STRING);
286
+
287
+ // Look up :zkc_log_level
288
+ // VALUE log_level = rb_hash_aref(options, ID2SYM(rb_intern("zkc_log_level")));
289
+ // if (NIL_P(log_level)) {
290
+ // zoo_set_debug_level(0); // no log messages
291
+ // } else {
292
+ // Check_Type(log_level, T_FIXNUM);
293
+ // zoo_set_debug_level(FIX2INT(log_level));
294
+ // }
295
+
296
+ volatile VALUE data;
297
+ zkrb_instance_data_t *zk_local_ctx;
298
+ data = Data_Make_Struct(CZookeeper, zkrb_instance_data_t, 0, free_zkrb_instance_data, zk_local_ctx);
299
+
300
+ // Look up :session_id and :session_passwd
301
+ VALUE session_id = rb_hash_aref(options, ID2SYM(rb_intern("session_id")));
302
+ VALUE password = rb_hash_aref(options, ID2SYM(rb_intern("session_passwd")));
303
+ if (!NIL_P(session_id) && !NIL_P(password)) {
304
+ Check_Type(password, T_STRING);
305
+
306
+ zk_local_ctx->myid.client_id = NUM2LL(session_id);
307
+ strncpy(zk_local_ctx->myid.passwd, RSTRING_PTR(password), 16);
308
+ }
309
+
310
+ zk_local_ctx->queue = zkrb_queue_alloc();
311
+
312
+ if (zk_local_ctx->queue == NULL)
313
+ rb_raise(rb_eRuntimeError, "could not allocate zkrb queue!");
314
+
315
+ zoo_deterministic_conn_order(0);
316
+
317
+ zkrb_calling_context *ctx =
318
+ zkrb_calling_context_alloc(ZKRB_GLOBAL_REQ, zk_local_ctx->queue);
319
+
320
+ zk_local_ctx->object_id = FIX2LONG(rb_obj_id(self));
321
+
322
+ zk_local_ctx->zh =
323
+ zookeeper_init(
324
+ RSTRING_PTR(hostPort), // const char *host
325
+ zkrb_state_callback, // watcher_fn
326
+ receive_timeout_msec(self), // recv_timeout
327
+ &zk_local_ctx->myid, // cilentid_t
328
+ ctx, // void *context
329
+ 0); // flags
330
+
331
+ zkrb_debug("method_zkrb_init, zk_local_ctx: %p, zh: %p, queue: %p, calling_ctx: %p",
332
+ zk_local_ctx, zk_local_ctx->zh, zk_local_ctx->queue, ctx);
333
+
334
+ if (!zk_local_ctx->zh) {
335
+ rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
336
+ }
337
+
338
+ zk_local_ctx->orig_pid = getpid();
339
+
340
+ rb_iv_set(self, "@_data", data);
341
+ rb_funcall(self, rb_intern("zkc_set_running_and_notify!"), 0);
342
+
343
+ return Qnil;
344
+ }
345
+
346
+ static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
347
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, call_type);
348
+
349
+ VALUE output = Qnil;
350
+ struct String_vector strings;
351
+ struct Stat stat;
352
+
353
+ int rc = 0;
354
+ switch (call_type) {
355
+
356
+ #ifdef THREADED
357
+ case SYNC:
358
+ rc = zkrb_call_zoo_get_children2(
359
+ zk->zh, RSTRING_PTR(path), 0, &strings, &stat);
360
+ break;
361
+
362
+ case SYNC_WATCH:
363
+ rc = zkrb_call_zoo_wget_children2(
364
+ zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), &strings, &stat);
365
+ break;
366
+ #endif
367
+
368
+ case ASYNC:
369
+ rc = zkrb_call_zoo_aget_children2(
370
+ zk->zh, RSTRING_PTR(path), 0, zkrb_strings_stat_callback, CTX_ALLOC(zk, reqid));
371
+ break;
372
+
373
+ case ASYNC_WATCH:
374
+ rc = zkrb_call_zoo_awget_children2(
375
+ zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), zkrb_strings_stat_callback, CTX_ALLOC(zk, reqid));
376
+ break;
377
+
378
+ default:
379
+ raise_invalid_call_type_err(call_type);
380
+ break;
381
+ }
382
+
383
+ output = rb_ary_new();
384
+ rb_ary_push(output, INT2FIX(rc));
385
+ if (IS_SYNC(call_type) && rc == ZOK) {
386
+ rb_ary_push(output, zkrb_string_vector_to_ruby(&strings));
387
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
388
+ }
389
+ return output;
390
+ }
391
+
392
+ static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
393
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, call_type);
394
+
395
+ VALUE output = Qnil;
396
+ struct Stat stat;
397
+
398
+ int rc = 0;
399
+ switch (call_type) {
400
+
401
+ #ifdef THREADED
402
+ case SYNC:
403
+ rc = zkrb_call_zoo_exists(zk->zh, RSTRING_PTR(path), 0, &stat);
404
+ break;
405
+
406
+ case SYNC_WATCH:
407
+ rc = zkrb_call_zoo_wexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), &stat);
408
+ break;
409
+ #endif
410
+
411
+ case ASYNC:
412
+ rc = zkrb_call_zoo_aexists(zk->zh, RSTRING_PTR(path), 0, zkrb_stat_callback, CTX_ALLOC(zk, reqid));
413
+ break;
414
+
415
+ case ASYNC_WATCH:
416
+ rc = zkrb_call_zoo_awexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), zkrb_stat_callback, CTX_ALLOC(zk, reqid));
417
+ break;
418
+
419
+ default:
420
+ raise_invalid_call_type_err(call_type);
421
+ break;
422
+ }
423
+
424
+ output = rb_ary_new();
425
+ rb_ary_push(output, INT2FIX(rc));
426
+ if (IS_SYNC(call_type) && rc == ZOK) {
427
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
428
+ }
429
+ return output;
430
+ }
431
+
432
+ // this method is *only* called asynchronously
433
+ static VALUE method_sync(VALUE self, VALUE reqid, VALUE path) {
434
+ int rc = ZOK;
435
+
436
+ // don't use STANDARD_PREAMBLE here b/c we don't need to determine call_type
437
+ assert_valid_params(reqid, path);
438
+ FETCH_DATA_PTR(self, zk);
439
+
440
+ rc = zkrb_call_zoo_async(zk->zh, RSTRING_PTR(path), zkrb_string_callback, CTX_ALLOC(zk, reqid));
441
+
442
+ return INT2FIX(rc);
443
+ }
444
+
445
+ static VALUE method_add_auth(VALUE self, VALUE reqid, VALUE scheme, VALUE cert) {
446
+ int rc = ZOK;
447
+
448
+ Check_Type(scheme, T_STRING);
449
+ Check_Type(cert, T_STRING);
450
+
451
+ FETCH_DATA_PTR(self, zk);
452
+
453
+ rc = zkrb_call_zoo_add_auth(zk->zh, RSTRING_PTR(scheme), RSTRING_PTR(cert), RSTRING_LEN(cert), zkrb_void_callback, CTX_ALLOC(zk, reqid));
454
+
455
+ return INT2FIX(rc);
456
+ }
457
+
458
+
459
+ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE acls, VALUE flags) {
460
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
461
+ VALUE output = Qnil;
462
+
463
+ if (data != Qnil) Check_Type(data, T_STRING);
464
+ Check_Type(flags, T_FIXNUM);
465
+ const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
466
+ ssize_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
467
+
468
+ struct ACL_vector *aclptr = NULL;
469
+ if (acls != Qnil) { aclptr = zkrb_ruby_to_aclvector(acls); }
470
+ char realpath[16384];
471
+
472
+ int invalid_call_type=0;
473
+
474
+ int rc = 0;
475
+ switch (call_type) {
476
+
477
+ #ifdef THREADED
478
+ case SYNC:
479
+ // casting data_len to int is OK as you can only store 1MB in zookeeper
480
+ rc = zkrb_call_zoo_create(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, aclptr, FIX2INT(flags), realpath, sizeof(realpath));
481
+ break;
482
+ #endif
483
+
484
+ case ASYNC:
485
+ rc = zkrb_call_zoo_acreate(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, aclptr, FIX2INT(flags), zkrb_string_callback, CTX_ALLOC(zk, reqid));
486
+ break;
487
+
488
+ default:
489
+ invalid_call_type=1;
490
+ break;
491
+ }
492
+
493
+ if (aclptr) {
494
+ deallocate_ACL_vector(aclptr);
495
+ free(aclptr);
496
+ }
497
+
498
+ if (invalid_call_type) raise_invalid_call_type_err(call_type);
499
+
500
+ output = rb_ary_new();
501
+ rb_ary_push(output, INT2FIX(rc));
502
+ if (IS_SYNC(call_type) && rc == ZOK) {
503
+ return rb_ary_push(output, rb_str_new2(realpath));
504
+ }
505
+ return output;
506
+ }
507
+
508
+ static VALUE method_delete(VALUE self, VALUE reqid, VALUE path, VALUE version, VALUE async) {
509
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
510
+ Check_Type(version, T_FIXNUM);
511
+
512
+ int rc = 0;
513
+ switch (call_type) {
514
+
515
+ #ifdef THREADED
516
+ case SYNC:
517
+ rc = zkrb_call_zoo_delete(zk->zh, RSTRING_PTR(path), FIX2INT(version));
518
+ break;
519
+ #endif
520
+
521
+ case ASYNC:
522
+ rc = zkrb_call_zoo_adelete(zk->zh, RSTRING_PTR(path), FIX2INT(version), zkrb_void_callback, CTX_ALLOC(zk, reqid));
523
+ break;
524
+
525
+ default:
526
+ raise_invalid_call_type_err(call_type);
527
+ break;
528
+ }
529
+
530
+ return INT2FIX(rc);
531
+ }
532
+
533
+ #define MAX_ZNODE_SIZE 1048576
534
+
535
+ static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
536
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, call_type);
537
+
538
+ VALUE output = Qnil;
539
+
540
+ int data_len = MAX_ZNODE_SIZE;
541
+ struct Stat stat;
542
+
543
+ char * data = NULL;
544
+ if (IS_SYNC(call_type)) {
545
+ data = malloc(MAX_ZNODE_SIZE); /* ugh */
546
+ memset(data, 0, MAX_ZNODE_SIZE);
547
+ }
548
+
549
+ int rc, invalid_call_type=0;
550
+
551
+ switch (call_type) {
552
+
553
+ #ifdef THREADED
554
+ case SYNC:
555
+ rc = zkrb_call_zoo_get(zk->zh, RSTRING_PTR(path), 0, data, &data_len, &stat);
556
+ break;
557
+
558
+ case SYNC_WATCH:
559
+ rc = zkrb_call_zoo_wget(
560
+ zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), data, &data_len, &stat);
561
+ break;
562
+ #endif
563
+
564
+ case ASYNC:
565
+ rc = zkrb_call_zoo_aget(zk->zh, RSTRING_PTR(path), 0, zkrb_data_callback, CTX_ALLOC(zk, reqid));
566
+ break;
567
+
568
+ case ASYNC_WATCH:
569
+ // first ctx is a watch, second is the async callback
570
+ rc = zkrb_call_zoo_awget(
571
+ zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), zkrb_data_callback, CTX_ALLOC(zk, reqid));
572
+ break;
573
+
574
+ default:
575
+ invalid_call_type=1;
576
+ goto cleanup;
577
+ break;
578
+ }
579
+
580
+ output = rb_ary_new();
581
+ rb_ary_push(output, INT2FIX(rc));
582
+ if (IS_SYNC(call_type) && rc == ZOK) {
583
+ if (data_len == -1)
584
+ rb_ary_push(output, Qnil); /* No data associated with path */
585
+ else
586
+ rb_ary_push(output, rb_str_new(data, data_len));
587
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
588
+ }
589
+
590
+ cleanup:
591
+ free(data);
592
+ if (invalid_call_type) raise_invalid_call_type_err(call_type);
593
+ return output;
594
+ }
595
+
596
+ static VALUE method_set(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE version) {
597
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
598
+
599
+ VALUE output = Qnil;
600
+ struct Stat stat;
601
+
602
+ if (data != Qnil) Check_Type(data, T_STRING);
603
+
604
+ const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
605
+ ssize_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
606
+
607
+ int rc=ZOK;
608
+ switch (call_type) {
609
+
610
+ #ifdef THREADED
611
+ case SYNC:
612
+ rc = zkrb_call_zoo_set2(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version), &stat);
613
+ break;
614
+ #endif
615
+
616
+ case ASYNC:
617
+ rc = zkrb_call_zoo_aset(
618
+ zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version), zkrb_stat_callback, CTX_ALLOC(zk, reqid));
619
+ break;
620
+
621
+ default:
622
+ raise_invalid_call_type_err(call_type);
623
+ break;
624
+ }
625
+
626
+ output = rb_ary_new();
627
+ rb_ary_push(output, INT2FIX(rc));
628
+ if (IS_SYNC(call_type) && rc == ZOK) {
629
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
630
+ }
631
+ return output;
632
+ }
633
+
634
+ static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VALUE async, VALUE version) {
635
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
636
+
637
+ struct ACL_vector * aclptr = zkrb_ruby_to_aclvector(acls);
638
+
639
+ int rc=ZOK, invalid_call_type=0;
640
+ switch (call_type) {
641
+
642
+ #ifdef THREADED
643
+ case SYNC:
644
+ rc = zkrb_call_zoo_set_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr);
645
+ break;
646
+ #endif
647
+
648
+ case ASYNC:
649
+ rc = zkrb_call_zoo_aset_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr, zkrb_void_callback, CTX_ALLOC(zk, reqid));
650
+ break;
651
+
652
+ default:
653
+ invalid_call_type=1;
654
+ break;
655
+ }
656
+
657
+ deallocate_ACL_vector(aclptr);
658
+ free(aclptr);
659
+
660
+ if (invalid_call_type) raise_invalid_call_type_err(call_type);
661
+
662
+ return INT2FIX(rc);
663
+ }
664
+
665
+ static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
666
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
667
+
668
+ VALUE output = Qnil;
669
+ struct ACL_vector acls;
670
+ struct Stat stat;
671
+
672
+ int rc=ZOK;
673
+ switch (call_type) {
674
+
675
+ #ifdef THREADED
676
+ case SYNC:
677
+ rc = zkrb_call_zoo_get_acl(zk->zh, RSTRING_PTR(path), &acls, &stat);
678
+ break;
679
+ #endif
680
+
681
+ case ASYNC:
682
+ rc = zkrb_call_zoo_aget_acl(zk->zh, RSTRING_PTR(path), zkrb_acl_callback, CTX_ALLOC(zk, reqid));
683
+ break;
684
+
685
+ default:
686
+ raise_invalid_call_type_err(call_type);
687
+ break;
688
+ }
689
+
690
+ output = rb_ary_new();
691
+ rb_ary_push(output, INT2FIX(rc));
692
+ if (IS_SYNC(call_type) && rc == ZOK) {
693
+ rb_ary_push(output, zkrb_acl_vector_to_ruby(&acls));
694
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
695
+ deallocate_ACL_vector(&acls);
696
+ }
697
+ return output;
698
+ }
699
+
700
+ #define is_running(self) RTEST(rb_iv_get(self, "@_running"))
701
+ #define is_closed(self) RTEST(rb_iv_get(self, "@_closed"))
702
+ #define is_shutting_down(self) RTEST(rb_iv_get(self, "@_shutting_down"))
703
+
704
+ static VALUE method_zkrb_get_next_event(VALUE self, VALUE blocking) {
705
+ // dbg.h
706
+ check_debug(!is_closed(self), "we are closed, not trying to get event");
707
+
708
+ char buf[64];
709
+ FETCH_DATA_PTR(self, zk);
710
+
711
+ for (;;) {
712
+ check_debug(!is_closed(self), "we're closed in the middle of method_zkrb_get_next_event, bailing");
713
+
714
+ zkrb_event_t *event = zkrb_dequeue(zk->queue, 1);
715
+
716
+ if (event == NULL) {
717
+ if (NIL_P(blocking) || (blocking == Qfalse)) {
718
+ goto error;
719
+ }
720
+ else {
721
+ // if we're shutting down, don't enter this section, we don't want to block
722
+ check_debug(!is_shutting_down(self), "method_zkrb_get_next_event, we're shutting down, don't enter blocking section");
723
+
724
+ int fd = zk->queue->pipe_read;
725
+ ssize_t bytes_read = 0;
726
+
727
+ // wait for an fd to become readable, opposite of rb_thread_fd_writable
728
+ rb_thread_wait_fd(fd);
729
+
730
+ // clear all bytes here, we'll catch all the events on subsequent calls
731
+ // (until we run out of events)
732
+ bytes_read = read(fd, buf, sizeof(buf));
733
+
734
+ if (bytes_read == -1) {
735
+ rb_raise(rb_eRuntimeError, "read failed: %d", errno);
736
+ }
737
+
738
+ zkrb_debug_inst(self, "read %zd bytes from the queue (%p)'s pipe", bytes_read, zk->queue);
739
+
740
+ continue;
741
+ }
742
+ }
743
+
744
+ VALUE hash = zkrb_event_to_ruby(event);
745
+ zkrb_event_free(event);
746
+ return hash;
747
+ }
748
+
749
+ error:
750
+ return Qnil;
751
+ }
752
+
753
+ // the single threaded version of this call. will go away when we do direct
754
+ // event delivery (soon)
755
+ static VALUE method_zkrb_get_next_event_st(VALUE self) {
756
+ volatile VALUE rval = Qnil;
757
+
758
+ if (is_closed(self)) {
759
+ zkrb_debug("we are closed, not gonna try to get an event");
760
+ return Qnil;
761
+ }
762
+
763
+ FETCH_DATA_PTR(self, zk);
764
+
765
+ zkrb_event_t *event = zkrb_dequeue(zk->queue, 0);
766
+
767
+ if (event != NULL) {
768
+ rval = zkrb_event_to_ruby(event);
769
+ zkrb_event_free(event);
770
+
771
+ #if THREADED
772
+ int fd = zk->queue->pipe_read;
773
+
774
+ // we don't care in this case. this is just until i can remove the self
775
+ // pipe from the queue
776
+ char b[128];
777
+ while(read(fd, b, sizeof(b)) == sizeof(b)){}
778
+ #endif
779
+ }
780
+
781
+ return rval;
782
+ }
783
+
784
+ inline static int get_self_pipe_read_fd(VALUE self) {
785
+ rb_io_t *fptr;
786
+ VALUE pipe_read = rb_iv_get(self, "@pipe_read");
787
+
788
+ if (NIL_P(pipe_read))
789
+ rb_raise(rb_eRuntimeError, "@pipe_read was nil!");
790
+
791
+ GetOpenFile(pipe_read, fptr);
792
+
793
+ rb_io_check_readable(fptr);
794
+
795
+ #ifdef ZKRB_RUBY_187
796
+ return fileno(fptr->f);
797
+ #else
798
+ return fptr->fd;
799
+ #endif
800
+ }
801
+
802
+ static VALUE method_zkrb_iterate_event_loop(VALUE self) {
803
+ FETCH_DATA_PTR(self, zk);
804
+
805
+ rb_fdset_t rfds, wfds, efds;
806
+ rb_fd_init(&rfds); rb_fd_init(&wfds); rb_fd_init(&efds);
807
+
808
+ int fd = 0, interest = 0, events = 0, rc = 0, maxfd = 0, irc = 0, prc = 0;
809
+ struct timeval tv;
810
+
811
+ irc = zookeeper_interest(zk->zh, &fd, &interest, &tv);
812
+
813
+ if (fd != -1) {
814
+ if (interest & ZOOKEEPER_READ) {
815
+ rb_fd_set(fd, &rfds);
816
+ } else {
817
+ rb_fd_clr(fd, &rfds);
818
+ }
819
+ if (interest & ZOOKEEPER_WRITE) {
820
+ rb_fd_set(fd, &wfds);
821
+ } else {
822
+ rb_fd_clr(fd, &wfds);
823
+ }
824
+ } else {
825
+ fd = 0;
826
+ }
827
+
828
+ // add our self-pipe to the read set, allow us to wake up in case our attention is needed
829
+ int pipe_r_fd = get_self_pipe_read_fd(self);
830
+
831
+ rb_fd_set(pipe_r_fd, &rfds);
832
+
833
+ maxfd = (pipe_r_fd > fd) ? pipe_r_fd : fd;
834
+
835
+ rc = rb_thread_fd_select(maxfd+1, &rfds, &wfds, &efds, &tv);
836
+
837
+ if (rc > 0) {
838
+ if (rb_fd_isset(fd, &rfds)) {
839
+ events |= ZOOKEEPER_READ;
840
+ }
841
+ if (rb_fd_isset(fd, &wfds)) {
842
+ events |= ZOOKEEPER_WRITE;
843
+ }
844
+
845
+ // we got woken up by the self-pipe
846
+ if (rb_fd_isset(pipe_r_fd, &rfds)) {
847
+ // one event has awoken us, so we clear one event from the pipe
848
+ char b[1];
849
+
850
+ if (read(pipe_r_fd, b, 1) < 0) {
851
+ rb_raise(rb_eRuntimeError, "read from pipe failed: %s", clean_errno());
852
+ }
853
+ }
854
+ }
855
+ else if (rc == 0) {
856
+ // zkrb_debug("timed out waiting for descriptor to be ready. interest=%d fd=%d pipe_r_fd=%d maxfd=%d irc=%d timeout=%f",
857
+ // interest, fd, pipe_r_fd, maxfd, irc, tv.tv_sec + (tv.tv_usec/ 1000.0 / 1000.0));
858
+ }
859
+ else {
860
+ log_err("select returned an error: rc=%d interest=%d fd=%d pipe_r_fd=%d maxfd=%d irc=%d timeout=%f",
861
+ rc, interest, fd, pipe_r_fd, maxfd, irc, tv.tv_sec + (tv.tv_usec/ 1000.0 / 1000.0));
862
+ }
863
+
864
+ prc = zookeeper_process(zk->zh, events);
865
+
866
+ if (rc == 0) {
867
+ zkrb_debug("timed out waiting for descriptor to be ready. prc=%d interest=%d fd=%d pipe_r_fd=%d maxfd=%d irc=%d timeout=%f",
868
+ prc, interest, fd, pipe_r_fd, maxfd, irc, tv.tv_sec + (tv.tv_usec/ 1000.0 / 1000.0));
869
+ }
870
+
871
+ rb_fd_term(&rfds);
872
+ rb_fd_term(&wfds);
873
+ rb_fd_term(&efds);
874
+ return INT2FIX(prc);
875
+ }
876
+
877
+ static VALUE method_has_events(VALUE self) {
878
+ VALUE rb_event;
879
+ FETCH_DATA_PTR(self, zk);
880
+
881
+ rb_event = zkrb_peek(zk->queue) != NULL ? Qtrue : Qfalse;
882
+ return rb_event;
883
+ }
884
+
885
+ static VALUE method_zoo_set_log_level(VALUE self, VALUE level) {
886
+ Check_Type(level, T_FIXNUM);
887
+ zoo_set_debug_level(FIX2INT(level));
888
+ return Qnil;
889
+ }
890
+
891
+ static VALUE method_close_handle(VALUE self) {
892
+ FETCH_DATA_PTR(self, zk);
893
+
894
+ if (ZKRBDebugging) {
895
+ zkrb_debug_inst(self, "CLOSING_ZK_INSTANCE");
896
+ print_zkrb_instance_data(zk);
897
+ }
898
+
899
+ // this is a value on the ruby side we can check to see if destroy_zkrb_instance
900
+ // has been called
901
+ rb_iv_set(self, "@_closed", Qtrue);
902
+
903
+ /* Note that after zookeeper_close() returns, ZK handle is invalid */
904
+ int rc = destroy_zkrb_instance(zk);
905
+
906
+ zkrb_debug("destroy_zkrb_instance returned: %d", rc);
907
+
908
+ return INT2FIX(rc);
909
+ }
910
+
911
+ static VALUE method_deterministic_conn_order(VALUE self, VALUE yn) {
912
+ zoo_deterministic_conn_order(yn == Qtrue);
913
+ return Qnil;
914
+ }
915
+
916
+ static VALUE method_is_unrecoverable(VALUE self) {
917
+ FETCH_DATA_PTR(self, zk);
918
+ return is_unrecoverable(zk->zh) == ZINVALIDSTATE ? Qtrue : Qfalse;
919
+ }
920
+
921
+ static VALUE method_zkrb_state(VALUE self) {
922
+ FETCH_DATA_PTR(self, zk);
923
+ return INT2NUM(zoo_state(zk->zh));
924
+ }
925
+
926
+ static VALUE method_recv_timeout(VALUE self) {
927
+ FETCH_DATA_PTR(self, zk);
928
+ return INT2NUM(zoo_recv_timeout(zk->zh));
929
+ }
930
+
931
+ // returns a CZookeeper::ClientId object with the values set for session_id and passwd
932
+ static VALUE method_client_id(VALUE self) {
933
+ FETCH_DATA_PTR(self, zk);
934
+ const clientid_t *cid = zoo_client_id(zk->zh);
935
+
936
+ VALUE session_id = LL2NUM(cid->client_id);
937
+ VALUE passwd = rb_str_new(cid->passwd, 16);
938
+
939
+ VALUE client_id_obj = rb_class_new_instance(0, RARRAY_PTR(rb_ary_new()), ZookeeperClientId);
940
+
941
+ rb_funcall(client_id_obj, rb_intern("session_id="), 1, session_id);
942
+ rb_funcall(client_id_obj, rb_intern("passwd="), 1, passwd);
943
+
944
+ return client_id_obj;
945
+ }
946
+
947
+ static VALUE klass_method_zkrb_set_debug_level(VALUE klass, VALUE level) {
948
+ Check_Type(level, T_FIXNUM);
949
+ ZKRBDebugging = (FIX2INT(level) == ZOO_LOG_LEVEL_DEBUG);
950
+ zoo_set_debug_level(FIX2INT(level));
951
+ return Qnil;
952
+ }
953
+
954
+ static VALUE method_zerror(VALUE self, VALUE errc) {
955
+ return rb_str_new2(zerror(FIX2INT(errc)));
956
+ }
957
+
958
+ static VALUE method_connected_host(VALUE self) {
959
+ FETCH_DATA_PTR(self, zk);
960
+
961
+ struct sockaddr addr;
962
+ socklen_t addr_len = sizeof(addr);
963
+
964
+ if (zookeeper_get_connected_host(zk->zh, &addr, &addr_len) != NULL) {
965
+ char buf[255];
966
+ char addrstr[128];
967
+ void *inaddr;
968
+ int port;
969
+
970
+ #if defined(AF_INET6)
971
+ if(addr.sa_family==AF_INET6){
972
+ inaddr = &((struct sockaddr_in6 *) &addr)->sin6_addr;
973
+ port = ((struct sockaddr_in6 *) &addr)->sin6_port;
974
+ } else {
975
+ #endif
976
+ inaddr = &((struct sockaddr_in *) &addr)->sin_addr;
977
+ port = ((struct sockaddr_in *) &addr)->sin_port;
978
+ #if defined(AF_INET6)
979
+ }
980
+ #endif
981
+
982
+ inet_ntop(addr.sa_family, inaddr, addrstr, sizeof(addrstr)-1);
983
+ snprintf(buf, sizeof(buf), "%s:%d", addrstr, ntohs(port));
984
+ return rb_str_new2(buf);
985
+ }
986
+
987
+ return Qnil;
988
+ }
989
+
990
+ static void zkrb_define_methods(void) {
991
+ #define DEFINE_METHOD(M, ARGS) { \
992
+ rb_define_method(CZookeeper, #M, method_ ## M, ARGS); }
993
+
994
+ #define DEFINE_CLASS_METHOD(M, ARGS) { \
995
+ rb_define_singleton_method(CZookeeper, #M, method_ ## M, ARGS); }
996
+
997
+ // defines a method with a zkrb_ prefix, the actual C method does not have this prefix
998
+ #define DEFINE_ZKRB_METHOD(M, ARGS) { \
999
+ rb_define_method(CZookeeper, zkrb_ ## M, method_ ## M, ARGS); }
1000
+
1001
+ // the number after the method name should be actual arity of C function - 1
1002
+ DEFINE_METHOD(zkrb_init, -1);
1003
+
1004
+ rb_define_method(CZookeeper, "zkrb_get_children", method_get_children, 4);
1005
+ rb_define_method(CZookeeper, "zkrb_exists", method_exists, 4);
1006
+ rb_define_method(CZookeeper, "zkrb_create", method_create, 6);
1007
+ rb_define_method(CZookeeper, "zkrb_delete", method_delete, 4);
1008
+ rb_define_method(CZookeeper, "zkrb_get", method_get, 4);
1009
+ rb_define_method(CZookeeper, "zkrb_set", method_set, 5);
1010
+ rb_define_method(CZookeeper, "zkrb_set_acl", method_set_acl, 5);
1011
+ rb_define_method(CZookeeper, "zkrb_get_acl", method_get_acl, 3);
1012
+ rb_define_method(CZookeeper, "zkrb_add_auth", method_add_auth, 3);
1013
+
1014
+ rb_define_singleton_method(CZookeeper, "zoo_set_log_level", method_zoo_set_log_level, 1);
1015
+
1016
+ DEFINE_METHOD(client_id, 0);
1017
+ DEFINE_METHOD(close_handle, 0);
1018
+ DEFINE_METHOD(deterministic_conn_order, 1);
1019
+ DEFINE_METHOD(is_unrecoverable, 0);
1020
+ DEFINE_METHOD(recv_timeout, 0);
1021
+ DEFINE_METHOD(zkrb_state, 0);
1022
+ DEFINE_METHOD(sync, 2);
1023
+ DEFINE_METHOD(zkrb_iterate_event_loop, 0);
1024
+ DEFINE_METHOD(zkrb_get_next_event_st, 0);
1025
+ DEFINE_METHOD(connected_host, 0);
1026
+
1027
+ // methods for the ruby-side event manager
1028
+ DEFINE_METHOD(zkrb_get_next_event, 1);
1029
+ DEFINE_METHOD(zkrb_get_next_event_st, 0);
1030
+ DEFINE_METHOD(has_events, 0);
1031
+
1032
+ // Make these class methods?
1033
+ DEFINE_METHOD(zerror, 1);
1034
+
1035
+ rb_define_singleton_method(CZookeeper, "set_zkrb_debug_level", klass_method_zkrb_set_debug_level, 1);
1036
+
1037
+ rb_attr(CZookeeper, rb_intern("selectable_io"), 1, 0, Qtrue);
1038
+
1039
+ }
1040
+
1041
+ // class CZookeeper::ClientId
1042
+ // attr_accessor :session_id, :passwd
1043
+ //
1044
+ // def initialize(session_id, passwd)
1045
+ // @session_id = session_id
1046
+ // @passwd = passwd
1047
+ // end
1048
+ // end
1049
+
1050
+ static VALUE zkrb_client_id_method_initialize(VALUE self) {
1051
+ rb_iv_set(self, "@session_id", Qnil);
1052
+ rb_iv_set(self, "@passwd", Qnil);
1053
+ return Qnil;
1054
+ }
1055
+
1056
+
1057
+ void Init_zookeeper_c() {
1058
+ // Don't debug by default
1059
+ ZKRBDebugging = 0;
1060
+ zoo_set_debug_level(0);
1061
+
1062
+ mZookeeper = rb_define_module("Zookeeper");
1063
+ mZookeeperExceptions = rb_define_module_under(mZookeeper, "Exceptions");
1064
+
1065
+ // this will likely fail if the load order is screwed up
1066
+ eHandleClosedException = rb_const_get(mZookeeperExceptions, rb_intern("HandleClosedException"));
1067
+
1068
+ /* initialize CZookeeper class */
1069
+ CZookeeper = rb_define_class_under(mZookeeper, "CZookeeper", rb_cObject);
1070
+ rb_define_alloc_func(CZookeeper, alloc_zkrb_instance);
1071
+ zkrb_define_methods();
1072
+
1073
+ ZookeeperClientId = rb_define_class_under(CZookeeper, "ClientId", rb_cObject);
1074
+ rb_define_method(ZookeeperClientId, "initialize", zkrb_client_id_method_initialize, 0);
1075
+ rb_define_attr(ZookeeperClientId, "session_id", 1, 1);
1076
+ rb_define_attr(ZookeeperClientId, "passwd", 1, 1);
1077
+
1078
+ }
1079
+
1080
+ // vim:ts=2:sw=2:sts=2:et