zookeeper-ng 1.5.2.1-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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.ctags_paths +1 -0
  3. data/.dotfiles/ruby-gemset +1 -0
  4. data/.dotfiles/ruby-version +1 -0
  5. data/.dotfiles/rvmrc +2 -0
  6. data/.github/workflows/build.yml +57 -0
  7. data/.gitignore +19 -0
  8. data/.gitmodules +3 -0
  9. data/CHANGELOG +408 -0
  10. data/Gemfile +30 -0
  11. data/Guardfile +8 -0
  12. data/LICENSE +23 -0
  13. data/Manifest +29 -0
  14. data/README.markdown +62 -0
  15. data/Rakefile +121 -0
  16. data/cause-abort.rb +117 -0
  17. data/ext/.gitignore +6 -0
  18. data/ext/Rakefile +41 -0
  19. data/ext/c_zookeeper.rb +398 -0
  20. data/ext/common.h +17 -0
  21. data/ext/dbg.h +53 -0
  22. data/ext/depend +5 -0
  23. data/ext/event_lib.c +740 -0
  24. data/ext/event_lib.h +175 -0
  25. data/ext/extconf.rb +103 -0
  26. data/ext/generate_gvl_code.rb +321 -0
  27. data/ext/patches/zkc-3.3.5-network.patch +24 -0
  28. data/ext/patches/zkc-3.4.5-buffer-overflow.patch +11 -0
  29. data/ext/patches/zkc-3.4.5-config.patch +5454 -0
  30. data/ext/patches/zkc-3.4.5-fetch-and-add.patch +16 -0
  31. data/ext/patches/zkc-3.4.5-logging.patch +41 -0
  32. data/ext/patches/zkc-3.4.5-out-of-order-ping.patch +163 -0
  33. data/ext/patches/zkc-3.4.5-yosemite-htonl-fix.patch +102 -0
  34. data/ext/zkc-3.4.5.tar.gz +0 -0
  35. data/ext/zkrb.c +1080 -0
  36. data/ext/zkrb_wrapper.c +775 -0
  37. data/ext/zkrb_wrapper.h +350 -0
  38. data/ext/zkrb_wrapper_compat.c +15 -0
  39. data/ext/zkrb_wrapper_compat.h +11 -0
  40. data/ext/zookeeper_base.rb +256 -0
  41. data/java/java_base.rb +501 -0
  42. data/lib/zookeeper/acls.rb +44 -0
  43. data/lib/zookeeper/callbacks.rb +108 -0
  44. data/lib/zookeeper/client.rb +30 -0
  45. data/lib/zookeeper/client_methods.rb +282 -0
  46. data/lib/zookeeper/common/queue_with_pipe.rb +110 -0
  47. data/lib/zookeeper/common.rb +122 -0
  48. data/lib/zookeeper/compatibility.rb +138 -0
  49. data/lib/zookeeper/constants.rb +97 -0
  50. data/lib/zookeeper/continuation.rb +223 -0
  51. data/lib/zookeeper/core_ext.rb +58 -0
  52. data/lib/zookeeper/em_client.rb +55 -0
  53. data/lib/zookeeper/exceptions.rb +135 -0
  54. data/lib/zookeeper/forked.rb +19 -0
  55. data/lib/zookeeper/latch.rb +34 -0
  56. data/lib/zookeeper/logger/forwarding_logger.rb +84 -0
  57. data/lib/zookeeper/logger.rb +39 -0
  58. data/lib/zookeeper/monitor.rb +19 -0
  59. data/lib/zookeeper/rake_tasks.rb +165 -0
  60. data/lib/zookeeper/request_registry.rb +153 -0
  61. data/lib/zookeeper/stat.rb +21 -0
  62. data/lib/zookeeper/version.rb +4 -0
  63. data/lib/zookeeper.rb +115 -0
  64. data/notes.txt +14 -0
  65. data/scripts/upgrade-1.0-sed-alike.rb +46 -0
  66. data/spec/c_zookeeper_spec.rb +51 -0
  67. data/spec/chrooted_connection_spec.rb +83 -0
  68. data/spec/compatibilty_spec.rb +8 -0
  69. data/spec/default_watcher_spec.rb +41 -0
  70. data/spec/em_spec.rb +51 -0
  71. data/spec/ext/zookeeper_base_spec.rb +19 -0
  72. data/spec/forked_connection_spec.rb +122 -0
  73. data/spec/latch_spec.rb +24 -0
  74. data/spec/log4j.properties +17 -0
  75. data/spec/shared/all_success_return_values.rb +10 -0
  76. data/spec/shared/connection_examples.rb +1081 -0
  77. data/spec/spec_helper.rb +61 -0
  78. data/spec/support/00_logging.rb +38 -0
  79. data/spec/support/10_spawn_zookeeper.rb +20 -0
  80. data/spec/support/progress_formatter.rb +15 -0
  81. data/spec/support/zookeeper_spec_helpers.rb +96 -0
  82. data/spec/zookeeper_spec.rb +24 -0
  83. data/zookeeper.gemspec +46 -0
  84. data/zoomonkey/duplicates +3 -0
  85. data/zoomonkey/zoomonkey.rb +194 -0
  86. metadata +185 -0
data/Rakefile ADDED
@@ -0,0 +1,121 @@
1
+ release_ops_path = File.expand_path('../releaseops/lib', __FILE__)
2
+
3
+ # if the special submodule is availabe, use it
4
+ # we use a submodule because it doesn't depend on anything else (*cough* bundler)
5
+ # and can be shared across projects
6
+ #
7
+ if File.exists?(release_ops_path)
8
+ require File.join(release_ops_path, 'releaseops')
9
+
10
+ # sets up the multi-ruby zk:test_all rake tasks
11
+ ReleaseOps::TestTasks.define_for(*%w[1.8.7 1.9.2 jruby rbx ree 1.9.3])
12
+
13
+ # sets up the task :default => 'spec:run' and defines a simple
14
+ # "run the specs with the current rvm profile" task
15
+ ReleaseOps::TestTasks.define_simple_default_for_travis
16
+
17
+ # Define a task to run code coverage tests
18
+ ReleaseOps::TestTasks.define_simplecov_tasks
19
+
20
+ # set up yard:server, yard:gems, and yard:clean tasks
21
+ # for doing documentation stuff
22
+ ReleaseOps::YardTasks.define
23
+
24
+ task :clean => 'yard:clean'
25
+
26
+ namespace :zk do
27
+ namespace :gems do
28
+ desc "Build gems to prepare for a release. Requires TAG="
29
+ task :build do
30
+ require 'tmpdir'
31
+
32
+ raise "You must specify a TAG" unless ENV['TAG']
33
+
34
+ ReleaseOps.with_tmpdir(:prefix => 'zookeeper') do |tmpdir|
35
+ tag = ENV['TAG']
36
+
37
+ sh "git clone . #{tmpdir}"
38
+
39
+ orig_dir = Dir.getwd
40
+
41
+ Dir.chdir tmpdir do
42
+ sh "git co #{tag} && git reset --hard && git clean -fdx"
43
+
44
+ ENV['JAVA_GEM'] = nil
45
+ sh "gem build zookeeper.gemspec"
46
+ sh "env JAVA_GEM=1 gem build zookeeper.gemspec"
47
+
48
+ mv FileList['*.gem'], orig_dir
49
+ end
50
+ end
51
+ end
52
+
53
+ desc "Release gems that have been built"
54
+ task :push do
55
+ gems = FileList['*.gem']
56
+ raise "No gemfiles to push!" if gems.empty?
57
+
58
+ gems.each do |gem|
59
+ sh "gem push #{gem}"
60
+ end
61
+ end
62
+
63
+ task :clean do
64
+ rm_rf FileList['*.gem']
65
+ end
66
+
67
+ task :all => [:build, :push, :clean]
68
+ end
69
+ end
70
+ end
71
+
72
+ task :clobber do
73
+ rm_rf 'tmp'
74
+ end
75
+
76
+ # cargo culted from http://blog.flavorjon.es/2009/06/easily-valgrind-gdb-your-ruby-c.html
77
+ VALGRIND_BASIC_OPTS = '--num-callers=50 --error-limit=no --partial-loads-ok=yes --undef-value-errors=no --trace-children=yes'
78
+
79
+ task 'valgrind' do
80
+ Dir.chdir 'ext' do
81
+ sh "rake clean build"
82
+ end
83
+
84
+ sh "valgrind #{VALGRIND_BASIC_OPTS} bundle exec rspec spec"
85
+ end
86
+
87
+ namespace :build do
88
+ task :clean do
89
+ Dir.chdir 'ext' do
90
+ sh 'rake clean'
91
+ end
92
+
93
+ Rake::Task['build'].invoke
94
+ end
95
+
96
+ task :clobber do
97
+ Dir.chdir 'ext' do
98
+ sh 'rake clobber'
99
+ end
100
+
101
+ Rake::Task['build'].invoke
102
+ end
103
+ end
104
+
105
+ desc "Build C component"
106
+ task :build do
107
+ Dir.chdir 'ext' do
108
+ sh "rake"
109
+ end
110
+ end
111
+
112
+ task 'spec:run' => 'build:clean' unless defined?(::JRUBY_VERSION)
113
+
114
+ task 'ctags' do
115
+ sh 'bundle-ctags'
116
+ end
117
+
118
+ # because i'm a creature of habit
119
+ task 'mb:test_all' => 'zk:test_all'
120
+
121
+
data/cause-abort.rb ADDED
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'zookeeper'
4
+ require File.expand_path('../spec/support/zookeeper_spec_helpers', __FILE__)
5
+
6
+ class CauseAbort
7
+ include Zookeeper::Logger
8
+ include Zookeeper::SpecHelpers
9
+
10
+ attr_reader :path, :pids_root, :data
11
+
12
+ def initialize
13
+ @path = "/_zktest_"
14
+ @pids_root = "#{@path}/pids"
15
+ @data = 'underpants'
16
+ end
17
+
18
+ def before
19
+ @zk = Zookeeper.new('localhost:2181')
20
+ rm_rf(@zk, path)
21
+ logger.debug { "----------------< BEFORE: END >-------------------" }
22
+ end
23
+
24
+ def process_alive?(pid)
25
+ Process.kill(0, @pid)
26
+ true
27
+ rescue Errno::ESRCH
28
+ false
29
+ end
30
+
31
+ def wait_for_child_safely(pid, timeout=5)
32
+ time_to_stop = Time.now + timeout
33
+
34
+ until Time.now > time_to_stop
35
+ if a = Process.wait2(@pid, Process::WNOHANG)
36
+ return a.last
37
+ else
38
+ sleep(0.01)
39
+ end
40
+ end
41
+
42
+ nil
43
+ end
44
+
45
+ def try_pause_and_resume
46
+ @zk.pause
47
+ logger.debug { "paused" }
48
+ @zk.resume
49
+ logger.debug { "resumed" }
50
+ @zk.close
51
+ logger.debug { "closed" }
52
+ end
53
+
54
+ def run_test
55
+ logger.debug { "----------------< TEST: BEGIN >-------------------" }
56
+ @zk.wait_until_connected
57
+
58
+ mkdir_p(@zk, pids_root)
59
+
60
+ # the parent's pid path
61
+ @zk.create(:path => "#{pids_root}/#{$$}", :data => $$.to_s)
62
+
63
+ @latch = Zookeeper::Latch.new
64
+ @event = nil
65
+
66
+ cb = proc do |h|
67
+ logger.debug { "watcher called back: #{h.inspect}" }
68
+ @event = h
69
+ @latch.release
70
+ end
71
+
72
+ @zk.stat(:path => "#{pids_root}/child", :watcher => cb)
73
+
74
+ logger.debug { "-------------------> FORK <---------------------------" }
75
+
76
+ @pid = fork do
77
+ rand_sleep = rand()
78
+
79
+ $stderr.puts "sleeping for rand_sleep: #{rand_sleep}"
80
+ sleep(rand_sleep)
81
+
82
+ logger.debug { "reopening connection in child: #{$$}" }
83
+ @zk.reopen
84
+ logger.debug { "creating path" }
85
+ rv = @zk.create(:path => "#{pids_root}/child", :data => $$.to_s)
86
+ logger.debug { "created path #{rv[:path]}" }
87
+ @zk.close
88
+
89
+ logger.debug { "close finished" }
90
+ exit!(0)
91
+ end
92
+
93
+ event_waiter_th = Thread.new do
94
+ @latch.await(5) unless @event
95
+ @event
96
+ end
97
+
98
+ logger.debug { "waiting on child #{@pid}" }
99
+
100
+ status = wait_for_child_safely(@pid)
101
+ raise "Child process did not exit, likely hung" unless status
102
+
103
+ if event_waiter_th.join(5) == event_waiter_th
104
+ logger.warn { "event waiter has not received events" }
105
+ end
106
+
107
+ exit(@event.nil? ? 1 : 0)
108
+ end
109
+
110
+ def run
111
+ before
112
+ run_test
113
+ # try_pause_and_resume
114
+ end
115
+ end
116
+
117
+ CauseAbort.new.run
data/ext/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ bin
2
+ include
3
+ lib
4
+ *.bundle
5
+
6
+ c
data/ext/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'rbconfig'
2
+
3
+ ZKRB_WRAPPER = %w[zkrb_wrapper.c zkrb_wrapper.h]
4
+
5
+ namespace :zkrb do
6
+ task :clean do
7
+ if File.exists?('Makefile')
8
+ sh 'make clean'
9
+ rm 'Makefile' # yep, regenerate this
10
+ else
11
+ $stderr.puts "nothing to clean, no Makefile"
12
+ end
13
+ end
14
+
15
+ task :clobber => :clean do
16
+ rm_rf %w[Makefile c lib bin include ._c] + ZKRB_WRAPPER
17
+ end
18
+ end
19
+
20
+ task :clean => 'zkrb:clean'
21
+ task :clobber => 'zkrb:clobber'
22
+ task :wrappers => ZKRB_WRAPPER
23
+ task :default => :build
24
+
25
+ file 'zkrb_wrapper.c' => 'generate_gvl_code.rb' do
26
+ sh "ruby generate_gvl_code.rb code"
27
+ end
28
+
29
+ file 'zkrb_wrapper.h' => 'generate_gvl_code.rb' do
30
+ sh "ruby generate_gvl_code.rb headers"
31
+ end
32
+
33
+ file 'Makefile' do
34
+ sh "ruby extconf.rb"
35
+ end
36
+
37
+ task :build => [ 'Makefile', :wrappers ] do
38
+ sh 'make'
39
+ end
40
+
41
+
@@ -0,0 +1,398 @@
1
+ Zookeeper.require_lib(
2
+ 'zookeeper/logger',
3
+ 'zookeeper/common',
4
+ 'zookeeper/constants',
5
+ 'zookeeper/exceptions' # zookeeper_c depends on exceptions defined in here
6
+ )
7
+
8
+ Zookeeper.require_root 'ext/zookeeper_c'
9
+
10
+ # require File.expand_path('../zookeeper_c', __FILE__)
11
+
12
+ module Zookeeper
13
+ # NOTE: this class extending (opening) the class defined in zkrb.c
14
+ class CZookeeper
15
+ include Forked
16
+ include Constants
17
+ include Exceptions
18
+ include Logger
19
+
20
+ DEFAULT_RECEIVE_TIMEOUT_MSEC = 10000
21
+
22
+ class GotNilEventException < StandardError; end
23
+
24
+ attr_accessor :original_pid
25
+
26
+ # assume we're at debug level
27
+ def self.get_debug_level
28
+ @debug_level ||= ZOO_LOG_LEVEL_INFO
29
+ end
30
+
31
+ def self.set_debug_level(value)
32
+ @debug_level = value
33
+ set_zkrb_debug_level(value)
34
+ end
35
+
36
+ # wrap these calls in our sync->async special sauce
37
+ %w[get set exists create delete get_acl set_acl get_children add_auth].each do |sym|
38
+ class_eval(<<-EOS, __FILE__, __LINE__+1)
39
+ def #{sym}(*args)
40
+ submit_and_block(:#{sym}, *args)
41
+ end
42
+ EOS
43
+ end
44
+
45
+ def initialize(host, event_queue, opts={})
46
+ @host = host
47
+ @event_queue = event_queue
48
+
49
+ # keep track of the pid that created us
50
+ update_pid!
51
+
52
+ # used by the C layer. CZookeeper sets this to true when the init method
53
+ # has completed. once this is set to true, it stays true.
54
+ #
55
+ # you should grab the @mutex before messing with this flag
56
+ @_running = nil
57
+
58
+ # This is set to true after destroy_zkrb_instance has been called and all
59
+ # CZookeeper state has been cleaned up
60
+ @_closed = false # also used by the C layer
61
+
62
+ # set by the ruby side to indicate we are in shutdown mode used by method_get_next_event
63
+ @_shutting_down = false
64
+
65
+ # the actual C data is stashed in this ivar. never *ever* touch this
66
+ @_data = nil
67
+
68
+ @_receive_timeout_msec = opts[:receive_timeout_msec] || DEFAULT_RECEIVE_TIMEOUT_MSEC
69
+
70
+ @mutex = Monitor.new
71
+
72
+ # used to signal that we're running
73
+ @running_cond = @mutex.new_cond
74
+
75
+ # used to signal we've received the connected event
76
+ @state_mutex = Monitor.new
77
+ @state_cond = @state_mutex.new_cond
78
+
79
+ # the current state of the connection
80
+ @state = ZOO_CLOSED_STATE
81
+
82
+ @pipe_read, @pipe_write = IO.pipe
83
+
84
+ @event_thread = nil
85
+
86
+ # hash of in-flight Continuation instances
87
+ @reg = Continuation::Registry.new
88
+
89
+ log_level = ENV['ZKC_DEBUG'] ? ZOO_LOG_LEVEL_DEBUG : ZOO_LOG_LEVEL_ERROR
90
+
91
+ logger.info { "initiating connection to #{@host}" }
92
+
93
+ zkrb_init(@host, opts)#, :zkc_log_level => log_level)
94
+
95
+ start_event_thread
96
+
97
+ logger.debug { "init returned!" }
98
+ end
99
+
100
+ def closed?
101
+ @mutex.synchronize { !!@_closed }
102
+ end
103
+
104
+ def running?
105
+ @mutex.synchronize { !!@_running }
106
+ end
107
+
108
+ def shutting_down?
109
+ @mutex.synchronize { !!@_shutting_down }
110
+ end
111
+
112
+ def connected?
113
+ state == ZOO_CONNECTED_STATE
114
+ end
115
+
116
+ def connecting?
117
+ state == ZOO_CONNECTING_STATE
118
+ end
119
+
120
+ def associating?
121
+ state == ZOO_ASSOCIATING_STATE
122
+ end
123
+
124
+ def close
125
+ return if closed?
126
+
127
+ fn_close = proc do
128
+ if !@_closed and @_data
129
+ logger.debug { "CALLING CLOSE HANDLE!!" }
130
+ close_handle
131
+ end
132
+ end
133
+
134
+ if forked?
135
+ fn_close.call
136
+ else
137
+ stop_event_thread
138
+ @mutex.synchronize(&fn_close)
139
+ end
140
+
141
+ [@pipe_read, @pipe_write].each { |io| io.close unless io.closed? }
142
+
143
+ nil
144
+ end
145
+
146
+ # call this to stop the event loop, you can resume with the
147
+ # resume method
148
+ #
149
+ # requests may still be added during this time, but they will not be
150
+ # processed until you call resume
151
+ def pause_before_fork_in_parent
152
+ logger.debug { "##{__method__}" }
153
+ @mutex.synchronize { stop_event_thread }
154
+ end
155
+
156
+ # call this if 'pause' was previously called to start the event loop again
157
+ def resume_after_fork_in_parent
158
+ logger.debug { "##{__method__}" }
159
+
160
+ @mutex.synchronize do
161
+ @_shutting_down = nil
162
+ start_event_thread
163
+ end
164
+ end
165
+
166
+ def state
167
+ return ZOO_CLOSED_STATE if closed?
168
+ @state_mutex.synchronize { @state }
169
+ end
170
+
171
+ # this implementation is gross, but i don't really see another way of doing it
172
+ # without more grossness
173
+ #
174
+ # returns true if we're connected, false if we're not
175
+ #
176
+ # if timeout is nil, we never time out, and wait forever for CONNECTED state
177
+ #
178
+ def wait_until_connected(timeout=10)
179
+ time_to_stop = timeout ? Time.now + timeout : nil
180
+
181
+ return false unless wait_until_running(timeout)
182
+
183
+ @state_mutex.synchronize do
184
+ while true
185
+ if timeout
186
+ now = Time.now
187
+ break if (@state == ZOO_CONNECTED_STATE) || unhealthy? || (now > time_to_stop)
188
+ delay = time_to_stop.to_f - now.to_f
189
+ @state_cond.wait(delay)
190
+ else
191
+ break if (@state == ZOO_CONNECTED_STATE) || unhealthy?
192
+ @state_cond.wait
193
+ end
194
+ end
195
+ end
196
+
197
+ connected?
198
+ end
199
+
200
+ private
201
+ # This method is NOT SYNCHRONIZED!
202
+ #
203
+ # you must hold the @mutex lock while calling this method
204
+ def unhealthy?
205
+ @_closed || @_shutting_down || is_unrecoverable
206
+ end
207
+
208
+ # This method is NOT SYNCHRONIZED!
209
+ #
210
+ # you must hold the @mutex lock while calling this method
211
+ def healthy?
212
+ !unhealthy?
213
+ end
214
+
215
+ # submits a job for processing
216
+ # blocks the caller until result has returned
217
+ def submit_and_block(meth, *args)
218
+ @mutex.synchronize do
219
+ raise Exceptions::NotConnected if unhealthy?
220
+ end
221
+
222
+ cnt = Continuation.new(meth, *args)
223
+ @reg.synchronize do |r|
224
+ if meth == :state
225
+ r.state_check << cnt
226
+ else
227
+ r.pending << cnt
228
+ end
229
+ end
230
+ wake_event_loop!
231
+ cnt.value
232
+ end
233
+
234
+ # this method is part of the reopen/close code, and is responsible for
235
+ # shutting down the dispatch thread.
236
+ #
237
+ # this method must be EXTERNALLY SYNCHRONIZED!
238
+ #
239
+ # @event_thread will be nil when this method exits
240
+ #
241
+ def stop_event_thread
242
+ if @event_thread
243
+ logger.debug { "##{__method__}" }
244
+ shut_down!
245
+ wake_event_loop!
246
+ @event_thread.join
247
+ @event_thread = nil
248
+ end
249
+ end
250
+
251
+ # starts the event thread running if not already started
252
+ # returns false if already running
253
+ def start_event_thread
254
+ return false if @event_thread
255
+ @event_thread = Thread.new(&method(:event_thread_body))
256
+ end
257
+
258
+ # will wait until the client has entered the running? state
259
+ # or until timeout seconds have passed.
260
+ #
261
+ # returns true if we're running, false if we timed out
262
+ def wait_until_running(timeout=5)
263
+ @mutex.synchronize do
264
+ return true if @_running
265
+ @running_cond.wait(timeout)
266
+ !!@_running
267
+ end
268
+ end
269
+
270
+ def event_thread_body
271
+ Thread.current.abort_on_exception = true
272
+ logger.debug { "##{__method__} starting event thread" }
273
+
274
+ event_thread_await_running
275
+
276
+ # this is the main loop
277
+ while healthy?
278
+ if @reg.anything_to_do? && connected?
279
+ submit_pending_calls
280
+ end
281
+
282
+ zkrb_iterate_event_loop
283
+ iterate_event_delivery
284
+ end
285
+
286
+ # ok, if we're exiting the event loop, and we still have a valid connection
287
+ # and there's still completions we're waiting to hear about, then we
288
+ # should pump the handle before leaving this loop
289
+ if @_shutting_down and not (@_closed or is_unrecoverable)
290
+ logger.debug { "we're in shutting down state, there are #{@reg.in_flight.length} in_flight completions" }
291
+
292
+ until @reg.in_flight.empty? or @_closed or is_unrecoverable
293
+ zkrb_iterate_event_loop
294
+ iterate_event_delivery
295
+ logger.debug { "there are #{@reg.in_flight} in_flight completions left" }
296
+ end
297
+
298
+ logger.debug { "finished completions" }
299
+ end
300
+
301
+ # anything left over after all that gets the finger
302
+ remaining = @reg.next_batch + @reg.in_flight.values
303
+
304
+ logger.debug { "there are #{remaining.length} completions to awaken" }
305
+
306
+ @reg.in_flight.clear
307
+
308
+ while cb = remaining.shift
309
+ cb.shutdown!
310
+ end
311
+ rescue ShuttingDownException
312
+ logger.error { "event thread saw @_shutting_down, bailing without entering loop" }
313
+ ensure
314
+ logger.debug { "##{__method__} exiting" }
315
+ end
316
+
317
+ def submit_pending_calls
318
+ calls = @reg.next_batch()
319
+
320
+ return if calls.empty?
321
+
322
+ while cntn = calls.shift
323
+ cntn.submit(self) # this delivers state check results (and does other stuff)
324
+ if req_id = cntn.req_id # state checks will not have a req_id
325
+ @reg.in_flight[req_id] = cntn # in_flight is only ever touched by us
326
+ end
327
+ end
328
+ end
329
+
330
+ def wake_event_loop!
331
+ @pipe_write && !@pipe_write.closed? && @pipe_write.write('1')
332
+ end
333
+
334
+ def iterate_event_delivery
335
+ while hash = zkrb_get_next_event_st()
336
+ logger.debug { "##{__method__} got #{hash.inspect} " }
337
+
338
+ if (hash[:req_id] == ZKRB_GLOBAL_CB_REQ) && (hash[:type] == -1)
339
+ ev_state = hash[:state]
340
+
341
+ @state_mutex.synchronize do
342
+ if @state != ev_state
343
+ @state = ev_state
344
+ @state_cond.broadcast
345
+ end
346
+ end
347
+ end
348
+
349
+ cntn = @reg.in_flight.delete(hash[:req_id])
350
+
351
+ if cntn and not cntn.user_callback? # this is one of "our" continuations
352
+ cntn.call(hash) # so we handle delivering it
353
+ next # and skip handing it to the dispatcher
354
+ end
355
+
356
+ # otherwise, the event was a session event (ZKRB_GLOBAL_CB_REQ)
357
+ # or a user-provided callback
358
+ @event_queue.push(hash)
359
+ end
360
+ end
361
+
362
+ def event_thread_await_running
363
+ logger.debug { "event_thread waiting until running: #{@_running}" }
364
+
365
+ @mutex.synchronize do
366
+ @running_cond.wait_until { @_running or @_shutting_down }
367
+ logger.debug { "event_thread running: #{@_running}" }
368
+
369
+ raise ShuttingDownException if @_shutting_down
370
+ end
371
+ end
372
+
373
+ # use this method to set the @_shutting_down flag to true
374
+ def shut_down!
375
+ logger.debug { "##{__method__}" }
376
+
377
+ @mutex.synchronize do
378
+ @_shutting_down = true
379
+ # ollie ollie oxen all home free!
380
+ @running_cond.broadcast
381
+ end
382
+
383
+ @state_mutex.synchronize do
384
+ @state_cond.broadcast
385
+ end
386
+ end
387
+
388
+ # called by underlying C code to signal we're running
389
+ def zkc_set_running_and_notify!
390
+ logger.debug { "##{__method__}" }
391
+
392
+ @mutex.synchronize do
393
+ @_running = true
394
+ @running_cond.broadcast
395
+ end
396
+ end
397
+ end
398
+ end
data/ext/common.h ADDED
@@ -0,0 +1,17 @@
1
+ #ifndef ZKRB_COMMON_H
2
+ #define ZKRB_COMMON_H
3
+
4
+ #include "ruby.h"
5
+
6
+ //#define THREADED
7
+ #undef THREADED // we are linking against the zookeeper_st lib, this is crucial
8
+
9
+ #ifndef RB_GC_GUARD_PTR
10
+ #define RB_GC_GUARD_PTR(V) (V);
11
+ #endif
12
+ #ifndef RB_GC_GUARD
13
+ #define RB_GC_GUARD(V) (V);
14
+ #endif
15
+
16
+
17
+ #endif /* ZKRB_COMMON_H */