zookeeper 1.2.6-java → 1.2.7-java

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 CHANGED
@@ -1,3 +1,22 @@
1
+ v1.2.7 further lock adjustments, deadlock risk reduction
2
+
3
+ * Refactor ZookeeperBase to not hold onto the mutex while waiting
4
+ for the dispatch thread to exit and the CZookeeper instance to close.
5
+ Instead, lock, nil out @czk, and unlock (which will cause all calls to
6
+ raise NotConnected), and then carry on with the shutdown procedure, greatly
7
+ reducing the chances of a deadlock. Also add a hardcoded 30 second timeout
8
+ to the join of the shutdown thread, that way we won't hang indefinitely in
9
+ the case of an unforseen condition.
10
+
11
+ * Improve the CZookeeper#wait_until_connected to use a deadline approach
12
+ to waiting for both running and connected states. Also, handle the
13
+ 'nil' (wait forever) timeout properly.
14
+
15
+ * Wake all waiting threads on all ConditionVariables when CZookeeper#shut_down!
16
+ is called
17
+
18
+ v1.2.6 fix build on fedora
19
+
1
20
  v1.2.5 cleanup locking in ZookeeperBase
2
21
 
3
22
  * There were several situations where we would hold the lock before calling
data/ext/c_zookeeper.rb CHANGED
@@ -161,7 +161,7 @@ class CZookeeper
161
161
 
162
162
  def state
163
163
  return ZOO_CLOSED_STATE if closed?
164
- submit_and_block(:state)
164
+ @mutex.synchronize { @state }
165
165
  end
166
166
 
167
167
  # this implementation is gross, but i don't really see another way of doing it
@@ -172,12 +172,22 @@ class CZookeeper
172
172
  # if timeout is nil, we never time out, and wait forever for CONNECTED state
173
173
  #
174
174
  def wait_until_connected(timeout=10)
175
+ time_to_stop = timeout ? Time.now + timeout : nil
175
176
 
176
177
  return false unless wait_until_running(timeout)
177
178
 
178
179
  @mutex.synchronize do
179
- # TODO: use deadline here
180
- @state_cond.wait(timeout) unless (@state == ZOO_CONNECTED_STATE)
180
+ while true
181
+ if timeout
182
+ now = Time.now
183
+ break if (@state == ZOO_CONNECTED_STATE) || @_shutting_down || @_closed || (now > time_to_stop)
184
+ delay = time_to_stop.to_f - now.to_f
185
+ @state_cond.wait(delay)
186
+ else
187
+ break if (@state == ZOO_CONNECTED_STATE) || @_shutting_down || @_closed
188
+ @state_cond.wait
189
+ end
190
+ end
181
191
  end
182
192
 
183
193
  connected?
@@ -343,7 +353,12 @@ class CZookeeper
343
353
  def shut_down!
344
354
  logger.debug { "##{__method__}" }
345
355
 
346
- @mutex.synchronize { @_shutting_down = true }
356
+ @mutex.synchronize do
357
+ @_shutting_down = true
358
+ # ollie ollie oxen all home free!
359
+ @state_cond.broadcast
360
+ @running_cond.broadcast
361
+ end
347
362
  end
348
363
 
349
364
  # called by underlying C code to signal we're running
@@ -355,11 +370,5 @@ class CZookeeper
355
370
  @running_cond.broadcast
356
371
  end
357
372
  end
358
-
359
- # def notify_state_change!
360
- # @mutex.synchronize do
361
- # @state_cond.broadcast
362
- # end
363
- # end
364
373
  end
365
374
  end
@@ -130,20 +130,34 @@ class ZookeeperBase
130
130
  # potentially dangerous and should only be called after a fork() to close
131
131
  # this instance
132
132
  def close!
133
- @czk && @czk.close
133
+ inst, @czk = @czk, nil
134
+ inst && inst.close
134
135
  end
135
136
 
136
137
  # close the connection normally, stops the dispatch thread and closes the
137
138
  # underlying connection cleanly
138
139
  def close
139
- shutdown_thread = Thread.new do
140
- @mutex.synchronize do
140
+ sd_thread = nil
141
+
142
+ @mutex.synchronize do
143
+ return unless @czk
144
+ inst, @czk = @czk, nil
145
+
146
+ sd_thread = Thread.new(inst) do |_inst|
141
147
  stop_dispatch_thread!
142
- close!
148
+ _inst.close
149
+ end
150
+ end
151
+
152
+ # if we're on the event dispatch thread for some stupid reason, then don't join
153
+ unless event_dispatch_thread?
154
+ # hard-coded 30 second delay, don't hang forever
155
+ if sd_thread.join(30) != sd_thread
156
+ logger.error { "timed out waiting for shutdown thread to exit" }
143
157
  end
144
158
  end
145
159
 
146
- shutdown_thread.join unless event_dispatch_thread?
160
+ nil
147
161
  end
148
162
 
149
163
  # the C lib doesn't strip the chroot path off of returned path values, which
@@ -10,15 +10,7 @@ module Common
10
10
  @dispatcher && (@dispatcher == Thread.current)
11
11
  end
12
12
 
13
- protected
14
- def get_next_event(blocking=true)
15
- @event_queue.pop(!blocking).tap do |event|
16
- logger.debug { "#{self.class}##{__method__} delivering event #{event.inspect}" }
17
- end
18
- rescue ThreadError
19
- nil
20
- end
21
-
13
+ private
22
14
  def setup_call(meth_name, opts)
23
15
  req_id = nil
24
16
  @mutex.synchronize {
@@ -71,21 +63,9 @@ protected
71
63
  return
72
64
  end
73
65
 
74
- logger.debug { "starting dispatch thread" }
75
-
76
- @dispatcher = Thread.new do
77
- while true
78
- begin
79
- dispatch_next_callback(get_next_event(true))
80
- rescue QueueWithPipe::ShutdownException
81
- logger.info { "dispatch thread exiting, got shutdown exception" }
82
- break
83
- rescue Exception => e
84
- $stderr.puts ["#{e.class}: #{e.message}", e.backtrace.map { |n| "\t#{n}" }.join("\n")].join("\n")
85
- end
86
- end
87
- signal_dispatch_thread_exit!
88
- end
66
+ logger.debug { "starting dispatch thread" }
67
+
68
+ @dispatcher = Thread.new(&method(:dispatch_thread_body))
89
69
  end
90
70
  end
91
71
 
@@ -120,11 +100,12 @@ protected
120
100
  end
121
101
  end
122
102
 
123
- def signal_dispatch_thread_exit!
124
- @mutex.synchronize do
125
- logger.debug { "dispatch thread exiting!" }
126
- @dispatch_shutdown_cond.broadcast
103
+ def get_next_event(blocking=true)
104
+ @event_queue.pop(!blocking).tap do |event|
105
+ logger.debug { "#{self.class}##{__method__} delivering event #{event.inspect}" }
127
106
  end
107
+ rescue ThreadError
108
+ nil
128
109
  end
129
110
 
130
111
  def dispatch_next_callback(hash)
@@ -177,7 +158,28 @@ protected
177
158
  end
178
159
  end
179
160
 
180
- private
161
+ def dispatch_thread_body
162
+ while true
163
+ begin
164
+ dispatch_next_callback(get_next_event(true))
165
+ rescue QueueWithPipe::ShutdownException
166
+ logger.info { "dispatch thread exiting, got shutdown exception" }
167
+ return
168
+ rescue Exception => e
169
+ $stderr.puts ["#{e.class}: #{e.message}", e.backtrace.map { |n| "\t#{n}" }.join("\n")].join("\n")
170
+ end
171
+ end
172
+ ensure
173
+ signal_dispatch_thread_exit!
174
+ end
175
+
176
+ def signal_dispatch_thread_exit!
177
+ @mutex.synchronize do
178
+ logger.debug { "dispatch thread exiting!" }
179
+ @dispatch_shutdown_cond.broadcast
180
+ end
181
+ end
182
+
181
183
  def prettify_event(hash)
182
184
  hash.dup.tap do |h|
183
185
  # pretty up the event display
@@ -1,4 +1,4 @@
1
1
  module Zookeeper
2
- VERSION = '1.2.6'
2
+ VERSION = '1.2.7'
3
3
  DRIVER_VERSION = '3.3.5'
4
4
  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: 19
4
+ hash: 17
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 2
9
- - 6
10
- version: 1.2.6
9
+ - 7
10
+ version: 1.2.7
11
11
  platform: java
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-06-04 00:00:00 Z
23
+ date: 2012-06-05 00:00:00 Z
24
24
  dependencies:
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: backports