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 +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
|