zookeeper-ng 1.5.2.1-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.
- checksums.yaml +7 -0
- data/.ctags_paths +1 -0
- data/.dotfiles/ruby-gemset +1 -0
- data/.dotfiles/ruby-version +1 -0
- data/.dotfiles/rvmrc +2 -0
- data/.github/workflows/build.yml +57 -0
- data/.gitignore +19 -0
- data/.gitmodules +3 -0
- data/CHANGELOG +408 -0
- data/Gemfile +30 -0
- data/Guardfile +8 -0
- data/LICENSE +23 -0
- data/Manifest +29 -0
- data/README.markdown +62 -0
- data/Rakefile +121 -0
- data/cause-abort.rb +117 -0
- data/ext/.gitignore +6 -0
- data/ext/Rakefile +41 -0
- data/ext/c_zookeeper.rb +398 -0
- data/ext/common.h +17 -0
- data/ext/dbg.h +53 -0
- data/ext/depend +5 -0
- data/ext/event_lib.c +740 -0
- data/ext/event_lib.h +175 -0
- data/ext/extconf.rb +103 -0
- data/ext/generate_gvl_code.rb +321 -0
- data/ext/patches/zkc-3.3.5-network.patch +24 -0
- data/ext/patches/zkc-3.4.5-buffer-overflow.patch +11 -0
- data/ext/patches/zkc-3.4.5-config.patch +5454 -0
- data/ext/patches/zkc-3.4.5-fetch-and-add.patch +16 -0
- data/ext/patches/zkc-3.4.5-logging.patch +41 -0
- data/ext/patches/zkc-3.4.5-out-of-order-ping.patch +163 -0
- data/ext/patches/zkc-3.4.5-yosemite-htonl-fix.patch +102 -0
- data/ext/zkc-3.4.5.tar.gz +0 -0
- data/ext/zkrb.c +1080 -0
- data/ext/zkrb_wrapper.c +775 -0
- data/ext/zkrb_wrapper.h +350 -0
- data/ext/zkrb_wrapper_compat.c +15 -0
- data/ext/zkrb_wrapper_compat.h +11 -0
- data/ext/zookeeper_base.rb +256 -0
- data/java/java_base.rb +501 -0
- data/lib/zookeeper/acls.rb +44 -0
- data/lib/zookeeper/callbacks.rb +108 -0
- data/lib/zookeeper/client.rb +30 -0
- data/lib/zookeeper/client_methods.rb +282 -0
- data/lib/zookeeper/common/queue_with_pipe.rb +110 -0
- data/lib/zookeeper/common.rb +122 -0
- data/lib/zookeeper/compatibility.rb +138 -0
- data/lib/zookeeper/constants.rb +97 -0
- data/lib/zookeeper/continuation.rb +223 -0
- data/lib/zookeeper/core_ext.rb +58 -0
- data/lib/zookeeper/em_client.rb +55 -0
- data/lib/zookeeper/exceptions.rb +135 -0
- data/lib/zookeeper/forked.rb +19 -0
- data/lib/zookeeper/latch.rb +34 -0
- data/lib/zookeeper/logger/forwarding_logger.rb +84 -0
- data/lib/zookeeper/logger.rb +39 -0
- data/lib/zookeeper/monitor.rb +19 -0
- data/lib/zookeeper/rake_tasks.rb +165 -0
- data/lib/zookeeper/request_registry.rb +153 -0
- data/lib/zookeeper/stat.rb +21 -0
- data/lib/zookeeper/version.rb +4 -0
- data/lib/zookeeper.rb +115 -0
- data/notes.txt +14 -0
- data/scripts/upgrade-1.0-sed-alike.rb +46 -0
- data/spec/c_zookeeper_spec.rb +51 -0
- data/spec/chrooted_connection_spec.rb +83 -0
- data/spec/compatibilty_spec.rb +8 -0
- data/spec/default_watcher_spec.rb +41 -0
- data/spec/em_spec.rb +51 -0
- data/spec/ext/zookeeper_base_spec.rb +19 -0
- data/spec/forked_connection_spec.rb +122 -0
- data/spec/latch_spec.rb +24 -0
- data/spec/log4j.properties +17 -0
- data/spec/shared/all_success_return_values.rb +10 -0
- data/spec/shared/connection_examples.rb +1081 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/00_logging.rb +38 -0
- data/spec/support/10_spawn_zookeeper.rb +20 -0
- data/spec/support/progress_formatter.rb +15 -0
- data/spec/support/zookeeper_spec_helpers.rb +96 -0
- data/spec/zookeeper_spec.rb +24 -0
- data/zookeeper.gemspec +46 -0
- data/zoomonkey/duplicates +3 -0
- data/zoomonkey/zoomonkey.rb +194 -0
- metadata +185 -0
data/ext/zkrb.c
ADDED
@@ -0,0 +1,1080 @@
|
|
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
|
+
* (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
|
+
*
|
59
|
+
* -------
|
60
|
+
*
|
61
|
+
* @rectalogic: any time you create a ruby value in C, and so there are no
|
62
|
+
* references to it in the VM except for your variable, and you then call into
|
63
|
+
* the VM (allowing a GC), and your reference is on the stack, then it needs to
|
64
|
+
* be volatile
|
65
|
+
*
|
66
|
+
*/
|
67
|
+
|
68
|
+
#include "ruby.h"
|
69
|
+
|
70
|
+
#ifdef ZKRB_RUBY_187
|
71
|
+
#include "rubyio.h"
|
72
|
+
#else
|
73
|
+
#include "ruby/io.h"
|
74
|
+
#endif
|
75
|
+
|
76
|
+
#ifndef HAVE_RB_THREAD_FD_SELECT
|
77
|
+
#define rb_fdset_t fd_set
|
78
|
+
#define rb_fd_isset(n, f) FD_ISSET(n, f)
|
79
|
+
#define rb_fd_init(f) FD_ZERO(f)
|
80
|
+
#define rb_fd_zero(f) FD_ZERO(f)
|
81
|
+
#define rb_fd_set(n, f) FD_SET(n, f)
|
82
|
+
#define rb_fd_clr(n, f) FD_CLR(n, f)
|
83
|
+
#define rb_fd_term(f)
|
84
|
+
#define rb_thread_fd_select rb_thread_select
|
85
|
+
#endif
|
86
|
+
|
87
|
+
#include "zookeeper/zookeeper.h"
|
88
|
+
#include <errno.h>
|
89
|
+
#include <stdio.h>
|
90
|
+
#include <stdlib.h>
|
91
|
+
#include <unistd.h>
|
92
|
+
#include <sys/fcntl.h>
|
93
|
+
#include <pthread.h>
|
94
|
+
#include <inttypes.h>
|
95
|
+
#include <time.h>
|
96
|
+
#include <arpa/inet.h>
|
97
|
+
#include <netinet/in.h>
|
98
|
+
|
99
|
+
#include "common.h"
|
100
|
+
#include "event_lib.h"
|
101
|
+
#include "zkrb_wrapper.h"
|
102
|
+
#include "dbg.h"
|
103
|
+
|
104
|
+
static VALUE mZookeeper = Qnil; // the Zookeeper module
|
105
|
+
static VALUE CZookeeper = Qnil; // the Zookeeper::CZookeeper class
|
106
|
+
static VALUE ZookeeperClientId = Qnil;
|
107
|
+
static VALUE mZookeeperExceptions = Qnil; // the Zookeeper::Exceptions module
|
108
|
+
static VALUE eHandleClosedException = Qnil; // raised when we don't have a valid handle in FETCH_DATA_PTR
|
109
|
+
|
110
|
+
// slyphon: possibly add a lock to this for synchronizing during get_next_event
|
111
|
+
|
112
|
+
struct zkrb_instance_data {
|
113
|
+
zhandle_t *zh;
|
114
|
+
clientid_t myid;
|
115
|
+
zkrb_queue_t *queue;
|
116
|
+
long object_id; // the ruby object this instance data is associated with
|
117
|
+
pid_t orig_pid;
|
118
|
+
};
|
119
|
+
|
120
|
+
typedef struct zkrb_instance_data zkrb_instance_data_t;
|
121
|
+
|
122
|
+
typedef enum {
|
123
|
+
SYNC = 0,
|
124
|
+
ASYNC = 1,
|
125
|
+
SYNC_WATCH = 2,
|
126
|
+
ASYNC_WATCH = 3
|
127
|
+
} zkrb_call_type;
|
128
|
+
|
129
|
+
inline static const char* call_type_to_str(zkrb_call_type ct) {
|
130
|
+
const char *rv = NULL;
|
131
|
+
switch (ct) {
|
132
|
+
case SYNC:
|
133
|
+
rv="SYNC";
|
134
|
+
break;
|
135
|
+
case ASYNC:
|
136
|
+
rv="ASYNC";
|
137
|
+
break;
|
138
|
+
case SYNC_WATCH:
|
139
|
+
rv="SYNC_WATCH";
|
140
|
+
break;
|
141
|
+
case ASYNC_WATCH:
|
142
|
+
rv="ASYNC_WATCH";
|
143
|
+
break;
|
144
|
+
}
|
145
|
+
return rv;
|
146
|
+
}
|
147
|
+
|
148
|
+
inline static void assert_valid_params(VALUE reqid, VALUE path) {
|
149
|
+
switch (TYPE(reqid)) {
|
150
|
+
case T_FIXNUM:
|
151
|
+
case T_BIGNUM:
|
152
|
+
break;
|
153
|
+
default:
|
154
|
+
rb_raise(rb_eTypeError, "reqid must be Fixnum/Bignum");
|
155
|
+
}
|
156
|
+
|
157
|
+
Check_Type(path, T_STRING);
|
158
|
+
}
|
159
|
+
|
160
|
+
inline static zkrb_call_type get_call_type(VALUE async, VALUE watch) {
|
161
|
+
if (RTEST(async)) {
|
162
|
+
return RTEST(watch) ? ASYNC_WATCH : ASYNC;
|
163
|
+
} else {
|
164
|
+
return RTEST(watch) ? SYNC_WATCH : SYNC;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
|
168
|
+
inline static void raise_invalid_call_type_err(zkrb_call_type call_type) {
|
169
|
+
rb_raise(rb_eRuntimeError, "hit the default case, call_type: %s", call_type_to_str(call_type));
|
170
|
+
}
|
171
|
+
|
172
|
+
#define IS_SYNC(zkrbcall) ((zkrbcall)==SYNC || (zkrbcall)==SYNC_WATCH)
|
173
|
+
#define IS_ASYNC(zkrbcall) ((zkrbcall)==ASYNC || (zkrbcall)==ASYNC_WATCH)
|
174
|
+
|
175
|
+
#define FETCH_DATA_PTR(SELF, ZK) \
|
176
|
+
zkrb_instance_data_t * ZK; \
|
177
|
+
Data_Get_Struct(rb_iv_get(SELF, "@_data"), zkrb_instance_data_t, ZK); \
|
178
|
+
if ((ZK)->zh == NULL) \
|
179
|
+
rb_raise(eHandleClosedException, "zookeeper handle is closed")
|
180
|
+
|
181
|
+
#define STANDARD_PREAMBLE(SELF, ZK, REQID, PATH, ASYNC, WATCH, CALL_TYPE) \
|
182
|
+
assert_valid_params(REQID, PATH); \
|
183
|
+
FETCH_DATA_PTR(SELF, ZK); \
|
184
|
+
zkrb_call_type CALL_TYPE = get_call_type(ASYNC, WATCH); \
|
185
|
+
|
186
|
+
#define CTX_ALLOC(ZK,REQID) zkrb_calling_context_alloc(NUM2LL(REQID), ZK->queue)
|
187
|
+
|
188
|
+
static void hexbufify(char *dest, const char *src, int len) {
|
189
|
+
int i=0;
|
190
|
+
|
191
|
+
for (i=0; i < len; i++) {
|
192
|
+
sprintf(&dest[i*2], "%x", src[i]);
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
inline static int we_are_forked(zkrb_instance_data_t *zk) {
|
197
|
+
int rv=0;
|
198
|
+
|
199
|
+
if ((!!zk) && (zk->orig_pid != getpid())) {
|
200
|
+
rv=1;
|
201
|
+
}
|
202
|
+
|
203
|
+
return rv;
|
204
|
+
}
|
205
|
+
|
206
|
+
static int destroy_zkrb_instance(zkrb_instance_data_t* zk) {
|
207
|
+
int rv = ZOK;
|
208
|
+
|
209
|
+
zkrb_debug("destroy_zkrb_instance, zk_local_ctx: %p, zh: %p, queue: %p", zk, zk->zh, zk->queue);
|
210
|
+
|
211
|
+
if (zk->zh) {
|
212
|
+
const void *ctx = zoo_get_context(zk->zh);
|
213
|
+
/* Note that after zookeeper_close() returns, ZK handle is invalid */
|
214
|
+
zkrb_debug("obj_id: %lx, calling zookeeper_close", zk->object_id);
|
215
|
+
|
216
|
+
if (we_are_forked(zk)) {
|
217
|
+
zkrb_debug("FORK DETECTED! orig_pid: %d, current pid: %d, "
|
218
|
+
"using socket-closing hack before zookeeper_close", zk->orig_pid, getpid());
|
219
|
+
|
220
|
+
int fd = ((int *)zk->zh)[0]; // nasty, brutish, and wonderfully effective hack (see above)
|
221
|
+
close(fd);
|
222
|
+
|
223
|
+
}
|
224
|
+
|
225
|
+
rv = zookeeper_close(zk->zh);
|
226
|
+
|
227
|
+
zkrb_debug("obj_id: %lx, zookeeper_close returned %d, calling context: %p", zk->object_id, rv, ctx);
|
228
|
+
zkrb_calling_context_free((zkrb_calling_context *) ctx);
|
229
|
+
}
|
230
|
+
|
231
|
+
zk->zh = NULL;
|
232
|
+
|
233
|
+
if (zk->queue) {
|
234
|
+
zkrb_debug("obj_id: %lx, freeing queue pointer: %p", zk->object_id, zk->queue);
|
235
|
+
zkrb_queue_free(zk->queue);
|
236
|
+
}
|
237
|
+
|
238
|
+
zk->queue = NULL;
|
239
|
+
|
240
|
+
return rv;
|
241
|
+
}
|
242
|
+
|
243
|
+
static void free_zkrb_instance_data(zkrb_instance_data_t* ptr) {
|
244
|
+
destroy_zkrb_instance(ptr);
|
245
|
+
}
|
246
|
+
|
247
|
+
VALUE alloc_zkrb_instance(VALUE klass) {
|
248
|
+
zkrb_instance_data_t* zk = ZALLOC_N(zkrb_instance_data_t, 1);
|
249
|
+
return Data_Wrap_Struct(klass, NULL, free_zkrb_instance_data, zk);
|
250
|
+
}
|
251
|
+
|
252
|
+
static void print_zkrb_instance_data(zkrb_instance_data_t* ptr) {
|
253
|
+
fprintf(stderr, "zkrb_instance_data (%p) {\n", ptr);
|
254
|
+
fprintf(stderr, " zh = %p\n", ptr->zh);
|
255
|
+
fprintf(stderr, " { state = %d }\n", zoo_state(ptr->zh));
|
256
|
+
fprintf(stderr, " id = %"PRId64"\n", ptr->myid.client_id); // PRId64 defined in inttypes.h
|
257
|
+
fprintf(stderr, " q = %p\n", ptr->queue);
|
258
|
+
fprintf(stderr, " obj_id = %lx\n", ptr->object_id);
|
259
|
+
fprintf(stderr, "}\n");
|
260
|
+
}
|
261
|
+
|
262
|
+
#define receive_timeout_msec(self) rb_iv_get(self, "@_receive_timeout_msec")
|
263
|
+
|
264
|
+
inline static void zkrb_debug_clientid_t(const clientid_t *cid) {
|
265
|
+
int pass_len = sizeof(cid->passwd);
|
266
|
+
int hex_len = 2 * pass_len + 1;
|
267
|
+
char buf[hex_len];
|
268
|
+
hexbufify(buf, cid->passwd, pass_len);
|
269
|
+
|
270
|
+
zkrb_debug("myid, client_id: %"PRId64", passwd: %*s", cid->client_id, hex_len, buf);
|
271
|
+
}
|
272
|
+
|
273
|
+
static VALUE method_zkrb_init(int argc, VALUE* argv, VALUE self) {
|
274
|
+
VALUE hostPort=Qnil;
|
275
|
+
VALUE options=Qnil;
|
276
|
+
|
277
|
+
rb_scan_args(argc, argv, "11", &hostPort, &options);
|
278
|
+
|
279
|
+
if (NIL_P(options)) {
|
280
|
+
options = rb_hash_new();
|
281
|
+
} else {
|
282
|
+
Check_Type(options, T_HASH);
|
283
|
+
}
|
284
|
+
|
285
|
+
Check_Type(hostPort, T_STRING);
|
286
|
+
|
287
|
+
// Look up :zkc_log_level
|
288
|
+
// VALUE log_level = rb_hash_aref(options, ID2SYM(rb_intern("zkc_log_level")));
|
289
|
+
// if (NIL_P(log_level)) {
|
290
|
+
// zoo_set_debug_level(0); // no log messages
|
291
|
+
// } else {
|
292
|
+
// Check_Type(log_level, T_FIXNUM);
|
293
|
+
// zoo_set_debug_level(FIX2INT(log_level));
|
294
|
+
// }
|
295
|
+
|
296
|
+
volatile VALUE data;
|
297
|
+
zkrb_instance_data_t *zk_local_ctx;
|
298
|
+
data = Data_Make_Struct(CZookeeper, zkrb_instance_data_t, 0, free_zkrb_instance_data, zk_local_ctx);
|
299
|
+
|
300
|
+
// Look up :session_id and :session_passwd
|
301
|
+
VALUE session_id = rb_hash_aref(options, ID2SYM(rb_intern("session_id")));
|
302
|
+
VALUE password = rb_hash_aref(options, ID2SYM(rb_intern("session_passwd")));
|
303
|
+
if (!NIL_P(session_id) && !NIL_P(password)) {
|
304
|
+
Check_Type(password, T_STRING);
|
305
|
+
|
306
|
+
zk_local_ctx->myid.client_id = NUM2LL(session_id);
|
307
|
+
strncpy(zk_local_ctx->myid.passwd, RSTRING_PTR(password), 16);
|
308
|
+
}
|
309
|
+
|
310
|
+
zk_local_ctx->queue = zkrb_queue_alloc();
|
311
|
+
|
312
|
+
if (zk_local_ctx->queue == NULL)
|
313
|
+
rb_raise(rb_eRuntimeError, "could not allocate zkrb queue!");
|
314
|
+
|
315
|
+
zoo_deterministic_conn_order(0);
|
316
|
+
|
317
|
+
zkrb_calling_context *ctx =
|
318
|
+
zkrb_calling_context_alloc(ZKRB_GLOBAL_REQ, zk_local_ctx->queue);
|
319
|
+
|
320
|
+
zk_local_ctx->object_id = FIX2LONG(rb_obj_id(self));
|
321
|
+
|
322
|
+
zk_local_ctx->zh =
|
323
|
+
zookeeper_init(
|
324
|
+
RSTRING_PTR(hostPort), // const char *host
|
325
|
+
zkrb_state_callback, // watcher_fn
|
326
|
+
receive_timeout_msec(self), // recv_timeout
|
327
|
+
&zk_local_ctx->myid, // cilentid_t
|
328
|
+
ctx, // void *context
|
329
|
+
0); // flags
|
330
|
+
|
331
|
+
zkrb_debug("method_zkrb_init, zk_local_ctx: %p, zh: %p, queue: %p, calling_ctx: %p",
|
332
|
+
zk_local_ctx, zk_local_ctx->zh, zk_local_ctx->queue, ctx);
|
333
|
+
|
334
|
+
if (!zk_local_ctx->zh) {
|
335
|
+
rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
|
336
|
+
}
|
337
|
+
|
338
|
+
zk_local_ctx->orig_pid = getpid();
|
339
|
+
|
340
|
+
rb_iv_set(self, "@_data", data);
|
341
|
+
rb_funcall(self, rb_intern("zkc_set_running_and_notify!"), 0);
|
342
|
+
|
343
|
+
return Qnil;
|
344
|
+
}
|
345
|
+
|
346
|
+
static VALUE method_get_children(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
|
347
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, call_type);
|
348
|
+
|
349
|
+
VALUE output = Qnil;
|
350
|
+
struct String_vector strings;
|
351
|
+
struct Stat stat;
|
352
|
+
|
353
|
+
int rc = 0;
|
354
|
+
switch (call_type) {
|
355
|
+
|
356
|
+
#ifdef THREADED
|
357
|
+
case SYNC:
|
358
|
+
rc = zkrb_call_zoo_get_children2(
|
359
|
+
zk->zh, RSTRING_PTR(path), 0, &strings, &stat);
|
360
|
+
break;
|
361
|
+
|
362
|
+
case SYNC_WATCH:
|
363
|
+
rc = zkrb_call_zoo_wget_children2(
|
364
|
+
zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), &strings, &stat);
|
365
|
+
break;
|
366
|
+
#endif
|
367
|
+
|
368
|
+
case ASYNC:
|
369
|
+
rc = zkrb_call_zoo_aget_children2(
|
370
|
+
zk->zh, RSTRING_PTR(path), 0, zkrb_strings_stat_callback, CTX_ALLOC(zk, reqid));
|
371
|
+
break;
|
372
|
+
|
373
|
+
case ASYNC_WATCH:
|
374
|
+
rc = zkrb_call_zoo_awget_children2(
|
375
|
+
zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), zkrb_strings_stat_callback, CTX_ALLOC(zk, reqid));
|
376
|
+
break;
|
377
|
+
|
378
|
+
default:
|
379
|
+
raise_invalid_call_type_err(call_type);
|
380
|
+
break;
|
381
|
+
}
|
382
|
+
|
383
|
+
output = rb_ary_new();
|
384
|
+
rb_ary_push(output, INT2FIX(rc));
|
385
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
386
|
+
rb_ary_push(output, zkrb_string_vector_to_ruby(&strings));
|
387
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
388
|
+
}
|
389
|
+
return output;
|
390
|
+
}
|
391
|
+
|
392
|
+
static VALUE method_exists(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
|
393
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, call_type);
|
394
|
+
|
395
|
+
VALUE output = Qnil;
|
396
|
+
struct Stat stat;
|
397
|
+
|
398
|
+
int rc = 0;
|
399
|
+
switch (call_type) {
|
400
|
+
|
401
|
+
#ifdef THREADED
|
402
|
+
case SYNC:
|
403
|
+
rc = zkrb_call_zoo_exists(zk->zh, RSTRING_PTR(path), 0, &stat);
|
404
|
+
break;
|
405
|
+
|
406
|
+
case SYNC_WATCH:
|
407
|
+
rc = zkrb_call_zoo_wexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), &stat);
|
408
|
+
break;
|
409
|
+
#endif
|
410
|
+
|
411
|
+
case ASYNC:
|
412
|
+
rc = zkrb_call_zoo_aexists(zk->zh, RSTRING_PTR(path), 0, zkrb_stat_callback, CTX_ALLOC(zk, reqid));
|
413
|
+
break;
|
414
|
+
|
415
|
+
case ASYNC_WATCH:
|
416
|
+
rc = zkrb_call_zoo_awexists(zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), zkrb_stat_callback, CTX_ALLOC(zk, reqid));
|
417
|
+
break;
|
418
|
+
|
419
|
+
default:
|
420
|
+
raise_invalid_call_type_err(call_type);
|
421
|
+
break;
|
422
|
+
}
|
423
|
+
|
424
|
+
output = rb_ary_new();
|
425
|
+
rb_ary_push(output, INT2FIX(rc));
|
426
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
427
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
428
|
+
}
|
429
|
+
return output;
|
430
|
+
}
|
431
|
+
|
432
|
+
// this method is *only* called asynchronously
|
433
|
+
static VALUE method_sync(VALUE self, VALUE reqid, VALUE path) {
|
434
|
+
int rc = ZOK;
|
435
|
+
|
436
|
+
// don't use STANDARD_PREAMBLE here b/c we don't need to determine call_type
|
437
|
+
assert_valid_params(reqid, path);
|
438
|
+
FETCH_DATA_PTR(self, zk);
|
439
|
+
|
440
|
+
rc = zkrb_call_zoo_async(zk->zh, RSTRING_PTR(path), zkrb_string_callback, CTX_ALLOC(zk, reqid));
|
441
|
+
|
442
|
+
return INT2FIX(rc);
|
443
|
+
}
|
444
|
+
|
445
|
+
static VALUE method_add_auth(VALUE self, VALUE reqid, VALUE scheme, VALUE cert) {
|
446
|
+
int rc = ZOK;
|
447
|
+
|
448
|
+
Check_Type(scheme, T_STRING);
|
449
|
+
Check_Type(cert, T_STRING);
|
450
|
+
|
451
|
+
FETCH_DATA_PTR(self, zk);
|
452
|
+
|
453
|
+
rc = zkrb_call_zoo_add_auth(zk->zh, RSTRING_PTR(scheme), RSTRING_PTR(cert), RSTRING_LEN(cert), zkrb_void_callback, CTX_ALLOC(zk, reqid));
|
454
|
+
|
455
|
+
return INT2FIX(rc);
|
456
|
+
}
|
457
|
+
|
458
|
+
|
459
|
+
static VALUE method_create(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE acls, VALUE flags) {
|
460
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
|
461
|
+
VALUE output = Qnil;
|
462
|
+
|
463
|
+
if (data != Qnil) Check_Type(data, T_STRING);
|
464
|
+
Check_Type(flags, T_FIXNUM);
|
465
|
+
const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
|
466
|
+
ssize_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
|
467
|
+
|
468
|
+
struct ACL_vector *aclptr = NULL;
|
469
|
+
if (acls != Qnil) { aclptr = zkrb_ruby_to_aclvector(acls); }
|
470
|
+
char realpath[16384];
|
471
|
+
|
472
|
+
int invalid_call_type=0;
|
473
|
+
|
474
|
+
int rc = 0;
|
475
|
+
switch (call_type) {
|
476
|
+
|
477
|
+
#ifdef THREADED
|
478
|
+
case SYNC:
|
479
|
+
// casting data_len to int is OK as you can only store 1MB in zookeeper
|
480
|
+
rc = zkrb_call_zoo_create(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, aclptr, FIX2INT(flags), realpath, sizeof(realpath));
|
481
|
+
break;
|
482
|
+
#endif
|
483
|
+
|
484
|
+
case ASYNC:
|
485
|
+
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));
|
486
|
+
break;
|
487
|
+
|
488
|
+
default:
|
489
|
+
invalid_call_type=1;
|
490
|
+
break;
|
491
|
+
}
|
492
|
+
|
493
|
+
if (aclptr) {
|
494
|
+
deallocate_ACL_vector(aclptr);
|
495
|
+
free(aclptr);
|
496
|
+
}
|
497
|
+
|
498
|
+
if (invalid_call_type) raise_invalid_call_type_err(call_type);
|
499
|
+
|
500
|
+
output = rb_ary_new();
|
501
|
+
rb_ary_push(output, INT2FIX(rc));
|
502
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
503
|
+
return rb_ary_push(output, rb_str_new2(realpath));
|
504
|
+
}
|
505
|
+
return output;
|
506
|
+
}
|
507
|
+
|
508
|
+
static VALUE method_delete(VALUE self, VALUE reqid, VALUE path, VALUE version, VALUE async) {
|
509
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
|
510
|
+
Check_Type(version, T_FIXNUM);
|
511
|
+
|
512
|
+
int rc = 0;
|
513
|
+
switch (call_type) {
|
514
|
+
|
515
|
+
#ifdef THREADED
|
516
|
+
case SYNC:
|
517
|
+
rc = zkrb_call_zoo_delete(zk->zh, RSTRING_PTR(path), FIX2INT(version));
|
518
|
+
break;
|
519
|
+
#endif
|
520
|
+
|
521
|
+
case ASYNC:
|
522
|
+
rc = zkrb_call_zoo_adelete(zk->zh, RSTRING_PTR(path), FIX2INT(version), zkrb_void_callback, CTX_ALLOC(zk, reqid));
|
523
|
+
break;
|
524
|
+
|
525
|
+
default:
|
526
|
+
raise_invalid_call_type_err(call_type);
|
527
|
+
break;
|
528
|
+
}
|
529
|
+
|
530
|
+
return INT2FIX(rc);
|
531
|
+
}
|
532
|
+
|
533
|
+
#define MAX_ZNODE_SIZE 1048576
|
534
|
+
|
535
|
+
static VALUE method_get(VALUE self, VALUE reqid, VALUE path, VALUE async, VALUE watch) {
|
536
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, watch, call_type);
|
537
|
+
|
538
|
+
VALUE output = Qnil;
|
539
|
+
|
540
|
+
int data_len = MAX_ZNODE_SIZE;
|
541
|
+
struct Stat stat;
|
542
|
+
|
543
|
+
char * data = NULL;
|
544
|
+
if (IS_SYNC(call_type)) {
|
545
|
+
data = malloc(MAX_ZNODE_SIZE); /* ugh */
|
546
|
+
memset(data, 0, MAX_ZNODE_SIZE);
|
547
|
+
}
|
548
|
+
|
549
|
+
int rc, invalid_call_type=0;
|
550
|
+
|
551
|
+
switch (call_type) {
|
552
|
+
|
553
|
+
#ifdef THREADED
|
554
|
+
case SYNC:
|
555
|
+
rc = zkrb_call_zoo_get(zk->zh, RSTRING_PTR(path), 0, data, &data_len, &stat);
|
556
|
+
break;
|
557
|
+
|
558
|
+
case SYNC_WATCH:
|
559
|
+
rc = zkrb_call_zoo_wget(
|
560
|
+
zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), data, &data_len, &stat);
|
561
|
+
break;
|
562
|
+
#endif
|
563
|
+
|
564
|
+
case ASYNC:
|
565
|
+
rc = zkrb_call_zoo_aget(zk->zh, RSTRING_PTR(path), 0, zkrb_data_callback, CTX_ALLOC(zk, reqid));
|
566
|
+
break;
|
567
|
+
|
568
|
+
case ASYNC_WATCH:
|
569
|
+
// first ctx is a watch, second is the async callback
|
570
|
+
rc = zkrb_call_zoo_awget(
|
571
|
+
zk->zh, RSTRING_PTR(path), zkrb_state_callback, CTX_ALLOC(zk, reqid), zkrb_data_callback, CTX_ALLOC(zk, reqid));
|
572
|
+
break;
|
573
|
+
|
574
|
+
default:
|
575
|
+
invalid_call_type=1;
|
576
|
+
goto cleanup;
|
577
|
+
break;
|
578
|
+
}
|
579
|
+
|
580
|
+
output = rb_ary_new();
|
581
|
+
rb_ary_push(output, INT2FIX(rc));
|
582
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
583
|
+
if (data_len == -1)
|
584
|
+
rb_ary_push(output, Qnil); /* No data associated with path */
|
585
|
+
else
|
586
|
+
rb_ary_push(output, rb_str_new(data, data_len));
|
587
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
588
|
+
}
|
589
|
+
|
590
|
+
cleanup:
|
591
|
+
free(data);
|
592
|
+
if (invalid_call_type) raise_invalid_call_type_err(call_type);
|
593
|
+
return output;
|
594
|
+
}
|
595
|
+
|
596
|
+
static VALUE method_set(VALUE self, VALUE reqid, VALUE path, VALUE data, VALUE async, VALUE version) {
|
597
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
|
598
|
+
|
599
|
+
VALUE output = Qnil;
|
600
|
+
struct Stat stat;
|
601
|
+
|
602
|
+
if (data != Qnil) Check_Type(data, T_STRING);
|
603
|
+
|
604
|
+
const char *data_ptr = (data == Qnil) ? NULL : RSTRING_PTR(data);
|
605
|
+
ssize_t data_len = (data == Qnil) ? -1 : RSTRING_LEN(data);
|
606
|
+
|
607
|
+
int rc=ZOK;
|
608
|
+
switch (call_type) {
|
609
|
+
|
610
|
+
#ifdef THREADED
|
611
|
+
case SYNC:
|
612
|
+
rc = zkrb_call_zoo_set2(zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version), &stat);
|
613
|
+
break;
|
614
|
+
#endif
|
615
|
+
|
616
|
+
case ASYNC:
|
617
|
+
rc = zkrb_call_zoo_aset(
|
618
|
+
zk->zh, RSTRING_PTR(path), data_ptr, (int)data_len, FIX2INT(version), zkrb_stat_callback, CTX_ALLOC(zk, reqid));
|
619
|
+
break;
|
620
|
+
|
621
|
+
default:
|
622
|
+
raise_invalid_call_type_err(call_type);
|
623
|
+
break;
|
624
|
+
}
|
625
|
+
|
626
|
+
output = rb_ary_new();
|
627
|
+
rb_ary_push(output, INT2FIX(rc));
|
628
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
629
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
630
|
+
}
|
631
|
+
return output;
|
632
|
+
}
|
633
|
+
|
634
|
+
static VALUE method_set_acl(VALUE self, VALUE reqid, VALUE path, VALUE acls, VALUE async, VALUE version) {
|
635
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
|
636
|
+
|
637
|
+
struct ACL_vector * aclptr = zkrb_ruby_to_aclvector(acls);
|
638
|
+
|
639
|
+
int rc=ZOK, invalid_call_type=0;
|
640
|
+
switch (call_type) {
|
641
|
+
|
642
|
+
#ifdef THREADED
|
643
|
+
case SYNC:
|
644
|
+
rc = zkrb_call_zoo_set_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr);
|
645
|
+
break;
|
646
|
+
#endif
|
647
|
+
|
648
|
+
case ASYNC:
|
649
|
+
rc = zkrb_call_zoo_aset_acl(zk->zh, RSTRING_PTR(path), FIX2INT(version), aclptr, zkrb_void_callback, CTX_ALLOC(zk, reqid));
|
650
|
+
break;
|
651
|
+
|
652
|
+
default:
|
653
|
+
invalid_call_type=1;
|
654
|
+
break;
|
655
|
+
}
|
656
|
+
|
657
|
+
deallocate_ACL_vector(aclptr);
|
658
|
+
free(aclptr);
|
659
|
+
|
660
|
+
if (invalid_call_type) raise_invalid_call_type_err(call_type);
|
661
|
+
|
662
|
+
return INT2FIX(rc);
|
663
|
+
}
|
664
|
+
|
665
|
+
static VALUE method_get_acl(VALUE self, VALUE reqid, VALUE path, VALUE async) {
|
666
|
+
STANDARD_PREAMBLE(self, zk, reqid, path, async, Qfalse, call_type);
|
667
|
+
|
668
|
+
VALUE output = Qnil;
|
669
|
+
struct ACL_vector acls;
|
670
|
+
struct Stat stat;
|
671
|
+
|
672
|
+
int rc=ZOK;
|
673
|
+
switch (call_type) {
|
674
|
+
|
675
|
+
#ifdef THREADED
|
676
|
+
case SYNC:
|
677
|
+
rc = zkrb_call_zoo_get_acl(zk->zh, RSTRING_PTR(path), &acls, &stat);
|
678
|
+
break;
|
679
|
+
#endif
|
680
|
+
|
681
|
+
case ASYNC:
|
682
|
+
rc = zkrb_call_zoo_aget_acl(zk->zh, RSTRING_PTR(path), zkrb_acl_callback, CTX_ALLOC(zk, reqid));
|
683
|
+
break;
|
684
|
+
|
685
|
+
default:
|
686
|
+
raise_invalid_call_type_err(call_type);
|
687
|
+
break;
|
688
|
+
}
|
689
|
+
|
690
|
+
output = rb_ary_new();
|
691
|
+
rb_ary_push(output, INT2FIX(rc));
|
692
|
+
if (IS_SYNC(call_type) && rc == ZOK) {
|
693
|
+
rb_ary_push(output, zkrb_acl_vector_to_ruby(&acls));
|
694
|
+
rb_ary_push(output, zkrb_stat_to_rarray(&stat));
|
695
|
+
deallocate_ACL_vector(&acls);
|
696
|
+
}
|
697
|
+
return output;
|
698
|
+
}
|
699
|
+
|
700
|
+
#define is_running(self) RTEST(rb_iv_get(self, "@_running"))
|
701
|
+
#define is_closed(self) RTEST(rb_iv_get(self, "@_closed"))
|
702
|
+
#define is_shutting_down(self) RTEST(rb_iv_get(self, "@_shutting_down"))
|
703
|
+
|
704
|
+
static VALUE method_zkrb_get_next_event(VALUE self, VALUE blocking) {
|
705
|
+
// dbg.h
|
706
|
+
check_debug(!is_closed(self), "we are closed, not trying to get event");
|
707
|
+
|
708
|
+
char buf[64];
|
709
|
+
FETCH_DATA_PTR(self, zk);
|
710
|
+
|
711
|
+
for (;;) {
|
712
|
+
check_debug(!is_closed(self), "we're closed in the middle of method_zkrb_get_next_event, bailing");
|
713
|
+
|
714
|
+
zkrb_event_t *event = zkrb_dequeue(zk->queue, 1);
|
715
|
+
|
716
|
+
if (event == NULL) {
|
717
|
+
if (NIL_P(blocking) || (blocking == Qfalse)) {
|
718
|
+
goto error;
|
719
|
+
}
|
720
|
+
else {
|
721
|
+
// if we're shutting down, don't enter this section, we don't want to block
|
722
|
+
check_debug(!is_shutting_down(self), "method_zkrb_get_next_event, we're shutting down, don't enter blocking section");
|
723
|
+
|
724
|
+
int fd = zk->queue->pipe_read;
|
725
|
+
ssize_t bytes_read = 0;
|
726
|
+
|
727
|
+
// wait for an fd to become readable, opposite of rb_thread_fd_writable
|
728
|
+
rb_thread_wait_fd(fd);
|
729
|
+
|
730
|
+
// clear all bytes here, we'll catch all the events on subsequent calls
|
731
|
+
// (until we run out of events)
|
732
|
+
bytes_read = read(fd, buf, sizeof(buf));
|
733
|
+
|
734
|
+
if (bytes_read == -1) {
|
735
|
+
rb_raise(rb_eRuntimeError, "read failed: %d", errno);
|
736
|
+
}
|
737
|
+
|
738
|
+
zkrb_debug_inst(self, "read %zd bytes from the queue (%p)'s pipe", bytes_read, zk->queue);
|
739
|
+
|
740
|
+
continue;
|
741
|
+
}
|
742
|
+
}
|
743
|
+
|
744
|
+
VALUE hash = zkrb_event_to_ruby(event);
|
745
|
+
zkrb_event_free(event);
|
746
|
+
return hash;
|
747
|
+
}
|
748
|
+
|
749
|
+
error:
|
750
|
+
return Qnil;
|
751
|
+
}
|
752
|
+
|
753
|
+
// the single threaded version of this call. will go away when we do direct
|
754
|
+
// event delivery (soon)
|
755
|
+
static VALUE method_zkrb_get_next_event_st(VALUE self) {
|
756
|
+
volatile VALUE rval = Qnil;
|
757
|
+
|
758
|
+
if (is_closed(self)) {
|
759
|
+
zkrb_debug("we are closed, not gonna try to get an event");
|
760
|
+
return Qnil;
|
761
|
+
}
|
762
|
+
|
763
|
+
FETCH_DATA_PTR(self, zk);
|
764
|
+
|
765
|
+
zkrb_event_t *event = zkrb_dequeue(zk->queue, 0);
|
766
|
+
|
767
|
+
if (event != NULL) {
|
768
|
+
rval = zkrb_event_to_ruby(event);
|
769
|
+
zkrb_event_free(event);
|
770
|
+
|
771
|
+
#if THREADED
|
772
|
+
int fd = zk->queue->pipe_read;
|
773
|
+
|
774
|
+
// we don't care in this case. this is just until i can remove the self
|
775
|
+
// pipe from the queue
|
776
|
+
char b[128];
|
777
|
+
while(read(fd, b, sizeof(b)) == sizeof(b)){}
|
778
|
+
#endif
|
779
|
+
}
|
780
|
+
|
781
|
+
return rval;
|
782
|
+
}
|
783
|
+
|
784
|
+
inline static int get_self_pipe_read_fd(VALUE self) {
|
785
|
+
rb_io_t *fptr;
|
786
|
+
VALUE pipe_read = rb_iv_get(self, "@pipe_read");
|
787
|
+
|
788
|
+
if (NIL_P(pipe_read))
|
789
|
+
rb_raise(rb_eRuntimeError, "@pipe_read was nil!");
|
790
|
+
|
791
|
+
GetOpenFile(pipe_read, fptr);
|
792
|
+
|
793
|
+
rb_io_check_readable(fptr);
|
794
|
+
|
795
|
+
#ifdef ZKRB_RUBY_187
|
796
|
+
return fileno(fptr->f);
|
797
|
+
#else
|
798
|
+
return fptr->fd;
|
799
|
+
#endif
|
800
|
+
}
|
801
|
+
|
802
|
+
static VALUE method_zkrb_iterate_event_loop(VALUE self) {
|
803
|
+
FETCH_DATA_PTR(self, zk);
|
804
|
+
|
805
|
+
rb_fdset_t rfds, wfds, efds;
|
806
|
+
rb_fd_init(&rfds); rb_fd_init(&wfds); rb_fd_init(&efds);
|
807
|
+
|
808
|
+
int fd = 0, interest = 0, events = 0, rc = 0, maxfd = 0, irc = 0, prc = 0;
|
809
|
+
struct timeval tv;
|
810
|
+
|
811
|
+
irc = zookeeper_interest(zk->zh, &fd, &interest, &tv);
|
812
|
+
|
813
|
+
if (fd != -1) {
|
814
|
+
if (interest & ZOOKEEPER_READ) {
|
815
|
+
rb_fd_set(fd, &rfds);
|
816
|
+
} else {
|
817
|
+
rb_fd_clr(fd, &rfds);
|
818
|
+
}
|
819
|
+
if (interest & ZOOKEEPER_WRITE) {
|
820
|
+
rb_fd_set(fd, &wfds);
|
821
|
+
} else {
|
822
|
+
rb_fd_clr(fd, &wfds);
|
823
|
+
}
|
824
|
+
} else {
|
825
|
+
fd = 0;
|
826
|
+
}
|
827
|
+
|
828
|
+
// add our self-pipe to the read set, allow us to wake up in case our attention is needed
|
829
|
+
int pipe_r_fd = get_self_pipe_read_fd(self);
|
830
|
+
|
831
|
+
rb_fd_set(pipe_r_fd, &rfds);
|
832
|
+
|
833
|
+
maxfd = (pipe_r_fd > fd) ? pipe_r_fd : fd;
|
834
|
+
|
835
|
+
rc = rb_thread_fd_select(maxfd+1, &rfds, &wfds, &efds, &tv);
|
836
|
+
|
837
|
+
if (rc > 0) {
|
838
|
+
if (rb_fd_isset(fd, &rfds)) {
|
839
|
+
events |= ZOOKEEPER_READ;
|
840
|
+
}
|
841
|
+
if (rb_fd_isset(fd, &wfds)) {
|
842
|
+
events |= ZOOKEEPER_WRITE;
|
843
|
+
}
|
844
|
+
|
845
|
+
// we got woken up by the self-pipe
|
846
|
+
if (rb_fd_isset(pipe_r_fd, &rfds)) {
|
847
|
+
// one event has awoken us, so we clear one event from the pipe
|
848
|
+
char b[1];
|
849
|
+
|
850
|
+
if (read(pipe_r_fd, b, 1) < 0) {
|
851
|
+
rb_raise(rb_eRuntimeError, "read from pipe failed: %s", clean_errno());
|
852
|
+
}
|
853
|
+
}
|
854
|
+
}
|
855
|
+
else if (rc == 0) {
|
856
|
+
// zkrb_debug("timed out waiting for descriptor to be ready. interest=%d fd=%d pipe_r_fd=%d maxfd=%d irc=%d timeout=%f",
|
857
|
+
// interest, fd, pipe_r_fd, maxfd, irc, tv.tv_sec + (tv.tv_usec/ 1000.0 / 1000.0));
|
858
|
+
}
|
859
|
+
else {
|
860
|
+
log_err("select returned an error: rc=%d interest=%d fd=%d pipe_r_fd=%d maxfd=%d irc=%d timeout=%f",
|
861
|
+
rc, interest, fd, pipe_r_fd, maxfd, irc, tv.tv_sec + (tv.tv_usec/ 1000.0 / 1000.0));
|
862
|
+
}
|
863
|
+
|
864
|
+
prc = zookeeper_process(zk->zh, events);
|
865
|
+
|
866
|
+
if (rc == 0) {
|
867
|
+
zkrb_debug("timed out waiting for descriptor to be ready. prc=%d interest=%d fd=%d pipe_r_fd=%d maxfd=%d irc=%d timeout=%f",
|
868
|
+
prc, interest, fd, pipe_r_fd, maxfd, irc, tv.tv_sec + (tv.tv_usec/ 1000.0 / 1000.0));
|
869
|
+
}
|
870
|
+
|
871
|
+
rb_fd_term(&rfds);
|
872
|
+
rb_fd_term(&wfds);
|
873
|
+
rb_fd_term(&efds);
|
874
|
+
return INT2FIX(prc);
|
875
|
+
}
|
876
|
+
|
877
|
+
static VALUE method_has_events(VALUE self) {
|
878
|
+
VALUE rb_event;
|
879
|
+
FETCH_DATA_PTR(self, zk);
|
880
|
+
|
881
|
+
rb_event = zkrb_peek(zk->queue) != NULL ? Qtrue : Qfalse;
|
882
|
+
return rb_event;
|
883
|
+
}
|
884
|
+
|
885
|
+
static VALUE method_zoo_set_log_level(VALUE self, VALUE level) {
|
886
|
+
Check_Type(level, T_FIXNUM);
|
887
|
+
zoo_set_debug_level(FIX2INT(level));
|
888
|
+
return Qnil;
|
889
|
+
}
|
890
|
+
|
891
|
+
static VALUE method_close_handle(VALUE self) {
|
892
|
+
FETCH_DATA_PTR(self, zk);
|
893
|
+
|
894
|
+
if (ZKRBDebugging) {
|
895
|
+
zkrb_debug_inst(self, "CLOSING_ZK_INSTANCE");
|
896
|
+
print_zkrb_instance_data(zk);
|
897
|
+
}
|
898
|
+
|
899
|
+
// this is a value on the ruby side we can check to see if destroy_zkrb_instance
|
900
|
+
// has been called
|
901
|
+
rb_iv_set(self, "@_closed", Qtrue);
|
902
|
+
|
903
|
+
/* Note that after zookeeper_close() returns, ZK handle is invalid */
|
904
|
+
int rc = destroy_zkrb_instance(zk);
|
905
|
+
|
906
|
+
zkrb_debug("destroy_zkrb_instance returned: %d", rc);
|
907
|
+
|
908
|
+
return INT2FIX(rc);
|
909
|
+
}
|
910
|
+
|
911
|
+
static VALUE method_deterministic_conn_order(VALUE self, VALUE yn) {
|
912
|
+
zoo_deterministic_conn_order(yn == Qtrue);
|
913
|
+
return Qnil;
|
914
|
+
}
|
915
|
+
|
916
|
+
static VALUE method_is_unrecoverable(VALUE self) {
|
917
|
+
FETCH_DATA_PTR(self, zk);
|
918
|
+
return is_unrecoverable(zk->zh) == ZINVALIDSTATE ? Qtrue : Qfalse;
|
919
|
+
}
|
920
|
+
|
921
|
+
static VALUE method_zkrb_state(VALUE self) {
|
922
|
+
FETCH_DATA_PTR(self, zk);
|
923
|
+
return INT2NUM(zoo_state(zk->zh));
|
924
|
+
}
|
925
|
+
|
926
|
+
static VALUE method_recv_timeout(VALUE self) {
|
927
|
+
FETCH_DATA_PTR(self, zk);
|
928
|
+
return INT2NUM(zoo_recv_timeout(zk->zh));
|
929
|
+
}
|
930
|
+
|
931
|
+
// returns a CZookeeper::ClientId object with the values set for session_id and passwd
|
932
|
+
static VALUE method_client_id(VALUE self) {
|
933
|
+
FETCH_DATA_PTR(self, zk);
|
934
|
+
const clientid_t *cid = zoo_client_id(zk->zh);
|
935
|
+
|
936
|
+
VALUE session_id = LL2NUM(cid->client_id);
|
937
|
+
VALUE passwd = rb_str_new(cid->passwd, 16);
|
938
|
+
|
939
|
+
VALUE client_id_obj = rb_class_new_instance(0, RARRAY_PTR(rb_ary_new()), ZookeeperClientId);
|
940
|
+
|
941
|
+
rb_funcall(client_id_obj, rb_intern("session_id="), 1, session_id);
|
942
|
+
rb_funcall(client_id_obj, rb_intern("passwd="), 1, passwd);
|
943
|
+
|
944
|
+
return client_id_obj;
|
945
|
+
}
|
946
|
+
|
947
|
+
static VALUE klass_method_zkrb_set_debug_level(VALUE klass, VALUE level) {
|
948
|
+
Check_Type(level, T_FIXNUM);
|
949
|
+
ZKRBDebugging = (FIX2INT(level) == ZOO_LOG_LEVEL_DEBUG);
|
950
|
+
zoo_set_debug_level(FIX2INT(level));
|
951
|
+
return Qnil;
|
952
|
+
}
|
953
|
+
|
954
|
+
static VALUE method_zerror(VALUE self, VALUE errc) {
|
955
|
+
return rb_str_new2(zerror(FIX2INT(errc)));
|
956
|
+
}
|
957
|
+
|
958
|
+
static VALUE method_connected_host(VALUE self) {
|
959
|
+
FETCH_DATA_PTR(self, zk);
|
960
|
+
|
961
|
+
struct sockaddr addr;
|
962
|
+
socklen_t addr_len = sizeof(addr);
|
963
|
+
|
964
|
+
if (zookeeper_get_connected_host(zk->zh, &addr, &addr_len) != NULL) {
|
965
|
+
char buf[255];
|
966
|
+
char addrstr[128];
|
967
|
+
void *inaddr;
|
968
|
+
int port;
|
969
|
+
|
970
|
+
#if defined(AF_INET6)
|
971
|
+
if(addr.sa_family==AF_INET6){
|
972
|
+
inaddr = &((struct sockaddr_in6 *) &addr)->sin6_addr;
|
973
|
+
port = ((struct sockaddr_in6 *) &addr)->sin6_port;
|
974
|
+
} else {
|
975
|
+
#endif
|
976
|
+
inaddr = &((struct sockaddr_in *) &addr)->sin_addr;
|
977
|
+
port = ((struct sockaddr_in *) &addr)->sin_port;
|
978
|
+
#if defined(AF_INET6)
|
979
|
+
}
|
980
|
+
#endif
|
981
|
+
|
982
|
+
inet_ntop(addr.sa_family, inaddr, addrstr, sizeof(addrstr)-1);
|
983
|
+
snprintf(buf, sizeof(buf), "%s:%d", addrstr, ntohs(port));
|
984
|
+
return rb_str_new2(buf);
|
985
|
+
}
|
986
|
+
|
987
|
+
return Qnil;
|
988
|
+
}
|
989
|
+
|
990
|
+
static void zkrb_define_methods(void) {
|
991
|
+
#define DEFINE_METHOD(M, ARGS) { \
|
992
|
+
rb_define_method(CZookeeper, #M, method_ ## M, ARGS); }
|
993
|
+
|
994
|
+
#define DEFINE_CLASS_METHOD(M, ARGS) { \
|
995
|
+
rb_define_singleton_method(CZookeeper, #M, method_ ## M, ARGS); }
|
996
|
+
|
997
|
+
// defines a method with a zkrb_ prefix, the actual C method does not have this prefix
|
998
|
+
#define DEFINE_ZKRB_METHOD(M, ARGS) { \
|
999
|
+
rb_define_method(CZookeeper, zkrb_ ## M, method_ ## M, ARGS); }
|
1000
|
+
|
1001
|
+
// the number after the method name should be actual arity of C function - 1
|
1002
|
+
DEFINE_METHOD(zkrb_init, -1);
|
1003
|
+
|
1004
|
+
rb_define_method(CZookeeper, "zkrb_get_children", method_get_children, 4);
|
1005
|
+
rb_define_method(CZookeeper, "zkrb_exists", method_exists, 4);
|
1006
|
+
rb_define_method(CZookeeper, "zkrb_create", method_create, 6);
|
1007
|
+
rb_define_method(CZookeeper, "zkrb_delete", method_delete, 4);
|
1008
|
+
rb_define_method(CZookeeper, "zkrb_get", method_get, 4);
|
1009
|
+
rb_define_method(CZookeeper, "zkrb_set", method_set, 5);
|
1010
|
+
rb_define_method(CZookeeper, "zkrb_set_acl", method_set_acl, 5);
|
1011
|
+
rb_define_method(CZookeeper, "zkrb_get_acl", method_get_acl, 3);
|
1012
|
+
rb_define_method(CZookeeper, "zkrb_add_auth", method_add_auth, 3);
|
1013
|
+
|
1014
|
+
rb_define_singleton_method(CZookeeper, "zoo_set_log_level", method_zoo_set_log_level, 1);
|
1015
|
+
|
1016
|
+
DEFINE_METHOD(client_id, 0);
|
1017
|
+
DEFINE_METHOD(close_handle, 0);
|
1018
|
+
DEFINE_METHOD(deterministic_conn_order, 1);
|
1019
|
+
DEFINE_METHOD(is_unrecoverable, 0);
|
1020
|
+
DEFINE_METHOD(recv_timeout, 0);
|
1021
|
+
DEFINE_METHOD(zkrb_state, 0);
|
1022
|
+
DEFINE_METHOD(sync, 2);
|
1023
|
+
DEFINE_METHOD(zkrb_iterate_event_loop, 0);
|
1024
|
+
DEFINE_METHOD(zkrb_get_next_event_st, 0);
|
1025
|
+
DEFINE_METHOD(connected_host, 0);
|
1026
|
+
|
1027
|
+
// methods for the ruby-side event manager
|
1028
|
+
DEFINE_METHOD(zkrb_get_next_event, 1);
|
1029
|
+
DEFINE_METHOD(zkrb_get_next_event_st, 0);
|
1030
|
+
DEFINE_METHOD(has_events, 0);
|
1031
|
+
|
1032
|
+
// Make these class methods?
|
1033
|
+
DEFINE_METHOD(zerror, 1);
|
1034
|
+
|
1035
|
+
rb_define_singleton_method(CZookeeper, "set_zkrb_debug_level", klass_method_zkrb_set_debug_level, 1);
|
1036
|
+
|
1037
|
+
rb_attr(CZookeeper, rb_intern("selectable_io"), 1, 0, Qtrue);
|
1038
|
+
|
1039
|
+
}
|
1040
|
+
|
1041
|
+
// class CZookeeper::ClientId
|
1042
|
+
// attr_accessor :session_id, :passwd
|
1043
|
+
//
|
1044
|
+
// def initialize(session_id, passwd)
|
1045
|
+
// @session_id = session_id
|
1046
|
+
// @passwd = passwd
|
1047
|
+
// end
|
1048
|
+
// end
|
1049
|
+
|
1050
|
+
static VALUE zkrb_client_id_method_initialize(VALUE self) {
|
1051
|
+
rb_iv_set(self, "@session_id", Qnil);
|
1052
|
+
rb_iv_set(self, "@passwd", Qnil);
|
1053
|
+
return Qnil;
|
1054
|
+
}
|
1055
|
+
|
1056
|
+
|
1057
|
+
void Init_zookeeper_c() {
|
1058
|
+
// Don't debug by default
|
1059
|
+
ZKRBDebugging = 0;
|
1060
|
+
zoo_set_debug_level(0);
|
1061
|
+
|
1062
|
+
mZookeeper = rb_define_module("Zookeeper");
|
1063
|
+
mZookeeperExceptions = rb_define_module_under(mZookeeper, "Exceptions");
|
1064
|
+
|
1065
|
+
// this will likely fail if the load order is screwed up
|
1066
|
+
eHandleClosedException = rb_const_get(mZookeeperExceptions, rb_intern("HandleClosedException"));
|
1067
|
+
|
1068
|
+
/* initialize CZookeeper class */
|
1069
|
+
CZookeeper = rb_define_class_under(mZookeeper, "CZookeeper", rb_cObject);
|
1070
|
+
rb_define_alloc_func(CZookeeper, alloc_zkrb_instance);
|
1071
|
+
zkrb_define_methods();
|
1072
|
+
|
1073
|
+
ZookeeperClientId = rb_define_class_under(CZookeeper, "ClientId", rb_cObject);
|
1074
|
+
rb_define_method(ZookeeperClientId, "initialize", zkrb_client_id_method_initialize, 0);
|
1075
|
+
rb_define_attr(ZookeeperClientId, "session_id", 1, 1);
|
1076
|
+
rb_define_attr(ZookeeperClientId, "passwd", 1, 1);
|
1077
|
+
|
1078
|
+
}
|
1079
|
+
|
1080
|
+
// vim:ts=2:sw=2:sts=2:et
|