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.
- checksums.yaml +7 -0
- data/.ctags_paths +1 -0
- data/.dotfiles/ruby-gemset +1 -0
- data/.dotfiles/ruby-version +1 -0
- data/.dotfiles/rvmrc +2 -0
- data/.github/workflows/build.yml +57 -0
- data/.gitignore +19 -0
- data/.gitmodules +3 -0
- data/CHANGELOG +408 -0
- data/Gemfile +30 -0
- data/Guardfile +8 -0
- data/LICENSE +23 -0
- data/Manifest +29 -0
- data/README.markdown +62 -0
- data/Rakefile +121 -0
- data/cause-abort.rb +117 -0
- data/ext/.gitignore +6 -0
- data/ext/Rakefile +41 -0
- data/ext/c_zookeeper.rb +398 -0
- data/ext/common.h +17 -0
- data/ext/dbg.h +53 -0
- data/ext/depend +5 -0
- data/ext/event_lib.c +740 -0
- data/ext/event_lib.h +175 -0
- data/ext/extconf.rb +103 -0
- data/ext/generate_gvl_code.rb +321 -0
- data/ext/patches/zkc-3.3.5-network.patch +24 -0
- data/ext/patches/zkc-3.4.5-buffer-overflow.patch +11 -0
- data/ext/patches/zkc-3.4.5-config.patch +5454 -0
- data/ext/patches/zkc-3.4.5-fetch-and-add.patch +16 -0
- data/ext/patches/zkc-3.4.5-logging.patch +41 -0
- data/ext/patches/zkc-3.4.5-out-of-order-ping.patch +163 -0
- data/ext/patches/zkc-3.4.5-yosemite-htonl-fix.patch +102 -0
- data/ext/zkc-3.4.5.tar.gz +0 -0
- data/ext/zkrb.c +1080 -0
- data/ext/zkrb_wrapper.c +775 -0
- data/ext/zkrb_wrapper.h +350 -0
- data/ext/zkrb_wrapper_compat.c +15 -0
- data/ext/zkrb_wrapper_compat.h +11 -0
- data/ext/zookeeper_base.rb +256 -0
- data/java/java_base.rb +501 -0
- data/lib/zookeeper/acls.rb +44 -0
- data/lib/zookeeper/callbacks.rb +108 -0
- data/lib/zookeeper/client.rb +30 -0
- data/lib/zookeeper/client_methods.rb +282 -0
- data/lib/zookeeper/common/queue_with_pipe.rb +110 -0
- data/lib/zookeeper/common.rb +122 -0
- data/lib/zookeeper/compatibility.rb +138 -0
- data/lib/zookeeper/constants.rb +97 -0
- data/lib/zookeeper/continuation.rb +223 -0
- data/lib/zookeeper/core_ext.rb +58 -0
- data/lib/zookeeper/em_client.rb +55 -0
- data/lib/zookeeper/exceptions.rb +135 -0
- data/lib/zookeeper/forked.rb +19 -0
- data/lib/zookeeper/latch.rb +34 -0
- data/lib/zookeeper/logger/forwarding_logger.rb +84 -0
- data/lib/zookeeper/logger.rb +39 -0
- data/lib/zookeeper/monitor.rb +19 -0
- data/lib/zookeeper/rake_tasks.rb +165 -0
- data/lib/zookeeper/request_registry.rb +153 -0
- data/lib/zookeeper/stat.rb +21 -0
- data/lib/zookeeper/version.rb +4 -0
- data/lib/zookeeper.rb +115 -0
- data/notes.txt +14 -0
- data/scripts/upgrade-1.0-sed-alike.rb +46 -0
- data/spec/c_zookeeper_spec.rb +51 -0
- data/spec/chrooted_connection_spec.rb +83 -0
- data/spec/compatibilty_spec.rb +8 -0
- data/spec/default_watcher_spec.rb +41 -0
- data/spec/em_spec.rb +51 -0
- data/spec/ext/zookeeper_base_spec.rb +19 -0
- data/spec/forked_connection_spec.rb +122 -0
- data/spec/latch_spec.rb +24 -0
- data/spec/log4j.properties +17 -0
- data/spec/shared/all_success_return_values.rb +10 -0
- data/spec/shared/connection_examples.rb +1081 -0
- data/spec/spec_helper.rb +61 -0
- data/spec/support/00_logging.rb +38 -0
- data/spec/support/10_spawn_zookeeper.rb +20 -0
- data/spec/support/progress_formatter.rb +15 -0
- data/spec/support/zookeeper_spec_helpers.rb +96 -0
- data/spec/zookeeper_spec.rb +24 -0
- data/zookeeper.gemspec +46 -0
- data/zoomonkey/duplicates +3 -0
- data/zoomonkey/zoomonkey.rb +194 -0
- 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/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
|
+
|
data/ext/c_zookeeper.rb
ADDED
@@ -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 */
|