zookeeper 1.2.14 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|