zookeeper 1.0.6-java → 1.1.0-java

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