zk 1.4.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.dotfiles/ctags_paths +1 -0
- data/.dotfiles/rspec-logging +2 -2
- data/.gitignore +1 -0
- data/Gemfile +9 -3
- data/Guardfile +36 -0
- data/README.markdown +21 -18
- data/RELEASES.markdown +10 -0
- data/Rakefile +1 -1
- data/lib/zk.rb +28 -21
- data/lib/zk/client/threaded.rb +107 -17
- data/lib/zk/client/unixisms.rb +1 -41
- data/lib/zk/core_ext.rb +28 -0
- data/lib/zk/election.rb +14 -3
- data/lib/zk/event_handler.rb +36 -37
- data/lib/zk/event_handler_subscription/actor.rb +37 -2
- data/lib/zk/event_handler_subscription/base.rb +9 -0
- data/lib/zk/exceptions.rb +5 -0
- data/lib/zk/fork_hook.rb +112 -0
- data/lib/zk/install_fork_hooks.rb +37 -0
- data/lib/zk/locker/exclusive_locker.rb +14 -10
- data/lib/zk/locker/locker_base.rb +43 -26
- data/lib/zk/locker/shared_locker.rb +9 -5
- data/lib/zk/logging.rb +29 -7
- data/lib/zk/node_deletion_watcher.rb +167 -0
- data/lib/zk/pool.rb +14 -4
- data/lib/zk/subscription.rb +15 -34
- data/lib/zk/threaded_callback.rb +113 -29
- data/lib/zk/threadpool.rb +136 -40
- data/lib/zk/version.rb +1 -1
- data/spec/logging_progress_bar_formatter.rb +12 -0
- data/spec/shared/client_contexts.rb +13 -1
- data/spec/shared/client_examples.rb +3 -1
- data/spec/spec_helper.rb +28 -3
- data/spec/support/client_forker.rb +49 -8
- data/spec/support/latch.rb +1 -19
- data/spec/support/logging.rb +26 -10
- data/spec/support/wait_watchers.rb +2 -2
- data/spec/zk/00_forked_client_integration_spec.rb +1 -1
- data/spec/zk/client_spec.rb +11 -2
- data/spec/zk/election_spec.rb +21 -7
- data/spec/zk/locker_spec.rb +42 -22
- data/spec/zk/node_deletion_watcher_spec.rb +69 -0
- data/spec/zk/pool_spec.rb +32 -18
- data/spec/zk/threaded_callback_spec.rb +78 -0
- data/spec/zk/threadpool_spec.rb +52 -0
- data/spec/zk/watch_spec.rb +4 -0
- data/zk.gemspec +2 -1
- metadata +36 -10
- data/spec/support/logging_progress_bar_formatter.rb +0 -14
@@ -0,0 +1 @@
|
|
1
|
+
~/vendor/ruby/*.{c,h}
|
data/.dotfiles/rspec-logging
CHANGED
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -8,11 +8,10 @@ source :rubygems
|
|
8
8
|
# keep closer track of this stuff to make bisecting easier and travis more
|
9
9
|
# accurate
|
10
10
|
|
11
|
-
# git 'git://github.com/slyphon/zookeeper.git', :tag => 'dev/zk/
|
12
|
-
# gem 'zookeeper', '~> 1.
|
11
|
+
# git 'git://github.com/slyphon/zookeeper.git', :tag => 'dev/zk/00006' do
|
12
|
+
# gem 'zookeeper', '~> 1.1.0'
|
13
13
|
# end
|
14
14
|
|
15
|
-
|
16
15
|
gem 'rake', :group => [:development, :test]
|
17
16
|
gem 'pry', :group => [:development]
|
18
17
|
|
@@ -28,6 +27,13 @@ platform :mri_19 do
|
|
28
27
|
gem 'simplecov', :group => :coverage, :require => false
|
29
28
|
end
|
30
29
|
|
30
|
+
group :development do
|
31
|
+
gem 'guard', :require => false
|
32
|
+
gem 'guard-rspec', :require => false
|
33
|
+
gem 'guard-shell', :require => false
|
34
|
+
gem 'guard-bundler', :require => false
|
35
|
+
end
|
36
|
+
|
31
37
|
group :test do
|
32
38
|
gem 'rspec', '~> 2.8.0'
|
33
39
|
gem 'flexmock', '~> 0.8.10'
|
data/Guardfile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
dot_rspec_path = File.expand_path('../.rspec', __FILE__)
|
5
|
+
|
6
|
+
rspec_options = File.open('.rspec', &:readlines).map(&:chomp).reject{|n| n =~ /\A(#|\Z)/}
|
7
|
+
|
8
|
+
guard 'bundler' do
|
9
|
+
watch 'Gemfile'
|
10
|
+
watch /\A.+\.gemspec\Z/
|
11
|
+
end
|
12
|
+
|
13
|
+
guard 'rspec', :version => 2 do
|
14
|
+
watch(%r{^spec/.+_spec\.rb$})
|
15
|
+
|
16
|
+
watch(%r%^spec/support/client_forker.rb$%) { 'spec/zk/00_forked_client_integration_spec.rb' }
|
17
|
+
|
18
|
+
watch(%r{^lib/(.+)\.rb$}) do |m|
|
19
|
+
case m[1]
|
20
|
+
when %r{^zk/event_handler$}
|
21
|
+
"spec/zk/watch_spec.rb"
|
22
|
+
when %r{^zk/client/threaded.rb$}
|
23
|
+
["spec/zk/client_spec.rb", "spec/zk/zookeeper_spec.rb"]
|
24
|
+
when %r{^zk/locker/}
|
25
|
+
"spec/zk/locker_spec.rb"
|
26
|
+
when %r{^zk\.rb$}
|
27
|
+
'spec' # run all tests
|
28
|
+
else
|
29
|
+
"spec/#{m[1]}_spec.rb"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
watch('spec/spec_helper.rb') { "spec" }
|
34
|
+
end
|
35
|
+
|
36
|
+
|
data/README.markdown
CHANGED
@@ -65,6 +65,27 @@ In addition to all of that, I would like to think that the public API the ZK::Cl
|
|
65
65
|
[zk-eventmachine]: https://github.com/slyphon/zk-eventmachine
|
66
66
|
|
67
67
|
## NEWS ##
|
68
|
+
### v1.5.0 ###
|
69
|
+
|
70
|
+
Ok, now seriously this time. I think all of the forking issues are done.
|
71
|
+
|
72
|
+
* Implemented a 'stop the world' feature to ensure safety when forking. All threads are stopped, but state is preserved. `fork()` can then be called safely, and after fork returns, all threads will be restarted in the parent, and the connection will be torn down and reopened in the child.
|
73
|
+
|
74
|
+
* The easiest, and supported, way of doing this is now to call `ZK.install_fork_hook` after requiring zk. This will install an `alias_method_chain` style hook around the `Kernel.fork` method, which handles pausing all clients in the parent, calling fork, then resuming in the parent and reconnecting in the child. If you're using ZK in resque, I *highly* recommend using this approach, as it will give the most consistent results.
|
75
|
+
|
76
|
+
In your app that requires an open ZK instance and `fork()`:
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
|
80
|
+
require 'zk'
|
81
|
+
ZK.install_fork_hook
|
82
|
+
|
83
|
+
```
|
84
|
+
|
85
|
+
Then use fork as you normally would.
|
86
|
+
|
87
|
+
* Logging is now off by default, but we now use the excellent, can't-recommend-it-enough, [logging](https://github.com/TwP/logging) gem. If you want to tap into the ZK logs, you can assign a stdlib compliant logger to `ZK.logger` and that will be used. Otherwise, you can use the Logging framework's controls. All ZK logs are consolidated under the 'ZK' logger instance.
|
88
|
+
|
68
89
|
|
69
90
|
### v1.4.1 ###
|
70
91
|
|
@@ -105,24 +126,6 @@ Phusion Passenger and Unicorn users are encouraged to upgrade!
|
|
105
126
|
|
106
127
|
* See the fork-handling documentation [on the wiki](http://github.com/slyphon/zk/wiki/Forking).
|
107
128
|
|
108
|
-
### v1.2.0 ###
|
109
|
-
|
110
|
-
You are __STRONGLY ENCOURAGED__ to go and look at the [CHANGELOG](http://git.io/tPbNBw) from the zookeeper 1.0.0 release
|
111
|
-
|
112
|
-
* NOTICE: This release uses the 1.0 release of the zookeeper gem, which has had a MAJOR REFACTORING of its namespaces. Included in that zookeeper release is a compatibility layer that should ease the transition, but any references to Zookeeper\* heirarchy should be changed.
|
113
|
-
|
114
|
-
* Refactoring related to the zokeeper gem, use all the new names internally now.
|
115
|
-
|
116
|
-
* Create a new Subscription class that will be used as the basis for all subscription-type things.
|
117
|
-
|
118
|
-
* Add new Locker features!
|
119
|
-
* `LockerBase#assert!` - will raise an exception if the lock is not held. This check is not only for local in-memory "are we locked?" state, but will check the connection state and re-run the algorithmic tests that determine if a given Locker implementation actually has the lock.
|
120
|
-
* `LockerBase#acquirable?` - an advisory method that checks if any condition would prevent the receiver from acquiring the lock.
|
121
|
-
|
122
|
-
* Deprecation of the `lock!` and `unlock!` methods. These may change to be exception-raising in a future relase, so document and refactor that `lock` and `unlock` are the way to go.
|
123
|
-
|
124
|
-
* Fixed a race condition in `event_catcher_spec.rb` that would cause 100% cpu usage and hang.
|
125
|
-
|
126
129
|
|
127
130
|
## Caveats
|
128
131
|
|
data/RELEASES.markdown
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
This file notes feature differences and bugfixes contained between releases.
|
2
2
|
|
3
|
+
### v1.5.0 ###
|
4
|
+
|
5
|
+
Ok, now seriously this time. I think all of the forking issues are done.
|
6
|
+
|
7
|
+
* Implemented a 'stop the world' feature to ensure safety when forking. All threads are stopped, but state is preserved. `fork()` can then be called safely, and after fork returns, all threads will be restarted in the parent, and the connection will be torn down and reopened in the child.
|
8
|
+
|
9
|
+
* The easiest, and supported, way of doing this is now to call `ZK.install_fork_hook` after requiring zk. This will install an `alias_method_chain` style hook around the `Kernel.fork` method, which handles pausing all clients in the parent, calling fork, then resuming in the parent and reconnecting in the child. If you're using ZK in resque, I *highly* recommend using this approach, as it will give the most consistent results.
|
10
|
+
|
11
|
+
* Logging is now off by default, and uses the excellent, can't-recommend-it-enough, [logging](https://github.com/TwP/logging) gem. If you want to tap into the ZK logs, you can assign a stdlib compliant logger to `ZK.logger` and that will be used. Otherwise, you can use the Logging framework's controls. All ZK logs are consolidated under the 'ZK' logger instance.
|
12
|
+
|
3
13
|
### v1.4.1 ###
|
4
14
|
|
5
15
|
* True fork safety! The `zookeeper` at 1.1.0 is finally fork-safe. You can now use ZK in whatever forking library you want. Just remember to call `#reopen` on your client instance in the child process before attempting any opersations.
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ if File.exists?(release_ops_path)
|
|
8
8
|
require File.join(release_ops_path, 'releaseops')
|
9
9
|
|
10
10
|
# sets up the multi-ruby zk:test_all rake tasks
|
11
|
-
ReleaseOps::TestTasks.define_for(*%w[1.8.7 1.9.2 jruby
|
11
|
+
ReleaseOps::TestTasks.define_for(*%w[1.8.7 1.9.2 jruby ree 1.9.3])
|
12
12
|
|
13
13
|
# sets up the task :default => 'spec:run' and defines a simple
|
14
14
|
# "run the specs with the current rvm profile" task
|
data/lib/zk.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'logging'
|
4
4
|
require 'zookeeper'
|
5
5
|
|
6
6
|
# XXX: after 1.0 we'll need this
|
@@ -12,21 +12,28 @@ require 'monitor'
|
|
12
12
|
require 'set'
|
13
13
|
require 'time'
|
14
14
|
require 'date'
|
15
|
+
require 'weakref'
|
15
16
|
|
16
17
|
module ZK
|
18
|
+
# just like stdlib Monitor but provides the SAME API AS MUTEX, FFS!
|
19
|
+
# @private
|
20
|
+
class Monitor < Zookeeper::Monitor
|
21
|
+
end
|
17
22
|
end
|
18
23
|
|
19
24
|
require 'zk/core_ext'
|
20
|
-
require 'zk/logging'
|
21
25
|
require 'zk/exceptions'
|
22
26
|
require 'zk/extensions'
|
27
|
+
require 'zk/logging'
|
23
28
|
require 'zk/event'
|
24
29
|
require 'zk/stat'
|
25
30
|
require 'zk/subscription'
|
31
|
+
require 'zk/fork_hook'
|
26
32
|
require 'zk/threadpool'
|
27
33
|
require 'zk/threaded_callback'
|
28
34
|
require 'zk/event_handler_subscription'
|
29
35
|
require 'zk/event_handler'
|
36
|
+
require 'zk/node_deletion_watcher'
|
30
37
|
require 'zk/message_queue'
|
31
38
|
require 'zk/locker'
|
32
39
|
require 'zk/election'
|
@@ -46,9 +53,7 @@ module ZK
|
|
46
53
|
KILL_TOKEN = Object.new
|
47
54
|
end
|
48
55
|
|
49
|
-
unless
|
50
|
-
@logger = Logger.new($stderr).tap { |n| n.level = ENV['ZK_DEBUG'] ? Logger::DEBUG : Logger::ERROR }
|
51
|
-
end
|
56
|
+
@@logger = nil unless defined? @@logger
|
52
57
|
|
53
58
|
@default_host = 'localhost' unless @default_host
|
54
59
|
@default_port = 2181 unless @default_port
|
@@ -65,14 +70,6 @@ module ZK
|
|
65
70
|
attr_accessor :default_chroot
|
66
71
|
end
|
67
72
|
|
68
|
-
# @private
|
69
|
-
def self.default_connection_string
|
70
|
-
"#{default_host}:#{default_port}".tap do |str|
|
71
|
-
# XXX: this is seriously blech
|
72
|
-
str.replace(File.join(str, default_chroot)) if default_chroot != ''
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
73
|
# The logger used by the ZK library. uses a Logger stderr with Logger::ERROR
|
77
74
|
# level. The only thing that should ever be logged are exceptions that are
|
78
75
|
# swallowed by background threads.
|
@@ -81,12 +78,20 @@ module ZK
|
|
81
78
|
# implements the stdllb Logger API.
|
82
79
|
#
|
83
80
|
def self.logger
|
84
|
-
|
81
|
+
@@logger
|
85
82
|
end
|
86
83
|
|
87
|
-
#
|
88
|
-
def self.logger=(
|
89
|
-
|
84
|
+
# set the ZK logger instance
|
85
|
+
def self.logger=(log)
|
86
|
+
@@logger = log
|
87
|
+
end
|
88
|
+
|
89
|
+
# @private
|
90
|
+
def self.default_connection_string
|
91
|
+
"#{default_host}:#{default_port}".tap do |str|
|
92
|
+
# XXX: this is seriously blech
|
93
|
+
str.replace(File.join(str, default_chroot)) if default_chroot != ''
|
94
|
+
end
|
90
95
|
end
|
91
96
|
|
92
97
|
# Create a new ZK::Client instance. If no arguments are given, the default
|
@@ -205,9 +210,10 @@ module ZK
|
|
205
210
|
cnx = new(*args)
|
206
211
|
yield cnx
|
207
212
|
ensure
|
208
|
-
|
209
|
-
|
210
|
-
|
213
|
+
if cnx
|
214
|
+
cnx.close!
|
215
|
+
Thread.pass until cnx.closed?
|
216
|
+
end
|
211
217
|
end
|
212
218
|
|
213
219
|
# creates a new ZK::Pool::Bounded with the default options.
|
@@ -292,7 +298,6 @@ module ZK
|
|
292
298
|
open(host) do |zk| # do path stuff with the virgin connection
|
293
299
|
unless zk.exists?(chroot_path) # someting must be done
|
294
300
|
if chroot_opt == :create # here, let me...
|
295
|
-
logger.debug { "creating chroot path #{chroot_path}" }
|
296
301
|
zk.mkdir_p(chroot_path) # ...get that for you
|
297
302
|
else # careful with that axe
|
298
303
|
raise Exceptions::ChrootPathDoesNotExistError.new(host, chroot_path) # ...eugene
|
@@ -304,3 +309,5 @@ module ZK
|
|
304
309
|
end
|
305
310
|
end
|
306
311
|
|
312
|
+
ZK::Logging.set_default
|
313
|
+
|
data/lib/zk/client/threaded.rb
CHANGED
@@ -140,8 +140,15 @@ module ZK
|
|
140
140
|
@reconnect = opts.fetch(:reconnect, true)
|
141
141
|
|
142
142
|
@mutex = Monitor.new
|
143
|
+
@cond = @mutex.new_cond
|
143
144
|
|
144
|
-
@
|
145
|
+
@cli_state = :running # this is to distinguish between *our* state and the underlying connection state
|
146
|
+
|
147
|
+
@fork_subs = [
|
148
|
+
ForkHook.prepare_for_fork(method(:pause_before_fork_in_parent)),
|
149
|
+
ForkHook.after_fork_in_parent(method(:resume_after_fork_in_parent)),
|
150
|
+
ForkHook.after_fork_in_child(method(:reopen)),
|
151
|
+
]
|
145
152
|
|
146
153
|
yield self if block_given?
|
147
154
|
|
@@ -169,25 +176,69 @@ module ZK
|
|
169
176
|
# ok, just to sanity check here
|
170
177
|
raise "[BUG] we hit the fork-reopening code in JRuby!!" if defined?(::JRUBY_VERSION)
|
171
178
|
|
172
|
-
logger.debug { "
|
179
|
+
logger.debug { "reopening everything, fork detected!" }
|
173
180
|
|
174
181
|
@mutex = Monitor.new
|
175
|
-
@threadpool.reopen_after_fork! # prune dead threadpool threads after a fork()
|
176
|
-
@event_handler.reopen_after_fork!
|
177
182
|
@pid = Process.pid
|
183
|
+
@cli_state = :running # reset state to running if we were paused
|
178
184
|
|
179
185
|
old_cnx, @cnx = @cnx, nil
|
180
186
|
old_cnx.close! if old_cnx # && !old_cnx.closed?
|
187
|
+
|
188
|
+
@mutex.synchronize do
|
189
|
+
# it's important that we're holding the lock, as access to 'cnx' is
|
190
|
+
# synchronized, and we want to avoid a race where event handlers
|
191
|
+
# might see a nil connection. I've seen this exception occur *once*
|
192
|
+
# so it's pretty rare (it was on 1.8.7 too), but just to be double
|
193
|
+
# extra paranoid
|
194
|
+
|
195
|
+
@event_handler.reopen_after_fork!
|
196
|
+
@threadpool.reopen_after_fork! # prune dead threadpool threads after a fork()
|
197
|
+
|
198
|
+
connect
|
199
|
+
end
|
181
200
|
else
|
182
|
-
|
183
|
-
|
201
|
+
@mutex.synchronize do
|
202
|
+
if @cli_state == :paused
|
203
|
+
# XXX: what to do in this case? does it matter?
|
204
|
+
end
|
205
|
+
|
206
|
+
logger.debug { "reopening, no fork detected" }
|
207
|
+
@cnx.reopen(timeout) # ok, we werent' forked, so just reopen
|
208
|
+
end
|
184
209
|
end
|
185
210
|
|
186
|
-
@mutex.synchronize { @close_requested = false }
|
187
|
-
connect
|
188
211
|
state
|
189
212
|
end
|
190
213
|
|
214
|
+
# Before forking, call this method to peform a "stop the world" operation on all
|
215
|
+
# objects associated with this connection. This means that this client will spin down
|
216
|
+
# and join all threads (so make sure none of your callbacks will block forever),
|
217
|
+
# and will tke no action to keep the session alive. With the default settings,
|
218
|
+
# if a ping is not received within 20 seconds, the session is considered dead
|
219
|
+
# and must be re-established so be sure to call {#resume_after_fork_in_parent}
|
220
|
+
# before that deadline, or you will have to re-establish your session.
|
221
|
+
#
|
222
|
+
# @raise [InvalidStateError] when called and not in running? state
|
223
|
+
def pause_before_fork_in_parent
|
224
|
+
@mutex.synchronize do
|
225
|
+
raise InvalidStateError, "client must be running? when you call #{__method__}" unless running?
|
226
|
+
@cli_state = :paused
|
227
|
+
end
|
228
|
+
logger.debug { "#{self.class}##{__method__}" }
|
229
|
+
[@event_handler, @threadpool, @cnx].each(&:pause_before_fork_in_parent)
|
230
|
+
end
|
231
|
+
|
232
|
+
def resume_after_fork_in_parent
|
233
|
+
@mutex.synchronize do
|
234
|
+
raise InvalidStateError, "client must be paused? when you call #{__method__}" unless paused?
|
235
|
+
@cli_state = :running
|
236
|
+
end
|
237
|
+
|
238
|
+
logger.debug { "#{self.class}##{__method__}" }
|
239
|
+
[@cnx, @event_handler, @threadpool].each(&:resume_after_fork_in_parent)
|
240
|
+
end
|
241
|
+
|
191
242
|
# (see Base#close!)
|
192
243
|
#
|
193
244
|
# @note We will make our best effort to do the right thing if you call
|
@@ -198,8 +249,9 @@ module ZK
|
|
198
249
|
#
|
199
250
|
def close!
|
200
251
|
@mutex.synchronize do
|
201
|
-
return if @
|
202
|
-
|
252
|
+
return if [:closed, :close_requested].include?(@cli_state)
|
253
|
+
# logger.debug { "moving to :close_requested state" }
|
254
|
+
@cli_state = :close_requested
|
203
255
|
end
|
204
256
|
|
205
257
|
on_tpool = on_threadpool?
|
@@ -213,18 +265,24 @@ module ZK
|
|
213
265
|
# and wait for it to exit
|
214
266
|
#
|
215
267
|
shutdown_thread = Thread.new do
|
216
|
-
@threadpool.shutdown(
|
268
|
+
@threadpool.shutdown(10)
|
217
269
|
super
|
218
|
-
end
|
219
270
|
|
220
|
-
|
271
|
+
@mutex.synchronize do
|
272
|
+
# logger.debug { "moving to :closed state" }
|
273
|
+
@cli_state = :closed
|
274
|
+
end
|
275
|
+
end
|
221
276
|
|
222
|
-
|
277
|
+
on_tpool ? shutdown_thread : shutdown_thread.join
|
223
278
|
end
|
224
279
|
|
225
280
|
# {see Base#close}
|
226
281
|
def close
|
227
282
|
super
|
283
|
+
subs, @fork_subs = @fork_subs, []
|
284
|
+
subs.each(&:unsubscribe)
|
285
|
+
nil
|
228
286
|
end
|
229
287
|
|
230
288
|
# (see Threadpool#on_threadpool?)
|
@@ -245,12 +303,13 @@ module ZK
|
|
245
303
|
return unless @reconnect
|
246
304
|
|
247
305
|
@mutex.synchronize do
|
248
|
-
unless
|
306
|
+
unless dead_or_dying? # a legitimate shutdown case
|
249
307
|
|
250
308
|
logger.error { "Got event #{event.state_name}, calling reopen(0)! things may be messed up until this works itself out!" }
|
251
309
|
|
252
310
|
# reopen(0) means that we don't want to wait for the connection
|
253
|
-
# to reach the connected state before returning
|
311
|
+
# to reach the connected state before returning as we're on the
|
312
|
+
# event thread.
|
254
313
|
reopen(0)
|
255
314
|
end
|
256
315
|
end
|
@@ -259,11 +318,42 @@ module ZK
|
|
259
318
|
logger.error { "BUG: Exception caught in raw_event_handler: #{e.to_std_format}" }
|
260
319
|
end
|
261
320
|
|
321
|
+
def closed?
|
322
|
+
return true if @mutex.synchronize { @cli_state == :closed }
|
323
|
+
super
|
324
|
+
end
|
325
|
+
|
326
|
+
# are we in running (not-paused) state?
|
327
|
+
def running?
|
328
|
+
@mutex.synchronize { @cli_state == :running }
|
329
|
+
end
|
330
|
+
|
331
|
+
# are we in paused state?
|
332
|
+
def paused?
|
333
|
+
@mutex.synchronize { @cli_state == :paused }
|
334
|
+
end
|
335
|
+
|
336
|
+
# has shutdown time arrived?
|
337
|
+
def close_requested?
|
338
|
+
@mutex.synchronize { @cli_state == :close_requested }
|
339
|
+
end
|
340
|
+
|
262
341
|
protected
|
342
|
+
# in the threaded version of the client, synchronize access around cnx
|
343
|
+
# so that callers don't wind up with a nil object when we're in the middle
|
344
|
+
# of reopening it
|
345
|
+
def cnx
|
346
|
+
@mutex.synchronize { @cnx }
|
347
|
+
end
|
348
|
+
|
263
349
|
# @private
|
264
350
|
def create_connection(*args)
|
265
351
|
::Zookeeper.new(*args)
|
266
352
|
end
|
267
|
-
|
353
|
+
|
354
|
+
def dead_or_dying?
|
355
|
+
(@cli_state == :close_requested) || (@cli_state == :closed)
|
356
|
+
end
|
357
|
+
end
|
268
358
|
end
|
269
359
|
end
|