zookeeper 0.2.2 → 0.3.0

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.
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
  }