zookeeper 0.4.4 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/CHANGELOG +95 -0
- data/Gemfile +17 -0
- data/Manifest +8 -2
- data/README.markdown +59 -0
- data/Rakefile +137 -7
- data/ext/.gitignore +6 -0
- data/ext/Rakefile +51 -0
- data/ext/c_zookeeper.rb +212 -0
- data/ext/dbg.h +53 -0
- data/ext/depend +5 -0
- data/ext/extconf.rb +44 -15
- data/ext/generate_gvl_code.rb +316 -0
- data/ext/zkc-3.3.5.tar.gz +0 -0
- data/ext/zkrb_wrapper.c +731 -0
- data/ext/zkrb_wrapper.h +330 -0
- data/ext/zkrb_wrapper_compat.c +15 -0
- data/ext/zkrb_wrapper_compat.h +11 -0
- data/ext/zookeeper_base.rb +211 -0
- data/ext/zookeeper_c.c +268 -97
- data/ext/zookeeper_lib.c +157 -92
- data/ext/zookeeper_lib.h +12 -6
- data/java/zookeeper_base.rb +477 -0
- data/lib/zookeeper/acls.rb +10 -1
- data/lib/zookeeper/callbacks.rb +5 -3
- data/lib/zookeeper/common/queue_with_pipe.rb +78 -0
- data/lib/zookeeper/common.rb +174 -0
- data/lib/zookeeper/constants.rb +31 -28
- data/lib/zookeeper/em_client.rb +55 -0
- data/lib/zookeeper/exceptions.rb +10 -2
- data/lib/zookeeper/stat.rb +11 -2
- data/lib/zookeeper/version.rb +6 -0
- data/lib/zookeeper.rb +155 -122
- data/notes.txt +14 -0
- data/spec/c_zookeeper_spec.rb +50 -0
- data/spec/chrooted_connection_spec.rb +81 -0
- data/spec/default_watcher_spec.rb +41 -0
- data/spec/em_spec.rb +51 -0
- data/spec/log4j.properties +17 -0
- data/spec/shared/all_success_return_values.rb +10 -0
- data/spec/shared/connection_examples.rb +1018 -0
- data/spec/spec_helper.rb +119 -0
- data/spec/support/progress_formatter.rb +15 -0
- data/spec/zookeeper_spec.rb +24 -0
- data/zookeeper.gemspec +37 -25
- metadata +78 -34
- data/README +0 -42
- data/ext/zkc-3.3.2.tar.gz +0 -0
data/.gitignore
ADDED
data/CHANGELOG
CHANGED
@@ -1,3 +1,97 @@
|
|
1
|
+
v0.9.3 Event thread shutdown fix, Windows compatibility fix
|
2
|
+
|
3
|
+
* Use a 'shutdown thread' to coordinate cleanup if close is called from the
|
4
|
+
event thread (prevents deadlock)
|
5
|
+
|
6
|
+
* Default Logger now uses $stderr instead of opening /dev/null [#16]
|
7
|
+
|
8
|
+
* Gemfile/gemspec/Rakefile refactoring.
|
9
|
+
|
10
|
+
v0.9.2 More efficient and simpler wrappers for GIL release
|
11
|
+
|
12
|
+
* After a code review by Andrew Wason (rectalogic), use a much simpler
|
13
|
+
technique for creating the arg structs and passing them to the
|
14
|
+
zkrb_gvl_* functions. No malloc(), no free(), no problem.
|
15
|
+
|
16
|
+
v0.9.1 see v0.8.4 notes, same patch
|
17
|
+
|
18
|
+
v0.9.0 RELEASE THE KRAK..er, GIL!!
|
19
|
+
|
20
|
+
* In >= 1.9.2 the ruby interpreter allows you to release the GIL when
|
21
|
+
calling into native code, sounds like a good idea.
|
22
|
+
|
23
|
+
This release makes use of that code by parsing the zookeeper.h header file
|
24
|
+
and extracting the method signatures of all relevant zoo_* functions, then
|
25
|
+
generating boilerplate that allows us to call those functions via the
|
26
|
+
rb_thread_blocking_region function.
|
27
|
+
|
28
|
+
1.8.7 compatibility is maintained by stubbing out that functionality if built
|
29
|
+
under 1.8.7.
|
30
|
+
|
31
|
+
* 1.8.7 is deprecated! I will continue to support 1.8.7 for the near future
|
32
|
+
but sometime soon, you're gonna have to upgrade.
|
33
|
+
|
34
|
+
v0.8.4 fix NameError, require 'forwardable'
|
35
|
+
|
36
|
+
* Really not sure why this didn't come up in tests
|
37
|
+
|
38
|
+
* issue here https://github.com/slyphon/zk/issues/22
|
39
|
+
|
40
|
+
v0.8.3 fix NonLocalJump exception in event delivery thread shutdown code
|
41
|
+
|
42
|
+
* hit a corner case where we're waiting for the zkc handle setup
|
43
|
+
and the user decides to shutdown, but before we've had a chance
|
44
|
+
to enter the delivery loop.
|
45
|
+
|
46
|
+
* Cleaned up some nasty code in ZookeeperConstants
|
47
|
+
|
48
|
+
* removed ZookeeperConstants#print_events and ZookeeperConstants#print_states
|
49
|
+
|
50
|
+
* changed EVENT_TYPE_NAMES and EVENT_STATE_NAMES in ZookeeperConstants
|
51
|
+
to use string values instead of symbols
|
52
|
+
|
53
|
+
v0.8.2 fix close after a fork()
|
54
|
+
|
55
|
+
* The dispatch thread will be dead in this situation, so we need to
|
56
|
+
check to see if it's already dead before waiting on it to exit.
|
57
|
+
|
58
|
+
v0.8.1 Java client fix, silence warnings
|
59
|
+
|
60
|
+
v0.8.0 Refactor C implementaion, EventMachine client
|
61
|
+
|
62
|
+
* separated CZookeeper and ZookeeperBase implementation
|
63
|
+
|
64
|
+
This solves issues with reopen not working properly, makes for a much
|
65
|
+
cleaner event delivery implementation. ZookeeperBase controls the lifecycle
|
66
|
+
of the event dispatch thread now, rather than it being tied to CZookeeper.
|
67
|
+
|
68
|
+
* added support for the 'sync' API call
|
69
|
+
|
70
|
+
* Refactored zookeeper_c.c and zookeeper_lib.c
|
71
|
+
|
72
|
+
More error checking in zookeeper_lib.c and restructure some things to make
|
73
|
+
logic easier to follow
|
74
|
+
|
75
|
+
Fix bug in method_get_next_event that made the shutdown case so complicated
|
76
|
+
|
77
|
+
* Massively simplified EMClient implementation
|
78
|
+
|
79
|
+
Rather than trying to hook the IO used by zookeeper_lib to notify zookeeper_c
|
80
|
+
about event availabiltiy directly into EventMachine, use the same event delivery
|
81
|
+
thread, but wrap the dispatch call in EM.schedule.
|
82
|
+
|
83
|
+
* Improve implementation of spin-lock-esque code that waits for the connection to be
|
84
|
+
established before returning.
|
85
|
+
|
86
|
+
This cut the test runtime down from 1m 20s to 2s.
|
87
|
+
|
88
|
+
* Java client refactoring, similar correctness changes
|
89
|
+
|
90
|
+
* Change ZookeeperException base class to StandardError instead of Exception
|
91
|
+
|
92
|
+
|
93
|
+
v0.4.5 Upgrade to ZooKeeper 3.3.3
|
94
|
+
|
1
95
|
v0.4.4 Fix race condition on close, possible data corruption on async get.
|
2
96
|
|
3
97
|
v0.4.3 Fix a handful of memory-related bugs, fix SIGSEGV on master change, reduce latency of event handling, fix compilation on OSX.
|
@@ -22,3 +116,4 @@ v0.2. Bundle C dependencies, like memcached.gem.
|
|
22
116
|
|
23
117
|
v0.1. First release.
|
24
118
|
|
119
|
+
# vim:ft=text:ts=2:sw=2:et
|
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
source :rubygems
|
2
|
+
|
3
|
+
gemspec
|
4
|
+
|
5
|
+
group :test do
|
6
|
+
gem "rspec", "~> 2.8.0"
|
7
|
+
gem 'flexmock', '~> 0.8.11'
|
8
|
+
gem 'eventmachine', '1.0.0.beta.4'
|
9
|
+
gem 'evented-spec', '~> 0.9.0'
|
10
|
+
end
|
11
|
+
|
12
|
+
group :development do
|
13
|
+
gem 'rake', '~> 0.9.0'
|
14
|
+
gem 'pry'
|
15
|
+
end
|
16
|
+
|
17
|
+
# vim:ft=ruby
|
data/Manifest
CHANGED
@@ -1,23 +1,29 @@
|
|
1
1
|
CHANGELOG
|
2
2
|
LICENSE
|
3
|
+
Manifest
|
3
4
|
README
|
4
5
|
Rakefile
|
5
6
|
examples/cloud_config.rb
|
6
7
|
ext/extconf.rb
|
7
|
-
ext/zkc-3.3.
|
8
|
+
ext/zkc-3.3.4.tar.gz
|
9
|
+
ext/zookeeper_base.rb
|
8
10
|
ext/zookeeper_c.c
|
9
11
|
ext/zookeeper_lib.c
|
10
12
|
ext/zookeeper_lib.h
|
13
|
+
java/zookeeper_base.rb
|
11
14
|
lib/zookeeper.rb
|
12
15
|
lib/zookeeper/acls.rb
|
13
16
|
lib/zookeeper/callbacks.rb
|
17
|
+
lib/zookeeper/common.rb
|
14
18
|
lib/zookeeper/constants.rb
|
15
19
|
lib/zookeeper/exceptions.rb
|
16
20
|
lib/zookeeper/stat.rb
|
21
|
+
spec/log4j.properties
|
22
|
+
spec/spec_helper.rb
|
23
|
+
spec/zookeeper_spec.rb
|
17
24
|
test/test_basic.rb
|
18
25
|
test/test_callback1.rb
|
19
26
|
test/test_close.rb
|
20
27
|
test/test_esoteric.rb
|
21
28
|
test/test_watcher1.rb
|
22
29
|
test/test_watcher2.rb
|
23
|
-
Manifest
|
data/README.markdown
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# zookeeper #
|
2
|
+
|
3
|
+
An interface to the Zookeeper cluster coordination server.
|
4
|
+
|
5
|
+
For a higher-level interface with a more convenient API and features such as locks, have a look at [ZK](https://github.com/slyphon/zk) (also available is [ZK-EventMachine](https://github.com/slyphon/zk-eventmachine) for those who prefer async).
|
6
|
+
|
7
|
+
## Big Plans for 1.0 ##
|
8
|
+
|
9
|
+
The 1.0 release will feature a reorganization of the heirarchy. There will be a single top-level `Zookeeper` namespace (as opposed to the current layout, with 5-6 different top-level constants), and for the next several releases, there will be a backwards compatible require for users that still need to use the old names.
|
10
|
+
|
11
|
+
## License
|
12
|
+
|
13
|
+
Copyright 2008 Phillip Pearson, and 2010 Twitter, Inc.
|
14
|
+
Licensed under the MIT License. See the included LICENSE file.
|
15
|
+
|
16
|
+
Portions copyright 2008-2010 the Apache Software Foundation, licensed under the
|
17
|
+
Apache 2 license, and used with permission.
|
18
|
+
|
19
|
+
Portions contributed to the open source community by HPDC, L.P.
|
20
|
+
|
21
|
+
## Install
|
22
|
+
|
23
|
+
sudo gem install zookeeper
|
24
|
+
|
25
|
+
## Usage
|
26
|
+
|
27
|
+
Connect to a server:
|
28
|
+
|
29
|
+
require 'rubygems'
|
30
|
+
require 'zookeeper'
|
31
|
+
z = Zookeeper.new("localhost:2181")
|
32
|
+
z.get_children(:path => "/")
|
33
|
+
|
34
|
+
## Idioms
|
35
|
+
|
36
|
+
The following methods are initially supported:
|
37
|
+
* get
|
38
|
+
* set
|
39
|
+
* get\_children
|
40
|
+
* stat
|
41
|
+
* create
|
42
|
+
* delete
|
43
|
+
* get\_acl
|
44
|
+
* set\_acl
|
45
|
+
|
46
|
+
All support async callbacks. get, get\_children and stat support both watchers and callbacks.
|
47
|
+
|
48
|
+
Calls take a dictionary of parameters. With the exception of set\_acl, the only required parameter is :path. Each call returns a dictionary with at minimum two keys :req\_id and :rc.
|
49
|
+
|
50
|
+
### A Bit about this repository ###
|
51
|
+
|
52
|
+
Twitter's open source office was kind enough to transfer this repository to facilitate development and administration of this repository. The `zookeeper` gem's last three releases were recorded in branches `v0.4.2`, `v0.4.3` and `v0.4.4`. Releases of the `slyphon-zookeeper` gem were cut off of the fork, and unfortunately (due to an oversight on my part) were tagged with unrelated versions. Those were tagged with names `release/0.9.2`.
|
53
|
+
|
54
|
+
The plan is to keep the `slyphon-zookeeper` tags, and to tag the `zookeeper` releases `twitter/release/0.4.x`.
|
55
|
+
|
56
|
+
Further work will be carried out on this repository. The `0.9.3` release of the zookeeper gem will be released under the 'zookeeper' name, and will bring the two divergent (conceptual) branches of development together.
|
57
|
+
|
58
|
+
|
59
|
+
|
data/Rakefile
CHANGED
@@ -1,9 +1,139 @@
|
|
1
|
-
|
1
|
+
# def gemset_name
|
2
|
+
# ENV.fetch('GEM_HOME').split('@').last
|
3
|
+
# end
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
GEM_FILES = FileList['slyphon-zookeeper-*.gem']
|
6
|
+
|
7
|
+
namespace :mb do
|
8
|
+
namespace :gems do
|
9
|
+
task :build do
|
10
|
+
sh "rvm 1.8.7 do gem build zookeeper.gemspec"
|
11
|
+
ENV['JAVA_GEM'] = '1'
|
12
|
+
sh "rvm 1.8.7 do gem build zookeeper.gemspec"
|
13
|
+
end
|
14
|
+
|
15
|
+
task :push do
|
16
|
+
GEM_FILES.each do |gem|
|
17
|
+
sh "gem push #{gem}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
task :clean do
|
22
|
+
rm_rf GEM_FILES
|
23
|
+
end
|
24
|
+
|
25
|
+
task :all => [:build, :push, :clean]
|
26
|
+
end
|
9
27
|
end
|
28
|
+
|
29
|
+
gemset_name = 'zookeeper'
|
30
|
+
|
31
|
+
# this nonsense w/ tmp and the Gemfile is a bundler optimization
|
32
|
+
|
33
|
+
%w[1.8.7 1.9.2 jruby rbx 1.9.3].each do |ns_name|
|
34
|
+
rvm_ruby = (ns_name == 'rbx') ? "rbx-2.0.testing" : ns_name
|
35
|
+
|
36
|
+
ruby_with_gemset = "#{rvm_ruby}@#{gemset_name}"
|
37
|
+
|
38
|
+
create_gemset_name = "mb:#{ns_name}:create_gemset"
|
39
|
+
clobber_task_name = "mb:#{ns_name}:clobber"
|
40
|
+
clean_task_name = "mb:#{ns_name}:clean"
|
41
|
+
build_task_name = "mb:#{ns_name}:build"
|
42
|
+
bundle_task_name = "mb:#{ns_name}:bundle_install"
|
43
|
+
rspec_task_name = "mb:#{ns_name}:run_rspec"
|
44
|
+
|
45
|
+
phony_gemfile_link_name = "Gemfile.#{ns_name}"
|
46
|
+
phony_gemfile_lock_name = "#{phony_gemfile_link_name}.lock"
|
47
|
+
|
48
|
+
file phony_gemfile_link_name do
|
49
|
+
# apparently, rake doesn't deal with symlinks intelligently :P
|
50
|
+
ln_s('Gemfile', phony_gemfile_link_name) unless File.symlink?(phony_gemfile_link_name)
|
51
|
+
end
|
52
|
+
|
53
|
+
task :clean do
|
54
|
+
rm_rf [phony_gemfile_lock_name, phony_gemfile_lock_name]
|
55
|
+
end
|
56
|
+
|
57
|
+
task create_gemset_name do
|
58
|
+
sh "rvm #{rvm_ruby} do rvm gemset create #{gemset_name}"
|
59
|
+
end
|
60
|
+
|
61
|
+
task clobber_task_name do
|
62
|
+
unless rvm_ruby == 'jruby'
|
63
|
+
cd 'ext' do
|
64
|
+
sh "rake clobber"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
task clean_task_name do
|
70
|
+
unless rvm_ruby == 'jruby'
|
71
|
+
cd 'ext' do
|
72
|
+
sh "rake clean"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
task build_task_name => [create_gemset_name, clean_task_name] do
|
78
|
+
unless rvm_ruby == 'jruby'
|
79
|
+
cd 'ext' do
|
80
|
+
sh "rvm #{ruby_with_gemset} do rake build"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
task bundle_task_name => [phony_gemfile_link_name, build_task_name] do
|
86
|
+
sh "rvm #{ruby_with_gemset} do bundle install --gemfile #{phony_gemfile_link_name}"
|
87
|
+
end
|
88
|
+
|
89
|
+
task rspec_task_name => bundle_task_name do
|
90
|
+
sh "rvm #{ruby_with_gemset} do env BUNDLE_GEMFILE=#{phony_gemfile_link_name} bundle exec rspec spec --fail-fast"
|
91
|
+
end
|
92
|
+
|
93
|
+
task "mb:#{ns_name}" => rspec_task_name
|
94
|
+
|
95
|
+
task "mb:test_all_rubies" => rspec_task_name
|
96
|
+
end
|
97
|
+
|
98
|
+
task "mb:test_all" do
|
99
|
+
require 'benchmark'
|
100
|
+
t = Benchmark.realtime do
|
101
|
+
Rake::Task['mb:test_all_rubies'].invoke
|
102
|
+
end
|
103
|
+
|
104
|
+
$stderr.puts "Test run took: #{t} s"
|
105
|
+
end
|
106
|
+
|
107
|
+
task :default => 'mb:1.9.3'
|
108
|
+
|
109
|
+
task :clobber do
|
110
|
+
rm_rf 'tmp'
|
111
|
+
end
|
112
|
+
|
113
|
+
# cargo culted from http://blog.flavorjon.es/2009/06/easily-valgrind-gdb-your-ruby-c.html
|
114
|
+
VALGRIND_BASIC_OPTS = '--num-callers=50 --error-limit=no --partial-loads-ok=yes --undef-value-errors=no'
|
115
|
+
|
116
|
+
task 'valgrind' do
|
117
|
+
cd 'ext' do
|
118
|
+
sh "rake clean build"
|
119
|
+
end
|
120
|
+
|
121
|
+
sh "valgrind #{VALGRIND_BASIC_OPTS} bundle exec rspec spec"
|
122
|
+
end
|
123
|
+
|
124
|
+
namespace :build do
|
125
|
+
task :clean do
|
126
|
+
cd 'ext' do
|
127
|
+
sh 'rake clean'
|
128
|
+
end
|
129
|
+
|
130
|
+
Rake::Task['build'].invoke
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
task :build do
|
135
|
+
cd 'ext' do
|
136
|
+
sh "rake"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
data/ext/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
task :clean do
|
3
|
+
if File.exists?('Makefile')
|
4
|
+
sh 'make clean'
|
5
|
+
else
|
6
|
+
$stderr.puts "nothing to clean, no Makefile"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
GENERATE_GVL_CODE_RB = 'generate_gvl_code.rb'
|
11
|
+
|
12
|
+
file 'c' do
|
13
|
+
if tarball = Dir['zkc-*.tar.gz'].first
|
14
|
+
sh "tar -zxf #{tarball}"
|
15
|
+
else
|
16
|
+
raise "couldn't find the tarball! wtf?!"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
file GENERATE_GVL_CODE_RB => 'c'
|
21
|
+
|
22
|
+
file 'zkrb_wrapper.c' => GENERATE_GVL_CODE_RB do
|
23
|
+
sh "ruby generate_gvl_code.rb code"
|
24
|
+
end
|
25
|
+
|
26
|
+
file 'zkrb_wrapper.h' => GENERATE_GVL_CODE_RB do
|
27
|
+
sh "ruby generate_gvl_code.rb headers"
|
28
|
+
end
|
29
|
+
|
30
|
+
ZKRB_WRAPPER = %w[zkrb_wrapper.c zkrb_wrapper.h]
|
31
|
+
|
32
|
+
|
33
|
+
task :wrappers => ZKRB_WRAPPER
|
34
|
+
|
35
|
+
|
36
|
+
task :clobber => :clean do
|
37
|
+
rm_rf %w[Makefile c lib bin include]
|
38
|
+
end
|
39
|
+
|
40
|
+
task :build_zkc do
|
41
|
+
sh 'ruby extconf.rb'
|
42
|
+
end
|
43
|
+
|
44
|
+
file 'Makefile' => :build_zkc
|
45
|
+
|
46
|
+
task :build => [ZKRB_WRAPPER, 'Makefile'].flatten do
|
47
|
+
sh 'make'
|
48
|
+
end
|
49
|
+
|
50
|
+
task :default => :build
|
51
|
+
|
data/ext/c_zookeeper.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'zookeeper/constants'
|
2
|
+
require File.expand_path('../zookeeper_c', __FILE__)
|
3
|
+
|
4
|
+
# TODO: see if we can get the destructor to handle thread/event queue teardown
|
5
|
+
# when we're garbage collected
|
6
|
+
class CZookeeper
|
7
|
+
include ZookeeperCommon
|
8
|
+
include ZookeeperConstants
|
9
|
+
include ZookeeperExceptions
|
10
|
+
|
11
|
+
DEFAULT_SESSION_TIMEOUT_MSEC = 10000
|
12
|
+
|
13
|
+
class GotNilEventException < StandardError; end
|
14
|
+
|
15
|
+
# assume we're at debug level
|
16
|
+
def self.get_debug_level
|
17
|
+
@debug_level ||= ZOO_LOG_LEVEL_INFO
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.set_debug_level(value)
|
21
|
+
@debug_level = value
|
22
|
+
set_zkrb_debug_level(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(host, event_queue, opts={})
|
26
|
+
@host = host
|
27
|
+
@event_queue = event_queue
|
28
|
+
|
29
|
+
# used by the C layer. CZookeeper sets this to true when the init method
|
30
|
+
# has completed. once this is set to true, it stays true.
|
31
|
+
#
|
32
|
+
# you should grab the @start_stop_mutex before messing with this flag
|
33
|
+
@_running = nil
|
34
|
+
|
35
|
+
# This is set to true after destroy_zkrb_instance has been called and all
|
36
|
+
# CZookeeper state has been cleaned up
|
37
|
+
@_closed = false # also used by the C layer
|
38
|
+
|
39
|
+
# set by the ruby side to indicate we are in shutdown mode used by method_get_next_event
|
40
|
+
@_shutting_down = false
|
41
|
+
|
42
|
+
# the actual C data is stashed in this ivar. never *ever* touch this
|
43
|
+
@_data = nil
|
44
|
+
|
45
|
+
@_session_timeout_msec = DEFAULT_SESSION_TIMEOUT_MSEC
|
46
|
+
|
47
|
+
@start_stop_mutex = Monitor.new
|
48
|
+
|
49
|
+
# used to signal that we're running
|
50
|
+
@running_cond = @start_stop_mutex.new_cond
|
51
|
+
|
52
|
+
@event_thread = nil
|
53
|
+
|
54
|
+
setup_event_thread!
|
55
|
+
|
56
|
+
zkrb_init(@host)
|
57
|
+
|
58
|
+
logger.debug { "init returned!" }
|
59
|
+
end
|
60
|
+
|
61
|
+
def closed?
|
62
|
+
@start_stop_mutex.synchronize { !!@_closed }
|
63
|
+
end
|
64
|
+
|
65
|
+
def running?
|
66
|
+
@start_stop_mutex.synchronize { !!@_running }
|
67
|
+
end
|
68
|
+
|
69
|
+
def shutting_down?
|
70
|
+
@start_stop_mutex.synchronize { !!@_shutting_down }
|
71
|
+
end
|
72
|
+
|
73
|
+
def connected?
|
74
|
+
state == ZOO_CONNECTED_STATE
|
75
|
+
end
|
76
|
+
|
77
|
+
def connecting?
|
78
|
+
state == ZOO_CONNECTING_STATE
|
79
|
+
end
|
80
|
+
|
81
|
+
def associating?
|
82
|
+
state == ZOO_ASSOCIATING_STATE
|
83
|
+
end
|
84
|
+
|
85
|
+
def close
|
86
|
+
return if closed?
|
87
|
+
|
88
|
+
shut_down!
|
89
|
+
stop_event_thread!
|
90
|
+
|
91
|
+
@start_stop_mutex.synchronize do
|
92
|
+
if !@_closed and @_data
|
93
|
+
close_handle
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
nil
|
98
|
+
end
|
99
|
+
|
100
|
+
def state
|
101
|
+
return ZOO_CLOSED_STATE if closed?
|
102
|
+
zkrb_state
|
103
|
+
end
|
104
|
+
|
105
|
+
# this implementation is gross, but i don't really see another way of doing it
|
106
|
+
# without more grossness
|
107
|
+
#
|
108
|
+
# returns true if we're connected, false if we're not
|
109
|
+
#
|
110
|
+
# if timeout is nil, we never time out, and wait forever for CONNECTED state
|
111
|
+
#
|
112
|
+
def wait_until_connected(timeout=10)
|
113
|
+
return false unless wait_until_running(timeout)
|
114
|
+
|
115
|
+
time_to_stop = timeout ? (Time.now + timeout) : nil
|
116
|
+
|
117
|
+
until connected? or (time_to_stop and Time.now > time_to_stop)
|
118
|
+
Thread.pass
|
119
|
+
end
|
120
|
+
|
121
|
+
connected?
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
# will wait until the client has entered the running? state
|
126
|
+
# or until timeout seconds have passed.
|
127
|
+
#
|
128
|
+
# returns true if we're running, false if we timed out
|
129
|
+
def wait_until_running(timeout=5)
|
130
|
+
@start_stop_mutex.synchronize do
|
131
|
+
return true if @_running
|
132
|
+
@running_cond.wait(timeout)
|
133
|
+
!!@_running
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def setup_event_thread!
|
138
|
+
@event_thread ||= Thread.new(&method(:_event_thread_body))
|
139
|
+
end
|
140
|
+
|
141
|
+
def _event_thread_body
|
142
|
+
logger.debug { "event_thread waiting until running: #{@_running}" }
|
143
|
+
|
144
|
+
@start_stop_mutex.synchronize do
|
145
|
+
@running_cond.wait_until { @_running }
|
146
|
+
|
147
|
+
if @_shutting_down
|
148
|
+
logger.error { "event thread saw @_shutting_down, bailing without entering loop" }
|
149
|
+
return
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
logger.debug { "event_thread running: #{@_running}" }
|
154
|
+
|
155
|
+
while true
|
156
|
+
begin
|
157
|
+
_iterate_event_delivery
|
158
|
+
rescue GotNilEventException
|
159
|
+
logger.debug { "#{self.class}##{__method__}: event delivery thread is exiting" }
|
160
|
+
break
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def _iterate_event_delivery
|
166
|
+
get_next_event(true).tap do |hash|
|
167
|
+
raise GotNilEventException if hash.nil?
|
168
|
+
@event_queue.push(hash)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# use this method to set the @_shutting_down flag to true
|
173
|
+
def shut_down!
|
174
|
+
logger.debug { "#{self.class}##{__method__}" }
|
175
|
+
|
176
|
+
@start_stop_mutex.synchronize do
|
177
|
+
@_shutting_down = true
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# this method is part of the reopen/close code, and is responsible for
|
182
|
+
# shutting down the dispatch thread.
|
183
|
+
#
|
184
|
+
# @dispatch will be nil when this method exits
|
185
|
+
#
|
186
|
+
def stop_event_thread!
|
187
|
+
logger.debug { "#{self.class}##{__method__}" }
|
188
|
+
|
189
|
+
if @event_thread
|
190
|
+
unless @_closed
|
191
|
+
wake_event_loop! # this is a C method
|
192
|
+
end
|
193
|
+
@event_thread.join
|
194
|
+
@event_thread = nil
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def logger
|
199
|
+
Zookeeper.logger
|
200
|
+
end
|
201
|
+
|
202
|
+
# called by underlying C code to signal we're running
|
203
|
+
def zkc_set_running_and_notify!
|
204
|
+
logger.debug { "#{self.class}##{__method__}" }
|
205
|
+
|
206
|
+
@start_stop_mutex.synchronize do
|
207
|
+
@_running = true
|
208
|
+
@running_cond.broadcast
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
data/ext/dbg.h
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#ifndef __dbg_h__
|
2
|
+
#define __dbg_h__
|
3
|
+
|
4
|
+
// ALL GLORY TO THE Zed A. Shaw
|
5
|
+
// http://c.learncodethehardway.org/book/learn-c-the-hard-waych21.html#x26-10500021
|
6
|
+
|
7
|
+
#include <stdio.h>
|
8
|
+
#include <errno.h>
|
9
|
+
#include <string.h>
|
10
|
+
|
11
|
+
#ifdef NDEBUG
|
12
|
+
#define debug(M, ...)
|
13
|
+
#else
|
14
|
+
#define debug(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
15
|
+
#endif
|
16
|
+
|
17
|
+
#define clean_errno() (errno == 0 ? "None" : strerror(errno))
|
18
|
+
|
19
|
+
#define log_err(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
20
|
+
|
21
|
+
#define log_warn(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, clean_errno(), ##__VA_ARGS__)
|
22
|
+
|
23
|
+
#define log_info(M, ...) fprintf(stderr, "[INFO] (%s:%d) " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
24
|
+
|
25
|
+
// acts to assert that A is true
|
26
|
+
#define check(A, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
|
27
|
+
|
28
|
+
// like check, but provide an explicit goto label name
|
29
|
+
#define check_goto(A, L, M, ...) if(!(A)) { log_err(M, ##__VA_ARGS__); errno=0; goto L; }
|
30
|
+
|
31
|
+
// like check, but implicit jump to 'unlock' label
|
32
|
+
#define check_unlock(A, M, ...) check_goto(A, unlock, M, ##__VA_ARGS__)
|
33
|
+
|
34
|
+
#define sentinel(M, ...) { log_err(M, ##__VA_ARGS__); errno=0; goto error; }
|
35
|
+
|
36
|
+
#define check_mem(A) check((A), "Out of memory.")
|
37
|
+
|
38
|
+
// checks the condition A, if not true, logs the message M given using zkrb_debug
|
39
|
+
// then does a goto to the label L
|
40
|
+
#define check_debug_goto(A, L, M, ...) if(!(A)) { zkrb_debug(M, ##__VA_ARGS__); errno=0; goto L; }
|
41
|
+
|
42
|
+
// check_debug_goto with implicit 'unlock' label
|
43
|
+
#define check_debug_unlock(A, M, ...) check_debug_goto(A, unlock, M, ##__VA_ARGS__)
|
44
|
+
|
45
|
+
// like check_debug_goto, but the label is implicitly 'error'
|
46
|
+
#define check_debug(A, M, ...) check_debug_goto(A, error, M, ##__VA_ARGS__)
|
47
|
+
|
48
|
+
#define zkrb_debug(M, ...) if (ZKRBDebugging) fprintf(stderr, "DEBUG %p:%s:%d: " M "\n", pthread_self(), __FILE__, __LINE__, ##__VA_ARGS__)
|
49
|
+
#define zkrb_debug_inst(O, M, ...) zkrb_debug("obj_id: %lx, " M, FIX2LONG(rb_obj_id(O)), ##__VA_ARGS__)
|
50
|
+
|
51
|
+
// __dbg_h__
|
52
|
+
#endif
|
53
|
+
|