zookeeper 1.0.6-java → 1.1.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,11 +8,64 @@
8
8
  * approach to isolate the ZK state machine from the ruby interpreter via an
9
9
  * event queue. It's similar to the ZookeeperFFI version except that it
10
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
+ *
11
59
  */
12
60
 
13
- #define THREADED
14
-
15
61
  #include "ruby.h"
62
+
63
+ #ifdef ZKRB_RUBY_187
64
+ #include "rubyio.h"
65
+ #else
66
+ #include "ruby/io.h"
67
+ #endif
68
+
16
69
  #include "c-client-src/zookeeper.h"
17
70
  #include <errno.h>
18
71
  #include <stdio.h>
@@ -21,15 +74,18 @@
21
74
  #include <sys/fcntl.h>
22
75
  #include <pthread.h>
23
76
  #include <inttypes.h>
77
+ #include <time.h>
24
78
 
25
- #include "zookeeper_lib.h"
79
+ #include "common.h"
80
+ #include "event_lib.h"
26
81
  #include "zkrb_wrapper.h"
27
82
  #include "dbg.h"
28
83
 
29
-
30
84
  static VALUE mZookeeper = Qnil; // the Zookeeper module
31
85
  static VALUE CZookeeper = Qnil; // the Zookeeper::CZookeeper class
32
86
  static VALUE ZookeeperClientId = Qnil;
87
+ static VALUE mZookeeperExceptions = Qnil; // the Zookeeper::Exceptions module
88
+ static VALUE eHandleClosedException = Qnil; // raised when we don't have a valid handle in FETCH_DATA_PTR
33
89
 
34
90
  // slyphon: possibly add a lock to this for synchronizing during get_next_event
35
91
 
@@ -41,6 +97,8 @@ struct zkrb_instance_data {
41
97
  pid_t orig_pid;
42
98
  };
43
99
 
100
+ typedef struct zkrb_instance_data zkrb_instance_data_t;
101
+
44
102
  typedef enum {
45
103
  SYNC = 0,
46
104
  ASYNC = 1,
@@ -48,41 +106,109 @@ typedef enum {
48
106
  ASYNC_WATCH = 3
49
107
  } zkrb_call_type;
50
108
 
109
+ inline static const char* call_type_to_str(zkrb_call_type ct) {
110
+ switch (ct) {
111
+ case SYNC:
112
+ return "SYNC";
113
+ case ASYNC:
114
+ return "ASYNC";
115
+ case SYNC_WATCH:
116
+ return "SYNC_WATCH";
117
+ case ASYNC_WATCH:
118
+ return "ASYNC_WATCH";
119
+ }
120
+ }
121
+
122
+ inline static void assert_valid_params(VALUE reqid, VALUE path) {
123
+ switch (TYPE(reqid)) {
124
+ case T_FIXNUM:
125
+ case T_BIGNUM:
126
+ break;
127
+ default:
128
+ rb_raise(rb_eTypeError, "reqid must be Fixnum/Bignum");
129
+ }
130
+
131
+ Check_Type(path, T_STRING);
132
+ }
133
+
134
+ inline static zkrb_call_type get_call_type(VALUE async, VALUE watch) {
135
+ if RTEST(async) {
136
+ return RTEST(watch) ? ASYNC_WATCH : ASYNC;
137
+ } else {
138
+ return RTEST(watch) ? SYNC_WATCH : SYNC;
139
+ }
140
+ }
141
+
142
+ inline static void raise_invalid_call_type_err(zkrb_call_type call_type) {
143
+ rb_raise(rb_eRuntimeError, "hit the default case, call_type: %s", call_type_to_str(call_type));
144
+ }
145
+
51
146
  #define IS_SYNC(zkrbcall) ((zkrbcall)==SYNC || (zkrbcall)==SYNC_WATCH)
52
147
  #define IS_ASYNC(zkrbcall) ((zkrbcall)==ASYNC || (zkrbcall)==ASYNC_WATCH)
53
148
 
149
+ #define FETCH_DATA_PTR(SELF, ZK) \
150
+ zkrb_instance_data_t * ZK; \
151
+ Data_Get_Struct(rb_iv_get(SELF, "@_data"), zkrb_instance_data_t, ZK); \
152
+ if ((ZK)->zh == NULL) \
153
+ rb_raise(eHandleClosedException, "zookeeper handle is closed")
154
+
155
+ #define STANDARD_PREAMBLE(SELF, ZK, REQID, PATH, ASYNC, WATCH, CALL_TYPE) \
156
+ assert_valid_params(REQID, PATH); \
157
+ FETCH_DATA_PTR(SELF, ZK); \
158
+ zkrb_call_type CALL_TYPE = get_call_type(ASYNC, WATCH); \
54
159
 
55
- static int destroy_zkrb_instance(struct zkrb_instance_data* ptr) {
160
+ #define CTX_ALLOC(ZK,REQID) zkrb_calling_context_alloc(NUM2LL(REQID), ZK->queue)
161
+
162
+ static void hexbufify(char *dest, const char *src, int len) {
163
+ int i=0;
164
+
165
+ for (i=0; i < len; i++) {
166
+ sprintf(&dest[i*2], "%x", src[i]);
167
+ }
168
+ }
169
+
170
+ static int destroy_zkrb_instance(zkrb_instance_data_t* zk) {
56
171
  int rv = ZOK;
57
172
 
58
- zkrb_debug("destroy_zkrb_instance, zk_local_ctx: %p, zh: %p, queue: %p", ptr, ptr->zh, ptr->queue);
173
+ zkrb_debug("destroy_zkrb_instance, zk_local_ctx: %p, zh: %p, queue: %p", zk, zk->zh, zk->queue);
59
174
 
60
- if (ptr->zh) {
61
- const void *ctx = zoo_get_context(ptr->zh);
175
+ if (zk->zh) {
176
+ const void *ctx = zoo_get_context(zk->zh);
62
177
  /* Note that after zookeeper_close() returns, ZK handle is invalid */
63
- zkrb_debug("obj_id: %lx, calling zookeeper_close", ptr->object_id);
64
- rv = zookeeper_close(ptr->zh);
65
- zkrb_debug("obj_id: %lx, zookeeper_close returned %d", ptr->object_id, rv);
66
- free((void *) ctx);
178
+ zkrb_debug("obj_id: %lx, calling zookeeper_close", zk->object_id);
179
+
180
+ if (zk->orig_pid != getpid()) {
181
+ zkrb_debug("FORK DETECTED! orig_pid: %d, current pid: %d, "
182
+ "using socket-closing hack before zookeeper_close", zk->orig_pid, getpid());
183
+
184
+ int fd = ((int *)zk->zh)[0]; // nasty, brutish, and wonderfully effective hack (see above)
185
+ close(fd);
186
+ }
187
+
188
+ rv = zookeeper_close(zk->zh);
189
+
190
+ zkrb_debug("obj_id: %lx, zookeeper_close returned %d", zk->object_id, rv);
191
+ zkrb_calling_context_free((zkrb_calling_context *) ctx);
67
192
  }
68
193
 
69
- #warning [wickman] TODO: fire off warning if queue is not empty
70
- if (ptr->queue) {
71
- zkrb_debug("obj_id: %lx, freeing queue pointer: %p", ptr->object_id, ptr->queue);
72
- zkrb_queue_free(ptr->queue);
194
+ zk->zh = NULL;
195
+
196
+ // [wickman] TODO: fire off warning if queue is not empty
197
+ if (zk->queue) {
198
+ zkrb_debug("obj_id: %lx, freeing queue pointer: %p", zk->object_id, zk->queue);
199
+ zkrb_queue_free(zk->queue);
73
200
  }
74
201
 
75
- ptr->zh = NULL;
76
- ptr->queue = NULL;
202
+ zk->queue = NULL;
77
203
 
78
204
  return rv;
79
205
  }
80
206
 
81
- static void free_zkrb_instance_data(struct zkrb_instance_data* ptr) {
207
+ static void free_zkrb_instance_data(zkrb_instance_data_t* ptr) {
82
208
  destroy_zkrb_instance(ptr);
83
209
  }
84
210
 
85
- static void print_zkrb_instance_data(struct zkrb_instance_data* ptr) {
211
+ static void print_zkrb_instance_data(zkrb_instance_data_t* ptr) {
86
212
  fprintf(stderr, "zkrb_instance_data (%p) {\n", ptr);
87
213
  fprintf(stderr, " zh = %p\n", ptr->zh);
88
214
  fprintf(stderr, " { state = %d }\n", zoo_state(ptr->zh));
@@ -92,52 +218,16 @@ static void print_zkrb_instance_data(struct zkrb_instance_data* ptr) {
92
218
  fprintf(stderr, "}\n");
93
219
  }
94
220
 
95
- // cargo culted from io.c
96
- static VALUE zkrb_new_instance _((VALUE));
97
-
98
- static VALUE zkrb_new_instance(VALUE args) {
99
- return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
100
- }
101
-
102
- static int zkrb_dup(int orig) {
103
- int fd;
104
-
105
- fd = dup(orig);
106
- if (fd < 0) {
107
- if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
108
- rb_gc();
109
- fd = dup(orig);
110
- }
111
- if (fd < 0) {
112
- rb_sys_fail(0);
113
- }
114
- }
115
- return fd;
116
- }
117
-
118
- #if 0
119
- static VALUE create_selectable_io(zkrb_queue_t *q) {
120
- // rb_cIO is the ruby IO class?
121
-
122
- int pipe, state, read_fd;
123
- VALUE args[3], reader;
124
-
125
- read_fd = zkrb_dup(q->pipe_read);
126
-
127
- args[0] = rb_cIO;
128
- args[1] = INT2NUM(read_fd);
129
- args[2] = INT2FIX(O_RDONLY);
130
- reader = rb_protect(zkrb_new_instance, (VALUE)args, &state);
221
+ #define session_timeout_msec(self) rb_iv_get(self, "@_session_timeout_msec")
131
222
 
132
- if (state) {
133
- rb_jump_tag(state);
134
- }
223
+ inline static void zkrb_debug_clientid_t(const clientid_t *cid) {
224
+ int pass_len = sizeof(cid->passwd);
225
+ int hex_len = 2 * pass_len;
226
+ char buf[hex_len];
227
+ hexbufify(buf, cid->passwd, pass_len);
135
228
 
136
- return reader;
229
+ zkrb_debug("myid, client_id: %"PRId64", passwd: %*s", cid->client_id, hex_len, buf);
137
230
  }
138
- #endif
139
-
140
- #define session_timeout_msec(self) rb_iv_get(self, "@_session_timeout_msec")
141
231
 
142
232
  static VALUE method_zkrb_init(int argc, VALUE* argv, VALUE self) {
143
233
  VALUE hostPort;
@@ -163,8 +253,8 @@ static VALUE method_zkrb_init(int argc, VALUE* argv, VALUE self) {
163
253
  }
164
254
 
165
255
  VALUE data;
166
- struct zkrb_instance_data *zk_local_ctx;
167
- data = Data_Make_Struct(CZookeeper, struct zkrb_instance_data, 0, free_zkrb_instance_data, zk_local_ctx);
256
+ zkrb_instance_data_t *zk_local_ctx;
257
+ data = Data_Make_Struct(CZookeeper, zkrb_instance_data_t, 0, free_zkrb_instance_data, zk_local_ctx);
168
258
 
169
259
  zk_local_ctx->queue = zkrb_queue_alloc();
170
260
 
@@ -190,7 +280,6 @@ static VALUE method_zkrb_init(int argc, VALUE* argv, VALUE self) {
190
280
  zkrb_debug("method_zkrb_init, zk_local_ctx: %p, zh: %p, queue: %p, calling_ctx: %p",
191
281
  zk_local_ctx, zk_local_ctx->zh, zk_local_ctx->queue, ctx);
192
282
 
193
- #warning [wickman] TODO handle this properly on the Ruby side rather than C side
194
283
  if (!zk_local_ctx->zh) {
195
284
  rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
196
285
  }
@@ -200,66 +289,47 @@ static VALUE method_zkrb_init(int argc, VALUE* argv, VALUE self) {
200
289
  rb_iv_set(self, "@_data", data);
201
290
  rb_funcall(self, rb_intern("zkc_set_running_and_notify!"), 0);
202
291
 
203
- error:
204
292
  return Qnil;
205
293
  }
206
294
 
207
- #define FETCH_DATA_PTR(X, Y) \
208
- struct zkrb_instance_data * Y; \
209
- Data_Get_Struct(rb_iv_get(X, "@_data"), struct zkrb_instance_data, Y); \
210
- if ((Y)->zh == NULL) \
211
- rb_raise(rb_eRuntimeError, "zookeeper handle is closed")
212
-
213
- #define STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, cb_ctx, w_ctx, call_type) \
214
- if (TYPE(reqid) != T_FIXNUM && TYPE(reqid) != T_BIGNUM) { \
215
- rb_raise(rb_eTypeError, "reqid must be Fixnum/Bignum"); \
216
- return Qnil; \
217
- } \
218
- Check_Type(path, T_STRING); \
219
- struct zkrb_instance_data * zk; \
220
- Data_Get_Struct(rb_iv_get(self, "@_data"), struct zkrb_instance_data, zk); \
221
- if (!zk->zh) \
222
- rb_raise(rb_eRuntimeError, "zookeeper handle is closed"); \
223
- zkrb_calling_context* cb_ctx = \
224
- (async != Qfalse && async != Qnil) ? \
225
- zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
226
- NULL; \
227
- zkrb_calling_context* w_ctx = \
228
- (watch != Qfalse && watch != Qnil) ? \
229
- zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
230
- NULL; \
231
- int a_ = (async != Qfalse && async != Qnil); \
232
- int w_ = (watch != Qfalse && watch != Qnil); \
233
- zkrb_call_type call_type; \
234
- if (a_) { if (w_) { call_type = ASYNC_WATCH; } else { call_type = ASYNC; } } \
235
- else { if (w_) { call_type = SYNC_WATCH; } else { call_type = SYNC; } }
236
-
237
295
  static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
238
- STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
296
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, call_type);
239
297
 
298
+ VALUE output = Qnil;
240
299
  struct String_vector strings;
241
300
  struct Stat stat;
242
301
 
243
302
  int rc;
244
303
  switch (call_type) {
304
+
305
+ #ifdef THREADED
245
306
  case SYNC:
246
- rc = zkrb_call_zoo_get_children2(zk->zh, RSTRING_PTR(path), 0, &strings, &stat);
307
+ rc = zkrb_call_zoo_get_children2(
308
+ zk->zh, RSTRING_PTR(path), 0, &strings, &stat);
247
309
  break;
248
310
 
249
311
  case SYNC_WATCH:
250
- rc = zkrb_call_zoo_wget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &strings, &stat);
312
+ rc = zkrb_call_zoo_wget_children2(
313
+ zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), &strings, &stat);
251
314
  break;
315
+ #endif
252
316
 
253
317
  case ASYNC:
254
- rc = zkrb_call_zoo_aget_children2(zk->zh, RSTRING_PTR(path), 0, zkrb_strings_stat_callback, data_ctx);
318
+ rc = zkrb_call_zoo_aget_children2(
319
+ zk->zh, RSTRING_PTR(path), 0, zkrb_strings_stat_callback, CTX_ALLOC(zk, reqid));
255
320
  break;
256
321
 
257
322
  case ASYNC_WATCH:
258
- rc = zkrb_call_zoo_awget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_strings_stat_callback, data_ctx);
323
+ rc = zkrb_call_zoo_awget_children2(
324
+ zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), zkrb_strings_stat_callback, CTX_ALLOC(zk, reqid));
325
+ break;
326
+
327
+ default:
328
+ raise_invalid_call_type_err(call_type);
259
329
  break;
260
330
  }
261
331
 
262
- VALUE output = rb_ary_new();
332
+ output = rb_ary_new();
263
333
  rb_ary_push(output, INT2FIX(rc));
264
334
  if (IS_SYNC(call_type) && rc == ZOK) {
265
335
  rb_ary_push(output, zkrb_string_vector_to_ruby(&strings));
@@ -269,30 +339,38 @@ static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE asyn
269
339
  }
270
340
 
271
341
  static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
272
- STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
342
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, call_type);
273
343
 
344
+ VALUE output = Qnil;
274
345
  struct Stat stat;
275
346
 
276
347
  int rc;
277
348
  switch (call_type) {
349
+
350
+ #ifdef THREADED
278
351
  case SYNC:
279
352
  rc = zkrb_call_zoo_exists(zk->zh, RSTRING_PTR(path), 0, &stat);
280
353
  break;
281
354
 
282
355
  case SYNC_WATCH:
283
- rc = zkrb_call_zoo_wexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &stat);
356
+ rc = zkrb_call_zoo_wexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), &stat);
284
357
  break;
358
+ #endif
285
359
 
286
360
  case ASYNC:
287
- rc = zkrb_call_zoo_aexists(zk->zh, RSTRING_PTR(path), 0, zkrb_stat_callback, data_ctx);
361
+ rc = zkrb_call_zoo_aexists(zk->zh, RSTRING_PTR(path), 0, zkrb_stat_callback, CTX_ALLOC(zk, reqid));
288
362
  break;
289
363
 
290
364
  case ASYNC_WATCH:
291
- rc = zkrb_call_zoo_awexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_stat_callback, data_ctx);
365
+ rc = zkrb_call_zoo_awexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), zkrb_stat_callback, CTX_ALLOC(zk, reqid));
366
+ break;
367
+
368
+ default:
369
+ raise_invalid_call_type_err(call_type);
292
370
  break;
293
371
  }
294
372
 
295
- VALUE output = rb_ary_new();
373
+ output = rb_ary_new();
296
374
  rb_ary_push(output, INT2FIX(rc));
297
375
  if (IS_SYNC(call_type) && rc == ZOK) {
298
376
  rb_ary_push(output, zkrb_stat_to_rarray(&stat));
@@ -302,20 +380,21 @@ static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VAL
302
380
 
303
381
  // this method is *only* called asynchronously
304
382
  static VALUE method_sync(VALUE self, VALUE reqid, VALUE path) {
305
- VALUE async = Qtrue;
306
- VALUE watch = Qfalse;
307
- int rc;
383
+ int rc = ZOK;
308
384
 
309
- STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
385
+ // don't use STANDARD_PREAMBLE here b/c we don't need to determine call_type
386
+ assert_valid_params(reqid, path);
387
+ FETCH_DATA_PTR(self, zk);
310
388
 
311
- rc = zkrb_call_zoo_async(zk->zh, RSTRING_PTR(path), zkrb_string_callback, data_ctx);
389
+ rc = zkrb_call_zoo_async(zk->zh, RSTRING_PTR(path), zkrb_string_callback, CTX_ALLOC(zk, reqid));
312
390
 
313
391
  return INT2FIX(rc);
314
392
  }
315
393
 
394
+
316
395
  static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE acls, VALUE flags) {
317
- VALUE watch = Qfalse;
318
- STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
396
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
397
+ VALUE output = Qnil;
319
398
 
320
399
  if (data != Qnil) Check_Type(data, T_STRING);
321
400
  Check_Type(flags, T_FIXNUM);
@@ -328,28 +407,29 @@ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALU
328
407
 
329
408
  int rc;
330
409
  switch (call_type) {
410
+
411
+ #ifdef THREADED
331
412
  case SYNC:
332
413
  // casting data_len to int is OK as you can only store 1MB in zookeeper
333
414
  rc = zkrb_call_zoo_create(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, aclptr, FIX2INT(flags), realpath, sizeof(realpath));
334
-
335
415
  break;
336
- case ASYNC:
337
- rc = zkrb_call_zoo_acreate(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, aclptr, FIX2INT(flags), zkrb_string_callback, data_ctx);
416
+ #endif
338
417
 
418
+ case ASYNC:
419
+ 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));
339
420
  break;
421
+
340
422
  default:
341
- /* TODO(wickman) raise proper argument error */
342
- return Qnil;
423
+ raise_invalid_call_type_err(call_type);
343
424
  break;
344
425
  }
345
426
 
346
-
347
427
  if (aclptr) {
348
428
  deallocate_ACL_vector(aclptr);
349
429
  free(aclptr);
350
430
  }
351
431
 
352
- VALUE output = rb_ary_new();
432
+ output = rb_ary_new();
353
433
  rb_ary_push(output, INT2FIX(rc));
354
434
  if (IS_SYNC(call_type) && rc == ZOK) {
355
435
  return rb_ary_push(output, rb_str_new2(realpath));
@@ -358,21 +438,24 @@ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALU
358
438
  }
359
439
 
360
440
  static VALUE method_delete(VALUE self, VALUE reqid, VALUE path, VALUE version, VALUE async) {
361
- VALUE watch = Qfalse;
362
- STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
441
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
363
442
  Check_Type(version, T_FIXNUM);
364
443
 
365
444
  int rc = 0;
366
445
  switch (call_type) {
446
+
447
+ #ifdef THREADED
367
448
  case SYNC:
368
449
  rc = zkrb_call_zoo_delete(zk->zh, RSTRING_PTR(path), FIX2INT(version));
369
450
  break;
451
+ #endif
452
+
370
453
  case ASYNC:
371
- rc = zkrb_call_zoo_adelete(zk->zh, RSTRING_PTR(path), FIX2INT(version), zkrb_void_callback, data_ctx);
454
+ rc = zkrb_call_zoo_adelete(zk->zh, RSTRING_PTR(path), FIX2INT(version), zkrb_void_callback, CTX_ALLOC(zk, reqid));
372
455
  break;
456
+
373
457
  default:
374
- /* TODO(wickman) raise proper argument error */
375
- return Qnil;
458
+ raise_invalid_call_type_err(call_type);
376
459
  break;
377
460
  }
378
461
 
@@ -382,34 +465,46 @@ static VALUE method_delete(VALUE self, VALUE reqid, VALUE path, VALUE version, V
382
465
  #define MAX_ZNODE_SIZE 1048576
383
466
 
384
467
  static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
385
- STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
468
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, call_type);
469
+
470
+ VALUE output = Qnil;
386
471
 
387
- /* ugh */
388
- char * data = malloc(MAX_ZNODE_SIZE);
389
472
  int data_len = MAX_ZNODE_SIZE;
390
473
  struct Stat stat;
391
474
 
475
+ char * data = xmalloc(MAX_ZNODE_SIZE); /* ugh */
476
+
392
477
  int rc;
393
478
 
394
479
  switch (call_type) {
480
+
481
+ #ifdef THREADED
395
482
  case SYNC:
396
483
  rc = zkrb_call_zoo_get(zk->zh, RSTRING_PTR(path), 0, data, &data_len, &stat);
397
484
  break;
398
485
 
399
486
  case SYNC_WATCH:
400
- rc = zkrb_call_zoo_wget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, data, &data_len, &stat);
487
+ rc = zkrb_call_zoo_wget(
488
+ zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), data, &data_len, &stat);
401
489
  break;
490
+ #endif
402
491
 
403
492
  case ASYNC:
404
- rc = zkrb_call_zoo_aget(zk->zh, RSTRING_PTR(path), 0, zkrb_data_callback, data_ctx);
493
+ rc = zkrb_call_zoo_aget(zk->zh, RSTRING_PTR(path), 0, zkrb_data_callback, CTX_ALLOC(zk, reqid));
405
494
  break;
406
495
 
407
496
  case ASYNC_WATCH:
408
- rc = zkrb_call_zoo_awget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_data_callback, data_ctx);
497
+ // first ctx is a watch, second is the async callback
498
+ rc = zkrb_call_zoo_awget(
499
+ zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), zkrb_data_callback, CTX_ALLOC(zk, reqid));
500
+ break;
501
+
502
+ default:
503
+ raise_invalid_call_type_err(call_type);
409
504
  break;
410
505
  }
411
506
 
412
- VALUE output = rb_ary_new();
507
+ output = rb_ary_new();
413
508
  rb_ary_push(output, INT2FIX(rc));
414
509
  if (IS_SYNC(call_type) && rc == ZOK) {
415
510
  if (data_len == -1)
@@ -418,36 +513,42 @@ static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE
418
513
  rb_ary_push(output, rb_str_new(data, data_len));
419
514
  rb_ary_push(output, zkrb_stat_to_rarray(&stat));
420
515
  }
421
- free(data);
422
516
 
517
+ xfree(data);
423
518
  return output;
424
519
  }
425
520
 
426
521
  static VALUE method_set(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE version) {
427
- VALUE watch = Qfalse;
428
- STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
522
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
429
523
 
524
+ VALUE output = Qnil;
430
525
  struct Stat stat;
526
+
431
527
  if (data != Qnil) Check_Type(data, T_STRING);
528
+
432
529
  const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
433
530
  size_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
434
531
 
435
532
  int rc;
436
533
  switch (call_type) {
534
+
535
+ #ifdef THREADED
437
536
  case SYNC:
438
537
  rc = zkrb_call_zoo_set2(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version), &stat);
439
538
  break;
539
+ #endif
540
+
440
541
  case ASYNC:
441
- rc = zkrb_call_zoo_aset(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version),
442
- zkrb_stat_callback, data_ctx);
542
+ rc = zkrb_call_zoo_aset(
543
+ zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version), zkrb_stat_callback, CTX_ALLOC(zk, reqid));
443
544
  break;
545
+
444
546
  default:
445
- /* TODO(wickman) raise proper argument error */
446
- return Qnil;
547
+ raise_invalid_call_type_err(call_type);
447
548
  break;
448
549
  }
449
550
 
450
- VALUE output = rb_ary_new();
551
+ output = rb_ary_new();
451
552
  rb_ary_push(output, INT2FIX(rc));
452
553
  if (IS_SYNC(call_type) && rc == ZOK) {
453
554
  rb_ary_push(output, zkrb_stat_to_rarray(&stat));
@@ -456,21 +557,25 @@ static VALUE method_set(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE a
456
557
  }
457
558
 
458
559
  static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VALUE async, VALUE version) {
459
- VALUE watch = Qfalse;
460
- STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
560
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
561
+
461
562
  struct ACL_vector * aclptr = zkrb_ruby_to_aclvector(acls);
462
563
 
463
564
  int rc;
464
565
  switch (call_type) {
566
+
567
+ #ifdef THREADED
465
568
  case SYNC:
466
569
  rc = zkrb_call_zoo_set_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr);
467
570
  break;
571
+ #endif
572
+
468
573
  case ASYNC:
469
- rc = zkrb_call_zoo_aset_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr, zkrb_void_callback, data_ctx);
574
+ rc = zkrb_call_zoo_aset_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr, zkrb_void_callback, CTX_ALLOC(zk, reqid));
470
575
  break;
576
+
471
577
  default:
472
- /* TODO(wickman) raise proper argument error */
473
- return Qnil;
578
+ raise_invalid_call_type_err(call_type);
474
579
  break;
475
580
  }
476
581
 
@@ -481,27 +586,31 @@ static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VAL
481
586
  }
482
587
 
483
588
  static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
484
- VALUE watch = Qfalse;
485
- STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
589
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
486
590
 
591
+ VALUE output = Qnil;
487
592
  struct ACL_vector acls;
488
593
  struct Stat stat;
489
594
 
490
595
  int rc;
491
596
  switch (call_type) {
597
+
598
+ #ifdef THREADED
492
599
  case SYNC:
493
600
  rc = zkrb_call_zoo_get_acl(zk->zh, RSTRING_PTR(path), &acls, &stat);
494
601
  break;
602
+ #endif
603
+
495
604
  case ASYNC:
496
- rc = zkrb_call_zoo_aget_acl(zk->zh, RSTRING_PTR(path), zkrb_acl_callback, data_ctx);
605
+ rc = zkrb_call_zoo_aget_acl(zk->zh, RSTRING_PTR(path), zkrb_acl_callback, CTX_ALLOC(zk, reqid));
497
606
  break;
607
+
498
608
  default:
499
- /* TODO(wickman) raise proper argument error */
500
- return Qnil;
609
+ raise_invalid_call_type_err(call_type);
501
610
  break;
502
611
  }
503
612
 
504
- VALUE output = rb_ary_new();
613
+ output = rb_ary_new();
505
614
  rb_ary_push(output, INT2FIX(rc));
506
615
  if (IS_SYNC(call_type) && rc == ZOK) {
507
616
  rb_ary_push(output, zkrb_acl_vector_to_ruby(&acls));
@@ -515,7 +624,7 @@ static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
515
624
  #define is_closed(self) RTEST(rb_iv_get(self, "@_closed"))
516
625
  #define is_shutting_down(self) RTEST(rb_iv_get(self, "@_shutting_down"))
517
626
 
518
- static VALUE method_get_next_event(VALUE self, VALUE blocking) {
627
+ static VALUE method_zkrb_get_next_event(VALUE self, VALUE blocking) {
519
628
  // dbg.h
520
629
  check_debug(!is_closed(self), "we are closed, not trying to get event");
521
630
 
@@ -523,7 +632,7 @@ static VALUE method_get_next_event(VALUE self, VALUE blocking) {
523
632
  FETCH_DATA_PTR(self, zk);
524
633
 
525
634
  for (;;) {
526
- check_debug(!is_closed(self), "we're closed in the middle of method_get_next_event, bailing");
635
+ check_debug(!is_closed(self), "we're closed in the middle of method_zkrb_get_next_event, bailing");
527
636
 
528
637
  zkrb_event_t *event = zkrb_dequeue(zk->queue, 1);
529
638
 
@@ -534,7 +643,7 @@ static VALUE method_get_next_event(VALUE self, VALUE blocking) {
534
643
  }
535
644
  else {
536
645
  // if we're shutting down, don't enter this section, we don't want to block
537
- check_debug(!is_shutting_down(self), "method_get_next_event, we're shutting down, don't enter blocking section");
646
+ check_debug(!is_shutting_down(self), "method_zkrb_get_next_event, we're shutting down, don't enter blocking section");
538
647
 
539
648
  int fd = zk->queue->pipe_read;
540
649
  ssize_t bytes_read = 0;
@@ -565,6 +674,117 @@ static VALUE method_get_next_event(VALUE self, VALUE blocking) {
565
674
  return Qnil;
566
675
  }
567
676
 
677
+ // the single threaded version of this call. will go away when we do direct
678
+ // event delivery (soon)
679
+ static VALUE method_zkrb_get_next_event_st(VALUE self) {
680
+ VALUE rval = Qnil;
681
+
682
+ if (is_closed(self)) {
683
+ zkrb_debug("we are closed, not gonna try to get an event");
684
+ return Qnil;
685
+ }
686
+
687
+ FETCH_DATA_PTR(self, zk);
688
+
689
+ zkrb_event_t *event = zkrb_dequeue(zk->queue, 0);
690
+
691
+ if (event != NULL) {
692
+ rval = zkrb_event_to_ruby(event);
693
+ zkrb_event_free(event);
694
+
695
+ int fd = zk->queue->pipe_read;
696
+
697
+ // we don't care in this case. this is just until i can remove the self
698
+ // pipe from the queue
699
+ char b[128];
700
+ while(read(fd, b, sizeof(b)) == sizeof(b)){}
701
+ }
702
+
703
+ return rval;
704
+ }
705
+
706
+ inline static int get_self_pipe_read_fd(VALUE self) {
707
+ rb_io_t *fptr;
708
+ VALUE pipe_read = rb_iv_get(self, "@pipe_read");
709
+
710
+ if NIL_P(pipe_read)
711
+ rb_raise(rb_eRuntimeError, "@pipe_read was nil!");
712
+
713
+ GetOpenFile(pipe_read, fptr);
714
+
715
+ rb_io_check_readable(fptr);
716
+
717
+ #ifdef ZKRB_RUBY_187
718
+ return fileno(fptr->f);
719
+ #else
720
+ return fptr->fd;
721
+ #endif
722
+ }
723
+
724
+
725
+ static VALUE method_zkrb_iterate_event_loop(VALUE self) {
726
+ FETCH_DATA_PTR(self, zk);
727
+
728
+ fd_set rfds, wfds, efds;
729
+ FD_ZERO(&rfds); FD_ZERO(&wfds); FD_ZERO(&efds);
730
+
731
+ int fd=0, interest=0, events=0, rc=0, maxfd=0;
732
+ struct timeval tv;
733
+
734
+ zookeeper_interest(zk->zh, &fd, &interest, &tv);
735
+
736
+ if (fd != -1) {
737
+ if (interest & ZOOKEEPER_READ) {
738
+ FD_SET(fd, &rfds);
739
+ } else {
740
+ FD_CLR(fd, &rfds);
741
+ }
742
+ if (interest & ZOOKEEPER_WRITE) {
743
+ FD_SET(fd, &wfds);
744
+ } else {
745
+ FD_CLR(fd, &wfds);
746
+ }
747
+ } else {
748
+ fd = 0;
749
+ }
750
+
751
+ // add our self-pipe to the read set, allow us to wake up in case our attention is needed
752
+ int pipe_r_fd = get_self_pipe_read_fd(self);
753
+
754
+ FD_SET(pipe_r_fd, &rfds);
755
+
756
+ maxfd = (pipe_r_fd > fd) ? pipe_r_fd : fd;
757
+
758
+ rc = rb_thread_select(maxfd+1, &rfds, &wfds, &efds, &tv);
759
+
760
+ if (rc > 0) {
761
+ if (FD_ISSET(fd, &rfds)) {
762
+ events |= ZOOKEEPER_READ;
763
+ }
764
+ if (FD_ISSET(fd, &wfds)) {
765
+ events |= ZOOKEEPER_WRITE;
766
+ }
767
+
768
+ // we got woken up by the self-pipe
769
+ if (FD_ISSET(pipe_r_fd, &rfds)) {
770
+ // flush the pipe (from mt_adaptor.c)
771
+ char b[1];
772
+ read(pipe_r_fd, b, 1); // one event has awoken us, so we clear one event from the pipe
773
+ }
774
+
775
+ rc = zookeeper_process(zk->zh, events);
776
+ }
777
+ else if (rc == 0) {
778
+ zkrb_debug("timed out waiting for descriptor to be ready");
779
+ }
780
+ else {
781
+ log_err("select returned: %d", rc);
782
+ }
783
+
784
+ return INT2FIX(rc);
785
+ }
786
+
787
+
568
788
  static VALUE method_has_events(VALUE self) {
569
789
  VALUE rb_event;
570
790
  FETCH_DATA_PTR(self, zk);
@@ -575,6 +795,7 @@ static VALUE method_has_events(VALUE self) {
575
795
 
576
796
 
577
797
  // wake up the event loop, used when shutting down
798
+ #if 0
578
799
  static VALUE method_wake_event_loop_bang(VALUE self) {
579
800
  FETCH_DATA_PTR(self, zk);
580
801
 
@@ -583,12 +804,12 @@ static VALUE method_wake_event_loop_bang(VALUE self) {
583
804
 
584
805
  return Qnil;
585
806
  };
807
+ #endif
586
808
 
587
809
  static VALUE method_close_handle(VALUE self) {
588
810
  FETCH_DATA_PTR(self, zk);
589
811
 
590
812
  if (ZKRBDebugging) {
591
- /* fprintf(stderr, "CLOSING ZK INSTANCE: obj_id %lx", FIX2LONG(rb_obj_id(self)));*/
592
813
  zkrb_debug_inst(self, "CLOSING_ZK_INSTANCE");
593
814
  print_zkrb_instance_data(zk);
594
815
  }
@@ -597,15 +818,12 @@ static VALUE method_close_handle(VALUE self) {
597
818
  // has been called
598
819
  rb_iv_set(self, "@_closed", Qtrue);
599
820
 
600
- zkrb_debug_inst(self, "calling destroy_zkrb_instance");
601
-
602
821
  /* Note that after zookeeper_close() returns, ZK handle is invalid */
603
822
  int rc = destroy_zkrb_instance(zk);
604
823
 
605
824
  zkrb_debug("destroy_zkrb_instance returned: %d", rc);
606
825
 
607
- return Qnil;
608
- /* return INT2FIX(rc);*/
826
+ return INT2FIX(rc);
609
827
  }
610
828
 
611
829
  static VALUE method_deterministic_conn_order(VALUE self, VALUE yn) {
@@ -634,12 +852,19 @@ static VALUE method_recv_timeout(VALUE self) {
634
852
  /* return UINT2NUM(id->client_id);*/
635
853
  /*}*/
636
854
 
637
-
638
855
  // returns a CZookeeper::ClientId object with the values set for session_id and passwd
639
856
  static VALUE method_client_id(VALUE self) {
640
857
  FETCH_DATA_PTR(self, zk);
858
+ char buf[32];
641
859
  const clientid_t *cid = zoo_client_id(zk->zh);
642
860
 
861
+ if (strlen(cid->passwd) != 16) {
862
+ zkrb_debug("passwd is not null-termniated");
863
+ } else {
864
+ hexbufify(buf, cid->passwd, 16);
865
+ zkrb_debug("password in hex is: %s", buf);
866
+ }
867
+
643
868
  VALUE session_id = LL2NUM(cid->client_id);
644
869
  VALUE passwd = rb_str_new2(cid->passwd);
645
870
 
@@ -663,21 +888,28 @@ static VALUE method_zerror(VALUE self, VALUE errc) {
663
888
  }
664
889
 
665
890
  static void zkrb_define_methods(void) {
666
- #define DEFINE_METHOD(method, args) { \
667
- rb_define_method(CZookeeper, #method, method_ ## method, args); }
668
- #define DEFINE_CLASS_METHOD(method, args) { \
669
- rb_define_singleton_method(CZookeeper, #method, method_ ## method, args); }
891
+ #define DEFINE_METHOD(M, ARGS) { \
892
+ rb_define_method(CZookeeper, #M, method_ ## M, ARGS); }
893
+
894
+ #define DEFINE_CLASS_METHOD(M, ARGS) { \
895
+ rb_define_singleton_method(CZookeeper, #M, method_ ## M, ARGS); }
896
+
897
+ // defines a method with a zkrb_ prefix, the actual C method does not have this prefix
898
+ #define DEFINE_ZKRB_METHOD(M, ARGS) { \
899
+ rb_define_method(CZookeeper, zkrb_ ## M, method_ ## M, ARGS); }
670
900
 
671
901
  // the number after the method name should be actual arity of C function - 1
672
902
  DEFINE_METHOD(zkrb_init, -1);
673
- DEFINE_METHOD(get_children, 4);
674
- DEFINE_METHOD(exists, 4);
675
- DEFINE_METHOD(create, 6);
676
- DEFINE_METHOD(delete, 4);
677
- DEFINE_METHOD(get, 4);
678
- DEFINE_METHOD(set, 5);
679
- DEFINE_METHOD(set_acl, 5);
680
- DEFINE_METHOD(get_acl, 3);
903
+
904
+ rb_define_method(CZookeeper, "zkrb_get_children", method_get_children, 4);
905
+ rb_define_method(CZookeeper, "zkrb_exists", method_exists, 4);
906
+ rb_define_method(CZookeeper, "zkrb_create", method_create, 6);
907
+ rb_define_method(CZookeeper, "zkrb_delete", method_delete, 4);
908
+ rb_define_method(CZookeeper, "zkrb_get", method_get, 4);
909
+ rb_define_method(CZookeeper, "zkrb_set", method_set, 5);
910
+ rb_define_method(CZookeeper, "zkrb_set_acl", method_set_acl, 5);
911
+ rb_define_method(CZookeeper, "zkrb_get_acl", method_get_acl, 3);
912
+
681
913
  DEFINE_METHOD(client_id, 0);
682
914
  DEFINE_METHOD(close_handle, 0);
683
915
  DEFINE_METHOD(deterministic_conn_order, 1);
@@ -685,12 +917,15 @@ static void zkrb_define_methods(void) {
685
917
  DEFINE_METHOD(recv_timeout, 1);
686
918
  DEFINE_METHOD(zkrb_state, 0);
687
919
  DEFINE_METHOD(sync, 2);
920
+ DEFINE_METHOD(zkrb_iterate_event_loop, 0);
921
+ DEFINE_METHOD(zkrb_get_next_event_st, 0);
688
922
 
689
923
  // TODO
690
924
  // DEFINE_METHOD(add_auth, 3);
691
925
 
692
926
  // methods for the ruby-side event manager
693
- DEFINE_METHOD(get_next_event, 1);
927
+ DEFINE_METHOD(zkrb_get_next_event, 1);
928
+ DEFINE_METHOD(zkrb_get_next_event_st, 0);
694
929
  DEFINE_METHOD(has_events, 0);
695
930
 
696
931
  // Make these class methods?
@@ -699,7 +934,6 @@ static void zkrb_define_methods(void) {
699
934
  rb_define_singleton_method(CZookeeper, "set_zkrb_debug_level", klass_method_zkrb_set_debug_level, 1);
700
935
 
701
936
  rb_attr(CZookeeper, rb_intern("selectable_io"), 1, 0, Qtrue);
702
- rb_define_method(CZookeeper, "wake_event_loop!", method_wake_event_loop_bang, 0);
703
937
 
704
938
  }
705
939
 
@@ -723,6 +957,10 @@ void Init_zookeeper_c() {
723
957
  ZKRBDebugging = 0;
724
958
 
725
959
  mZookeeper = rb_define_module("Zookeeper");
960
+ mZookeeperExceptions = rb_define_module_under(mZookeeper, "Exceptions");
961
+
962
+ // this will likely fail if the load order is screwed up
963
+ eHandleClosedException = rb_const_get(mZookeeperExceptions, rb_intern("HandleClosedException"));
726
964
 
727
965
  /* initialize CZookeeper class */
728
966
  CZookeeper = rb_define_class_under(mZookeeper, "CZookeeper", rb_cObject);
@@ -732,6 +970,7 @@ void Init_zookeeper_c() {
732
970
  rb_define_method(ZookeeperClientId, "initialize", zkrb_client_id_method_initialize, 0);
733
971
  rb_define_attr(ZookeeperClientId, "session_id", 1, 1);
734
972
  rb_define_attr(ZookeeperClientId, "passwd", 1, 1);
973
+
735
974
  }
736
975
 
737
976
  // vim:ts=2:sw=2:sts=2:et