zookeeper 1.2.14 → 1.3.0
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/CHANGELOG +7 -0
- data/ext/zookeeper_base.rb +13 -56
- data/java/java_base.rb +5 -20
- data/lib/zookeeper.rb +1 -0
- data/lib/zookeeper/client_methods.rb +51 -28
- data/lib/zookeeper/common.rb +1 -87
- data/lib/zookeeper/request_registry.rb +153 -0
- data/lib/zookeeper/version.rb +1 -1
- data/spec/c_zookeeper_spec.rb +1 -1
- metadata +6 -5
data/CHANGELOG
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
v1.3.0 much needed refactor of event and async result delivery
|
2
|
+
|
3
|
+
* event and async blocks were previously mixed in with a bunch of other
|
4
|
+
common code, and shared a Monitor with other unrelated functionality. This
|
5
|
+
code has been gently refactored into its own self-contained class (with its
|
6
|
+
own task-specific lock), which should help with maintenance.
|
7
|
+
|
1
8
|
v1.2.14 merge add_auth pull request, reduce chances for ContinuationTimeoutError
|
2
9
|
|
3
10
|
* added support for the add_auth call (h/t: @bradhe) see pull req #25
|
data/ext/zookeeper_base.rb
CHANGED
@@ -20,18 +20,12 @@ class ZookeeperBase
|
|
20
20
|
# @private
|
21
21
|
class ClientShutdownException < StandardError; end
|
22
22
|
|
23
|
-
# @private
|
24
|
-
KILL_TOKEN = Object.new unless defined?(KILL_TOKEN)
|
25
|
-
|
26
|
-
ZKRB_GLOBAL_CB_REQ = -1
|
27
|
-
|
28
23
|
# debug levels
|
29
24
|
ZOO_LOG_LEVEL_ERROR = 1
|
30
25
|
ZOO_LOG_LEVEL_WARN = 2
|
31
26
|
ZOO_LOG_LEVEL_INFO = 3
|
32
27
|
ZOO_LOG_LEVEL_DEBUG = 4
|
33
28
|
|
34
|
-
|
35
29
|
def_delegators :czk, :get_children, :exists, :delete, :get, :set,
|
36
30
|
:set_acl, :get_acl, :client_id, :sync, :add_auth, :wait_until_connected
|
37
31
|
|
@@ -66,11 +60,8 @@ class ZookeeperBase
|
|
66
60
|
end
|
67
61
|
private :reopen_after_fork!
|
68
62
|
|
69
|
-
|
70
63
|
def reopen(timeout = 10, watcher=nil)
|
71
|
-
|
72
|
-
raise "You cannot set the watcher to a different value this way anymore!"
|
73
|
-
end
|
64
|
+
raise "You cannot set the watcher to a different value this way anymore!" if watcher
|
74
65
|
|
75
66
|
reopen_after_fork! if forked?
|
76
67
|
|
@@ -79,8 +70,7 @@ class ZookeeperBase
|
|
79
70
|
@czk = CZookeeper.new(@host, @event_queue)
|
80
71
|
|
81
72
|
# flushes all outstanding watcher reqs.
|
82
|
-
@
|
83
|
-
set_default_global_watcher
|
73
|
+
@req_registry.clear_watchers!
|
84
74
|
|
85
75
|
@czk.wait_until_connected(timeout)
|
86
76
|
end
|
@@ -90,24 +80,21 @@ class ZookeeperBase
|
|
90
80
|
end
|
91
81
|
|
92
82
|
def initialize(host, timeout = 10, watcher=nil)
|
93
|
-
@watcher_reqs = {}
|
94
|
-
@completion_reqs = {}
|
95
|
-
|
96
|
-
@current_req_id = 0
|
97
|
-
|
98
|
-
@dispatcher = @czk = nil
|
99
|
-
|
100
|
-
update_pid!
|
101
|
-
reopen_after_fork!
|
102
|
-
|
103
83
|
# approximate the java behavior of raising java.lang.IllegalArgumentException if the host
|
104
84
|
# argument ends with '/'
|
105
85
|
raise ArgumentError, "Host argument #{host.inspect} may not end with /" if host.end_with?('/')
|
106
86
|
|
107
87
|
@host = host.dup
|
108
88
|
|
109
|
-
|
89
|
+
watcher ||= get_default_global_watcher
|
90
|
+
|
91
|
+
@req_registry = RequestRegistry.new(watcher, :chroot_path => chroot_path)
|
110
92
|
|
93
|
+
@dispatcher = @czk = nil
|
94
|
+
|
95
|
+
update_pid!
|
96
|
+
reopen_after_fork!
|
97
|
+
|
111
98
|
yield self if block_given?
|
112
99
|
|
113
100
|
reopen(timeout)
|
@@ -166,7 +153,7 @@ class ZookeeperBase
|
|
166
153
|
def create(*args)
|
167
154
|
# since we don't care about the inputs, just glob args
|
168
155
|
rc, new_path = czk.create(*args)
|
169
|
-
[rc, strip_chroot_from(new_path)]
|
156
|
+
[rc, @req_registry.strip_chroot_from(new_path)]
|
170
157
|
end
|
171
158
|
|
172
159
|
def set_debug_level(int)
|
@@ -176,12 +163,7 @@ class ZookeeperBase
|
|
176
163
|
|
177
164
|
# set the watcher object/proc that will receive all global events (such as session/state events)
|
178
165
|
def set_default_global_watcher
|
179
|
-
|
180
|
-
|
181
|
-
@mutex.synchronize do
|
182
|
-
# @default_watcher = block # save this here for reopen() to use
|
183
|
-
@watcher_reqs[ZKRB_GLOBAL_CB_REQ] = { :watcher => @default_watcher, :watcher_context => nil }
|
184
|
-
end
|
166
|
+
raise "NO! YOU CANNOT HAZ set_default_global_watcher"
|
185
167
|
end
|
186
168
|
|
187
169
|
def state
|
@@ -233,34 +215,9 @@ class ZookeeperBase
|
|
233
215
|
end
|
234
216
|
|
235
217
|
protected
|
236
|
-
# this is a hack: to provide consistency between the C and Java drivers when
|
237
|
-
# using a chrooted connection, we wrap the callback in a block that will
|
238
|
-
# strip the chroot path from the returned path (important in an async create
|
239
|
-
# sequential call). This is the only place where we can hook *just* the C
|
240
|
-
# version. The non-async manipulation is handled in ZookeeperBase#create.
|
241
|
-
#
|
242
|
-
# TODO: need to move the continuation setup into here, so that it can get
|
243
|
-
# added to the callback hash
|
244
|
-
#
|
245
|
-
def setup_completion(req_id, meth_name, call_opts)
|
246
|
-
if (meth_name == :create) and cb = call_opts[:callback]
|
247
|
-
call_opts[:callback] = lambda do |hash|
|
248
|
-
# in this case the string will be the absolute zookeeper path (i.e.
|
249
|
-
# with the chroot still prepended to the path). Here's where we strip it off
|
250
|
-
hash[:string] = strip_chroot_from(hash[:string])
|
251
|
-
|
252
|
-
# call the original callback
|
253
|
-
cb.call(hash)
|
254
|
-
end
|
255
|
-
end
|
256
|
-
|
257
|
-
# pass this along to the Zookeeper::Common implementation
|
258
|
-
super(req_id, meth_name, call_opts)
|
259
|
-
end
|
260
|
-
|
261
218
|
def czk
|
262
219
|
rval = @mutex.synchronize { @czk }
|
263
|
-
raise Exceptions::NotConnected unless rval
|
220
|
+
raise Exceptions::NotConnected, "underlying connection was nil" unless rval
|
264
221
|
rval
|
265
222
|
end
|
266
223
|
|
data/java/java_base.rb
CHANGED
@@ -186,9 +186,7 @@ class JavaBase
|
|
186
186
|
# watcher ||= @default_watcher
|
187
187
|
|
188
188
|
@mutex.synchronize do
|
189
|
-
|
190
|
-
@watcher_reqs.clear
|
191
|
-
set_default_global_watcher
|
189
|
+
@req_registry.clear_watchers!
|
192
190
|
|
193
191
|
replace_jzk!
|
194
192
|
wait_until_connected
|
@@ -205,19 +203,19 @@ class JavaBase
|
|
205
203
|
def initialize(host, timeout=10, watcher=nil, options={})
|
206
204
|
@host = host
|
207
205
|
@event_queue = QueueWithPipe.new
|
208
|
-
|
206
|
+
|
207
|
+
watcher ||= get_default_global_watcher()
|
208
|
+
|
209
|
+
@req_registry = RequestRegistry.new(watcher)
|
209
210
|
|
210
211
|
@mutex = Monitor.new
|
211
212
|
@dispatch_shutdown_cond = @mutex.new_cond
|
212
213
|
@connected_latch = Latch.new
|
213
214
|
|
214
|
-
@watcher_reqs = {}
|
215
|
-
@completion_reqs = {}
|
216
215
|
@_running = nil
|
217
216
|
@_closed = false
|
218
217
|
@options = {}
|
219
218
|
|
220
|
-
@default_watcher = (watcher || get_default_global_watcher)
|
221
219
|
|
222
220
|
# allows connected-state handlers to be registered before
|
223
221
|
yield self if block_given?
|
@@ -415,19 +413,6 @@ class JavaBase
|
|
415
413
|
raise NotConnected unless connected?
|
416
414
|
end
|
417
415
|
|
418
|
-
# set the watcher object/proc that will receive all global events (such as session/state events)
|
419
|
-
#---
|
420
|
-
# XXX: this code needs to be duplicated from ext/zookeeper_base.rb because
|
421
|
-
# it's called from the initializer, and because of the C impl. we can't have
|
422
|
-
# the two decend from a common base, and a module wouldn't work
|
423
|
-
#
|
424
|
-
# XXX: this is probably a relic?
|
425
|
-
def set_default_global_watcher
|
426
|
-
@mutex.synchronize do
|
427
|
-
@watcher_reqs[ZKRB_GLOBAL_CB_REQ] = { :watcher => @default_watcher, :watcher_context => nil }
|
428
|
-
end
|
429
|
-
end
|
430
|
-
|
431
416
|
def session_id
|
432
417
|
jzk.session_id
|
433
418
|
end
|
data/lib/zookeeper.rb
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
module Zookeeper
|
2
2
|
module ClientMethods
|
3
|
+
extend Forwardable
|
3
4
|
include Constants
|
4
5
|
include ACLs
|
5
6
|
include Logger
|
6
7
|
|
8
|
+
# @req_registry is set up in the platform-specific base classes
|
9
|
+
def_delegators :@req_registry, :setup_call
|
10
|
+
private :setup_call
|
11
|
+
|
7
12
|
def reopen(timeout=10, watcher=nil)
|
8
13
|
warn "WARN: ZookeeperBase#reopen watcher argument is now ignored" if watcher
|
9
14
|
super
|
@@ -15,8 +20,9 @@ module ClientMethods
|
|
15
20
|
|
16
21
|
def add_auth(options = {})
|
17
22
|
assert_open
|
18
|
-
|
19
|
-
|
23
|
+
assert_keys(options,
|
24
|
+
:supported => [:scheme, :cert],
|
25
|
+
:required => [:scheme, :cert])
|
20
26
|
|
21
27
|
req_id = setup_call(:add_auth, options)
|
22
28
|
rc = super(req_id, options[:scheme], options[:cert])
|
@@ -26,8 +32,9 @@ module ClientMethods
|
|
26
32
|
|
27
33
|
def get(options = {})
|
28
34
|
assert_open
|
29
|
-
|
30
|
-
|
35
|
+
assert_keys(options,
|
36
|
+
:supported => [:path, :watcher, :watcher_context, :callback, :callback_context],
|
37
|
+
:required => [:path])
|
31
38
|
|
32
39
|
req_id = setup_call(:get, options)
|
33
40
|
rc, value, stat = super(req_id, options[:path], options[:callback], options[:watcher])
|
@@ -38,8 +45,10 @@ module ClientMethods
|
|
38
45
|
|
39
46
|
def set(options = {})
|
40
47
|
assert_open
|
41
|
-
|
42
|
-
|
48
|
+
assert_keys(options,
|
49
|
+
:supported => [:path, :data, :version, :callback, :callback_context],
|
50
|
+
:required => [:path])
|
51
|
+
|
43
52
|
assert_valid_data_size!(options[:data])
|
44
53
|
options[:version] ||= -1
|
45
54
|
|
@@ -52,8 +61,9 @@ module ClientMethods
|
|
52
61
|
|
53
62
|
def get_children(options = {})
|
54
63
|
assert_open
|
55
|
-
|
56
|
-
|
64
|
+
assert_keys(options,
|
65
|
+
:supported => [:path, :callback, :callback_context, :watcher, :watcher_context],
|
66
|
+
:required => [:path])
|
57
67
|
|
58
68
|
req_id = setup_call(:get_children, options)
|
59
69
|
rc, children, stat = super(req_id, options[:path], options[:callback], options[:watcher])
|
@@ -64,8 +74,9 @@ module ClientMethods
|
|
64
74
|
|
65
75
|
def stat(options = {})
|
66
76
|
assert_open
|
67
|
-
|
68
|
-
|
77
|
+
assert_keys(options,
|
78
|
+
:supported => [:path, :callback, :callback_context, :watcher, :watcher_context],
|
79
|
+
:required => [:path])
|
69
80
|
|
70
81
|
req_id = setup_call(:stat, options)
|
71
82
|
rc, stat = exists(req_id, options[:path], options[:callback], options[:watcher])
|
@@ -76,8 +87,10 @@ module ClientMethods
|
|
76
87
|
|
77
88
|
def create(options = {})
|
78
89
|
assert_open
|
79
|
-
|
80
|
-
|
90
|
+
assert_keys(options,
|
91
|
+
:supported => [:path, :data, :acl, :ephemeral, :sequence, :callback, :callback_context],
|
92
|
+
:required => [:path])
|
93
|
+
|
81
94
|
assert_valid_data_size!(options[:data])
|
82
95
|
|
83
96
|
flags = 0
|
@@ -95,8 +108,10 @@ module ClientMethods
|
|
95
108
|
|
96
109
|
def delete(options = {})
|
97
110
|
assert_open
|
98
|
-
|
99
|
-
|
111
|
+
assert_keys(options,
|
112
|
+
:supported => [:path, :version, :callback, :callback_context],
|
113
|
+
:required => [:path])
|
114
|
+
|
100
115
|
options[:version] ||= -1
|
101
116
|
|
102
117
|
req_id = setup_call(:delete, options)
|
@@ -113,8 +128,9 @@ module ClientMethods
|
|
113
128
|
#
|
114
129
|
def sync(options = {})
|
115
130
|
assert_open
|
116
|
-
|
117
|
-
|
131
|
+
assert_keys(options,
|
132
|
+
:supported => [:path, :callback, :callback_context],
|
133
|
+
:required => [:path, :callback])
|
118
134
|
|
119
135
|
req_id = setup_call(:sync, options)
|
120
136
|
|
@@ -125,8 +141,9 @@ module ClientMethods
|
|
125
141
|
|
126
142
|
def set_acl(options = {})
|
127
143
|
assert_open
|
128
|
-
|
129
|
-
|
144
|
+
assert_keys(options,
|
145
|
+
:supported => [:path, :acl, :version, :callback, :callback_context],
|
146
|
+
:required => [:path, :acl])
|
130
147
|
options[:version] ||= -1
|
131
148
|
|
132
149
|
req_id = setup_call(:set_acl, options)
|
@@ -137,8 +154,9 @@ module ClientMethods
|
|
137
154
|
|
138
155
|
def get_acl(options = {})
|
139
156
|
assert_open
|
140
|
-
|
141
|
-
|
157
|
+
assert_keys(options,
|
158
|
+
:supported => [:path, :callback, :callback_context],
|
159
|
+
:required => [:path])
|
142
160
|
|
143
161
|
req_id = setup_call(:get_acl, options)
|
144
162
|
rc, acls, stat = super(req_id, options[:path], options[:callback])
|
@@ -241,14 +259,19 @@ protected
|
|
241
259
|
end
|
242
260
|
|
243
261
|
private
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
262
|
+
def assert_keys(args, opts={})
|
263
|
+
supported = opts[:supported] || []
|
264
|
+
required = opts[:required] || []
|
265
|
+
|
266
|
+
unless (args.keys - supported).empty?
|
267
|
+
raise Zookeeper::Exceptions::BadArguments,
|
268
|
+
"Supported arguments are: #{supported.inspect}, but arguments #{args.keys.inspect} were supplied instead"
|
269
|
+
end
|
270
|
+
|
271
|
+
unless (required - args.keys).empty?
|
272
|
+
raise Zookeeper::Exceptions::BadArguments,
|
273
|
+
"Required arguments are: #{required.inspect}, but only the arguments #{args.keys.inspect} were supplied."
|
274
|
+
end
|
252
275
|
end
|
253
276
|
|
254
277
|
# must be supplied by parent class impl.
|
data/lib/zookeeper/common.rb
CHANGED
@@ -3,59 +3,11 @@ require 'zookeeper/common/queue_with_pipe'
|
|
3
3
|
|
4
4
|
module Zookeeper
|
5
5
|
module Common
|
6
|
-
# sigh, i guess define this here?
|
7
|
-
ZKRB_GLOBAL_CB_REQ = -1
|
8
|
-
|
9
6
|
def event_dispatch_thread?
|
10
7
|
@dispatcher && (@dispatcher == Thread.current)
|
11
8
|
end
|
12
9
|
|
13
10
|
private
|
14
|
-
def setup_call(meth_name, opts)
|
15
|
-
req_id = nil
|
16
|
-
@mutex.synchronize {
|
17
|
-
req_id = @current_req_id
|
18
|
-
@current_req_id += 1
|
19
|
-
setup_completion(req_id, meth_name, opts) if opts[:callback]
|
20
|
-
setup_watcher(req_id, opts) if opts[:watcher]
|
21
|
-
}
|
22
|
-
req_id
|
23
|
-
end
|
24
|
-
|
25
|
-
def setup_watcher(req_id, call_opts)
|
26
|
-
@mutex.synchronize do
|
27
|
-
@watcher_reqs[req_id] = {
|
28
|
-
:watcher => call_opts[:watcher],
|
29
|
-
:context => call_opts[:watcher_context]
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
# as a hack, to provide consistency between the java implementation and the C
|
35
|
-
# implementation when dealing w/ chrooted connections, we override this in
|
36
|
-
# ext/zookeeper_base.rb to wrap the callback in a chroot-path-stripping block.
|
37
|
-
#
|
38
|
-
# we don't use meth_name here, but we need it in the C implementation
|
39
|
-
#
|
40
|
-
def setup_completion(req_id, meth_name, call_opts)
|
41
|
-
@mutex.synchronize do
|
42
|
-
@completion_reqs[req_id] = {
|
43
|
-
:callback => call_opts[:callback],
|
44
|
-
:context => call_opts[:callback_context]
|
45
|
-
}
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def get_watcher(req_id)
|
50
|
-
@mutex.synchronize {
|
51
|
-
(req_id == ZKRB_GLOBAL_CB_REQ) ? @watcher_reqs[req_id] : @watcher_reqs.delete(req_id)
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
def get_completion(req_id)
|
56
|
-
@mutex.synchronize { @completion_reqs.delete(req_id) }
|
57
|
-
end
|
58
|
-
|
59
11
|
def setup_dispatch_thread!
|
60
12
|
@mutex.synchronize do
|
61
13
|
if @dispatcher
|
@@ -118,31 +70,7 @@ private
|
|
118
70
|
hash[:stat] = Zookeeper::Stat.new(hash[:stat]) if hash.has_key?(:stat)
|
119
71
|
hash[:acl] = hash[:acl].map { |acl| Zookeeper::ACLs::ACL.new(acl) } if hash[:acl]
|
120
72
|
|
121
|
-
callback_context =
|
122
|
-
|
123
|
-
@mutex.synchronize do
|
124
|
-
callback_context = is_completion ? get_completion(hash[:req_id]) : get_watcher(hash[:req_id])
|
125
|
-
|
126
|
-
# When connectivity to the server has been lost (as indicated by SESSION_EVENT)
|
127
|
-
# we want to rerun the callback at a later time when we eventually do have
|
128
|
-
# a valid response.
|
129
|
-
#
|
130
|
-
# XXX: this code needs to be refactored, get_completion shouldn't remove the context
|
131
|
-
# in the case of a session event. this would involve changing the
|
132
|
-
# platform implementations as well, as the C version does some funky
|
133
|
-
# stuff to maintain compatibilty w/ java in chrooted envs.
|
134
|
-
#
|
135
|
-
# The point is that this lock ^^ is unnecessary if the functions above lock internally
|
136
|
-
# and don't do the wrong thing, requiring us to do the below.
|
137
|
-
#
|
138
|
-
if hash[:type] == Zookeeper::Constants::ZOO_SESSION_EVENT
|
139
|
-
if is_completion
|
140
|
-
setup_completion(hash[:req_id], callback_context)
|
141
|
-
else
|
142
|
-
setup_watcher(hash[:req_id], callback_context)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
73
|
+
callback_context = @req_registry.get_context_for(hash)
|
146
74
|
|
147
75
|
if callback_context
|
148
76
|
callback = is_completion ? callback_context[:callback] : callback_context[:watcher]
|
@@ -160,20 +88,6 @@ private
|
|
160
88
|
true
|
161
89
|
end
|
162
90
|
|
163
|
-
def assert_supported_keys(args, supported)
|
164
|
-
unless (args.keys - supported).empty?
|
165
|
-
raise Zookeeper::Exceptions::BadArguments,
|
166
|
-
"Supported arguments are: #{supported.inspect}, but arguments #{args.keys.inspect} were supplied instead"
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def assert_required_keys(args, required)
|
171
|
-
unless (required - args.keys).empty?
|
172
|
-
raise Zookeeper::Exceptions::BadArguments,
|
173
|
-
"Required arguments are: #{required.inspect}, but only the arguments #{args.keys.inspect} were supplied."
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
91
|
def dispatch_thread_body
|
178
92
|
while true
|
179
93
|
begin
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module Zookeeper
|
2
|
+
class RequestRegistry
|
3
|
+
include Constants
|
4
|
+
include Logger
|
5
|
+
|
6
|
+
# @param [Hash] opts
|
7
|
+
# @option opts [String] :chroot_path (nil) if given, will be used to
|
8
|
+
# correct a discrepancy between the C and Java clients when using a
|
9
|
+
# chrooted connection. If given, the chroot path will be stripped from
|
10
|
+
# the string returned by a `create`. It should be an absolute path.
|
11
|
+
#
|
12
|
+
def initialize(watcher, opts={})
|
13
|
+
@mutex = Monitor.new
|
14
|
+
|
15
|
+
@default_watcher = watcher
|
16
|
+
|
17
|
+
@current_req_id = 0
|
18
|
+
@watcher_reqs = {}
|
19
|
+
@completion_reqs = {}
|
20
|
+
|
21
|
+
@chroot_path = opts[:chroot_path]
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_watcher
|
25
|
+
@mutex.synchronize { @default_watcher }
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_watcher=(blk)
|
29
|
+
@mutex.synchronize { @default_watcher = blk }
|
30
|
+
end
|
31
|
+
|
32
|
+
def setup_call(meth_name, opts)
|
33
|
+
req_id = nil
|
34
|
+
@mutex.synchronize {
|
35
|
+
req_id = @current_req_id
|
36
|
+
@current_req_id += 1
|
37
|
+
setup_completion(req_id, meth_name, opts) if opts[:callback]
|
38
|
+
setup_watcher(req_id, opts) if opts[:watcher]
|
39
|
+
}
|
40
|
+
req_id
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_context_for(hash)
|
44
|
+
return nil unless hash
|
45
|
+
|
46
|
+
is_session_event = (hash[:type] == ZOO_SESSION_EVENT)
|
47
|
+
|
48
|
+
req_id = hash.fetch(:req_id)
|
49
|
+
|
50
|
+
if hash.has_key?(:rc)
|
51
|
+
get_completion(req_id, :keep => is_session_event)
|
52
|
+
else
|
53
|
+
get_watcher(req_id, :keep => is_session_event)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def clear_watchers!
|
58
|
+
@mutex.synchronize { @watcher_reqs.clear }
|
59
|
+
end
|
60
|
+
|
61
|
+
# if we're chrooted, this method will strip the chroot prefix from +path+
|
62
|
+
def strip_chroot_from(path)
|
63
|
+
return path unless (chrooted? and path and path.start_with?(@chroot_path))
|
64
|
+
path[@chroot_path.length..-1]
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
def get_completion(req_id, opts={})
|
69
|
+
@mutex.synchronize do
|
70
|
+
if opts[:keep]
|
71
|
+
@completion_reqs[req_id]
|
72
|
+
else
|
73
|
+
@completion_reqs.delete(req_id)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Return the watcher hash associated with the req_id. If the req_id
|
79
|
+
# is the ZKRB_GLOBAL_CB_REQ, then does not clear the req from the internal
|
80
|
+
# store, otherwise the req_id is removed.
|
81
|
+
#
|
82
|
+
def get_watcher(req_id, opts={})
|
83
|
+
@mutex.synchronize do
|
84
|
+
if Constants::ZKRB_GLOBAL_CB_REQ == req_id
|
85
|
+
{ :watcher => @default_watcher, :watcher_context => nil }
|
86
|
+
elsif opts[:keep]
|
87
|
+
@watcher_reqs[req_id]
|
88
|
+
else
|
89
|
+
@watcher_reqs.delete(req_id)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
def setup_watcher(req_id, call_opts)
|
96
|
+
@mutex.synchronize do
|
97
|
+
@watcher_reqs[req_id] = {
|
98
|
+
:watcher => call_opts[:watcher],
|
99
|
+
:context => call_opts[:watcher_context]
|
100
|
+
}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# as a hack, to provide consistency between the java implementation and the C
|
105
|
+
# implementation when dealing w/ chrooted connections, we override this in
|
106
|
+
# ext/zookeeper_base.rb to wrap the callback in a chroot-path-stripping block.
|
107
|
+
#
|
108
|
+
# we don't use meth_name here, but we need it in the C implementation
|
109
|
+
#
|
110
|
+
def setup_completion(req_id, meth_name, call_opts)
|
111
|
+
@mutex.synchronize do
|
112
|
+
@completion_reqs[req_id] = {
|
113
|
+
:callback => maybe_wrap_callback(meth_name, call_opts[:callback]),
|
114
|
+
:context => call_opts[:callback_context]
|
115
|
+
}
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# this is a hack: to provide consistency between the C and Java drivers when
|
120
|
+
# using a chrooted connection, we wrap the callback in a block that will
|
121
|
+
# strip the chroot path from the returned path (important in an async create
|
122
|
+
# sequential call). This is the only place where we can hook *just* the C
|
123
|
+
# version. The non-async manipulation is handled in ZookeeperBase#create.
|
124
|
+
#
|
125
|
+
# TODO: need to move the continuation setup into here, so that it can get
|
126
|
+
# added to the callback hash
|
127
|
+
#
|
128
|
+
def maybe_wrap_callback(meth_name, cb)
|
129
|
+
return cb unless cb and chrooted? and (meth_name == :create)
|
130
|
+
|
131
|
+
lambda do |hash|
|
132
|
+
# in this case the string will be the absolute zookeeper path (i.e.
|
133
|
+
# with the chroot still prepended to the path). Here's where we strip it off
|
134
|
+
hash[:string] = strip_chroot_from(hash[:string])
|
135
|
+
|
136
|
+
# call the original callback
|
137
|
+
cb.call(hash)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def chrooted?
|
142
|
+
@chroot_path && !@chroot_path.empty?
|
143
|
+
end
|
144
|
+
|
145
|
+
def default_watcher_proc
|
146
|
+
Proc.new { |args|
|
147
|
+
logger.debug { "Ruby ZK Global CB called type=#{event_by_value(args[:type])} state=#{state_by_value(args[:state])}" }
|
148
|
+
true
|
149
|
+
}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
data/lib/zookeeper/version.rb
CHANGED
data/spec/c_zookeeper_spec.rb
CHANGED
@@ -40,7 +40,7 @@ unless defined?(::JRUBY_VERSION)
|
|
40
40
|
it %[should have a connection event after being connected] do
|
41
41
|
event = wait_until(2) { @event_queue.pop }
|
42
42
|
event.should be
|
43
|
-
event[:req_id].should == Zookeeper::
|
43
|
+
event[:req_id].should == Zookeeper::Constants::ZKRB_GLOBAL_CB_REQ
|
44
44
|
event[:type].should == Zookeeper::Constants::ZOO_SESSION_EVENT
|
45
45
|
event[:state].should == Zookeeper::Constants::ZOO_CONNECTED_STATE
|
46
46
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zookeeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 27
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 3
|
9
|
+
- 0
|
10
|
+
version: 1.3.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Phillip Pearson
|
@@ -20,7 +20,7 @@ autorequire:
|
|
20
20
|
bindir: bin
|
21
21
|
cert_chain: []
|
22
22
|
|
23
|
-
date: 2012-08-
|
23
|
+
date: 2012-08-17 00:00:00 Z
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: logging
|
@@ -103,6 +103,7 @@ files:
|
|
103
103
|
- lib/zookeeper/logger.rb
|
104
104
|
- lib/zookeeper/monitor.rb
|
105
105
|
- lib/zookeeper/rake_tasks.rb
|
106
|
+
- lib/zookeeper/request_registry.rb
|
106
107
|
- lib/zookeeper/stat.rb
|
107
108
|
- lib/zookeeper/version.rb
|
108
109
|
- notes.txt
|