zookeeper 1.2.4 → 1.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +21 -0
- data/ext/c_zookeeper.rb +4 -6
- data/ext/extconf.rb +7 -0
- data/ext/zkrb.c +0 -9
- data/ext/zkrb_wrapper_compat.c +3 -3
- data/ext/zookeeper_base.rb +15 -9
- data/lib/zookeeper/continuation.rb +24 -3
- data/lib/zookeeper/exceptions.rb +4 -0
- data/lib/zookeeper/version.rb +1 -1
- metadata +4 -4
data/CHANGELOG
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
v1.2.5 cleanup locking in ZookeeperBase
|
2
|
+
|
3
|
+
* There were several situations where we would hold the lock before calling
|
4
|
+
a method on CZookeeper (inquisitors and #create in particular). This
|
5
|
+
exposed us to deadlocks in situations where an async event would be
|
6
|
+
delivered (probably a SESSION_EXPIRED event), but the callback block could
|
7
|
+
not be called because the dispatch thread would block on the mutex being
|
8
|
+
held by the caller of create.
|
9
|
+
|
10
|
+
This version cleans up that usage, and ensures that the only time we hold
|
11
|
+
the mutex is during startup/shutdown (when the value of @czk may be changing),
|
12
|
+
and in all other cases we grab the mutex, dereference, and unlock then perform
|
13
|
+
whatever action on the reference.
|
14
|
+
|
15
|
+
* Add a safety net to Continuation (which will soon be called 'Promise' or
|
16
|
+
'Future' at the request of @eric). If any operation takes more than 30s
|
17
|
+
an exception will be raised in the calling thread. The session timeout
|
18
|
+
setting makes it so that no operation should take more than 20s, so we know
|
19
|
+
if we haven't received a reply in *longer* than that, something has gone
|
20
|
+
awry.
|
21
|
+
|
1
22
|
v1.2.4 fix buffer overflow in CZookeeper client_id code
|
2
23
|
|
3
24
|
* the 'passwd' part of the struct is a char[16], but isn't null terminated.
|
data/ext/c_zookeeper.rb
CHANGED
@@ -176,6 +176,7 @@ class CZookeeper
|
|
176
176
|
return false unless wait_until_running(timeout)
|
177
177
|
|
178
178
|
@mutex.synchronize do
|
179
|
+
# TODO: use deadline here
|
179
180
|
@state_cond.wait(timeout) unless (@state == ZOO_CONNECTED_STATE)
|
180
181
|
end
|
181
182
|
|
@@ -191,15 +192,12 @@ class CZookeeper
|
|
191
192
|
end
|
192
193
|
|
193
194
|
cnt = Continuation.new(meth, *args)
|
194
|
-
@reg.
|
195
|
-
begin
|
195
|
+
@reg.synchronize do |r|
|
196
196
|
if meth == :state
|
197
|
-
|
197
|
+
r.state_check << cnt
|
198
198
|
else
|
199
|
-
|
199
|
+
r.pending << cnt
|
200
200
|
end
|
201
|
-
ensure
|
202
|
-
@reg.unlock rescue nil
|
203
201
|
end
|
204
202
|
wake_event_loop!
|
205
203
|
cnt.value
|
data/ext/extconf.rb
CHANGED
@@ -42,6 +42,11 @@ $LDFLAGS = "#{$libraries} #{$LDFLAGS}"
|
|
42
42
|
$LIBPATH = ["#{HERE}/lib"]
|
43
43
|
$DEFLIBPATH = []
|
44
44
|
|
45
|
+
# fix for rbenv?
|
46
|
+
if $LIBRUBYARG == ''
|
47
|
+
$LIBRUBYARG = RbConfig::CONFIG['LIBRUBYARG']
|
48
|
+
end
|
49
|
+
|
45
50
|
def safe_sh(cmd)
|
46
51
|
puts cmd
|
47
52
|
system(cmd)
|
@@ -87,6 +92,8 @@ Dir.chdir("#{HERE}/lib") do
|
|
87
92
|
end
|
88
93
|
$LIBS << " -lzookeeper_st_gem"
|
89
94
|
|
95
|
+
have_func('rb_thread_blocking_region')
|
96
|
+
|
90
97
|
$CFLAGS << ' -Wall' if ZK_DEV
|
91
98
|
create_makefile 'zookeeper_c'
|
92
99
|
|
data/ext/zkrb.c
CHANGED
@@ -824,7 +824,6 @@ static VALUE method_zkrb_iterate_event_loop(VALUE self) {
|
|
824
824
|
return INT2FIX(rc);
|
825
825
|
}
|
826
826
|
|
827
|
-
|
828
827
|
static VALUE method_has_events(VALUE self) {
|
829
828
|
VALUE rb_event;
|
830
829
|
FETCH_DATA_PTR(self, zk);
|
@@ -882,16 +881,8 @@ static VALUE method_recv_timeout(VALUE self) {
|
|
882
881
|
// returns a CZookeeper::ClientId object with the values set for session_id and passwd
|
883
882
|
static VALUE method_client_id(VALUE self) {
|
884
883
|
FETCH_DATA_PTR(self, zk);
|
885
|
-
char buf[32];
|
886
884
|
const clientid_t *cid = zoo_client_id(zk->zh);
|
887
885
|
|
888
|
-
/* if (strlen(cid->passwd) != 16) { */
|
889
|
-
/* zkrb_debug("passwd is not null-terminated");*/
|
890
|
-
/* } else {*/
|
891
|
-
/* hexbufify(buf, cid->passwd, 16);*/
|
892
|
-
/* zkrb_debug("password in hex is: %s", buf);*/
|
893
|
-
/* }*/
|
894
|
-
|
895
886
|
VALUE session_id = LL2NUM(cid->client_id);
|
896
887
|
VALUE passwd = rb_str_new(cid->passwd, 16);
|
897
888
|
|
data/ext/zkrb_wrapper_compat.c
CHANGED
@@ -4,10 +4,10 @@
|
|
4
4
|
|
5
5
|
VALUE zkrb_thread_blocking_region(zkrb_blocking_function_t *func, void *data1) {
|
6
6
|
|
7
|
-
#ifdef
|
8
|
-
return func(data1);
|
9
|
-
#else
|
7
|
+
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
10
8
|
return rb_thread_blocking_region((rb_blocking_function_t *)func, data1, RUBY_UBF_IO, 0);
|
9
|
+
#else
|
10
|
+
return func(data1);
|
11
11
|
#endif
|
12
12
|
|
13
13
|
}
|
data/ext/zookeeper_base.rb
CHANGED
@@ -31,17 +31,15 @@ class ZookeeperBase
|
|
31
31
|
ZOO_LOG_LEVEL_DEBUG = 4
|
32
32
|
|
33
33
|
|
34
|
-
def_delegators
|
34
|
+
def_delegators :czk, :get_children, :exists, :delete, :get, :set,
|
35
35
|
:set_acl, :get_acl, :client_id, :sync, :wait_until_connected
|
36
36
|
|
37
|
-
# some state methods need to be more paranoid about locking to ensure the correct
|
38
|
-
# state is returned
|
39
|
-
#
|
40
37
|
def self.threadsafe_inquisitor(*syms)
|
41
38
|
syms.each do |sym|
|
42
39
|
class_eval(<<-EOM, __FILE__, __LINE__+1)
|
43
40
|
def #{sym}
|
44
|
-
|
41
|
+
c = @mutex.synchronize { @czk }
|
42
|
+
false|(c && c.#{sym})
|
45
43
|
end
|
46
44
|
EOM
|
47
45
|
end
|
@@ -117,7 +115,7 @@ class ZookeeperBase
|
|
117
115
|
# if either of these happen, the user will need to renegotiate a connection via reopen
|
118
116
|
def assert_open
|
119
117
|
@mutex.synchronize do
|
120
|
-
raise Exceptions::NotConnected if closed?
|
118
|
+
raise Exceptions::NotConnected if !@czk or @czk.closed?
|
121
119
|
if forked?
|
122
120
|
raise InheritedConnectionError, <<-EOS.gsub(/(?:^|\n)\s*/, ' ').strip
|
123
121
|
You tried to use a connection inherited from another process
|
@@ -152,7 +150,7 @@ class ZookeeperBase
|
|
152
150
|
# is pretty damn annoying. this is used to clean things up.
|
153
151
|
def create(*args)
|
154
152
|
# since we don't care about the inputs, just glob args
|
155
|
-
rc, new_path =
|
153
|
+
rc, new_path = czk.create(*args)
|
156
154
|
[rc, strip_chroot_from(new_path)]
|
157
155
|
end
|
158
156
|
|
@@ -173,7 +171,7 @@ class ZookeeperBase
|
|
173
171
|
|
174
172
|
def state
|
175
173
|
return ZOO_CLOSED_STATE if closed?
|
176
|
-
|
174
|
+
czk.state
|
177
175
|
end
|
178
176
|
|
179
177
|
def session_id
|
@@ -190,7 +188,9 @@ class ZookeeperBase
|
|
190
188
|
|
191
189
|
# we are closed if there is no @czk instance or @czk.closed?
|
192
190
|
def closed?
|
193
|
-
|
191
|
+
czk.closed?
|
192
|
+
rescue Exceptions::NotConnected
|
193
|
+
true
|
194
194
|
end
|
195
195
|
|
196
196
|
def pause_before_fork_in_parent
|
@@ -243,6 +243,12 @@ protected
|
|
243
243
|
super(req_id, meth_name, call_opts)
|
244
244
|
end
|
245
245
|
|
246
|
+
def czk
|
247
|
+
rval = @mutex.synchronize { @czk }
|
248
|
+
raise Exceptions::NotConnected unless rval
|
249
|
+
rval
|
250
|
+
end
|
251
|
+
|
246
252
|
# if we're chrooted, this method will strip the chroot prefix from +path+
|
247
253
|
def strip_chroot_from(path)
|
248
254
|
return path unless (chrooted? and path and path.start_with?(chroot_path))
|
@@ -6,6 +6,8 @@ module Zookeeper
|
|
6
6
|
include Constants
|
7
7
|
include Logger
|
8
8
|
|
9
|
+
OPERATION_TIMEOUT = 30 # seconds
|
10
|
+
|
9
11
|
# for keeping track of which continuations are pending, and which ones have
|
10
12
|
# been submitted and are awaiting a repsonse
|
11
13
|
#
|
@@ -79,8 +81,8 @@ module Zookeeper
|
|
79
81
|
def initialize(meth, *args)
|
80
82
|
@meth = meth
|
81
83
|
@args = args
|
82
|
-
@mutex =
|
83
|
-
@cond =
|
84
|
+
@mutex = Monitor.new
|
85
|
+
@cond = @mutex.new_cond
|
84
86
|
@rval = nil
|
85
87
|
|
86
88
|
# make this error reporting more robust if necessary, right now, just set to state
|
@@ -88,9 +90,28 @@ module Zookeeper
|
|
88
90
|
end
|
89
91
|
|
90
92
|
# the caller calls this method and receives the response from the async loop
|
93
|
+
# this method has a hard-coded 30 second timeout as a safety feature. No
|
94
|
+
# call should take more than 20s (as the session timeout is set to 20s)
|
95
|
+
# so if any call takes longer than that, something has gone horribly wrong.
|
96
|
+
#
|
97
|
+
# @raise [ContinuationTimeoutError] if a response is not received within 30s
|
98
|
+
#
|
91
99
|
def value
|
100
|
+
time_to_stop = Time.now + OPERATION_TIMEOUT
|
101
|
+
now = nil
|
102
|
+
|
92
103
|
@mutex.synchronize do
|
93
|
-
|
104
|
+
while true
|
105
|
+
now = Time.now
|
106
|
+
break if @rval or @error or (now > time_to_stop)
|
107
|
+
|
108
|
+
deadline = time_to_stop.to_f - now.to_f
|
109
|
+
@cond.wait(deadline)
|
110
|
+
end
|
111
|
+
|
112
|
+
if now > time_to_stop
|
113
|
+
raise ContinuationTimeoutError, "response for meth: #{meth.inspect}, args: #{args.inspect}, not received within #{OPERATION_TIMEOUT} seconds"
|
114
|
+
end
|
94
115
|
|
95
116
|
case @error
|
96
117
|
when nil
|
data/lib/zookeeper/exceptions.rb
CHANGED
@@ -84,6 +84,10 @@ stacktrace:
|
|
84
84
|
# maybe use this for continuation
|
85
85
|
class InterruptedException < ZookeeperException ; end
|
86
86
|
|
87
|
+
# raised when a continuation operation takes more time than is reasonable and
|
88
|
+
# the thread should be awoken. (i.e. prevents a call that never returns)
|
89
|
+
class ContinuationTimeoutError < ZookeeperException; end
|
90
|
+
|
87
91
|
# raised when the user tries to use a connection after a fork()
|
88
92
|
# without calling reopen() in the C client
|
89
93
|
#
|
data/lib/zookeeper/version.rb
CHANGED
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: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 1
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 1.2.
|
9
|
+
- 5
|
10
|
+
version: 1.2.5
|
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-
|
23
|
+
date: 2012-06-03 00:00:00 Z
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: backports
|