zookeeper 0.1

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.tar.gz.sig ADDED
@@ -0,0 +1 @@
1
+ ��0i�4E�X��� ������I�>���Ya�0����� >��s���xSʷ����(9��?�#�2i2�#j����P��?E9Q!��T��Q)}v�HL��k�i�al)��(�U鱗kZ�r�?��->��������V��?s���s�CQ�^aL�N����R�đn��7�V�a��0/�_T c���1s��ͦJ��Р;�LC�ͅA-��{��I��",��@���Gs&h���6���D]إi�g�����6���
data/CHANGELOG ADDED
@@ -0,0 +1,2 @@
1
+
2
+ v0.1. First release.
data/Manifest ADDED
@@ -0,0 +1,8 @@
1
+ CHANGELOG
2
+ README
3
+ Rakefile
4
+ ext/zookeeper_c/extconf.rb
5
+ ext/zookeeper_c/zookeeper_ruby.c
6
+ lib/zookeeper_client.rb
7
+ test/test_basic.rb
8
+ Manifest
data/README ADDED
@@ -0,0 +1,98 @@
1
+ zookeeper_client
2
+ by Phillip Pearson
3
+ http://github.com/myelin/zookeeper_client
4
+
5
+ == DESCRIPTION:
6
+
7
+ zookeeper_client is a Ruby library to interface with the ZooKeeper
8
+ replicated object store / lock server.
9
+
10
+ Project maturity: early alpha. Working, although very chatty and
11
+ there may be bugs to do with threading. Expect to get your hands
12
+ dirty.
13
+
14
+ == REQUIREMENTS:
15
+
16
+ * ZooKeeper C client library (http://zookeeper.sourceforge.net/)
17
+
18
+ See installation instructions in c/README, in the ZooKeeper source
19
+ distribution. zookeeper_client expects the headers to live in
20
+ /usr/include/c-client-src/, which doesn't feel right but is where
21
+ they go on my system when I run 'make install'.
22
+
23
+ == INSTALL:
24
+
25
+ $ gem sources -a http://gems.github.com/
26
+ $ gem install myelin-zookeeper_client
27
+
28
+ == USAGE:
29
+
30
+ = Connect to a server
31
+
32
+ require 'rubygems'
33
+ require 'myelin-zookeeper_client'
34
+ z = ZooKeeper.new("localhost:2181")
35
+
36
+ = Create, set and read nodes
37
+
38
+ z.create("/bacon", "text to be stored in the new node", 0)
39
+ # => "/bacon"
40
+
41
+ data, stat = z.get("/bacon")
42
+ # => ["text to be stored in the new node", #<ZkStat:0xb771be54 @ephemeralOwner=0, @ctime=1216196667669, @aversion=0, @mzxid=1008, @cversion=0, @version=0, @czxid=1008, @mtime=1216196667669>]
43
+
44
+ z.set("/bacon", "an entirely different line of text", stat.version)
45
+ # => nil
46
+
47
+ z.set("/bacon", "this won't work", stat.version)
48
+ # CZooKeeper::BadVersionError: expected version does not match actual version
49
+
50
+ data, stat = z.get("/bacon")
51
+ # => ["an entirely different line of text", #<ZkStat:0xb77125d4 @ephemeralOwner=0, @ctime=1216196667669, @aversion=0, @mzxid=1009, @cversion=0, @version=1, @czxid=1008, @mtime=1216196704709>]
52
+
53
+ z.delete("/bacon", stat.version)
54
+ # => nil
55
+
56
+ = Create ephemeral and sequence nodes
57
+
58
+ z.create("/parent", "parent node", 0)
59
+ # => "/parent"
60
+
61
+ z.create("/parent/test-", "an ordered node that will disappear when the connection goes down", ZooKeeper::EPHEMERAL | ZooKeeper::SEQUENCE)
62
+ # => "/parent/test-0"
63
+
64
+ z.create("/parent/test-", "an ordered node that will disappear when the connection goes down", ZooKeeper::EPHEMERAL | ZooKeeper::SEQUENCE)
65
+ # => "/parent/test-1"
66
+
67
+ = Acquire locks
68
+
69
+ z.try_acquire "/parent/lock-", "content for the lock file" do |have_lock|
70
+ puts have_lock ? "we have the lock" : "we don't have the lock"
71
+ end
72
+ # we have the lock
73
+ # => nil
74
+
75
+ == LICENSE:
76
+
77
+ (The MIT License)
78
+
79
+ Copyright (C) 2008 Phillip Pearson
80
+
81
+ Permission is hereby granted, free of charge, to any person obtaining
82
+ a copy of this software and associated documentation files (the
83
+ 'Software'), to deal in the Software without restriction, including
84
+ without limitation the rights to use, copy, modify, merge, publish,
85
+ distribute, sublicense, and/or sell copies of the Software, and to
86
+ permit persons to whom the Software is furnished to do so, subject to
87
+ the following conditions:
88
+
89
+ The above copyright notice and this permission notice shall be
90
+ included in all copies or substantial portions of the Software.
91
+
92
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
93
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
94
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
95
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
96
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
97
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
98
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require 'echoe'
2
+
3
+ Echoe.new("zookeeper") do |p|
4
+ p.author = "Phillip Pearson, Eric Maland, Evan Weaver"
5
+ p.project = "fauna"
6
+ p.summary = "A Ruby wrapper for the ZooKeeper C client library."
7
+ p.url = "http://blog.evanweaver.com/files/doc/fauna/zookeeper/"
8
+ p.docs_host = "blog.evanweaver.com:~/www/bax/public/files/doc/"
9
+ end
@@ -0,0 +1,14 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("zookeeper")
4
+
5
+ have_header "sys/errno.h"
6
+ have_header "stdio.h"
7
+ find_header("zookeeper/zookeeper.h") or
8
+ raise "zookeeper.h not found."
9
+ find_library("zookeeper_mt", "zoo_set_debug_level") or
10
+ raise "libzookeeper_mt not found."
11
+
12
+ dir_config('zookeeper_c')
13
+ create_makefile( 'zookeeper_c')
14
+
@@ -0,0 +1,518 @@
1
+ /* Ruby wrapper for the ZooKeeper C API
2
+ * Phillip Pearson <pp@myelin.co.nz>
3
+ * Eric Maland <eric@twitter.com>
4
+ */
5
+
6
+ #define THREADED
7
+
8
+ #include "ruby.h"
9
+
10
+ #include "zookeeper/zookeeper.h"
11
+ #include <errno.h>
12
+ #include <stdio.h>
13
+
14
+ static VALUE ZooKeeper = Qnil;
15
+ static VALUE eNoNode = Qnil;
16
+ static VALUE eBadVersion = Qnil;
17
+
18
+ struct zk_rb_data {
19
+ zhandle_t *zh;
20
+ clientid_t myid;
21
+ };
22
+
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));
49
+ }
50
+ }
51
+
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
+ static VALUE method_initialize(VALUE self, VALUE hostPort) {
69
+ VALUE data;
70
+ struct zk_rb_data* zk = NULL;
71
+
72
+ Check_Type(hostPort, T_STRING);
73
+
74
+ data = Data_Make_Struct(ZooKeeper, struct zk_rb_data, 0, free_zk_rb_data, zk);
75
+
76
+ zoo_set_debug_level(ZOO_LOG_LEVEL_INFO);
77
+ 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) {
81
+ rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
82
+ }
83
+
84
+ rb_iv_set(self, "@data", data);
85
+
86
+ return Qnil;
87
+ }
88
+
89
+ #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) {
94
+ 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));
102
+
103
+ output = rb_ary_new();
104
+ for (i = 0; i < strings.count; ++i) {
105
+ rb_ary_push(output, rb_str_new2(strings.data[i]));
106
+ }
107
+ return output;
108
+ }
109
+
110
+ static VALUE method_exists(VALUE self, VALUE path, VALUE watch) {
111
+ struct Stat stat;
112
+
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));
117
+
118
+ return array_from_stat(&stat);
119
+ }
120
+
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);
126
+ Check_Type(flags, T_FIXNUM);
127
+
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);
136
+ }
137
+
138
+ static VALUE method_delete(VALUE self, VALUE path, VALUE version) {
139
+ Check_Type(path, T_STRING);
140
+ 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
+
159
+ check_errors(zoo_get(zk->zh, RSTRING(path)->ptr, 0, data, &data_len, &stat));
160
+
161
+ return rb_ary_new3(2,
162
+ rb_str_new(data, data_len),
163
+ array_from_stat(&stat));
164
+ }
165
+
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
+
179
+ if(!NIL_P(v_version))
180
+ real_version = FIX2INT(v_version);
181
+
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)));
186
+
187
+ return Qtrue;
188
+ }
189
+
190
+ static void void_completion_callback(int rc, const void *data) {
191
+
192
+ }
193
+
194
+ static void string_completion_callback(int rc, const char *value, const void *data) {
195
+
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;
203
+
204
+ }
205
+
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; */
211
+
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); */
217
+
218
+ /* if(!NIL_P(v_version)) */
219
+ /* real_version = FIX2INT(v_version); */
220
+
221
+ /* Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk); */
222
+
223
+ /* check_errors(zoo_set(zk->zh, RSTRING(v_path)->ptr, */
224
+ /* RSTRING(v_data)->ptr, RSTRING(v_data)->len, */
225
+ /* FIX2INT(v_version))); */
226
+
227
+ return Qnil;
228
+ }
229
+
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); // ???
259
+
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);
270
+
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)));
276
+
277
+ return Qtrue;
278
+ }
279
+
280
+ static VALUE method_client_id(VALUE self) {
281
+ FETCH_DATA_PTR(self, zk);
282
+ const clientid_t *id = zoo_client_id(zk->zh);
283
+ return UINT2NUM(id->client_id);
284
+ }
285
+
286
+ static VALUE method_close(VALUE self) {
287
+ FETCH_DATA_PTR(self, zk);
288
+ check_errors(zookeeper_close(zk->zh));
289
+ return Qtrue;
290
+ }
291
+
292
+ static VALUE method_deterministic_conn_order(VALUE self, VALUE yn) {
293
+ zoo_deterministic_conn_order(yn == Qtrue);
294
+ return Qnil;
295
+ }
296
+
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) {
353
+ 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;
366
+ }
367
+
368
+ static VALUE method_is_unrecoverable(VALUE self) {
369
+ FETCH_DATA_PTR(self, zk);
370
+ if(is_unrecoverable(zk->zh) == ZINVALIDSTATE)
371
+ return Qtrue;
372
+
373
+ return Qfalse;
374
+ }
375
+
376
+ static VALUE method_recv_timeout(VALUE self) {
377
+ FETCH_DATA_PTR(self, zk);
378
+ return INT2NUM(zoo_recv_timeout(zk->zh));
379
+ }
380
+
381
+ #warning [emaland] make this a class method or global
382
+ static VALUE method_set_debug_level(VALUE self, VALUE level) {
383
+ FETCH_DATA_PTR(self, zk);
384
+ Check_Type(level, T_FIXNUM);
385
+ zoo_set_debug_level(FIX2INT(level));
386
+ return Qnil;
387
+ }
388
+
389
+ #warning [emaland] make this a class method or global
390
+ static VALUE method_zerror(VALUE self, VALUE errc) {
391
+ return rb_str_new2(zerror(FIX2INT(errc)));
392
+ }
393
+
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
+
418
+ #define DEFINE_METHOD(method, args) { \
419
+ rb_define_method(ZooKeeper, #method, method_ ## method, args); }
420
+
421
+ 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);
433
+ DEFINE_METHOD(client_id, 0);
434
+ DEFINE_METHOD(close, 0);
435
+ DEFINE_METHOD(deterministic_conn_order, 1);
436
+ DEFINE_METHOD(get_acl, 2);
437
+ DEFINE_METHOD(is_unrecoverable, 0);
438
+ 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
+ DEFINE_METHOD(state, 0);
444
+ DEFINE_METHOD(zerror, 1);
445
+
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
+
518
+ }
@@ -0,0 +1,78 @@
1
+ # Ruby wrapper for the ZooKeeper C API
2
+ # Phillip Pearson <pp@myelin.co.nz>
3
+
4
+ require 'zookeeper_c'
5
+
6
+ class ZkStat
7
+ attr_reader :version
8
+ def initialize(ary)
9
+ @czxid, @mzxid, @ctime, @mtime, @version, @cversion, @aversion, @ephemeralOwner = ary
10
+ end
11
+ end
12
+
13
+ class ZooKeeper < CZooKeeper
14
+ def initialize(host)
15
+ super(host)
16
+ @watchers = {} # path => [ block, block, ... ]
17
+ end
18
+
19
+ def exists(path, &blk)
20
+ (@watchers[path] ||= []) << blk if blk
21
+ ZkStat.new(super(path, !!blk))
22
+ end
23
+
24
+ def stat(path, &blk)
25
+ exists(path, &blk)
26
+ rescue ZooKeeper::NoNodeError
27
+ nil
28
+ end
29
+
30
+ def get(path)
31
+ value, stat = super
32
+ [value, ZkStat.new(stat)]
33
+ end
34
+
35
+ def try_acquire(path, value)
36
+ # create the parent node if it doesn't exist already
37
+ create(path, "lock node", 0) unless stat(path)
38
+
39
+ # attempt to obtain the lock
40
+ realpath = create("#{path}/lock-", value, ZooKeeper::ZOO_EPHEMERAL | ZooKeeper::ZOO_SEQUENCE)
41
+ #puts "created lock node #{realpath}"
42
+
43
+ # see if we got it
44
+ serial = /lock-(\d+)$/.match(realpath).captures[0].to_i
45
+ have_lock = true
46
+ ls(path).each do |child|
47
+ if m = /lock-(\d+)$/.match(child)
48
+ if m.captures[0].to_i < serial
49
+ have_lock = false
50
+ break
51
+ end
52
+ end
53
+ end
54
+
55
+ # call block
56
+ yield(have_lock)
57
+
58
+ # release the lock
59
+ #puts "deleting #{realpath}"
60
+ delete(realpath, stat(realpath).version)
61
+ end
62
+
63
+ def watcher(type, state, path)
64
+ raise Exception("watchers don't work in ruby yet") # ... until I figure out how to synchronize access to the Ruby interpreter
65
+
66
+ return unless type == ZOO_SESSION_EVENT
67
+
68
+ case state
69
+ when ZOO_CONNECTED_STATE
70
+ puts "ruby watcher; got an event for #{path}"
71
+
72
+ when ZOO_AUTH_FAILED_STATE
73
+ raise Exception, "auth failure"
74
+ when ZOO_EXPIRED_SESSION_STATE
75
+ raise Exception, "session expired"
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,63 @@
1
+ $LOAD_PATH << '/home/eric/zk-clients/lib'
2
+ require 'rubygems'
3
+ require 'zookeeper_client'
4
+
5
+ z = ZooKeeper.new("localhost:2181")
6
+
7
+ puts "root: #{z.get_children("/").inspect}"
8
+
9
+ path = "/testing_node"
10
+
11
+ puts "working with path #{path}"
12
+
13
+ stat = z.stat(path)
14
+ puts "exists? #{stat.inspect}"
15
+
16
+ unless stat.nil?
17
+ z.get_children(path).each do |o|
18
+ puts " child object: #{o}"
19
+ end
20
+ puts "delete: #{z.delete(path, stat.version).inspect}"
21
+ end
22
+
23
+ puts "create: #{z.create(path, "initial value", 0).inspect}"
24
+
25
+ value, stat = z.get(path)
26
+ puts "current value #{value}, stat #{stat.inspect}"
27
+
28
+ puts "set: #{z.set(path, "this is a test", stat.version).inspect}"
29
+
30
+ value, stat = z.get(path)
31
+ puts "new value: #{value.inspect} #{stat.inspect}"
32
+
33
+ puts "delete: #{z.delete(path, stat.version).inspect}"
34
+
35
+ begin
36
+ puts "exists? #{z.exists(path)}"
37
+ raise Exception, "it shouldn't exist"
38
+ rescue ZooKeeper::NoNodeError
39
+ puts "doesn't exist - good, because we just deleted it!"
40
+ end
41
+
42
+ puts "trying a watcher"
43
+ puts z
44
+ if s = z.stat("/test"); z.delete("/test", s.version); end
45
+ z.create("/test", "foo", 0)
46
+ z.exists("/test") do
47
+ puts "callback!!!"
48
+ end
49
+ puts "now changing it"
50
+ z.set("/test", "bar", 0)
51
+ sleep 1
52
+ puts "did the watcher say something?"
53
+
54
+ puts "let's try using a lock"
55
+ z.try_acquire("/test_lock", "this is the content of the lock file") do |have_lock|
56
+ puts have_lock ? "we have the lock!" : "failed to obtain lock :("
57
+ if have_lock
58
+ puts "sleeping"
59
+ sleep 5
60
+ end
61
+ end
62
+ puts "done with locking..."
63
+
data/zookeeper.gemspec ADDED
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{zookeeper}
5
+ s.version = "0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Phillip Pearson, Eric Maland, Evan Weaver"]
9
+ s.cert_chain = ["/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-public_cert.pem"]
10
+ s.date = %q{2010-02-09}
11
+ s.description = %q{A Ruby wrapper for the ZooKeeper C client library.}
12
+ s.email = %q{}
13
+ s.extensions = ["ext/zookeeper_c/extconf.rb"]
14
+ s.extra_rdoc_files = ["CHANGELOG", "README", "ext/zookeeper_c/extconf.rb", "ext/zookeeper_c/zookeeper_ruby.c", "lib/zookeeper_client.rb"]
15
+ s.files = ["CHANGELOG", "README", "Rakefile", "ext/zookeeper_c/extconf.rb", "ext/zookeeper_c/zookeeper_ruby.c", "lib/zookeeper_client.rb", "test/test_basic.rb", "Manifest", "zookeeper.gemspec"]
16
+ s.homepage = %q{http://blog.evanweaver.com/files/doc/fauna/zookeeper/}
17
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Zookeeper", "--main", "README"]
18
+ s.require_paths = ["lib", "ext"]
19
+ s.rubyforge_project = %q{fauna}
20
+ s.rubygems_version = %q{1.3.5}
21
+ s.signing_key = %q{/Users/eweaver/p/configuration/gem_certificates/evan_weaver-original-private_key.pem}
22
+ s.summary = %q{A Ruby wrapper for the ZooKeeper C client library.}
23
+ s.test_files = ["test/test_basic.rb"]
24
+
25
+ if s.respond_to? :specification_version then
26
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
27
+ s.specification_version = 3
28
+
29
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
30
+ else
31
+ end
32
+ else
33
+ end
34
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zookeeper
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Phillip Pearson, Eric Maland, Evan Weaver
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDLjCCAhagAwIBAgIBADANBgkqhkiG9w0BAQUFADA9MQ0wCwYDVQQDDARldmFu
14
+ MRgwFgYKCZImiZPyLGQBGRYIY2xvdWRidXIxEjAQBgoJkiaJk/IsZAEZFgJzdDAe
15
+ Fw0wNzA5MTYxMDMzMDBaFw0wODA5MTUxMDMzMDBaMD0xDTALBgNVBAMMBGV2YW4x
16
+ GDAWBgoJkiaJk/IsZAEZFghjbG91ZGJ1cjESMBAGCgmSJomT8ixkARkWAnN0MIIB
17
+ IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5C0Io89nyApnr+PvbNFge9Vs
18
+ yRWAlGBUEMahpXp28VrrfXZT0rAW7JBo4PlCE3jl4nE4dzE6gAdItSycjTosrw7A
19
+ Ir5+xoyl4Vb35adv56TIQQXvNz+BzlqnkAY5JN0CSBRTQb6mxS3hFyD/h4qgDosj
20
+ R2RFVzHqSxCS8xq4Ny8uzOwOi+Xyu4w67fI5JvnPvMxqrlR1eaIQHmxnf76RzC46
21
+ QO5QhufjAYGGXd960XzbQsQyTDUYJzrvT7AdOfiyZzKQykKt8dEpDn+QPjFTnGnT
22
+ QmgJBX5WJN0lHF2l1sbv3gh4Kn1tZu+kTUqeXY6ShAoDTyvZRiFqQdwh8w2lTQID
23
+ AQABozkwNzAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHQ4EFgQU+WqJz3xQ
24
+ XSea1hRvvHWcIMgeeC4wDQYJKoZIhvcNAQEFBQADggEBAGLZ75jfOEW8Nsl26CTt
25
+ JFrWxQTcQT/UljeefVE3xYr7lc9oQjbqO3FOyued3qW7TaNEtZfSHoYeUSMYbpw1
26
+ XAwocIPuSRFDGM4B+hgQGVDx8PMGiJKom4qLXjO40UZsR7QyN/u869Vj45LURm6h
27
+ MBcPeqCASI+WNprj9+uZa2kmHiitrFqqfMBNlm5IFbn9XeYSta9AHVvs5QQqV2m5
28
+ hIPfLqCyxsn/YgOGvo6iwyQTWyTswamaAC3HRWZxIS1sfn/Ssqa7E7oQMkv5FAXr
29
+ x5rKePfXINf8XTJczkl9OBEYdE9aNdJsJpXD0asLgGVwBICS5Bjohp6mizJcDC1+
30
+ yZ0=
31
+ -----END CERTIFICATE-----
32
+
33
+ date: 2010-02-09 00:00:00 -08:00
34
+ default_executable:
35
+ dependencies: []
36
+
37
+ description: A Ruby wrapper for the ZooKeeper C client library.
38
+ email: ""
39
+ executables: []
40
+
41
+ extensions:
42
+ - ext/zookeeper_c/extconf.rb
43
+ extra_rdoc_files:
44
+ - CHANGELOG
45
+ - README
46
+ - ext/zookeeper_c/extconf.rb
47
+ - ext/zookeeper_c/zookeeper_ruby.c
48
+ - lib/zookeeper_client.rb
49
+ files:
50
+ - CHANGELOG
51
+ - README
52
+ - Rakefile
53
+ - ext/zookeeper_c/extconf.rb
54
+ - ext/zookeeper_c/zookeeper_ruby.c
55
+ - lib/zookeeper_client.rb
56
+ - test/test_basic.rb
57
+ - Manifest
58
+ - zookeeper.gemspec
59
+ has_rdoc: true
60
+ homepage: http://blog.evanweaver.com/files/doc/fauna/zookeeper/
61
+ licenses: []
62
+
63
+ post_install_message:
64
+ rdoc_options:
65
+ - --line-numbers
66
+ - --inline-source
67
+ - --title
68
+ - Zookeeper
69
+ - --main
70
+ - README
71
+ require_paths:
72
+ - lib
73
+ - ext
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: "0"
79
+ version:
80
+ required_rubygems_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: "1.2"
85
+ version:
86
+ requirements: []
87
+
88
+ rubyforge_project: fauna
89
+ rubygems_version: 1.3.5
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: A Ruby wrapper for the ZooKeeper C client library.
93
+ test_files:
94
+ - test/test_basic.rb
metadata.gz.sig ADDED
Binary file