zookeeper 0.4.4 → 0.9.3
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/.gitignore +10 -0
- data/CHANGELOG +95 -0
- data/Gemfile +17 -0
- data/Manifest +8 -2
- data/README.markdown +59 -0
- data/Rakefile +137 -7
- data/ext/.gitignore +6 -0
- data/ext/Rakefile +51 -0
- data/ext/c_zookeeper.rb +212 -0
- data/ext/dbg.h +53 -0
- data/ext/depend +5 -0
- data/ext/extconf.rb +44 -15
- data/ext/generate_gvl_code.rb +316 -0
- data/ext/zkc-3.3.5.tar.gz +0 -0
- data/ext/zkrb_wrapper.c +731 -0
- data/ext/zkrb_wrapper.h +330 -0
- data/ext/zkrb_wrapper_compat.c +15 -0
- data/ext/zkrb_wrapper_compat.h +11 -0
- data/ext/zookeeper_base.rb +211 -0
- data/ext/zookeeper_c.c +268 -97
- data/ext/zookeeper_lib.c +157 -92
- data/ext/zookeeper_lib.h +12 -6
- data/java/zookeeper_base.rb +477 -0
- data/lib/zookeeper/acls.rb +10 -1
- data/lib/zookeeper/callbacks.rb +5 -3
- data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
- data/lib/zookeeper/common.rb +174 -0
- data/lib/zookeeper/constants.rb +31 -28
- data/lib/zookeeper/em_client.rb +55 -0
- data/lib/zookeeper/exceptions.rb +10 -2
- data/lib/zookeeper/stat.rb +11 -2
- data/lib/zookeeper/version.rb +6 -0
- data/lib/zookeeper.rb +155 -122
- data/notes.txt +14 -0
- data/spec/c_zookeeper_spec.rb +50 -0
- data/spec/chrooted_connection_spec.rb +81 -0
- data/spec/default_watcher_spec.rb +41 -0
- data/spec/em_spec.rb +51 -0
- data/spec/log4j.properties +17 -0
- data/spec/shared/all_success_return_values.rb +10 -0
- data/spec/shared/connection_examples.rb +1018 -0
- data/spec/spec_helper.rb +119 -0
- data/spec/support/progress_formatter.rb +15 -0
- data/spec/zookeeper_spec.rb +24 -0
- data/zookeeper.gemspec +37 -25
- metadata +78 -34
- data/README +0 -42
- data/ext/zkc-3.3.2.tar.gz +0 -0
@@ -0,0 +1,477 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'thread'
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
gem 'slyphon-log4j', '= 1.2.15'
|
6
|
+
gem 'slyphon-zookeeper_jar', '= 3.3.5'
|
7
|
+
|
8
|
+
require 'log4j'
|
9
|
+
require 'zookeeper_jar'
|
10
|
+
|
11
|
+
# The low-level wrapper-specific methods for the Java lib,
|
12
|
+
# subclassed by the top-level Zookeeper class
|
13
|
+
class ZookeeperBase
|
14
|
+
include Java
|
15
|
+
include ZookeeperCommon
|
16
|
+
include ZookeeperConstants
|
17
|
+
include ZookeeperCallbacks
|
18
|
+
include ZookeeperExceptions
|
19
|
+
include ZookeeperACLs
|
20
|
+
include ZookeeperStat
|
21
|
+
|
22
|
+
JZK = org.apache.zookeeper
|
23
|
+
JZKD = org.apache.zookeeper.data
|
24
|
+
Code = JZK::KeeperException::Code
|
25
|
+
|
26
|
+
ANY_VERSION = -1
|
27
|
+
DEFAULT_SESSION_TIMEOUT = 10_000
|
28
|
+
|
29
|
+
ZKRB_GLOBAL_CB_REQ = -1 unless defined?(ZKRB_GLOBAL_CB_REQ)
|
30
|
+
|
31
|
+
JZKD::Stat.class_eval do
|
32
|
+
MEMBERS = [:version, :czxid, :mzxid, :ctime, :mtime, :cversion, :aversion, :ephemeralOwner, :dataLength, :numChildren, :pzxid]
|
33
|
+
def to_hash
|
34
|
+
MEMBERS.inject({}) { |h,k| h[k] = __send__(k); h }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
JZKD::Id.class_eval do
|
39
|
+
def to_hash
|
40
|
+
{ :scheme => getScheme, :id => getId }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
JZKD::ACL.class_eval do
|
45
|
+
def self.from_ruby_acl(acl)
|
46
|
+
raise TypeError, "acl must be a ZookeeperACLs::ACL not #{acl.inspect}" unless acl.kind_of?(ZookeeperACLs::ACL)
|
47
|
+
id = org.apache.zookeeper.data.Id.new(acl.id.scheme.to_s, acl.id.id.to_s)
|
48
|
+
new(acl.perms.to_i, id)
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_hash
|
52
|
+
{ :perms => getPerms, :id => getId.to_hash }
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
JZK::WatchedEvent.class_eval do
|
57
|
+
def to_hash
|
58
|
+
{ :type => getType.getIntValue, :state => getState.getIntValue, :path => getPath }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# used for internal dispatching
|
63
|
+
module JavaCB #:nodoc:
|
64
|
+
class Callback
|
65
|
+
attr_reader :req_id
|
66
|
+
|
67
|
+
def initialize(req_id)
|
68
|
+
@req_id = req_id
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
def logger
|
73
|
+
Zookeeper.logger
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class DataCallback < Callback
|
78
|
+
include JZK::AsyncCallback::DataCallback
|
79
|
+
|
80
|
+
def processResult(rc, path, queue, data, stat)
|
81
|
+
logger.debug { "#{self.class.name}#processResult rc: #{rc}, req_id: #{req_id}, path: #{path}, queue: #{queue.inspect}, data: #{data.inspect}, stat: #{stat.inspect}" }
|
82
|
+
|
83
|
+
hash = {
|
84
|
+
:rc => rc,
|
85
|
+
:req_id => req_id,
|
86
|
+
:path => path,
|
87
|
+
:data => (data && String.from_java_bytes(data)),
|
88
|
+
:stat => (stat && stat.to_hash),
|
89
|
+
}
|
90
|
+
|
91
|
+
# if rc == Zookeeper::ZOK
|
92
|
+
# hash.merge!({
|
93
|
+
# :data => String.from_java_bytes(data),
|
94
|
+
# :stat => stat.to_hash,
|
95
|
+
# })
|
96
|
+
# end
|
97
|
+
|
98
|
+
queue.push(hash)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
class StringCallback < Callback
|
103
|
+
include JZK::AsyncCallback::StringCallback
|
104
|
+
|
105
|
+
def processResult(rc, path, queue, str)
|
106
|
+
logger.debug { "#{self.class.name}#processResult rc: #{rc}, req_id: #{req_id}, path: #{path}, queue: #{queue.inspect}, str: #{str.inspect}" }
|
107
|
+
queue.push(:rc => rc, :req_id => req_id, :path => path, :string => str)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class StatCallback < Callback
|
112
|
+
include JZK::AsyncCallback::StatCallback
|
113
|
+
|
114
|
+
def processResult(rc, path, queue, stat)
|
115
|
+
logger.debug { "#{self.class.name}#processResult rc: #{rc.inspect}, req_id: #{req_id}, path: #{path.inspect}, queue: #{queue.inspect}, stat: #{stat.inspect}" }
|
116
|
+
queue.push(:rc => rc, :req_id => req_id, :stat => (stat and stat.to_hash), :path => path)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
class Children2Callback < Callback
|
121
|
+
include JZK::AsyncCallback::Children2Callback
|
122
|
+
|
123
|
+
def processResult(rc, path, queue, children, stat)
|
124
|
+
logger.debug { "#{self.class.name}#processResult rc: #{rc}, req_id: #{req_id}, path: #{path}, queue: #{queue.inspect}, children: #{children.inspect}, stat: #{stat.inspect}" }
|
125
|
+
hash = {
|
126
|
+
:rc => rc,
|
127
|
+
:req_id => req_id,
|
128
|
+
:path => path,
|
129
|
+
:strings => (children && children.to_a),
|
130
|
+
:stat => (stat and stat.to_hash),
|
131
|
+
}
|
132
|
+
|
133
|
+
queue.push(hash)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
class ACLCallback < Callback
|
138
|
+
include JZK::AsyncCallback::ACLCallback
|
139
|
+
|
140
|
+
def processResult(rc, path, queue, acl, stat)
|
141
|
+
logger.debug { "ACLCallback#processResult rc: #{rc.inspect}, req_id: #{req_id}, path: #{path.inspect}, queue: #{queue.inspect}, acl: #{acl.inspect}, stat: #{stat.inspect}" }
|
142
|
+
a = Array(acl).map { |a| a.to_hash }
|
143
|
+
queue.push(:rc => rc, :req_id => req_id, :path => path, :acl => a, :stat => (stat && stat.to_hash))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class VoidCallback < Callback
|
148
|
+
include JZK::AsyncCallback::VoidCallback
|
149
|
+
|
150
|
+
def processResult(rc, path, queue)
|
151
|
+
logger.debug { "#{self.class.name}#processResult rc: #{rc}, req_id: #{req_id}, queue: #{queue.inspect}" }
|
152
|
+
queue.push(:rc => rc, :req_id => req_id, :path => path)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
class WatcherCallback < Callback
|
157
|
+
include JZK::Watcher
|
158
|
+
|
159
|
+
def initialize(event_queue)
|
160
|
+
@event_queue = event_queue
|
161
|
+
super(ZookeeperBase::ZKRB_GLOBAL_CB_REQ)
|
162
|
+
end
|
163
|
+
|
164
|
+
def process(event)
|
165
|
+
logger.debug { "WatcherCallback got event: #{event.to_hash.inspect}" }
|
166
|
+
hash = event.to_hash.merge(:req_id => req_id)
|
167
|
+
@event_queue.push(hash)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
attr_reader :event_queue
|
173
|
+
|
174
|
+
def reopen(timeout=10, watcher=nil)
|
175
|
+
# watcher ||= @default_watcher
|
176
|
+
|
177
|
+
@mutex.synchronize do
|
178
|
+
# flushes all outstanding watcher reqs.
|
179
|
+
@watcher_reqs.clear
|
180
|
+
set_default_global_watcher
|
181
|
+
|
182
|
+
replace_jzk!
|
183
|
+
wait_until_connected
|
184
|
+
end
|
185
|
+
|
186
|
+
state
|
187
|
+
end
|
188
|
+
|
189
|
+
def wait_until_connected(timeout=10)
|
190
|
+
time_to_stop = timeout ? (Time.now + timeout) : nil
|
191
|
+
|
192
|
+
until connected? or (time_to_stop and Time.now > time_to_stop)
|
193
|
+
Thread.pass
|
194
|
+
end
|
195
|
+
|
196
|
+
connected?
|
197
|
+
end
|
198
|
+
|
199
|
+
def initialize(host, timeout=10, watcher=nil, options={})
|
200
|
+
@host = host
|
201
|
+
@event_queue = QueueWithPipe.new
|
202
|
+
@current_req_id = 0
|
203
|
+
|
204
|
+
@mutex = Monitor.new
|
205
|
+
@dispatch_shutdown_cond = @mutex.new_cond
|
206
|
+
|
207
|
+
@watcher_reqs = {}
|
208
|
+
@completion_reqs = {}
|
209
|
+
@_running = nil
|
210
|
+
@_closed = false
|
211
|
+
@options = {}
|
212
|
+
|
213
|
+
@default_watcher = (watcher || get_default_global_watcher)
|
214
|
+
|
215
|
+
# allows connected-state handlers to be registered before
|
216
|
+
yield self if block_given?
|
217
|
+
|
218
|
+
reopen(timeout)
|
219
|
+
return nil unless connected?
|
220
|
+
@_running = true
|
221
|
+
setup_dispatch_thread!
|
222
|
+
end
|
223
|
+
|
224
|
+
def close
|
225
|
+
shutdown_thread = Thread.new do
|
226
|
+
@mutex.synchronize do
|
227
|
+
unless @_closed
|
228
|
+
@_closed = true # these are probably unnecessary
|
229
|
+
@_running = false
|
230
|
+
|
231
|
+
stop_dispatch_thread!
|
232
|
+
@jzk.close if @jzk
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
shutdown_thread.join unless event_dispatch_thread?
|
238
|
+
end
|
239
|
+
|
240
|
+
def state
|
241
|
+
@mutex.synchronize { @jzk.state }
|
242
|
+
end
|
243
|
+
|
244
|
+
def connected?
|
245
|
+
state == JZK::ZooKeeper::States::CONNECTED
|
246
|
+
end
|
247
|
+
|
248
|
+
def connecting?
|
249
|
+
state == JZK::ZooKeeper::States::CONNECTING
|
250
|
+
end
|
251
|
+
|
252
|
+
def associating?
|
253
|
+
state == JZK::ZooKeeper::States::ASSOCIATING
|
254
|
+
end
|
255
|
+
|
256
|
+
def running?
|
257
|
+
@_running
|
258
|
+
end
|
259
|
+
|
260
|
+
def closed?
|
261
|
+
@_closed
|
262
|
+
end
|
263
|
+
|
264
|
+
def self.set_debug_level(*a)
|
265
|
+
# IGNORED IN JRUBY
|
266
|
+
end
|
267
|
+
|
268
|
+
def set_debug_level(*a)
|
269
|
+
# IGNORED IN JRUBY
|
270
|
+
end
|
271
|
+
|
272
|
+
def get(req_id, path, callback, watcher)
|
273
|
+
handle_keeper_exception do
|
274
|
+
watch_cb = watcher ? create_watcher(req_id, path) : false
|
275
|
+
|
276
|
+
if callback
|
277
|
+
jzk.getData(path, watch_cb, JavaCB::DataCallback.new(req_id), event_queue)
|
278
|
+
[Code::Ok, nil, nil] # the 'nil, nil' isn't strictly necessary here
|
279
|
+
else # sync
|
280
|
+
stat = JZKD::Stat.new
|
281
|
+
data = String.from_java_bytes(jzk.getData(path, watch_cb, stat))
|
282
|
+
|
283
|
+
[Code::Ok, data, stat.to_hash]
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
def set(req_id, path, data, callback, version)
|
289
|
+
handle_keeper_exception do
|
290
|
+
version ||= ANY_VERSION
|
291
|
+
|
292
|
+
if callback
|
293
|
+
jzk.setData(path, data.to_java_bytes, version, JavaCB::StatCallback.new(req_id), event_queue)
|
294
|
+
[Code::Ok, nil]
|
295
|
+
else
|
296
|
+
stat = jzk.setData(path, data.to_java_bytes, version).to_hash
|
297
|
+
[Code::Ok, stat]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
def get_children(req_id, path, callback, watcher)
|
303
|
+
handle_keeper_exception do
|
304
|
+
watch_cb = watcher ? create_watcher(req_id, path) : false
|
305
|
+
|
306
|
+
if callback
|
307
|
+
jzk.getChildren(path, watch_cb, JavaCB::Children2Callback.new(req_id), event_queue)
|
308
|
+
[Code::Ok, nil, nil]
|
309
|
+
else
|
310
|
+
stat = JZKD::Stat.new
|
311
|
+
children = jzk.getChildren(path, watch_cb, stat)
|
312
|
+
[Code::Ok, children.to_a, stat.to_hash]
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def create(req_id, path, data, callback, acl, flags)
|
318
|
+
handle_keeper_exception do
|
319
|
+
acl = Array(acl).map{ |a| JZKD::ACL.from_ruby_acl(a) }
|
320
|
+
mode = JZK::CreateMode.fromFlag(flags)
|
321
|
+
|
322
|
+
data ||= ''
|
323
|
+
|
324
|
+
if callback
|
325
|
+
jzk.create(path, data.to_java_bytes, acl, mode, JavaCB::StringCallback.new(req_id), event_queue)
|
326
|
+
[Code::Ok, nil]
|
327
|
+
else
|
328
|
+
new_path = jzk.create(path, data.to_java_bytes, acl, mode)
|
329
|
+
[Code::Ok, new_path]
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def sync(req_id, path)
|
335
|
+
handle_keeper_exception do
|
336
|
+
jzk.sync(path, JavaCB::VoidCallback.new(req_id), event_queue)
|
337
|
+
Code::Ok
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
def delete(req_id, path, version, callback)
|
342
|
+
handle_keeper_exception do
|
343
|
+
if callback
|
344
|
+
jzk.delete(path, version, JavaCB::VoidCallback.new(req_id), event_queue)
|
345
|
+
else
|
346
|
+
jzk.delete(path, version)
|
347
|
+
end
|
348
|
+
|
349
|
+
Code::Ok
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
def set_acl(req_id, path, acl, callback, version)
|
354
|
+
handle_keeper_exception do
|
355
|
+
logger.debug { "set_acl: acl #{acl.inspect}" }
|
356
|
+
acl = Array(acl).flatten.map { |a| JZKD::ACL.from_ruby_acl(a) }
|
357
|
+
logger.debug { "set_acl: converted #{acl.inspect}" }
|
358
|
+
|
359
|
+
if callback
|
360
|
+
jzk.setACL(path, acl, version, JavaCB::ACLCallback.new(req_id), event_queue)
|
361
|
+
else
|
362
|
+
jzk.setACL(path, acl, version)
|
363
|
+
end
|
364
|
+
|
365
|
+
Code::Ok
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
def exists(req_id, path, callback, watcher)
|
370
|
+
handle_keeper_exception do
|
371
|
+
watch_cb = watcher ? create_watcher(req_id, path) : false
|
372
|
+
|
373
|
+
if callback
|
374
|
+
jzk.exists(path, watch_cb, JavaCB::StatCallback.new(req_id), event_queue)
|
375
|
+
[Code::Ok, nil, nil]
|
376
|
+
else
|
377
|
+
stat = jzk.exists(path, watch_cb)
|
378
|
+
[Code::Ok, (stat and stat.to_hash)]
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
def get_acl(req_id, path, callback)
|
384
|
+
handle_keeper_exception do
|
385
|
+
stat = JZKD::Stat.new
|
386
|
+
|
387
|
+
if callback
|
388
|
+
logger.debug { "calling getACL, path: #{path.inspect}, stat: #{stat.inspect}" }
|
389
|
+
jzk.getACL(path, stat, JavaCB::ACLCallback.new(req_id), event_queue)
|
390
|
+
[Code::Ok, nil, nil]
|
391
|
+
else
|
392
|
+
acls = jzk.getACL(path, stat).map { |a| a.to_hash }
|
393
|
+
|
394
|
+
[Code::Ok, Array(acls).map{|m| m.to_hash}, stat.to_hash]
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
def assert_open
|
400
|
+
# XXX don't know how to check for valid session state!
|
401
|
+
raise ZookeeperException::NotConnected unless connected?
|
402
|
+
end
|
403
|
+
|
404
|
+
# set the watcher object/proc that will receive all global events (such as session/state events)
|
405
|
+
#---
|
406
|
+
# XXX: this code needs to be duplicated from ext/zookeeper_base.rb because
|
407
|
+
# it's called from the initializer, and because of the C impl. we can't have
|
408
|
+
# the two decend from a common base, and a module wouldn't work
|
409
|
+
def set_default_global_watcher
|
410
|
+
@mutex.synchronize do
|
411
|
+
@watcher_reqs[ZKRB_GLOBAL_CB_REQ] = { :watcher => @default_watcher, :watcher_context => nil }
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
def session_id
|
416
|
+
jzk.session_id
|
417
|
+
end
|
418
|
+
|
419
|
+
def session_passwd
|
420
|
+
jzk.session_passwd.to_s
|
421
|
+
end
|
422
|
+
|
423
|
+
protected
|
424
|
+
def jzk
|
425
|
+
@mutex.synchronize { @jzk }
|
426
|
+
end
|
427
|
+
|
428
|
+
def handle_keeper_exception
|
429
|
+
yield
|
430
|
+
rescue JZK::KeeperException => e
|
431
|
+
e.cause.code.intValue
|
432
|
+
end
|
433
|
+
|
434
|
+
def call_type(callback, watcher)
|
435
|
+
if callback
|
436
|
+
watcher ? :async_watch : :async
|
437
|
+
else
|
438
|
+
watcher ? :sync_watch : :sync
|
439
|
+
end
|
440
|
+
end
|
441
|
+
|
442
|
+
def create_watcher(req_id, path)
|
443
|
+
logger.debug { "creating watcher for req_id: #{req_id} path: #{path}" }
|
444
|
+
lambda do |event|
|
445
|
+
logger.debug { "watcher for req_id #{req_id}, path: #{path} called back" }
|
446
|
+
h = { :req_id => req_id, :type => event.type.int_value, :state => event.state.int_value, :path => path }
|
447
|
+
event_queue.push(h)
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
# method to wait until block passed returns true or timeout (default is 10 seconds) is reached
|
452
|
+
def wait_until(timeout=10, &block)
|
453
|
+
time_to_stop = Time.now + timeout
|
454
|
+
until yield do
|
455
|
+
break if Time.now > time_to_stop
|
456
|
+
sleep 0.1
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
# TODO: Make all global puts configurable
|
461
|
+
def get_default_global_watcher
|
462
|
+
Proc.new { |args|
|
463
|
+
logger.debug { "Ruby ZK Global CB called type=#{event_by_value(args[:type])} state=#{state_by_value(args[:state])}" }
|
464
|
+
true
|
465
|
+
}
|
466
|
+
end
|
467
|
+
|
468
|
+
private
|
469
|
+
def replace_jzk!
|
470
|
+
orig_jzk = @jzk
|
471
|
+
@jzk = JZK::ZooKeeper.new(@host, DEFAULT_SESSION_TIMEOUT, JavaCB::WatcherCallback.new(event_queue))
|
472
|
+
ensure
|
473
|
+
orig_jzk.close if orig_jzk
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
|
data/lib/zookeeper/acls.rb
CHANGED
@@ -5,13 +5,22 @@ module ZookeeperACLs
|
|
5
5
|
@scheme = hash[:scheme]
|
6
6
|
@id = hash[:id]
|
7
7
|
end
|
8
|
+
|
9
|
+
def to_hash
|
10
|
+
{ :id => id, :scheme => scheme }
|
11
|
+
end
|
8
12
|
end
|
9
13
|
|
10
14
|
class ACL
|
11
15
|
attr_reader :perms, :id
|
12
16
|
def initialize(hash)
|
13
17
|
@perms = hash[:perms]
|
14
|
-
|
18
|
+
v = hash[:id]
|
19
|
+
@id = v.kind_of?(Hash) ? Id.new(v) : v
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_hash
|
23
|
+
{ :perms => perms, :id => id.to_hash }
|
15
24
|
end
|
16
25
|
end
|
17
26
|
|
data/lib/zookeeper/callbacks.rb
CHANGED
@@ -45,10 +45,12 @@ module ZookeeperCallbacks
|
|
45
45
|
|
46
46
|
class StringCallback < Callback
|
47
47
|
## acreate, async
|
48
|
-
attr_reader :return_code, :
|
48
|
+
attr_reader :return_code, :string, :context
|
49
|
+
|
50
|
+
alias path string
|
49
51
|
|
50
52
|
def initialize_context(hash)
|
51
|
-
@return_code, @
|
53
|
+
@return_code, @string, @context = hash[:rc], hash[:string], hash[:context]
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
@@ -57,7 +59,7 @@ module ZookeeperCallbacks
|
|
57
59
|
attr_reader :return_code, :children, :stat
|
58
60
|
|
59
61
|
def initialize_context(hash)
|
60
|
-
@return_code, @children, @stat, @context = hash[:rc], hash[:
|
62
|
+
@return_code, @children, @stat, @context = hash[:rc], hash[:strings], hash[:stat], hash[:context]
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module ZookeeperCommon
|
2
|
+
# Ceci n'est pas une pipe
|
3
|
+
class QueueWithPipe
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
def_delegators :@queue, :clear
|
7
|
+
|
8
|
+
# raised when close has been called, and pop() is performed
|
9
|
+
#
|
10
|
+
class ShutdownException < StandardError; end
|
11
|
+
|
12
|
+
# @private
|
13
|
+
KILL_TOKEN = Object.new unless defined?(KILL_TOKEN)
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
# r, w = IO.pipe
|
17
|
+
# @pipe = { :read => r, :write => w }
|
18
|
+
@queue = Queue.new
|
19
|
+
|
20
|
+
# with the EventMachine client, we want to let EM handle clearing the
|
21
|
+
# event pipe, so we set this to false
|
22
|
+
# @clear_reads_on_pop = true
|
23
|
+
|
24
|
+
@mutex = Mutex.new
|
25
|
+
@closed = false
|
26
|
+
@graceful = false
|
27
|
+
end
|
28
|
+
|
29
|
+
def push(obj)
|
30
|
+
logger.debug { "#{self.class}##{__method__} obj: #{obj.inspect}, kill_token? #{obj == KILL_TOKEN}" }
|
31
|
+
@queue.push(obj)
|
32
|
+
end
|
33
|
+
|
34
|
+
def pop(non_blocking=false)
|
35
|
+
raise ShutdownException if closed? # this may get us in trouble
|
36
|
+
|
37
|
+
rv = @queue.pop(non_blocking)
|
38
|
+
|
39
|
+
if rv == KILL_TOKEN
|
40
|
+
close
|
41
|
+
raise ShutdownException
|
42
|
+
end
|
43
|
+
|
44
|
+
rv
|
45
|
+
end
|
46
|
+
|
47
|
+
# close the queue and causes ShutdownException to be raised on waiting threads
|
48
|
+
def graceful_close!
|
49
|
+
@mutex.synchronize do
|
50
|
+
return if @graceful or @closed
|
51
|
+
logger.debug { "#{self.class}##{__method__} gracefully closing" }
|
52
|
+
@graceful = true
|
53
|
+
push(KILL_TOKEN)
|
54
|
+
end
|
55
|
+
nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def close
|
59
|
+
@mutex.synchronize do
|
60
|
+
return if @closed
|
61
|
+
@closed = true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def closed?
|
66
|
+
@mutex.synchronize { !!@closed }
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
def clear_reads_on_pop?
|
71
|
+
@clear_reads_on_pop
|
72
|
+
end
|
73
|
+
|
74
|
+
def logger
|
75
|
+
Zookeeper.logger
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|