zookeeper 0.9.3-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +10 -0
- data/CHANGELOG +119 -0
- data/Gemfile +17 -0
- data/LICENSE +23 -0
- data/Manifest +29 -0
- data/README.markdown +59 -0
- data/Rakefile +139 -0
- data/examples/cloud_config.rb +125 -0
- data/ext/.gitignore +6 -0
- data/ext/Rakefile +51 -0
- data/ext/c_zookeeper.rb +212 -0
- data/ext/dbg.h +53 -0
- data/ext/depend +5 -0
- data/ext/extconf.rb +85 -0
- data/ext/generate_gvl_code.rb +316 -0
- data/ext/zkc-3.3.5.tar.gz +0 -0
- data/ext/zkrb_wrapper.c +731 -0
- data/ext/zkrb_wrapper.h +330 -0
- data/ext/zkrb_wrapper_compat.c +15 -0
- data/ext/zkrb_wrapper_compat.h +11 -0
- data/ext/zookeeper_base.rb +211 -0
- data/ext/zookeeper_c.c +725 -0
- data/ext/zookeeper_lib.c +677 -0
- data/ext/zookeeper_lib.h +172 -0
- data/java/zookeeper_base.rb +477 -0
- data/lib/zookeeper.rb +297 -0
- data/lib/zookeeper/acls.rb +40 -0
- data/lib/zookeeper/callbacks.rb +91 -0
- data/lib/zookeeper/common.rb +174 -0
- data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
- data/lib/zookeeper/constants.rb +57 -0
- data/lib/zookeeper/em_client.rb +55 -0
- data/lib/zookeeper/exceptions.rb +100 -0
- data/lib/zookeeper/stat.rb +21 -0
- data/lib/zookeeper/version.rb +6 -0
- data/notes.txt +14 -0
- data/spec/c_zookeeper_spec.rb +50 -0
- data/spec/chrooted_connection_spec.rb +81 -0
- data/spec/default_watcher_spec.rb +41 -0
- data/spec/em_spec.rb +51 -0
- data/spec/log4j.properties +17 -0
- data/spec/shared/all_success_return_values.rb +10 -0
- data/spec/shared/connection_examples.rb +1018 -0
- data/spec/spec_helper.rb +119 -0
- data/spec/support/progress_formatter.rb +15 -0
- data/spec/zookeeper_spec.rb +24 -0
- data/test/test_basic.rb +37 -0
- data/test/test_callback1.rb +36 -0
- data/test/test_close.rb +16 -0
- data/test/test_esoteric.rb +7 -0
- data/test/test_watcher1.rb +56 -0
- data/test/test_watcher2.rb +52 -0
- metadata +181 -0
data/ext/zookeeper_c.c
ADDED
@@ -0,0 +1,725 @@
|
|
1
|
+
/* Ruby wrapper for the Zookeeper C API
|
2
|
+
* Phillip Pearson <pp@myelin.co.nz>
|
3
|
+
* Eric Maland <eric@twitter.com>
|
4
|
+
* Brian Wickman <wickman@twitter.com>
|
5
|
+
* Jonathan D. Simms <slyphon@gmail.com>
|
6
|
+
*
|
7
|
+
* This fork is a 90% rewrite of the original. It takes a more evented
|
8
|
+
* approach to isolate the ZK state machine from the ruby interpreter via an
|
9
|
+
* event queue. It's similar to the ZookeeperFFI version except that it
|
10
|
+
* actually works on MRI 1.8.
|
11
|
+
*/
|
12
|
+
|
13
|
+
#define THREADED
|
14
|
+
|
15
|
+
#include "ruby.h"
|
16
|
+
#include "c-client-src/zookeeper.h"
|
17
|
+
#include <errno.h>
|
18
|
+
#include <stdio.h>
|
19
|
+
#include <stdlib.h>
|
20
|
+
#include <unistd.h>
|
21
|
+
#include <sys/fcntl.h>
|
22
|
+
#include <pthread.h>
|
23
|
+
#include <inttypes.h>
|
24
|
+
|
25
|
+
#include "zookeeper_lib.h"
|
26
|
+
#include "zkrb_wrapper.h"
|
27
|
+
#include "dbg.h"
|
28
|
+
|
29
|
+
static VALUE Zookeeper = Qnil;
|
30
|
+
static VALUE ZookeeperClientId = Qnil;
|
31
|
+
|
32
|
+
// slyphon: possibly add a lock to this for synchronizing during get_next_event
|
33
|
+
|
34
|
+
struct zkrb_instance_data {
|
35
|
+
zhandle_t *zh;
|
36
|
+
clientid_t myid;
|
37
|
+
zkrb_queue_t *queue;
|
38
|
+
long object_id; // the ruby object this instance data is associated with
|
39
|
+
};
|
40
|
+
|
41
|
+
typedef enum {
|
42
|
+
SYNC = 0,
|
43
|
+
ASYNC = 1,
|
44
|
+
SYNC_WATCH = 2,
|
45
|
+
ASYNC_WATCH = 3
|
46
|
+
} zkrb_call_type;
|
47
|
+
|
48
|
+
#define IS_SYNC(zkrbcall) ((zkrbcall)==SYNC || (zkrbcall)==SYNC_WATCH)
|
49
|
+
#define IS_ASYNC(zkrbcall) ((zkrbcall)==ASYNC || (zkrbcall)==ASYNC_WATCH)
|
50
|
+
|
51
|
+
|
52
|
+
static int destroy_zkrb_instance(struct zkrb_instance_data* ptr) {
|
53
|
+
int rv = ZOK;
|
54
|
+
|
55
|
+
if (ptr->zh) {
|
56
|
+
const void *ctx = zoo_get_context(ptr->zh);
|
57
|
+
/* Note that after zookeeper_close() returns, ZK handle is invalid */
|
58
|
+
zkrb_debug("obj_id: %lx, calling zookeeper_close", ptr->object_id);
|
59
|
+
rv = zookeeper_close(ptr->zh);
|
60
|
+
zkrb_debug("obj_id: %lx, zookeeper_close returned %d", ptr->object_id, rv);
|
61
|
+
free((void *) ctx);
|
62
|
+
}
|
63
|
+
|
64
|
+
#warning [wickman] TODO: fire off warning if queue is not empty
|
65
|
+
if (ptr->queue) {
|
66
|
+
zkrb_debug("obj_id: %lx, freeing queue pointer: %p", ptr->object_id, ptr->queue);
|
67
|
+
zkrb_queue_free(ptr->queue);
|
68
|
+
}
|
69
|
+
|
70
|
+
ptr->zh = NULL;
|
71
|
+
ptr->queue = NULL;
|
72
|
+
|
73
|
+
return rv;
|
74
|
+
}
|
75
|
+
|
76
|
+
static void free_zkrb_instance_data(struct zkrb_instance_data* ptr) {
|
77
|
+
destroy_zkrb_instance(ptr);
|
78
|
+
}
|
79
|
+
|
80
|
+
static void print_zkrb_instance_data(struct zkrb_instance_data* ptr) {
|
81
|
+
fprintf(stderr, "zkrb_instance_data (%p) {\n", ptr);
|
82
|
+
fprintf(stderr, " zh = %p\n", ptr->zh);
|
83
|
+
fprintf(stderr, " { state = %d }\n", zoo_state(ptr->zh));
|
84
|
+
fprintf(stderr, " id = %"PRId64"\n", ptr->myid.client_id); // PRId64 defined in inttypes.h
|
85
|
+
fprintf(stderr, " q = %p\n", ptr->queue);
|
86
|
+
fprintf(stderr, " obj_id = %lx\n", ptr->object_id);
|
87
|
+
fprintf(stderr, "}\n");
|
88
|
+
}
|
89
|
+
|
90
|
+
// cargo culted from io.c
|
91
|
+
static VALUE zkrb_new_instance _((VALUE));
|
92
|
+
|
93
|
+
static VALUE zkrb_new_instance(VALUE args) {
|
94
|
+
return rb_class_new_instance(2, (VALUE*)args+1, *(VALUE*)args);
|
95
|
+
}
|
96
|
+
|
97
|
+
static int zkrb_dup(int orig) {
|
98
|
+
int fd;
|
99
|
+
|
100
|
+
fd = dup(orig);
|
101
|
+
if (fd < 0) {
|
102
|
+
if (errno == EMFILE || errno == ENFILE || errno == ENOMEM) {
|
103
|
+
rb_gc();
|
104
|
+
fd = dup(orig);
|
105
|
+
}
|
106
|
+
if (fd < 0) {
|
107
|
+
rb_sys_fail(0);
|
108
|
+
}
|
109
|
+
}
|
110
|
+
return fd;
|
111
|
+
}
|
112
|
+
|
113
|
+
#if 0
|
114
|
+
static VALUE create_selectable_io(zkrb_queue_t *q) {
|
115
|
+
// rb_cIO is the ruby IO class?
|
116
|
+
|
117
|
+
int pipe, state, read_fd;
|
118
|
+
VALUE args[3], reader;
|
119
|
+
|
120
|
+
read_fd = zkrb_dup(q->pipe_read);
|
121
|
+
|
122
|
+
args[0] = rb_cIO;
|
123
|
+
args[1] = INT2NUM(read_fd);
|
124
|
+
args[2] = INT2FIX(O_RDONLY);
|
125
|
+
reader = rb_protect(zkrb_new_instance, (VALUE)args, &state);
|
126
|
+
|
127
|
+
if (state) {
|
128
|
+
rb_jump_tag(state);
|
129
|
+
}
|
130
|
+
|
131
|
+
return reader;
|
132
|
+
}
|
133
|
+
#endif
|
134
|
+
|
135
|
+
#define session_timeout_msec(self) rb_iv_get(self, "@_session_timeout_msec")
|
136
|
+
|
137
|
+
static VALUE method_zkrb_init(int argc, VALUE* argv, VALUE self) {
|
138
|
+
VALUE hostPort;
|
139
|
+
VALUE options;
|
140
|
+
|
141
|
+
rb_scan_args(argc, argv, "11", &hostPort, &options);
|
142
|
+
|
143
|
+
if (NIL_P(options)) {
|
144
|
+
options = rb_hash_new();
|
145
|
+
} else {
|
146
|
+
Check_Type(options, T_HASH);
|
147
|
+
}
|
148
|
+
|
149
|
+
Check_Type(hostPort, T_STRING);
|
150
|
+
|
151
|
+
// Look up :zkc_log_level
|
152
|
+
VALUE log_level = rb_hash_aref(options, ID2SYM(rb_intern("zkc_log_level")));
|
153
|
+
if (NIL_P(log_level)) {
|
154
|
+
zoo_set_debug_level(0); // no log messages
|
155
|
+
} else {
|
156
|
+
Check_Type(log_level, T_FIXNUM);
|
157
|
+
zoo_set_debug_level((int)log_level);
|
158
|
+
}
|
159
|
+
|
160
|
+
|
161
|
+
VALUE data;
|
162
|
+
struct zkrb_instance_data *zk_local_ctx;
|
163
|
+
data = Data_Make_Struct(Zookeeper, struct zkrb_instance_data, 0, free_zkrb_instance_data, zk_local_ctx);
|
164
|
+
zk_local_ctx->queue = zkrb_queue_alloc();
|
165
|
+
|
166
|
+
if (zk_local_ctx->queue == NULL)
|
167
|
+
rb_raise(rb_eRuntimeError, "could not allocate zkrb queue!");
|
168
|
+
|
169
|
+
zoo_deterministic_conn_order(0);
|
170
|
+
|
171
|
+
zkrb_calling_context *ctx =
|
172
|
+
zkrb_calling_context_alloc(ZKRB_GLOBAL_REQ, zk_local_ctx->queue);
|
173
|
+
|
174
|
+
zk_local_ctx->object_id = FIX2LONG(rb_obj_id(self));
|
175
|
+
|
176
|
+
zk_local_ctx->zh =
|
177
|
+
zookeeper_init(
|
178
|
+
RSTRING_PTR(hostPort),
|
179
|
+
zkrb_state_callback,
|
180
|
+
session_timeout_msec(self),
|
181
|
+
&zk_local_ctx->myid,
|
182
|
+
ctx,
|
183
|
+
0);
|
184
|
+
|
185
|
+
#warning [wickman] TODO handle this properly on the Ruby side rather than C side
|
186
|
+
if (!zk_local_ctx->zh) {
|
187
|
+
rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
|
188
|
+
}
|
189
|
+
|
190
|
+
rb_iv_set(self, "@_data", data);
|
191
|
+
rb_funcall(self, rb_intern("zkc_set_running_and_notify!"), 0);
|
192
|
+
|
193
|
+
error:
|
194
|
+
return Qnil;
|
195
|
+
}
|
196
|
+
|
197
|
+
#define FETCH_DATA_PTR(X, Y) \
|
198
|
+
struct zkrb_instance_data * Y; \
|
199
|
+
Data_Get_Struct(rb_iv_get(X, "@_data"), struct zkrb_instance_data, Y); \
|
200
|
+
if ((Y)->zh == NULL) \
|
201
|
+
rb_raise(rb_eRuntimeError, "zookeeper handle is closed")
|
202
|
+
|
203
|
+
#define STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, cb_ctx, w_ctx, call_type) \
|
204
|
+
if (TYPE(reqid) != T_FIXNUM && TYPE(reqid) != T_BIGNUM) { \
|
205
|
+
rb_raise(rb_eTypeError, "reqid must be Fixnum/Bignum"); \
|
206
|
+
return Qnil; \
|
207
|
+
} \
|
208
|
+
Check_Type(path, T_STRING); \
|
209
|
+
struct zkrb_instance_data * zk; \
|
210
|
+
Data_Get_Struct(rb_iv_get(self, "@_data"), struct zkrb_instance_data, zk); \
|
211
|
+
if (!zk->zh) \
|
212
|
+
rb_raise(rb_eRuntimeError, "zookeeper handle is closed"); \
|
213
|
+
zkrb_calling_context* cb_ctx = \
|
214
|
+
(async != Qfalse && async != Qnil) ? \
|
215
|
+
zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
|
216
|
+
NULL; \
|
217
|
+
zkrb_calling_context* w_ctx = \
|
218
|
+
(watch != Qfalse && watch != Qnil) ? \
|
219
|
+
zkrb_calling_context_alloc(NUM2LL(reqid), zk->queue) : \
|
220
|
+
NULL; \
|
221
|
+
int a_ = (async != Qfalse && async != Qnil); \
|
222
|
+
int w_ = (watch != Qfalse && watch != Qnil); \
|
223
|
+
zkrb_call_type call_type; \
|
224
|
+
if (a_) { if (w_) { call_type = ASYNC_WATCH; } else { call_type = ASYNC; } } \
|
225
|
+
else { if (w_) { call_type = SYNC_WATCH; } else { call_type = SYNC; } }
|
226
|
+
|
227
|
+
static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
|
228
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
|
229
|
+
|
230
|
+
struct String_vector strings;
|
231
|
+
struct Stat stat;
|
232
|
+
|
233
|
+
int rc;
|
234
|
+
switch (call_type) {
|
235
|
+
case SYNC:
|
236
|
+
rc = zkrb_call_zoo_get_children2(zk->zh, RSTRING_PTR(path), 0, &strings, &stat);
|
237
|
+
break;
|
238
|
+
|
239
|
+
case SYNC_WATCH:
|
240
|
+
rc = zkrb_call_zoo_wget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &strings, &stat);
|
241
|
+
break;
|
242
|
+
|
243
|
+
case ASYNC:
|
244
|
+
rc = zkrb_call_zoo_aget_children2(zk->zh, RSTRING_PTR(path), 0, zkrb_strings_stat_callback, data_ctx);
|
245
|
+
break;
|
246
|
+
|
247
|
+
case ASYNC_WATCH:
|
248
|
+
rc = zkrb_call_zoo_awget_children2(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_strings_stat_callback, data_ctx);
|
249
|
+
break;
|
250
|
+
}
|
251
|
+
|
252
|
+
VALUE output = rb_ary_new();
|
253
|
+
rb_ary_push(output, INT2FIX(rc));
|
254
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
255
|
+
rb_ary_push(output, zkrb_string_vector_to_ruby(&strings));
|
256
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
257
|
+
}
|
258
|
+
return output;
|
259
|
+
}
|
260
|
+
|
261
|
+
static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
|
262
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
|
263
|
+
|
264
|
+
struct Stat stat;
|
265
|
+
|
266
|
+
int rc;
|
267
|
+
switch (call_type) {
|
268
|
+
case SYNC:
|
269
|
+
rc = zkrb_call_zoo_exists(zk->zh, RSTRING_PTR(path), 0, &stat);
|
270
|
+
break;
|
271
|
+
|
272
|
+
case SYNC_WATCH:
|
273
|
+
rc = zkrb_call_zoo_wexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, &stat);
|
274
|
+
break;
|
275
|
+
|
276
|
+
case ASYNC:
|
277
|
+
rc = zkrb_call_zoo_aexists(zk->zh, RSTRING_PTR(path), 0, zkrb_stat_callback, data_ctx);
|
278
|
+
break;
|
279
|
+
|
280
|
+
case ASYNC_WATCH:
|
281
|
+
rc = zkrb_call_zoo_awexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_stat_callback, data_ctx);
|
282
|
+
break;
|
283
|
+
}
|
284
|
+
|
285
|
+
VALUE output = rb_ary_new();
|
286
|
+
rb_ary_push(output, INT2FIX(rc));
|
287
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
288
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
289
|
+
}
|
290
|
+
return output;
|
291
|
+
}
|
292
|
+
|
293
|
+
// this method is *only* called asynchronously
|
294
|
+
static VALUE method_sync(VALUE self, VALUE reqid, VALUE path) {
|
295
|
+
VALUE async = Qtrue;
|
296
|
+
VALUE watch = Qfalse;
|
297
|
+
int rc;
|
298
|
+
|
299
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
|
300
|
+
|
301
|
+
rc = zkrb_call_zoo_async(zk->zh, RSTRING_PTR(path), zkrb_string_callback, data_ctx);
|
302
|
+
|
303
|
+
return INT2FIX(rc);
|
304
|
+
}
|
305
|
+
|
306
|
+
static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE acls, VALUE flags) {
|
307
|
+
VALUE watch = Qfalse;
|
308
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
|
309
|
+
|
310
|
+
if (data != Qnil) Check_Type(data, T_STRING);
|
311
|
+
Check_Type(flags, T_FIXNUM);
|
312
|
+
const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
|
313
|
+
size_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
|
314
|
+
|
315
|
+
struct ACL_vector *aclptr = NULL;
|
316
|
+
if (acls != Qnil) { aclptr = zkrb_ruby_to_aclvector(acls); }
|
317
|
+
char realpath[16384];
|
318
|
+
|
319
|
+
int rc;
|
320
|
+
switch (call_type) {
|
321
|
+
case SYNC:
|
322
|
+
// casting data_len to int is OK as you can only store 1MB in zookeeper
|
323
|
+
rc = zkrb_call_zoo_create(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, aclptr, FIX2INT(flags), realpath, sizeof(realpath));
|
324
|
+
|
325
|
+
break;
|
326
|
+
case ASYNC:
|
327
|
+
rc = zkrb_call_zoo_acreate(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, aclptr, FIX2INT(flags), zkrb_string_callback, data_ctx);
|
328
|
+
|
329
|
+
break;
|
330
|
+
default:
|
331
|
+
/* TODO(wickman) raise proper argument error */
|
332
|
+
return Qnil;
|
333
|
+
break;
|
334
|
+
}
|
335
|
+
|
336
|
+
|
337
|
+
if (aclptr) {
|
338
|
+
deallocate_ACL_vector(aclptr);
|
339
|
+
free(aclptr);
|
340
|
+
}
|
341
|
+
|
342
|
+
VALUE output = rb_ary_new();
|
343
|
+
rb_ary_push(output, INT2FIX(rc));
|
344
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
345
|
+
return rb_ary_push(output, rb_str_new2(realpath));
|
346
|
+
}
|
347
|
+
return output;
|
348
|
+
}
|
349
|
+
|
350
|
+
static VALUE method_delete(VALUE self, VALUE reqid, VALUE path, VALUE version, VALUE async) {
|
351
|
+
VALUE watch = Qfalse;
|
352
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
|
353
|
+
Check_Type(version, T_FIXNUM);
|
354
|
+
|
355
|
+
int rc = 0;
|
356
|
+
switch (call_type) {
|
357
|
+
case SYNC:
|
358
|
+
rc = zkrb_call_zoo_delete(zk->zh, RSTRING_PTR(path), FIX2INT(version));
|
359
|
+
break;
|
360
|
+
case ASYNC:
|
361
|
+
rc = zkrb_call_zoo_adelete(zk->zh, RSTRING_PTR(path), FIX2INT(version), zkrb_void_callback, data_ctx);
|
362
|
+
break;
|
363
|
+
default:
|
364
|
+
/* TODO(wickman) raise proper argument error */
|
365
|
+
return Qnil;
|
366
|
+
break;
|
367
|
+
}
|
368
|
+
|
369
|
+
return INT2FIX(rc);
|
370
|
+
}
|
371
|
+
|
372
|
+
#define MAX_ZNODE_SIZE 1048576
|
373
|
+
|
374
|
+
static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
|
375
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
|
376
|
+
|
377
|
+
/* ugh */
|
378
|
+
char * data = malloc(MAX_ZNODE_SIZE);
|
379
|
+
int data_len = MAX_ZNODE_SIZE;
|
380
|
+
struct Stat stat;
|
381
|
+
|
382
|
+
int rc;
|
383
|
+
|
384
|
+
switch (call_type) {
|
385
|
+
case SYNC:
|
386
|
+
rc = zkrb_call_zoo_get(zk->zh, RSTRING_PTR(path), 0, data, &data_len, &stat);
|
387
|
+
break;
|
388
|
+
|
389
|
+
case SYNC_WATCH:
|
390
|
+
rc = zkrb_call_zoo_wget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, data, &data_len, &stat);
|
391
|
+
break;
|
392
|
+
|
393
|
+
case ASYNC:
|
394
|
+
rc = zkrb_call_zoo_aget(zk->zh, RSTRING_PTR(path), 0, zkrb_data_callback, data_ctx);
|
395
|
+
break;
|
396
|
+
|
397
|
+
case ASYNC_WATCH:
|
398
|
+
rc = zkrb_call_zoo_awget(zk->zh, RSTRING_PTR(path), zkrb_state_callback, watch_ctx, zkrb_data_callback, data_ctx);
|
399
|
+
break;
|
400
|
+
}
|
401
|
+
|
402
|
+
VALUE output = rb_ary_new();
|
403
|
+
rb_ary_push(output, INT2FIX(rc));
|
404
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
405
|
+
if (data_len == -1)
|
406
|
+
rb_ary_push(output, Qnil); /* No data associated with path */
|
407
|
+
else
|
408
|
+
rb_ary_push(output, rb_str_new(data, data_len));
|
409
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
410
|
+
}
|
411
|
+
free(data);
|
412
|
+
|
413
|
+
return output;
|
414
|
+
}
|
415
|
+
|
416
|
+
static VALUE method_set(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE version) {
|
417
|
+
VALUE watch = Qfalse;
|
418
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
|
419
|
+
|
420
|
+
struct Stat stat;
|
421
|
+
if (data != Qnil) Check_Type(data, T_STRING);
|
422
|
+
const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
|
423
|
+
size_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
|
424
|
+
|
425
|
+
int rc;
|
426
|
+
switch (call_type) {
|
427
|
+
case SYNC:
|
428
|
+
rc = zkrb_call_zoo_set2(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version), &stat);
|
429
|
+
break;
|
430
|
+
case ASYNC:
|
431
|
+
rc = zkrb_call_zoo_aset(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version),
|
432
|
+
zkrb_stat_callback, data_ctx);
|
433
|
+
break;
|
434
|
+
default:
|
435
|
+
/* TODO(wickman) raise proper argument error */
|
436
|
+
return Qnil;
|
437
|
+
break;
|
438
|
+
}
|
439
|
+
|
440
|
+
VALUE output = rb_ary_new();
|
441
|
+
rb_ary_push(output, INT2FIX(rc));
|
442
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
443
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
444
|
+
}
|
445
|
+
return output;
|
446
|
+
}
|
447
|
+
|
448
|
+
static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VALUE async, VALUE version) {
|
449
|
+
VALUE watch = Qfalse;
|
450
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
|
451
|
+
struct ACL_vector * aclptr = zkrb_ruby_to_aclvector(acls);
|
452
|
+
|
453
|
+
int rc;
|
454
|
+
switch (call_type) {
|
455
|
+
case SYNC:
|
456
|
+
rc = zkrb_call_zoo_set_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr);
|
457
|
+
break;
|
458
|
+
case ASYNC:
|
459
|
+
rc = zkrb_call_zoo_aset_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr, zkrb_void_callback, data_ctx);
|
460
|
+
break;
|
461
|
+
default:
|
462
|
+
/* TODO(wickman) raise proper argument error */
|
463
|
+
return Qnil;
|
464
|
+
break;
|
465
|
+
}
|
466
|
+
|
467
|
+
deallocate_ACL_vector(aclptr);
|
468
|
+
free(aclptr);
|
469
|
+
|
470
|
+
return INT2FIX(rc);
|
471
|
+
}
|
472
|
+
|
473
|
+
static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
|
474
|
+
VALUE watch = Qfalse;
|
475
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, data_ctx, watch_ctx, call_type);
|
476
|
+
|
477
|
+
struct ACL_vector acls;
|
478
|
+
struct Stat stat;
|
479
|
+
|
480
|
+
int rc;
|
481
|
+
switch (call_type) {
|
482
|
+
case SYNC:
|
483
|
+
rc = zkrb_call_zoo_get_acl(zk->zh, RSTRING_PTR(path), &acls, &stat);
|
484
|
+
break;
|
485
|
+
case ASYNC:
|
486
|
+
rc = zkrb_call_zoo_aget_acl(zk->zh, RSTRING_PTR(path), zkrb_acl_callback, data_ctx);
|
487
|
+
break;
|
488
|
+
default:
|
489
|
+
/* TODO(wickman) raise proper argument error */
|
490
|
+
return Qnil;
|
491
|
+
break;
|
492
|
+
}
|
493
|
+
|
494
|
+
VALUE output = rb_ary_new();
|
495
|
+
rb_ary_push(output, INT2FIX(rc));
|
496
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
497
|
+
rb_ary_push(output, zkrb_acl_vector_to_ruby(&acls));
|
498
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
499
|
+
deallocate_ACL_vector(&acls);
|
500
|
+
}
|
501
|
+
return output;
|
502
|
+
}
|
503
|
+
|
504
|
+
#define is_running(self) RTEST(rb_iv_get(self, "@_running"))
|
505
|
+
#define is_closed(self) RTEST(rb_iv_get(self, "@_closed"))
|
506
|
+
#define is_shutting_down(self) RTEST(rb_iv_get(self, "@_shutting_down"))
|
507
|
+
|
508
|
+
static VALUE method_get_next_event(VALUE self, VALUE blocking) {
|
509
|
+
// dbg.h
|
510
|
+
check_debug(!is_closed(self), "we are closed, not trying to get event");
|
511
|
+
|
512
|
+
char buf[64];
|
513
|
+
FETCH_DATA_PTR(self, zk);
|
514
|
+
|
515
|
+
for (;;) {
|
516
|
+
check_debug(!is_closed(self), "we're closed in the middle of method_get_next_event, bailing");
|
517
|
+
|
518
|
+
zkrb_event_t *event = zkrb_dequeue(zk->queue, 1);
|
519
|
+
|
520
|
+
/* Wait for an event using rb_thread_select() on the queue's pipe */
|
521
|
+
if (event == NULL) {
|
522
|
+
if (NIL_P(blocking) || (blocking == Qfalse)) {
|
523
|
+
goto error;
|
524
|
+
}
|
525
|
+
else {
|
526
|
+
// if we're shutting down, don't enter this section, we don't want to block
|
527
|
+
check_debug(!is_shutting_down(self), "method_get_next_event, we're shutting down, don't enter blocking section");
|
528
|
+
|
529
|
+
int fd = zk->queue->pipe_read;
|
530
|
+
ssize_t bytes_read = 0;
|
531
|
+
|
532
|
+
// wait for an fd to become readable, opposite of rb_thread_fd_writable
|
533
|
+
rb_thread_wait_fd(fd);
|
534
|
+
|
535
|
+
// clear all bytes here, we'll catch all the events on subsequent calls
|
536
|
+
// (until we run out of events)
|
537
|
+
bytes_read = read(fd, buf, sizeof(buf));
|
538
|
+
|
539
|
+
if (bytes_read == -1) {
|
540
|
+
rb_raise(rb_eRuntimeError, "read failed: %d", errno);
|
541
|
+
}
|
542
|
+
|
543
|
+
zkrb_debug_inst(self, "read %zd bytes from the queue (%p)'s pipe", bytes_read, zk->queue);
|
544
|
+
|
545
|
+
continue;
|
546
|
+
}
|
547
|
+
}
|
548
|
+
|
549
|
+
VALUE hash = zkrb_event_to_ruby(event);
|
550
|
+
zkrb_event_free(event);
|
551
|
+
return hash;
|
552
|
+
}
|
553
|
+
|
554
|
+
error:
|
555
|
+
return Qnil;
|
556
|
+
}
|
557
|
+
|
558
|
+
static VALUE method_has_events(VALUE self) {
|
559
|
+
VALUE rb_event;
|
560
|
+
FETCH_DATA_PTR(self, zk);
|
561
|
+
|
562
|
+
rb_event = zkrb_peek(zk->queue) != NULL ? Qtrue : Qfalse;
|
563
|
+
return rb_event;
|
564
|
+
}
|
565
|
+
|
566
|
+
|
567
|
+
// wake up the event loop, used when shutting down
|
568
|
+
static VALUE method_wake_event_loop_bang(VALUE self) {
|
569
|
+
FETCH_DATA_PTR(self, zk);
|
570
|
+
|
571
|
+
zkrb_debug_inst(self, "Waking event loop: %p", zk->queue);
|
572
|
+
zkrb_signal(zk->queue);
|
573
|
+
|
574
|
+
return Qnil;
|
575
|
+
};
|
576
|
+
|
577
|
+
static VALUE method_close_handle(VALUE self) {
|
578
|
+
FETCH_DATA_PTR(self, zk);
|
579
|
+
|
580
|
+
if (ZKRBDebugging) {
|
581
|
+
/* fprintf(stderr, "CLOSING ZK INSTANCE: obj_id %lx", FIX2LONG(rb_obj_id(self)));*/
|
582
|
+
zkrb_debug_inst(self, "CLOSING_ZK_INSTANCE");
|
583
|
+
print_zkrb_instance_data(zk);
|
584
|
+
}
|
585
|
+
|
586
|
+
// this is a value on the ruby side we can check to see if destroy_zkrb_instance
|
587
|
+
// has been called
|
588
|
+
rb_iv_set(self, "@_closed", Qtrue);
|
589
|
+
|
590
|
+
zkrb_debug_inst(self, "calling destroy_zkrb_instance");
|
591
|
+
|
592
|
+
/* Note that after zookeeper_close() returns, ZK handle is invalid */
|
593
|
+
int rc = destroy_zkrb_instance(zk);
|
594
|
+
|
595
|
+
zkrb_debug("destroy_zkrb_instance returned: %d", rc);
|
596
|
+
|
597
|
+
return Qnil;
|
598
|
+
/* return INT2FIX(rc);*/
|
599
|
+
}
|
600
|
+
|
601
|
+
static VALUE method_deterministic_conn_order(VALUE self, VALUE yn) {
|
602
|
+
zoo_deterministic_conn_order(yn == Qtrue);
|
603
|
+
return Qnil;
|
604
|
+
}
|
605
|
+
|
606
|
+
static VALUE method_is_unrecoverable(VALUE self) {
|
607
|
+
FETCH_DATA_PTR(self, zk);
|
608
|
+
return is_unrecoverable(zk->zh) == ZINVALIDSTATE ? Qtrue : Qfalse;
|
609
|
+
}
|
610
|
+
|
611
|
+
static VALUE method_zkrb_state(VALUE self) {
|
612
|
+
FETCH_DATA_PTR(self, zk);
|
613
|
+
return INT2NUM(zoo_state(zk->zh));
|
614
|
+
}
|
615
|
+
|
616
|
+
static VALUE method_recv_timeout(VALUE self) {
|
617
|
+
FETCH_DATA_PTR(self, zk);
|
618
|
+
return INT2NUM(zoo_recv_timeout(zk->zh));
|
619
|
+
}
|
620
|
+
|
621
|
+
/*static VALUE method_client_id(VALUE self) {*/
|
622
|
+
/* FETCH_DATA_PTR(self, zk);*/
|
623
|
+
/* const clientid_t *id = zoo_client_id(zk->zh);*/
|
624
|
+
/* return UINT2NUM(id->client_id);*/
|
625
|
+
/*}*/
|
626
|
+
|
627
|
+
|
628
|
+
// returns a CZookeeper::ClientId object with the values set for session_id and passwd
|
629
|
+
static VALUE method_client_id(VALUE self) {
|
630
|
+
FETCH_DATA_PTR(self, zk);
|
631
|
+
const clientid_t *cid = zoo_client_id(zk->zh);
|
632
|
+
|
633
|
+
VALUE session_id = LL2NUM(cid->client_id);
|
634
|
+
VALUE passwd = rb_str_new2(cid->passwd);
|
635
|
+
|
636
|
+
VALUE client_id_obj = rb_class_new_instance(0, RARRAY_PTR(rb_ary_new()), ZookeeperClientId);
|
637
|
+
|
638
|
+
rb_funcall(client_id_obj, rb_intern("session_id="), 1, session_id);
|
639
|
+
rb_funcall(client_id_obj, rb_intern("passwd="), 1, passwd);
|
640
|
+
|
641
|
+
return client_id_obj;
|
642
|
+
}
|
643
|
+
|
644
|
+
static VALUE klass_method_zkrb_set_debug_level(VALUE klass, VALUE level) {
|
645
|
+
Check_Type(level, T_FIXNUM);
|
646
|
+
ZKRBDebugging = (FIX2INT(level) == ZOO_LOG_LEVEL_DEBUG);
|
647
|
+
zoo_set_debug_level(FIX2INT(level));
|
648
|
+
return Qnil;
|
649
|
+
}
|
650
|
+
|
651
|
+
static VALUE method_zerror(VALUE self, VALUE errc) {
|
652
|
+
return rb_str_new2(zerror(FIX2INT(errc)));
|
653
|
+
}
|
654
|
+
|
655
|
+
static void zkrb_define_methods(void) {
|
656
|
+
#define DEFINE_METHOD(method, args) { \
|
657
|
+
rb_define_method(Zookeeper, #method, method_ ## method, args); }
|
658
|
+
#define DEFINE_CLASS_METHOD(method, args) { \
|
659
|
+
rb_define_singleton_method(Zookeeper, #method, method_ ## method, args); }
|
660
|
+
|
661
|
+
// the number after the method name should be actual arity of C function - 1
|
662
|
+
DEFINE_METHOD(zkrb_init, -1);
|
663
|
+
DEFINE_METHOD(get_children, 4);
|
664
|
+
DEFINE_METHOD(exists, 4);
|
665
|
+
DEFINE_METHOD(create, 6);
|
666
|
+
DEFINE_METHOD(delete, 4);
|
667
|
+
DEFINE_METHOD(get, 4);
|
668
|
+
DEFINE_METHOD(set, 5);
|
669
|
+
DEFINE_METHOD(set_acl, 5);
|
670
|
+
DEFINE_METHOD(get_acl, 3);
|
671
|
+
DEFINE_METHOD(client_id, 0);
|
672
|
+
DEFINE_METHOD(close_handle, 0);
|
673
|
+
DEFINE_METHOD(deterministic_conn_order, 1);
|
674
|
+
DEFINE_METHOD(is_unrecoverable, 0);
|
675
|
+
DEFINE_METHOD(recv_timeout, 1);
|
676
|
+
DEFINE_METHOD(zkrb_state, 0);
|
677
|
+
DEFINE_METHOD(sync, 2);
|
678
|
+
|
679
|
+
// TODO
|
680
|
+
// DEFINE_METHOD(add_auth, 3);
|
681
|
+
|
682
|
+
// methods for the ruby-side event manager
|
683
|
+
DEFINE_METHOD(get_next_event, 1);
|
684
|
+
DEFINE_METHOD(has_events, 0);
|
685
|
+
|
686
|
+
// Make these class methods?
|
687
|
+
DEFINE_METHOD(zerror, 1);
|
688
|
+
|
689
|
+
rb_define_singleton_method(Zookeeper, "set_zkrb_debug_level", klass_method_zkrb_set_debug_level, 1);
|
690
|
+
|
691
|
+
rb_attr(Zookeeper, rb_intern("selectable_io"), 1, 0, Qtrue);
|
692
|
+
rb_define_method(Zookeeper, "wake_event_loop!", method_wake_event_loop_bang, 0);
|
693
|
+
|
694
|
+
}
|
695
|
+
|
696
|
+
// class CZookeeper::ClientId
|
697
|
+
// attr_accessor :session_id, :passwd
|
698
|
+
//
|
699
|
+
// def initialize(session_id, passwd)
|
700
|
+
// @session_id = session_id
|
701
|
+
// @passwd = passwd
|
702
|
+
// end
|
703
|
+
// end
|
704
|
+
|
705
|
+
static VALUE zkrb_client_id_method_initialize(VALUE self) {
|
706
|
+
rb_iv_set(self, "@session_id", Qnil);
|
707
|
+
rb_iv_set(self, "@passwd", Qnil);
|
708
|
+
return Qnil;
|
709
|
+
}
|
710
|
+
|
711
|
+
|
712
|
+
void Init_zookeeper_c() {
|
713
|
+
ZKRBDebugging = 0;
|
714
|
+
|
715
|
+
/* initialize Zookeeper class */
|
716
|
+
Zookeeper = rb_define_class("CZookeeper", rb_cObject);
|
717
|
+
zkrb_define_methods();
|
718
|
+
|
719
|
+
ZookeeperClientId = rb_define_class_under(Zookeeper, "ClientId", rb_cObject);
|
720
|
+
rb_define_method(ZookeeperClientId, "initialize", zkrb_client_id_method_initialize, 0);
|
721
|
+
rb_define_attr(ZookeeperClientId, "session_id", 1, 1);
|
722
|
+
rb_define_attr(ZookeeperClientId, "passwd", 1, 1);
|
723
|
+
}
|
724
|
+
|
725
|
+
// vim:ts=2:sw=2:sts=2:et
|