zookeeper 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +1 -0
- data/CHANGELOG +2 -0
- data/Manifest +8 -0
- data/README +98 -0
- data/Rakefile +9 -0
- data/ext/zookeeper_c/extconf.rb +14 -0
- data/ext/zookeeper_c/zookeeper_ruby.c +518 -0
- data/lib/zookeeper_client.rb +78 -0
- data/test/test_basic.rb +63 -0
- data/zookeeper.gemspec +34 -0
- metadata +94 -0
- metadata.gz.sig +0 -0
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/�_Tc���1s��ͦJ��Р;�LC�ͅA-��{��I��",��@���Gs&h���6���D]إi�g�����6���
|
data/CHANGELOG
ADDED
data/Manifest
ADDED
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
|
data/test/test_basic.rb
ADDED
@@ -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
|