zookeeper 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/zookeeper_c.c CHANGED
@@ -1,83 +1,79 @@
1
1
  /* Ruby wrapper for the Zookeeper C API
2
2
  * Phillip Pearson <pp@myelin.co.nz>
3
3
  * Eric Maland <eric@twitter.com>
4
+ * Brian Wickman <wickman@twitter.com>
5
+ *
6
+ * This fork is a 90% rewrite of the original. It takes a more evented
7
+ * approach to isolate the ZK state machine from the ruby interpreter via an
8
+ * event queue. It's similar to the ZookeeperFFI version except that it
9
+ * actually works on MRI 1.8.
4
10
  */
5
11
 
6
12
  #define THREADED
7
13
 
8
14
  #include "ruby.h"
9
-
10
15
  #include "c-client-src/zookeeper.h"
11
16
  #include <errno.h>
12
17
  #include <stdio.h>
18
+ #include <stdlib.h>
19
+
20
+ #include "zookeeper_lib.h"
13
21
 
14
22
  static VALUE Zookeeper = Qnil;
15
- static VALUE eNoNode = Qnil;
16
- static VALUE eBadVersion = Qnil;
17
23
 
18
- struct zk_rb_data {
19
- zhandle_t *zh;
20
- clientid_t myid;
24
+ struct zkrb_instance_data {
25
+ zhandle_t *zh;
26
+ clientid_t myid;
27
+ zkrb_queue_t *queue;
21
28
  };
22
29
 
23
- static void watcher(zhandle_t *zh, int type, int state, const char *path, void *ctx) {
24
- VALUE self, watcher_id;
25
- (void)ctx;
26
- return; // watchers don't work in ruby yet
27
-
28
- self = (VALUE)zoo_get_context(zh);;
29
- watcher_id = rb_intern("watcher");
30
-
31
- fprintf(stderr,"C watcher %d state = %d for %s.\n", type, state, (path ? path: "null"));
32
- rb_funcall(self, watcher_id, 3, INT2FIX(type), INT2FIX(state), rb_str_new2(path));
33
- }
34
-
35
- #warning [emaland] incomplete - but easier to read!
36
- static void check_errors(int rc) {
37
- switch (rc) {
38
- case ZOK:
39
- /* all good! */
40
- break;
41
- case ZNONODE:
42
- rb_raise(eNoNode, "the node does not exist");
43
- break;
44
- case ZBADVERSION:
45
- rb_raise(eBadVersion, "expected version does not match actual version");
46
- break;
47
- default:
48
- rb_raise(rb_eRuntimeError, "unknown error returned from zookeeper: %d (%s)", rc, zerror(rc));
30
+ typedef enum {
31
+ SYNC = 0,
32
+ ASYNC = 1,
33
+ SYNC_WATCH = 2,
34
+ ASYNC_WATCH = 3
35
+ } zkrb_call_type;
36
+
37
+ #define IS_SYNC(zkrbcall) ((zkrbcall)==SYNC || (zkrbcall)==SYNC_WATCH)
38
+ #define IS_ASYNC(zkrbcall) ((zkrbcall)==ASYNC || (zkrbcall)==ASYNC_WATCH)
39
+
40
+ static void free_zkrb_instance_data(struct zkrb_instance_data* ptr) {
41
+ #warning [wickman] TODO: free queue
42
+ #warning [wickman] TODO: fire off warning if queue is not empty
43
+ if (ptr->zh && zoo_state(ptr->zh) == ZOO_CONNECTED_STATE) {
44
+ zookeeper_close(ptr->zh);
49
45
  }
50
46
  }
51
47
 
52
- static void free_zk_rb_data(struct zk_rb_data* ptr) {
53
- zookeeper_close(ptr->zh);
54
- }
55
-
56
- static VALUE array_from_stat(const struct Stat* stat) {
57
- return rb_ary_new3(8,
58
- LL2NUM(stat->czxid),
59
- LL2NUM(stat->mzxid),
60
- LL2NUM(stat->ctime),
61
- LL2NUM(stat->mtime),
62
- INT2NUM(stat->version),
63
- INT2NUM(stat->cversion),
64
- INT2NUM(stat->aversion),
65
- LL2NUM(stat->ephemeralOwner));
66
- }
67
-
68
48
  static VALUE method_initialize(VALUE self, VALUE hostPort) {
69
- VALUE data;
70
- struct zk_rb_data* zk = NULL;
71
-
72
49
  Check_Type(hostPort, T_STRING);
73
50
 
74
- data = Data_Make_Struct(Zookeeper, struct zk_rb_data, 0, free_zk_rb_data, zk);
75
-
51
+ VALUE data;
52
+ struct zkrb_instance_data *zk_local_ctx = NULL;
53
+ data = Data_Make_Struct(Zookeeper,
54
+ struct zkrb_instance_data,
55
+ 0,
56
+ free_zkrb_instance_data,
57
+ zk_local_ctx);
58
+ zk_local_ctx->queue = zkrb_queue_alloc();
59
+
76
60
  zoo_set_debug_level(ZOO_LOG_LEVEL_INFO);
77
61
  zoo_deterministic_conn_order(0);
78
-
79
- zk->zh = zookeeper_init(RSTRING(hostPort)->ptr, watcher, 10000, &zk->myid, (void*)self, 0);
80
- if (!zk->zh) {
62
+
63
+ zkrb_calling_context *ctx =
64
+ zkrb_calling_context_alloc(ZKRB_GLOBAL_REQ, zk_local_ctx->queue);
65
+
66
+ zk_local_ctx->zh =
67
+ zookeeper_init(
68
+ RSTRING(hostPort)->ptr,
69
+ zkrb_state_callback,
70
+ 10000,
71
+ &zk_local_ctx->myid,
72
+ ctx,
73
+ 0);
74
+
75
+ #warning [wickman] TODO handle this properly on the Ruby side rather than C side
76
+ if (!zk_local_ctx->zh) {
81
77
  rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
82
78
  }
83
79
 
@@ -87,194 +83,298 @@ static VALUE method_initialize(VALUE self, VALUE hostPort) {
87
83
  }
88
84
 
89
85
  #define FETCH_DATA_PTR(x, y) \
90
- struct zk_rb_data * y; \
91
- Data_Get_Struct(rb_iv_get(x, "@data"), struct zk_rb_data, y)
92
-
93
- static VALUE method_get_children(VALUE self, VALUE path) {
86
+ struct zkrb_instance_data * y; \
87
+ Data_Get_Struct(rb_iv_get(x, "@data"), struct zkrb_instance_data, y)
88
+
89
+ #define STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, cb_ctx, w_ctx, call_type) \
90
+ if (TYPE(reqid) != T_FIXNUM && TYPE(reqid) != T_BIGNUM) { \
91
+ rb_raise(rb_eTypeError, "reqid must be Fixnum/Bignum"); \
92
+ return Qnil; \
93
+ } \
94
+ Check_Type(path, T_STRING); \
95
+ struct zkrb_instance_data * zk; \
96
+ Data_Get_Struct(rb_iv_get(self, "@data"), struct zkrb_instance_data, zk); \
97
+ zkrb_calling_context* cb_ctx = \
98
+ (async != Qfalse && async != Qnil) ? \
99
+ zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
100
+ NULL; \
101
+ zkrb_calling_context* w_ctx = \
102
+ (watch != Qfalse && watch != Qnil) ? \
103
+ zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
104
+ NULL; \
105
+ int a = (async != Qfalse && async != Qnil); \
106
+ int w = (watch != Qfalse && watch != Qnil); \
107
+ zkrb_call_type call_type; \
108
+ if (a) { if (w) { call_type = ASYNC_WATCH; } else { call_type = ASYNC; } } \
109
+ else { if (w) { call_type = SYNC_WATCH; } else { call_type = SYNC; } }
110
+
111
+ static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
112
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
113
+
94
114
  struct String_vector strings;
95
- int i;
96
- VALUE output;
97
-
98
- Check_Type(path, T_STRING);
99
- FETCH_DATA_PTR(self, zk);
100
-
101
- check_errors(zoo_get_children(zk->zh, RSTRING(path)->ptr, 0, &strings));
115
+ struct Stat stat;
116
+
117
+ int rc;
118
+ switch (call_type) {
119
+ case SYNC:
120
+ rc = zoo_get_children2(zk->zh, RSTRING(path)->ptr, 0, &strings, &stat);
121
+ break;
122
+
123
+ case SYNC_WATCH:
124
+ rc = zoo_wget_children2(zk->zh, RSTRING(path)->ptr, zkrb_state_callback, watch_ctx, &strings, &stat);
125
+ break;
126
+
127
+ case ASYNC:
128
+ rc = zoo_aget_children2(zk->zh, RSTRING(path)->ptr, 0, zkrb_strings_stat_callback, data_ctx);
129
+ break;
130
+
131
+ case ASYNC_WATCH:
132
+ rc = zoo_awget_children2(zk->zh, RSTRING(path)->ptr, zkrb_state_callback, watch_ctx, zkrb_strings_stat_callback, data_ctx);
133
+ break;
134
+ }
102
135
 
103
- output = rb_ary_new();
104
- for (i = 0; i < strings.count; ++i) {
105
- rb_ary_push(output, rb_str_new2(strings.data[i]));
136
+ VALUE output = rb_ary_new();
137
+ rb_ary_push(output, INT2FIX(rc));
138
+ if (IS_SYNC(call_type) && rc == ZOK) {
139
+ rb_ary_push(output, zkrb_string_vector_to_ruby(&strings));
140
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
106
141
  }
107
142
  return output;
108
143
  }
109
144
 
110
- static VALUE method_exists(VALUE self, VALUE path, VALUE watch) {
145
+ static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
146
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
147
+
111
148
  struct Stat stat;
112
149
 
113
- Check_Type(path, T_STRING);
114
- FETCH_DATA_PTR(self, zk);
115
-
116
- check_errors(zoo_exists(zk->zh, RSTRING(path)->ptr, (watch != Qfalse && watch != Qnil), &stat));
150
+ int rc;
151
+ switch (call_type) {
152
+ case SYNC:
153
+ rc = zoo_exists(zk->zh, RSTRING(path)->ptr, 0, &stat);
154
+ break;
155
+
156
+ case SYNC_WATCH:
157
+ rc = zoo_wexists(zk->zh, RSTRING(path)->ptr, zkrb_state_callback, watch_ctx, &stat);
158
+ break;
159
+
160
+ case ASYNC:
161
+ rc = zoo_aexists(zk->zh, RSTRING(path)->ptr, 0, zkrb_stat_callback, data_ctx);
162
+ break;
163
+
164
+ case ASYNC_WATCH:
165
+ rc = zoo_awexists(zk->zh, RSTRING(path)->ptr, zkrb_state_callback, watch_ctx, zkrb_stat_callback, data_ctx);
166
+ break;
167
+ }
117
168
 
118
- return array_from_stat(&stat);
169
+ VALUE output = rb_ary_new();
170
+ rb_ary_push(output, INT2FIX(rc));
171
+ if (IS_SYNC(call_type) && rc == ZOK) {
172
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
173
+ }
174
+ return output;
119
175
  }
120
176
 
121
- static VALUE method_create(VALUE self, VALUE path, VALUE value, VALUE flags) {
122
- char realpath[10240];
123
-
124
- Check_Type(path, T_STRING);
125
- Check_Type(value, T_STRING);
177
+ static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE acls, VALUE flags) {
178
+ VALUE watch = Qfalse;
179
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
180
+
181
+ struct Stat stat;
182
+ if (data != Qnil) Check_Type(data, T_STRING);
126
183
  Check_Type(flags, T_FIXNUM);
184
+ const char *data_ptr = (data == Qnil) ? NULL : RSTRING(data)->ptr;
185
+ size_t data_len = (data == Qnil) ? -1 : RSTRING(data)->len;
186
+
187
+ struct ACL_vector *aclptr = NULL;
188
+ if (acls != Qnil) { aclptr = zkrb_ruby_to_aclvector(acls); }
189
+ char realpath[16384];
190
+
191
+ int rc;
192
+ switch (call_type) {
193
+ case SYNC:
194
+ rc = zoo_create(zk->zh, RSTRING(path)->ptr, data_ptr, data_len, aclptr, FIX2INT(flags), realpath, sizeof(realpath));
195
+ if (aclptr != NULL) deallocate_ACL_vector(aclptr);
196
+ break;
197
+ case ASYNC:
198
+ rc = zoo_acreate(zk->zh, RSTRING(path)->ptr, data_ptr, data_len, aclptr, FIX2INT(flags), zkrb_string_callback, data_ctx);
199
+ if (aclptr != NULL) deallocate_ACL_vector(aclptr);
200
+ break;
201
+ default:
202
+ /* TODO(wickman) raise proper argument error */
203
+ return Qnil;
204
+ break;
205
+ }
127
206
 
128
- FETCH_DATA_PTR(self, zk);
129
-
130
- check_errors(zoo_create(zk->zh, RSTRING(path)->ptr,
131
- RSTRING(value)->ptr, RSTRING(value)->len,
132
- &ZOO_OPEN_ACL_UNSAFE, FIX2INT(flags),
133
- realpath, sizeof(realpath)));
134
-
135
- return rb_str_new2(realpath);
207
+ VALUE output = rb_ary_new();
208
+ rb_ary_push(output, INT2FIX(rc));
209
+ if (IS_SYNC(call_type) && rc == ZOK) {
210
+ return rb_ary_push(output, rb_str_new2(realpath));
211
+ }
212
+ return output;
136
213
  }
137
214
 
138
- static VALUE method_delete(VALUE self, VALUE path, VALUE version) {
139
- Check_Type(path, T_STRING);
215
+ static VALUE method_delete(VALUE self, VALUE reqid, VALUE path, VALUE version, VALUE async) {
216
+ VALUE watch = Qfalse;
217
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
140
218
  Check_Type(version, T_FIXNUM);
141
-
142
- FETCH_DATA_PTR(self, zk);
143
-
144
- check_errors(zoo_delete(zk->zh, RSTRING(path)->ptr, FIX2INT(version)));
145
-
146
- return Qtrue;
147
- }
148
-
149
- static VALUE method_get(VALUE self, VALUE path) {
150
- char data[1024];
151
- int data_len = sizeof(data);
152
-
153
- struct Stat stat;
154
- memset(data, 0, sizeof(data));
155
-
156
- Check_Type(path, T_STRING);
157
- FETCH_DATA_PTR(self, zk);
158
219
 
159
- check_errors(zoo_get(zk->zh, RSTRING(path)->ptr, 0, data, &data_len, &stat));
220
+ int rc = 0;
221
+ switch (call_type) {
222
+ case SYNC:
223
+ rc = zoo_delete(zk->zh, RSTRING(path)->ptr, FIX2INT(version));
224
+ break;
225
+ case ASYNC:
226
+ rc = zoo_adelete(zk->zh, RSTRING(path)->ptr, FIX2INT(version), zkrb_void_callback, data_ctx);
227
+ break;
228
+ default:
229
+ /* TODO(wickman) raise proper argument error */
230
+ return Qnil;
231
+ break;
232
+ }
160
233
 
161
- return rb_ary_new3(2,
162
- rb_str_new(data, data_len),
163
- array_from_stat(&stat));
234
+ return INT2FIX(rc);
164
235
  }
165
236
 
166
- static VALUE method_set(int argc, VALUE* argv, VALUE self)
167
- {
168
- VALUE v_path, v_data, v_version;
169
- int real_version = -1;
170
-
171
- FETCH_DATA_PTR(self, zk);
172
-
173
- rb_scan_args(argc, argv, "21", &v_path, &v_data, &v_version);
174
-
175
- Check_Type(v_path, T_STRING);
176
- Check_Type(v_data, T_STRING);
177
- Check_Type(v_version, T_FIXNUM);
178
237
 
179
- if(!NIL_P(v_version))
180
- real_version = FIX2INT(v_version);
238
+ #define MAX_ZNODE_SIZE 1048576
181
239
 
182
- check_errors(zoo_set(zk->zh,
183
- RSTRING(v_path)->ptr,
184
- RSTRING(v_data)->ptr, RSTRING(v_data)->len,
185
- FIX2INT(v_version)));
240
+ static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
241
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
186
242
 
187
- return Qtrue;
188
- }
243
+ /* ugh */
244
+ char * data = malloc(MAX_ZNODE_SIZE);
245
+ int data_len = MAX_ZNODE_SIZE;
246
+ struct Stat stat;
189
247
 
190
- static void void_completion_callback(int rc, const void *data) {
248
+ int rc;
249
+ switch (call_type) {
250
+ case SYNC:
251
+ rc = zoo_get(zk->zh, RSTRING(path)->ptr, 0, data, &data_len, &stat);
252
+ break;
253
+
254
+ case SYNC_WATCH:
255
+ rc = zoo_wget(zk->zh, RSTRING(path)->ptr, zkrb_state_callback, watch_ctx, data, &data_len, &stat);
256
+ break;
257
+
258
+ case ASYNC:
259
+ rc = zoo_aget(zk->zh, RSTRING(path)->ptr, 0, zkrb_data_callback, data_ctx);
260
+ break;
261
+
262
+ case ASYNC_WATCH:
263
+ rc = zoo_awget(zk->zh, RSTRING(path)->ptr, zkrb_state_callback, watch_ctx, zkrb_data_callback, data_ctx);
264
+ break;
265
+ }
191
266
 
267
+ VALUE output = rb_ary_new();
268
+ rb_ary_push(output, INT2FIX(rc));
269
+ if (IS_SYNC(call_type) && rc == ZOK) {
270
+ rb_ary_push(output, rb_str_new(data, data_len));
271
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
272
+ }
273
+ free(data);
274
+ return output;
192
275
  }
193
276
 
194
- static void string_completion_callback(int rc, const char *value, const void *data) {
277
+ static VALUE method_set(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE version) {
278
+ VALUE watch = Qfalse;
279
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
195
280
 
196
- }
197
-
198
- #warning [emaland] to be implemented
199
- static VALUE method_set2(int argc, VALUE *argv, VALUE self) {
200
- // ZOOAPI int zoo_set2(zhandle_t *zh, const char *path, const char *buffer,
201
- // int buflen, int version, struct Stat *stat);
202
- return Qnil;
281
+ struct Stat stat;
282
+ if (data != Qnil) Check_Type(data, T_STRING);
283
+ const char *data_ptr = (data == Qnil) ? NULL : RSTRING(data)->ptr;
284
+ size_t data_len = (data == Qnil) ? -1 : RSTRING(data)->len;
285
+
286
+ int rc;
287
+ switch (call_type) {
288
+ case SYNC:
289
+ rc = zoo_set2(zk->zh, RSTRING(path)->ptr, data_ptr, data_len, FIX2INT(version), &stat);
290
+ break;
291
+ case ASYNC:
292
+ rc = zoo_aset(zk->zh, RSTRING(path)->ptr, data_ptr, data_len, FIX2INT(version),
293
+ zkrb_stat_callback, data_ctx);
294
+ break;
295
+ default:
296
+ /* TODO(wickman) raise proper argument error */
297
+ return Qnil;
298
+ break;
299
+ }
203
300
 
301
+ VALUE output = rb_ary_new();
302
+ rb_ary_push(output, INT2FIX(rc));
303
+ if (IS_SYNC(call_type) && rc == ZOK) {
304
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
305
+ }
306
+ return output;
204
307
  }
205
308
 
206
- static VALUE method_set_acl(int argc, VALUE* argv, VALUE self) {
207
- /* STUB */
208
- /* VALUE v_path, v_data, v_version; */
209
- /* struct zk_rb_data* zk; */
210
- /* int real_version = -1; */
309
+ static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VALUE async, VALUE version) {
310
+ VALUE watch = Qfalse;
311
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
312
+ struct ACL_vector * aclptr = zkrb_ruby_to_aclvector(acls);
313
+
314
+ int rc;
315
+ switch (call_type) {
316
+ case SYNC:
317
+ rc = zoo_set_acl(zk->zh, RSTRING(path)->ptr, FIX2INT(version), aclptr);
318
+ deallocate_ACL_vector(aclptr);
319
+ break;
320
+ case ASYNC:
321
+ rc = zoo_aset_acl(zk->zh, RSTRING(path)->ptr, FIX2INT(version), aclptr, zkrb_void_callback, data_ctx);
322
+ deallocate_ACL_vector(aclptr);
323
+ break;
324
+ default:
325
+ /* TODO(wickman) raise proper argument error */
326
+ return Qnil;
327
+ break;
328
+ }
211
329
 
212
- /* rb_scan_args(argc, argv, "21", &v_path, &v_data, &v_version); */
213
-
214
- /* Check_Type(v_path, T_STRING); */
215
- /* Check_Type(v_data, T_STRING); */
216
- /* Check_Type(v_version, T_FIXNUM); */
330
+ return INT2FIX(rc);
331
+ }
217
332
 
218
- /* if(!NIL_P(v_version)) */
219
- /* real_version = FIX2INT(v_version); */
333
+ static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
334
+ VALUE watch = Qfalse;
335
+ STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
220
336
 
221
- /* Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk); */
337
+ struct ACL_vector acls;
338
+ struct Stat stat;
222
339
 
223
- /* check_errors(zoo_set(zk->zh, RSTRING(v_path)->ptr, */
224
- /* RSTRING(v_data)->ptr, RSTRING(v_data)->len, */
225
- /* FIX2INT(v_version))); */
340
+ int rc;
341
+ switch (call_type) {
342
+ case SYNC:
343
+ rc = zoo_get_acl(zk->zh, RSTRING(path)->ptr, &acls, &stat);
344
+ break;
345
+ case ASYNC:
346
+ rc = zoo_aget_acl(zk->zh, RSTRING(path)->ptr, zkrb_acl_callback, data_ctx);
347
+ break;
348
+ default:
349
+ /* TODO(wickman) raise proper argument error */
350
+ return Qnil;
351
+ break;
352
+ }
226
353
 
227
- return Qnil;
354
+ // do we need to deallocate the strings in the acl vector????
355
+ VALUE output = rb_ary_new();
356
+ rb_ary_push(output, INT2FIX(rc));
357
+ if (IS_SYNC(call_type) && rc == ZOK) {
358
+ rb_ary_push(output, zkrb_acl_vector_to_ruby(&acls));
359
+ rb_ary_push(output, zkrb_stat_to_rarray(&stat));
360
+ }
361
+ return output;
228
362
  }
229
363
 
230
- /*
231
- PARAMETERS:
232
- zh: the zookeeper handle obtained by a call to zookeeper.init
233
- scheme: the id of authentication scheme. Natively supported:
234
- 'digest' password-based authentication
235
- cert: application credentials. The actual value depends on the scheme.
236
- completion: the routine to invoke when the request completes. One of
237
- the following result codes may be passed into the completion callback:
238
- OK operation completed successfully
239
- AUTHFAILED authentication failed
240
-
241
- RETURNS:
242
- OK on success or one of the following errcodes on failure:
243
- BADARGUMENTS - invalid input parameters
244
- INVALIDSTATE - zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAI
245
- LED_STATE
246
- MARSHALLINGERROR - failed to marshall a request; possibly, out of memory
247
- SYSTEMERROR - a system error occured
248
- */
249
- #warning [emaland] make these magically synchronous for now?
250
- static VALUE method_add_auth(VALUE self, VALUE scheme,
251
- VALUE cert, VALUE completion,
252
- VALUE completion_data) {
253
- struct zk_rb_data* zk;
254
- Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk);
255
-
256
- Check_Type(scheme, T_STRING);
257
- Check_Type(cert, T_STRING);
258
- // Check_Type(completion, T_OBJECT); // ???
364
+ static VALUE method_get_next_event(VALUE self) {
365
+ FETCH_DATA_PTR(self, zk);
259
366
 
260
- check_errors(zoo_add_auth(zk->zh, RSTRING(scheme)->ptr,
261
- RSTRING(cert)->ptr, RSTRING(cert)->len,
262
- void_completion_callback, DATA_PTR(completion_data)));
263
- return Qtrue;
264
- }
265
-
266
- static VALUE method_async(VALUE self, VALUE path,
267
- VALUE completion, VALUE completion_data) {
268
- struct zk_rb_data* zk;
269
- Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk);
367
+ zkrb_event_t *event = zkrb_dequeue(zk->queue);
368
+ if (event == NULL) return Qnil;
270
369
 
271
- Check_Type(path, T_STRING);
272
- // Check_Type(completion, T_OBJECT); // ???
273
-
274
- check_errors(zoo_async(zk->zh, RSTRING(path)->ptr,
275
- string_completion_callback, DATA_PTR(completion_data)));
370
+ VALUE hash = zkrb_event_to_ruby(event);
371
+ zkrb_event_free(event);
372
+ return hash;
373
+ }
276
374
 
277
- return Qtrue;
375
+ static VALUE method_has_events(VALUE self) {
376
+ FETCH_DATA_PTR(self, zk);
377
+ return zkrb_peek(zk->queue) != NULL ? Qtrue : Qfalse;
278
378
  }
279
379
 
280
380
  static VALUE method_client_id(VALUE self) {
@@ -285,8 +385,8 @@ static VALUE method_client_id(VALUE self) {
285
385
 
286
386
  static VALUE method_close(VALUE self) {
287
387
  FETCH_DATA_PTR(self, zk);
288
- check_errors(zookeeper_close(zk->zh));
289
- return Qtrue;
388
+ int rc = zookeeper_close(zk->zh);
389
+ return INT2FIX(rc);
290
390
  }
291
391
 
292
392
  static VALUE method_deterministic_conn_order(VALUE self, VALUE yn) {
@@ -294,83 +394,14 @@ static VALUE method_deterministic_conn_order(VALUE self, VALUE yn) {
294
394
  return Qnil;
295
395
  }
296
396
 
297
- static VALUE id_to_ruby(struct Id *id) {
298
- VALUE hash = rb_hash_new();
299
- rb_hash_aset(hash, rb_str_new2("scheme"), rb_str_new2(id->scheme));
300
- rb_hash_aset(hash, rb_str_new2("id"), rb_str_new2(id->id));
301
- return hash;
302
- }
303
-
304
- static VALUE acl_to_ruby(struct ACL *acl) {
305
- VALUE hash = rb_hash_new();
306
- rb_hash_aset(hash, rb_str_new2("perms"), INT2NUM(acl->perms));
307
- rb_hash_aset(hash, rb_str_new2("id"), id_to_ruby(&(acl->id)));
308
- return hash;
309
- }
310
-
311
- static VALUE acl_vector_to_ruby(struct ACL_vector *acl_vector) {
312
- int i = 0;
313
- VALUE ary = rb_ary_new();
314
- for(i = 0; i < acl_vector->count; i++) {
315
- rb_ary_push(ary, acl_to_ruby(acl_vector->data+i));
316
- }
317
- return ary;
318
- }
319
-
320
- /*
321
- struct Stat {
322
- int64_t czxid;
323
- int64_t mzxid;
324
- int64_t ctime;
325
- int64_t mtime;
326
- int32_t version;
327
- int32_t cversion;
328
- int32_t aversion;
329
- int64_t ephemeralOwner;
330
- int32_t dataLength;
331
- int32_t numChildren;
332
- int64_t pzxid;
333
- }
334
- }
335
- */
336
- static VALUE stat_to_ruby(struct Stat *stat) {
337
- VALUE hash = rb_hash_new();
338
- rb_hash_aset(hash, rb_str_new2("czxid"), UINT2NUM(stat->czxid));
339
- rb_hash_aset(hash, rb_str_new2("mzxid"), UINT2NUM(stat->mzxid));
340
- rb_hash_aset(hash, rb_str_new2("ctime"), UINT2NUM(stat->ctime));
341
- rb_hash_aset(hash, rb_str_new2("mtime"), UINT2NUM(stat->mtime));
342
- rb_hash_aset(hash, rb_str_new2("version"), INT2NUM(stat->version));
343
- rb_hash_aset(hash, rb_str_new2("cversion"), INT2NUM(stat->cversion));
344
- rb_hash_aset(hash, rb_str_new2("aversion"), INT2NUM(stat->aversion));
345
- rb_hash_aset(hash, rb_str_new2("ephemeralOwner"), UINT2NUM(stat->ephemeralOwner));
346
- rb_hash_aset(hash, rb_str_new2("dataLength"), INT2NUM(stat->dataLength));
347
- rb_hash_aset(hash, rb_str_new2("numChildren"), INT2NUM(stat->numChildren));
348
- rb_hash_aset(hash, rb_str_new2("pzxid"), UINT2NUM(stat->pzxid));
349
- return hash;
350
- }
351
-
352
- static VALUE method_get_acl(VALUE self, VALUE path) {
397
+ static VALUE method_is_unrecoverable(VALUE self) {
353
398
  FETCH_DATA_PTR(self, zk);
354
- Check_Type(path, T_STRING);
355
-
356
- // ZOOAPI int zoo_get_acl(zhandle_t *zh, const char *path, struct ACL_vector *acl,
357
- // struct Stat *stat);
358
- struct ACL_vector acl;
359
- struct Stat stat;
360
- check_errors(zoo_get_acl(zk->zh, RSTRING(path)->ptr, &acl, &stat));
361
-
362
- VALUE result = rb_ary_new();
363
- rb_ary_push(result, acl_vector_to_ruby(&acl));
364
- rb_ary_push(result, stat_to_ruby(&stat));
365
- return result;
399
+ return is_unrecoverable(zk->zh) == ZINVALIDSTATE ? Qtrue : Qfalse;
366
400
  }
367
401
 
368
- static VALUE method_is_unrecoverable(VALUE self) {
402
+ static VALUE method_state(VALUE self) {
369
403
  FETCH_DATA_PTR(self, zk);
370
- if(is_unrecoverable(zk->zh) == ZINVALIDSTATE)
371
- return Qtrue;
372
-
373
- return Qfalse;
404
+ return INT2NUM(zoo_state(zk->zh));
374
405
  }
375
406
 
376
407
  static VALUE method_recv_timeout(VALUE self) {
@@ -378,141 +409,55 @@ static VALUE method_recv_timeout(VALUE self) {
378
409
  return INT2NUM(zoo_recv_timeout(zk->zh));
379
410
  }
380
411
 
381
- #warning [emaland] make this a class method or global
412
+ // how do you make a class method??
382
413
  static VALUE method_set_debug_level(VALUE self, VALUE level) {
383
- FETCH_DATA_PTR(self, zk);
384
414
  Check_Type(level, T_FIXNUM);
415
+ ZKRBDebugging = (FIX2INT(level) == ZOO_LOG_LEVEL_DEBUG);
385
416
  zoo_set_debug_level(FIX2INT(level));
386
417
  return Qnil;
387
418
  }
388
419
 
389
- #warning [emaland] make this a class method or global
390
420
  static VALUE method_zerror(VALUE self, VALUE errc) {
391
421
  return rb_str_new2(zerror(FIX2INT(errc)));
392
422
  }
393
423
 
394
- static VALUE method_state(VALUE self) {
395
- FETCH_DATA_PTR(self, zk);
396
- return INT2NUM(zoo_state(zk->zh));
397
- }
398
-
399
- #warning [emaland] make this a class method or global
400
- static VALUE method_set_log_stream(VALUE self, VALUE stream) {
401
- // convert stream to FILE*
402
- FILE *fp_stream = (FILE*)stream;
403
- zoo_set_log_stream(fp_stream);
404
- return Qnil;
405
- }
406
-
407
- static VALUE method_set_watcher(VALUE self, VALUE new_watcher) {
408
- FETCH_DATA_PTR(self, zk);
409
- #warning [emaland] needs to be tested/implemented
410
- return Qnil;
411
- // watcher_fn old_watcher = zoo_set_watcher(zk->zh, new_watcher);
412
- // return old_watcher;
413
- }
414
-
415
- void Init_zookeeper_c() {
416
- Zookeeper = rb_define_class("CZookeeper", rb_cObject);
417
-
424
+ static void zkrb_define_methods(void) {
418
425
  #define DEFINE_METHOD(method, args) { \
419
426
  rb_define_method(Zookeeper, #method, method_ ## method, args); }
427
+ #define DEFINE_CLASS_METHOD(method, args) { \
428
+ rb_define_singleton_method(Zookeeper, #method, method_ ## method, args); }
420
429
 
421
430
  DEFINE_METHOD(initialize, 1);
422
- DEFINE_METHOD(get_children, 1);
423
- DEFINE_METHOD(exists, 2);
424
- DEFINE_METHOD(create, 3);
425
- DEFINE_METHOD(delete, 2);
426
- DEFINE_METHOD(get, 1);
427
- DEFINE_METHOD(set, -1);
428
-
429
- /* TODO */
430
- DEFINE_METHOD(add_auth, 3);
431
- DEFINE_METHOD(set_acl, -1);
432
- DEFINE_METHOD(async, 1);
431
+ DEFINE_METHOD(get_children, 4);
432
+ DEFINE_METHOD(exists, 4);
433
+ DEFINE_METHOD(create, 6);
434
+ DEFINE_METHOD(delete, 4);
435
+ DEFINE_METHOD(get, 4);
436
+ DEFINE_METHOD(set, 5);
437
+ DEFINE_METHOD(set_acl, 5);
438
+ DEFINE_METHOD(get_acl, 3);
433
439
  DEFINE_METHOD(client_id, 0);
434
440
  DEFINE_METHOD(close, 0);
435
441
  DEFINE_METHOD(deterministic_conn_order, 1);
436
- DEFINE_METHOD(get_acl, 2);
437
442
  DEFINE_METHOD(is_unrecoverable, 0);
438
443
  DEFINE_METHOD(recv_timeout, 1);
439
- DEFINE_METHOD(set2, -1);
440
- DEFINE_METHOD(set_debug_level, 1);
441
- DEFINE_METHOD(set_log_stream, 1);
442
- DEFINE_METHOD(set_watcher, 2);
443
444
  DEFINE_METHOD(state, 0);
445
+ // TODO
446
+ // DEFINE_METHOD(add_auth, 3);
447
+ // DEFINE_METHOD(async, 1);
448
+
449
+ // methods for the ruby-side event manager
450
+ DEFINE_METHOD(get_next_event, 0);
451
+ DEFINE_METHOD(has_events, 0);
452
+
453
+ // Make these class methods?
454
+ DEFINE_METHOD(set_debug_level, 1);
444
455
  DEFINE_METHOD(zerror, 1);
456
+ }
457
+ void Init_zookeeper_c() {
458
+ ZKRBDebugging = 0;
445
459
 
446
- eNoNode = rb_define_class_under(Zookeeper, "NoNodeError", rb_eRuntimeError);
447
- eBadVersion = rb_define_class_under(Zookeeper, "BadVersionError", rb_eRuntimeError);
448
-
449
- #define EXPORT_CONST(x) { rb_define_const(Zookeeper, #x, INT2FIX(x)); }
450
-
451
- /* create flags */
452
- EXPORT_CONST(ZOO_EPHEMERAL);
453
- EXPORT_CONST(ZOO_SEQUENCE);
454
-
455
- /*
456
- session state
457
- */
458
- EXPORT_CONST(ZOO_EXPIRED_SESSION_STATE);
459
- EXPORT_CONST(ZOO_AUTH_FAILED_STATE);
460
- EXPORT_CONST(ZOO_CONNECTING_STATE);
461
- EXPORT_CONST(ZOO_ASSOCIATING_STATE);
462
- EXPORT_CONST(ZOO_CONNECTED_STATE);
463
-
464
- /* notifications */
465
- EXPORT_CONST(ZOOKEEPER_WRITE);
466
- EXPORT_CONST(ZOOKEEPER_READ);
467
-
468
- /* errors */
469
- EXPORT_CONST(ZOK);
470
- EXPORT_CONST(ZSYSTEMERROR);
471
- EXPORT_CONST(ZRUNTIMEINCONSISTENCY);
472
- EXPORT_CONST(ZDATAINCONSISTENCY);
473
- EXPORT_CONST(ZCONNECTIONLOSS);
474
- EXPORT_CONST(ZMARSHALLINGERROR);
475
- EXPORT_CONST(ZUNIMPLEMENTED);
476
- EXPORT_CONST(ZOPERATIONTIMEOUT);
477
- EXPORT_CONST(ZBADARGUMENTS);
478
- EXPORT_CONST(ZINVALIDSTATE);
479
-
480
- /** API errors. */
481
- EXPORT_CONST(ZAPIERROR);
482
- EXPORT_CONST(ZNONODE);
483
- EXPORT_CONST(ZNOAUTH);
484
- EXPORT_CONST(ZBADVERSION);
485
- EXPORT_CONST(ZNOCHILDRENFOREPHEMERALS);
486
- EXPORT_CONST(ZNODEEXISTS);
487
- EXPORT_CONST(ZNOTEMPTY);
488
- EXPORT_CONST(ZSESSIONEXPIRED);
489
- EXPORT_CONST(ZINVALIDCALLBACK);
490
- EXPORT_CONST(ZINVALIDACL);
491
- EXPORT_CONST(ZAUTHFAILED);
492
- EXPORT_CONST(ZCLOSING);
493
- EXPORT_CONST(ZNOTHING);
494
- EXPORT_CONST(ZSESSIONMOVED);
495
-
496
- /* debug levels */
497
- EXPORT_CONST(ZOO_LOG_LEVEL_ERROR);
498
- EXPORT_CONST(ZOO_LOG_LEVEL_WARN);
499
- EXPORT_CONST(ZOO_LOG_LEVEL_INFO);
500
- EXPORT_CONST(ZOO_LOG_LEVEL_DEBUG);
501
-
502
- /* ACL constants */
503
- EXPORT_CONST(ZOO_PERM_READ);
504
- EXPORT_CONST(ZOO_PERM_WRITE);
505
- EXPORT_CONST(ZOO_PERM_CREATE);
506
- EXPORT_CONST(ZOO_PERM_DELETE);
507
- EXPORT_CONST(ZOO_PERM_ADMIN);
508
- EXPORT_CONST(ZOO_PERM_ALL);
509
-
510
- /* Watch types */
511
- EXPORT_CONST(ZOO_CREATED_EVENT);
512
- EXPORT_CONST(ZOO_DELETED_EVENT);
513
- EXPORT_CONST(ZOO_CHANGED_EVENT);
514
- EXPORT_CONST(ZOO_CHILD_EVENT);
515
- EXPORT_CONST(ZOO_SESSION_EVENT);
516
- EXPORT_CONST(ZOO_NOTWATCHING_EVENT);
517
-
460
+ /* initialize Zookeeper class */
461
+ Zookeeper = rb_define_class("CZookeeper", rb_cObject);
462
+ zkrb_define_methods();
518
463
  }