carlosnz-zookeeper 0.2
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/README +70 -0
- data/ext/zookeeper_c/extconf.rb +9 -0
- data/ext/zookeeper_c/zookeeper.rb +86 -0
- data/ext/zookeeper_c/zookeeper_ruby.c +206 -0
- data/lib/zookeeper.rb +22 -0
- data/lib/zookeeper/acl.rb +19 -0
- data/lib/zookeeper/id.rb +18 -0
- data/lib/zookeeper/keeper_exception.rb +71 -0
- data/lib/zookeeper/logging.rb +5 -0
- data/lib/zookeeper/permission.rb +12 -0
- data/lib/zookeeper/queue.rb +57 -0
- data/lib/zookeeper/stat.rb +11 -0
- data/lib/zookeeper/sync_primitive.rb +32 -0
- data/lib/zookeeper/watcher_event.rb +24 -0
- metadata +72 -0
data/README
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
zookeeper
|
2
|
+
by Shane Mingins
|
3
|
+
http://github.com/smingins/zookeeper/tree/master
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Ruby Interface to Yahoo's ZooKeeper http://zookeeper.wiki.sourceforge.net/
|
8
|
+
|
9
|
+
|
10
|
+
== FEATURES/PROBLEMS:
|
11
|
+
|
12
|
+
Work in progress -- most of the needed ZooKeeper methods have been supported.
|
13
|
+
Queue was a hacked copy from the Java Tutorial on the site --- will refactor into a useable Recipe at some point.
|
14
|
+
ACL issues exist in ZooKeeper that have been patched, but patch only seems to work on trunk (Revision 176). See https://issues.apache.org/jira/browse/ZOOKEEPER-48
|
15
|
+
|
16
|
+
== TODO
|
17
|
+
|
18
|
+
Extend support for Ruby using ZooKeeper C API's
|
19
|
+
|
20
|
+
== SYNOPSIS:
|
21
|
+
|
22
|
+
Given a running ZooKeeper server listening for a client connection on port 2181:
|
23
|
+
|
24
|
+
zk = ZooKeeper.new(:host => "localhost:2181")
|
25
|
+
zk.create(:path => "/test", :data => "test_data")
|
26
|
+
|
27
|
+
See spec/zookeeper_spec for expected use and behaviour.
|
28
|
+
|
29
|
+
== REQUIREMENTS:
|
30
|
+
|
31
|
+
ZooKeeper installed and running.
|
32
|
+
|
33
|
+
I built zookeeper from source with the ACL patch https://issues.apache.org/jira/secure/attachment/12384350/acl_3.patch applied
|
34
|
+
|
35
|
+
For MRI version, ZooKeeper C client library (http://zookeeper.sourceforge.net/)
|
36
|
+
|
37
|
+
== INSTALL:
|
38
|
+
|
39
|
+
gem install smingins-zookeeper --source=http://gems.github.com/
|
40
|
+
|
41
|
+
jruby -S gem install smingins-zookeeper --source=http://gems.github.com/
|
42
|
+
|
43
|
+
== TESTS:
|
44
|
+
|
45
|
+
To run specs for MRI version execute extconf.rb to create makefile and then run make to create zookeeper_c.bundle, then run specs.
|
46
|
+
|
47
|
+
== LICENSE:
|
48
|
+
|
49
|
+
(The MIT License)
|
50
|
+
|
51
|
+
Copyright (c) 2008 Shane Mingins)
|
52
|
+
|
53
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
54
|
+
a copy of this software and associated documentation files (the
|
55
|
+
'Software'), to deal in the Software without restriction, including
|
56
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
57
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
58
|
+
permit persons to whom the Software is furnished to do so, subject to
|
59
|
+
the following conditions:
|
60
|
+
|
61
|
+
The above copyright notice and this permission notice shall be
|
62
|
+
included in all copies or substantial portions of the Software.
|
63
|
+
|
64
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
65
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
66
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
67
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
68
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
69
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
70
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'zookeeper_c'
|
2
|
+
|
3
|
+
class ZooKeeper < CZooKeeper
|
4
|
+
|
5
|
+
def initialize(args)
|
6
|
+
args = {:host => args} unless args.is_a?(Hash)
|
7
|
+
host = args[:host]
|
8
|
+
# timeout = args[:timeout] || DEFAULTS[:timeout]
|
9
|
+
# watcher = args[:watcher] || DefaultWatcher.new
|
10
|
+
# super(host, timeout, watcher)
|
11
|
+
super(host)
|
12
|
+
@watchers = {} # path => [ block, block, ... ]
|
13
|
+
end
|
14
|
+
|
15
|
+
def connected?
|
16
|
+
state == CONNECTED_STATE
|
17
|
+
end
|
18
|
+
|
19
|
+
def closed?
|
20
|
+
true # we hope TODO fix this
|
21
|
+
end
|
22
|
+
|
23
|
+
def close
|
24
|
+
# TODO
|
25
|
+
end
|
26
|
+
|
27
|
+
def create(args)
|
28
|
+
path = args[:path]
|
29
|
+
data = args[:data]
|
30
|
+
flags = 0
|
31
|
+
flags |= EPHEMERAL if args[:ephemeral]
|
32
|
+
flags |= SEQUENCE if args[:sequence]
|
33
|
+
super(path, data, flags)
|
34
|
+
end
|
35
|
+
|
36
|
+
def exists(path, &blk)
|
37
|
+
(@watchers[path] ||= []) << blk if blk
|
38
|
+
Stat.new(super(path, !!blk))
|
39
|
+
rescue NoNodeError
|
40
|
+
return nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def get(args)
|
44
|
+
args = {:path => args} unless args.is_a?(Hash)
|
45
|
+
path = args[:path]
|
46
|
+
watch = args[:watch] || false
|
47
|
+
callback = args[:callback]
|
48
|
+
context = args[:context]
|
49
|
+
|
50
|
+
value, stat = super(path)
|
51
|
+
[value, Stat.new(stat)]
|
52
|
+
rescue NoNodeError
|
53
|
+
raise KeeperException::NoNode
|
54
|
+
end
|
55
|
+
|
56
|
+
def set(args)
|
57
|
+
path = args[:path]
|
58
|
+
data = args[:data]
|
59
|
+
version = args[:version] || -1
|
60
|
+
callback = args[:callback]
|
61
|
+
context = args[:context]
|
62
|
+
|
63
|
+
super(path, data, version)
|
64
|
+
end
|
65
|
+
|
66
|
+
def delete(args)
|
67
|
+
args = {:path => args} unless args.is_a?(Hash)
|
68
|
+
path = args[:path]
|
69
|
+
version = args[:version] || -1
|
70
|
+
callback = args[:callback]
|
71
|
+
context = args[:context]
|
72
|
+
|
73
|
+
super(path, version)
|
74
|
+
end
|
75
|
+
|
76
|
+
def children(args)
|
77
|
+
args = {:path => args} unless args.is_a?(Hash)
|
78
|
+
path = args[:path]
|
79
|
+
watch = args[:watch] || false
|
80
|
+
callback = args[:callback]
|
81
|
+
context = args[:context]
|
82
|
+
|
83
|
+
ls(path)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
/* Ruby wrapper for the ZooKeeper C API
|
2
|
+
* Phillip Pearson <pp@myelin.co.nz>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#define THREADED
|
6
|
+
|
7
|
+
#include "ruby.h"
|
8
|
+
|
9
|
+
#include "c-client-src/zookeeper.h"
|
10
|
+
#include <errno.h>
|
11
|
+
|
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) {
|
24
|
+
VALUE self, watcher_id;
|
25
|
+
|
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
|
+
static void check_errors(int rc) {
|
36
|
+
switch (rc) {
|
37
|
+
case ZOK: /* all good! */ break;
|
38
|
+
case ZBADARGUMENTS: rb_raise(rb_eRuntimeError, "invalid input parameters");
|
39
|
+
case ZMARSHALLINGERROR: rb_raise(rb_eRuntimeError, "failed to marshall a request; possibly out of memory");
|
40
|
+
case ZOPERATIONTIMEOUT: rb_raise(rb_eRuntimeError, "failed to flush the buffers within the specified timeout");
|
41
|
+
case ZCONNECTIONLOSS: rb_raise(rb_eRuntimeError, "a network error occured while attempting to send request to server");
|
42
|
+
case ZSYSTEMERROR: rb_raise(rb_eRuntimeError, "a system (OS) error occured; it's worth checking errno to get details");
|
43
|
+
case ZNONODE: rb_raise(eNoNode, "the node does not exist");
|
44
|
+
case ZNOAUTH: rb_raise(rb_eRuntimeError, "the client does not have permission");
|
45
|
+
case ZBADVERSION: rb_raise(eBadVersion, "expected version does not match actual version");
|
46
|
+
case ZINVALIDSTATE: rb_raise(rb_eRuntimeError, "zhandle state is either SESSION_EXPIRED_STATE or AUTH_FAILED_STATE");
|
47
|
+
case ZNODEEXISTS: rb_raise(rb_eRuntimeError, "the node already exists");
|
48
|
+
case ZNOCHILDRENFOREPHEMERALS: rb_raise(rb_eRuntimeError, "cannot create children of ephemeral nodes");
|
49
|
+
case ZINVALIDACL: rb_raise(rb_eRuntimeError, "invalid ACL specified");
|
50
|
+
default: rb_raise(rb_eRuntimeError, "unknown error returned from zookeeper: %d", rc);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
static void free_zk_rb_data(struct zk_rb_data* ptr) {
|
55
|
+
/*fprintf(stderr, "free zk_rb_data at %p\n", ptr);*/
|
56
|
+
zookeeper_close(ptr->zh);
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE array_from_stat(const struct Stat* stat) {
|
60
|
+
return rb_ary_new3(8,
|
61
|
+
LL2NUM(stat->czxid),
|
62
|
+
LL2NUM(stat->mzxid),
|
63
|
+
LL2NUM(stat->ctime),
|
64
|
+
LL2NUM(stat->mtime),
|
65
|
+
INT2NUM(stat->version),
|
66
|
+
INT2NUM(stat->cversion),
|
67
|
+
INT2NUM(stat->aversion),
|
68
|
+
LL2NUM(stat->ephemeralOwner));
|
69
|
+
}
|
70
|
+
|
71
|
+
static VALUE method_initialize(VALUE self, VALUE hostPort) {
|
72
|
+
VALUE data;
|
73
|
+
struct zk_rb_data* zk = NULL;
|
74
|
+
|
75
|
+
Check_Type(hostPort, T_STRING);
|
76
|
+
|
77
|
+
data = Data_Make_Struct(ZooKeeper, struct zk_rb_data, 0, free_zk_rb_data, zk);
|
78
|
+
|
79
|
+
zoo_set_debug_level(ZOO_LOG_LEVEL_INFO);
|
80
|
+
zoo_deterministic_conn_order(0);
|
81
|
+
zk->zh = zookeeper_init(RSTRING(hostPort)->ptr, watcher, 10000, &zk->myid, (void*)self, 0);
|
82
|
+
if (!zk->zh) {
|
83
|
+
rb_raise(rb_eRuntimeError, "error connecting to zookeeper: %d", errno);
|
84
|
+
}
|
85
|
+
|
86
|
+
rb_iv_set(self, "@data", data);
|
87
|
+
|
88
|
+
return Qnil;
|
89
|
+
}
|
90
|
+
|
91
|
+
static VALUE method_ls(VALUE self, VALUE path) {
|
92
|
+
struct zk_rb_data* zk;
|
93
|
+
struct String_vector strings;
|
94
|
+
int i;
|
95
|
+
VALUE output;
|
96
|
+
|
97
|
+
Check_Type(path, T_STRING);
|
98
|
+
Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk);
|
99
|
+
|
100
|
+
check_errors(zoo_get_children(zk->zh, RSTRING(path)->ptr, 0, &strings));
|
101
|
+
|
102
|
+
output = rb_ary_new();
|
103
|
+
for (i = 0; i < strings.count; ++i) {
|
104
|
+
rb_ary_push(output, rb_str_new2(strings.data[i]));
|
105
|
+
}
|
106
|
+
return output;
|
107
|
+
}
|
108
|
+
|
109
|
+
static VALUE method_exists(VALUE self, VALUE path, VALUE watch) {
|
110
|
+
struct zk_rb_data* zk;
|
111
|
+
struct Stat stat;
|
112
|
+
|
113
|
+
Check_Type(path, T_STRING);
|
114
|
+
Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, 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
|
+
struct zk_rb_data* zk;
|
123
|
+
char realpath[10240];
|
124
|
+
|
125
|
+
Check_Type(path, T_STRING);
|
126
|
+
Check_Type(value, T_STRING);
|
127
|
+
Check_Type(flags, T_FIXNUM);
|
128
|
+
Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk);
|
129
|
+
|
130
|
+
check_errors(zoo_create(zk->zh, RSTRING(path)->ptr, RSTRING(value)->ptr, RSTRING(value)->len,
|
131
|
+
&ZOO_OPEN_ACL_UNSAFE, FIX2INT(flags), realpath, 10240));
|
132
|
+
|
133
|
+
return rb_str_new2(realpath);
|
134
|
+
}
|
135
|
+
|
136
|
+
static VALUE method_delete(VALUE self, VALUE path, VALUE version) {
|
137
|
+
struct zk_rb_data* zk;
|
138
|
+
|
139
|
+
Check_Type(path, T_STRING);
|
140
|
+
Check_Type(version, T_FIXNUM);
|
141
|
+
Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk);
|
142
|
+
|
143
|
+
check_errors(zoo_delete(zk->zh, RSTRING(path)->ptr, FIX2INT(version)));
|
144
|
+
|
145
|
+
return Qnil;
|
146
|
+
}
|
147
|
+
|
148
|
+
static VALUE method_get(VALUE self, VALUE path) {
|
149
|
+
struct zk_rb_data* zk;
|
150
|
+
char data[1024];
|
151
|
+
int data_len = 1024;
|
152
|
+
struct Stat stat;
|
153
|
+
|
154
|
+
Check_Type(path, T_STRING);
|
155
|
+
Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk);
|
156
|
+
|
157
|
+
check_errors(zoo_get(zk->zh, RSTRING(path)->ptr, 0, data, &data_len, &stat));
|
158
|
+
/*printf("got some data; version=%d\n", stat.version);*/
|
159
|
+
|
160
|
+
return rb_ary_new3(2,
|
161
|
+
rb_str_new(data, data_len),
|
162
|
+
array_from_stat(&stat));
|
163
|
+
}
|
164
|
+
|
165
|
+
|
166
|
+
static VALUE method_set(VALUE self, VALUE path, VALUE data, VALUE version) {
|
167
|
+
struct zk_rb_data* zk;
|
168
|
+
|
169
|
+
Check_Type(path, T_STRING);
|
170
|
+
Check_Type(data, T_STRING);
|
171
|
+
Check_Type(version, T_FIXNUM);
|
172
|
+
Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk);
|
173
|
+
|
174
|
+
check_errors(zoo_set(zk->zh, RSTRING(path)->ptr, RSTRING(data)->ptr, RSTRING(data)->len, FIX2INT(version)));
|
175
|
+
|
176
|
+
return Qnil;
|
177
|
+
}
|
178
|
+
|
179
|
+
static VALUE method_state(VALUE self) {
|
180
|
+
struct zk_rb_data* zk;
|
181
|
+
Data_Get_Struct(rb_iv_get(self, "@data"), struct zk_rb_data, zk);
|
182
|
+
return INT2NUM(zoo_state(zk->zh));
|
183
|
+
}
|
184
|
+
|
185
|
+
void Init_zookeeper_c() {
|
186
|
+
ZooKeeper = rb_define_class("CZooKeeper", rb_cObject);
|
187
|
+
rb_define_method(ZooKeeper, "initialize", method_initialize, 1);
|
188
|
+
rb_define_method(ZooKeeper, "ls", method_ls, 1);
|
189
|
+
rb_define_method(ZooKeeper, "exists", method_exists, 2);
|
190
|
+
rb_define_method(ZooKeeper, "create", method_create, 3);
|
191
|
+
rb_define_method(ZooKeeper, "delete", method_delete, 2);
|
192
|
+
rb_define_method(ZooKeeper, "get", method_get, 1);
|
193
|
+
rb_define_method(ZooKeeper, "set", method_set, 3);
|
194
|
+
rb_define_method(ZooKeeper, "state", method_state, 0);
|
195
|
+
|
196
|
+
eNoNode = rb_define_class_under(ZooKeeper, "NoNodeError", rb_eRuntimeError);
|
197
|
+
eBadVersion = rb_define_class_under(ZooKeeper, "BadVersionError", rb_eRuntimeError);
|
198
|
+
|
199
|
+
rb_define_const(ZooKeeper, "EPHEMERAL", INT2FIX(ZOO_EPHEMERAL));
|
200
|
+
rb_define_const(ZooKeeper, "SEQUENCE", INT2FIX(ZOO_SEQUENCE));
|
201
|
+
|
202
|
+
rb_define_const(ZooKeeper, "SESSION_EVENT", INT2FIX(ZOO_SESSION_EVENT));
|
203
|
+
rb_define_const(ZooKeeper, "CONNECTED_STATE", INT2FIX(ZOO_CONNECTED_STATE));
|
204
|
+
rb_define_const(ZooKeeper, "AUTH_FAILED_STATE", INT2FIX(ZOO_AUTH_FAILED_STATE));
|
205
|
+
rb_define_const(ZooKeeper, "EXPIRED_SESSION_STATE", INT2FIX(ZOO_EXPIRED_SESSION_STATE));
|
206
|
+
}
|
data/lib/zookeeper.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
if defined?(JRUBY_VERSION)
|
2
|
+
require 'zookeeper_j/zookeeper'
|
3
|
+
else
|
4
|
+
require 'zookeeper_c/zookeeper'
|
5
|
+
end
|
6
|
+
|
7
|
+
class ZooKeeper
|
8
|
+
DEFAULTS = {
|
9
|
+
:timeout => 10000
|
10
|
+
}
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'zookeeper/id'
|
15
|
+
require 'zookeeper/permission'
|
16
|
+
require 'zookeeper/acl'
|
17
|
+
require 'zookeeper/stat'
|
18
|
+
require 'zookeeper/keeper_exception'
|
19
|
+
require 'zookeeper/watcher_event'
|
20
|
+
require 'zookeeper/sync_primitive'
|
21
|
+
require 'zookeeper/queue'
|
22
|
+
require 'zookeeper/logging'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class ZooKeeper
|
2
|
+
class ACL
|
3
|
+
attr_reader :permissions, :id
|
4
|
+
|
5
|
+
def initialize(permissions, id)
|
6
|
+
@permissions, @id = permissions, id
|
7
|
+
end
|
8
|
+
|
9
|
+
def ==(obj)
|
10
|
+
self.permissions == obj.permissions &&
|
11
|
+
self.id == obj.id
|
12
|
+
end
|
13
|
+
|
14
|
+
OPEN_ACL_UNSAFE = [ACL.new(Permission::ALL, Id::ANYONE_ID_UNSAFE)]
|
15
|
+
READ_ACL_UNSAFE = [ACL.new(Permission::READ, Id::ANYONE_ID_UNSAFE)]
|
16
|
+
CREATOR_ALL_ACL = [ACL.new(Permission::ALL | Permission::ADMIN, Id::AUTH_IDS)]
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
data/lib/zookeeper/id.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class ZooKeeper
|
2
|
+
class Id
|
3
|
+
attr_reader :scheme, :identification
|
4
|
+
|
5
|
+
def initialize(scheme, id)
|
6
|
+
@scheme, @identification = scheme, id
|
7
|
+
end
|
8
|
+
|
9
|
+
def ==(obj)
|
10
|
+
self.scheme == obj.scheme &&
|
11
|
+
self.identification == obj.identification
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
ANYONE_ID_UNSAFE = Id.new("world", "anyone")
|
16
|
+
AUTH_IDS = Id.new("auth", "")
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class KeeperException < Exception
|
2
|
+
|
3
|
+
OK = 0
|
4
|
+
# System and server-side errors
|
5
|
+
SYSTEMERROR = -1
|
6
|
+
RUNTIMEINCONSISTENCY = SYSTEMERROR - 1
|
7
|
+
DATAINCONSISTENCY = SYSTEMERROR - 2
|
8
|
+
CONNECTIONLOSS = SYSTEMERROR - 3
|
9
|
+
MARSHALLINGERROR = SYSTEMERROR - 4
|
10
|
+
UNIMPLEMENTED = SYSTEMERROR - 5
|
11
|
+
OPERATIONTIMEOUT = SYSTEMERROR - 6
|
12
|
+
BADARGUMENTS = SYSTEMERROR - 7
|
13
|
+
# API errors
|
14
|
+
APIERROR = -100;
|
15
|
+
NONODE = APIERROR - 1 # Node does not exist
|
16
|
+
NOAUTH = APIERROR - 2 # Current operation not permitted
|
17
|
+
BADVERSION = APIERROR - 3 # Version conflict
|
18
|
+
NOCHILDRENFOREPHEMERALS = APIERROR - 8
|
19
|
+
NODEEXISTS = APIERROR - 10
|
20
|
+
NOTEMPTY = APIERROR - 11
|
21
|
+
SESSIONEXPIRED = APIERROR - 12
|
22
|
+
INVALIDCALLBACK = APIERROR - 13
|
23
|
+
INVALIDACL = APIERROR - 14
|
24
|
+
AUTHFAILED = APIERROR - 15 # client authentication failed
|
25
|
+
|
26
|
+
class SystemError < KeeperException; end
|
27
|
+
class RunTimeInconsistency < KeeperException; end
|
28
|
+
class DataInconsistency < KeeperException; end
|
29
|
+
class ConnectionLoss < KeeperException; end
|
30
|
+
class MarshallingError < KeeperException; end
|
31
|
+
class Unimplemented < KeeperException; end
|
32
|
+
class OperationTimeOut < KeeperException; end
|
33
|
+
class BadArguments < KeeperException; end
|
34
|
+
class ApiError < KeeperException; end
|
35
|
+
class NoNode < KeeperException; end
|
36
|
+
class NoAuth < KeeperException; end
|
37
|
+
class BadVersion < KeeperException; end
|
38
|
+
class NoChildrenForEphemerals < KeeperException; end
|
39
|
+
class NodeExists < KeeperException; end
|
40
|
+
class NotEmpty < KeeperException; end
|
41
|
+
class SessionExpired < KeeperException; end
|
42
|
+
class InvalidCallback < KeeperException; end
|
43
|
+
class InvalidACL < KeeperException; end
|
44
|
+
class AuthFailed < KeeperException; end
|
45
|
+
|
46
|
+
def self.by_code(code)
|
47
|
+
case code
|
48
|
+
when OK: Ok
|
49
|
+
when SYSTEMERROR: SystemError
|
50
|
+
when RUNTIMEINCONSISTENCY: RunTimeInconsistency
|
51
|
+
when DATAINCONSISTENCY: DataInconsistency
|
52
|
+
when CONNECTIONLOSS: ConnectionLoss
|
53
|
+
when MARSHALLINGERROR: MarshallingError
|
54
|
+
when UNIMPLEMENTED: Unimplemented
|
55
|
+
when OPERATIONTIMEOUT: OperationTimeOut
|
56
|
+
when BADARGUMENTS: BadArguments
|
57
|
+
when APIERROR: ApiError
|
58
|
+
when NONODE: NoNode
|
59
|
+
when NOAUTH: NoAuth
|
60
|
+
when BADVERSION: BadVersion
|
61
|
+
when NOCHILDRENFOREPHEMERALS: NoChildrenForEphemerals
|
62
|
+
when NODEEXISTS: NodeExists
|
63
|
+
when NOTEMPTY: NotEmpty
|
64
|
+
when SESSIONEXPIRED: SessionExpired
|
65
|
+
when INVALIDCALLBACK: InvalidCallback
|
66
|
+
when INVALIDACL: InvalidACL
|
67
|
+
when AUTHFAILED: AuthFailed
|
68
|
+
else Exception.new("no exception defined for code #{code}")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class ZooKeeper
|
2
|
+
|
3
|
+
class Queue < SyncPrimitive
|
4
|
+
|
5
|
+
def initialize(address, name)
|
6
|
+
super(address)
|
7
|
+
until @@zk.connected? do; end
|
8
|
+
@root = name
|
9
|
+
if @@zk && @@zk.exists(@root).nil?
|
10
|
+
@@zk.create(:path => @root, :data => "")
|
11
|
+
end
|
12
|
+
rescue Exception => e
|
13
|
+
$LOG.error "Exception instantiating queue #{e.message}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def produce(data)
|
17
|
+
@@zk.create(:path => "#{@root}/element", :data => data, :sequence => true) and return true
|
18
|
+
end
|
19
|
+
|
20
|
+
def consume
|
21
|
+
@@monitor.synchronize do
|
22
|
+
loop do
|
23
|
+
list = @@zk.children(:path => @root, :watch => true)
|
24
|
+
|
25
|
+
if list.empty?
|
26
|
+
$LOG.info 'Queue empty, going to wait'
|
27
|
+
@@consume.wait
|
28
|
+
else
|
29
|
+
minimum_node = list.inject {|e1, e2| e2.delete("element").to_i < e1.delete("element").to_i ? e2 : e1 }
|
30
|
+
data, stat = @@zk.get("#{@root}/#{minimum_node}")
|
31
|
+
@@zk.delete(:path => "#{@root}/#{minimum_node}", :version => 0)
|
32
|
+
return data
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def empty?
|
39
|
+
@@zk.children(:path => @root).empty?
|
40
|
+
end
|
41
|
+
|
42
|
+
def stop
|
43
|
+
@@zk.close
|
44
|
+
@@zk = nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def stopped?
|
48
|
+
@@zk.nil?
|
49
|
+
end
|
50
|
+
|
51
|
+
def active?
|
52
|
+
@@zk.connected?
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class ZooKeeper
|
2
|
+
class Stat
|
3
|
+
attr_reader :created_zxid, :last_modified_zxid, :created_time, :last_modified_time, :version, :child_list_version,
|
4
|
+
:acl_list_version, :ephemeral_owner
|
5
|
+
|
6
|
+
def initialize(attributes)
|
7
|
+
@created_zxid, @last_modified_zxid, @created_time, @last_modified_time, @version,
|
8
|
+
@child_list_version, @acl_list_version, @ephemeral_owner = attributes
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
|
3
|
+
class ZooKeeper
|
4
|
+
|
5
|
+
class SyncPrimitive
|
6
|
+
|
7
|
+
@@zk =nil
|
8
|
+
@@monitor = nil
|
9
|
+
@@consume = nil
|
10
|
+
|
11
|
+
attr_accessor :root
|
12
|
+
|
13
|
+
def initialize(address)
|
14
|
+
unless @@zk
|
15
|
+
$LOG.info 'Connecting Zookeeper Client'
|
16
|
+
@@zk = ZooKeeper.new(:host => address, :timeout => 10000, :watcher => self)
|
17
|
+
@@monitor = Monitor.new
|
18
|
+
@@consume = @@monitor.new_cond
|
19
|
+
$LOG.info 'Zookeeper Client Started'
|
20
|
+
end
|
21
|
+
rescue Exception => e
|
22
|
+
$LOG.error "Exception connecting Zookeeper to #{address} #{e.message}"
|
23
|
+
@@zk = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def process(event)
|
27
|
+
@@monitor.synchronize { @@consume.signal }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class ZooKeeper
|
2
|
+
class WatcherEvent
|
3
|
+
attr_reader :type, :state, :path
|
4
|
+
|
5
|
+
def initialize(type, state, path)
|
6
|
+
@type, @state, @path = type, state, path
|
7
|
+
end
|
8
|
+
|
9
|
+
# constants for connection states
|
10
|
+
KeeperStateChanged = 0
|
11
|
+
KeeperStateUnknown = -1
|
12
|
+
KeeperStateDisconnected = 0
|
13
|
+
KeeperStateNoSyncConnected = 1
|
14
|
+
KeeperStateSyncConnected = 3
|
15
|
+
KeeperStateExpired = -112
|
16
|
+
|
17
|
+
# constants for event types
|
18
|
+
EventNone = -1
|
19
|
+
EventNodeCreated = 1
|
20
|
+
EventNodeDeleted = 2
|
21
|
+
EventNodeDataChanged = 3
|
22
|
+
EventNodeChildrenChanged = 4
|
23
|
+
end
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: carlosnz-zookeeper
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.2"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shane Mingins
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-06-13 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: A Ruby client interface to the Java ZooKeeper server.
|
17
|
+
email: smingins@elctech.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions:
|
21
|
+
- ext/zookeeper_c/extconf.rb
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- lib/zookeeper.rb
|
27
|
+
- lib/zookeeper/acl.rb
|
28
|
+
- lib/zookeeper/id.rb
|
29
|
+
- lib/zookeeper/keeper_exception.rb
|
30
|
+
- lib/zookeeper/logging.rb
|
31
|
+
- lib/zookeeper/permission.rb
|
32
|
+
- lib/zookeeper/stat.rb
|
33
|
+
- lib/zookeeper/watcher_event.rb
|
34
|
+
- lib/zookeeper/sync_primitive.rb
|
35
|
+
- lib/zookeeper/queue.rb
|
36
|
+
- ext/zookeeper_c/zookeeper_ruby.c
|
37
|
+
- ext/zookeeper_c/zookeeper.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage:
|
40
|
+
licenses:
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options:
|
43
|
+
- --line-numbers
|
44
|
+
- --inline-source
|
45
|
+
- --title
|
46
|
+
- ZooKeeper
|
47
|
+
- --main
|
48
|
+
- README
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
- ext
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: "0"
|
57
|
+
version:
|
58
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: "0"
|
63
|
+
version:
|
64
|
+
requirements: []
|
65
|
+
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 1.3.5
|
68
|
+
signing_key:
|
69
|
+
specification_version: 2
|
70
|
+
summary: A Ruby client interface to the Java ZooKeeper server.
|
71
|
+
test_files: []
|
72
|
+
|