zookeeper 0.9.4 → 1.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.dotfiles/rvmrc +1 -0
  2. data/.gitignore +3 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +22 -0
  5. data/CHANGELOG +38 -5
  6. data/Gemfile +18 -1
  7. data/README.markdown +2 -0
  8. data/Rakefile +47 -109
  9. data/ext/c_zookeeper.rb +10 -6
  10. data/ext/zookeeper_base.rb +23 -11
  11. data/ext/zookeeper_c.c +14 -10
  12. data/java/{zookeeper_base.rb → java_base.rb} +13 -12
  13. data/lib/zookeeper.rb +32 -244
  14. data/lib/zookeeper/acls.rb +17 -13
  15. data/lib/zookeeper/callbacks.rb +28 -11
  16. data/lib/zookeeper/client.rb +30 -0
  17. data/lib/zookeeper/client_methods.rb +241 -0
  18. data/lib/zookeeper/common.rb +13 -12
  19. data/lib/zookeeper/common/queue_with_pipe.rb +3 -7
  20. data/lib/zookeeper/compatibility.rb +135 -0
  21. data/lib/zookeeper/constants.rb +35 -1
  22. data/lib/zookeeper/em_client.rb +1 -1
  23. data/lib/zookeeper/exceptions.rb +117 -93
  24. data/lib/zookeeper/rake_tasks.rb +165 -0
  25. data/lib/zookeeper/stat.rb +16 -16
  26. data/lib/zookeeper/version.rb +2 -4
  27. data/scripts/upgrade-1.0-sed-alike.rb +46 -0
  28. data/spec/c_zookeeper_spec.rb +10 -9
  29. data/spec/chrooted_connection_spec.rb +2 -2
  30. data/spec/default_watcher_spec.rb +4 -4
  31. data/spec/em_spec.rb +1 -1
  32. data/spec/shared/connection_examples.rb +52 -37
  33. data/spec/spec_helper.rb +22 -84
  34. data/spec/support/00_spawn_zookeeper.rb +20 -0
  35. data/spec/support/zookeeper_spec_helpers.rb +84 -0
  36. data/spec/zookeeper_spec.rb +1 -1
  37. metadata +47 -34
  38. data/examples/cloud_config.rb +0 -125
  39. data/test/test_basic.rb +0 -37
  40. data/test/test_callback1.rb +0 -36
  41. data/test/test_close.rb +0 -16
  42. data/test/test_esoteric.rb +0 -7
  43. data/test/test_watcher1.rb +0 -56
  44. data/test/test_watcher2.rb +0 -52
@@ -0,0 +1 @@
1
+ rvm ruby-1.9.3@zookeeper --create
data/.gitignore CHANGED
@@ -8,3 +8,6 @@ pkg
8
8
  zookeeper.gemspec
9
9
  Gemfile.*
10
10
  tmp/
11
+ .rvmrc
12
+ .zkserver
13
+ coverage
@@ -0,0 +1,3 @@
1
+ [submodule "releaseops"]
2
+ path = releaseops
3
+ url = git://github.com/slyphon/releaseops.git
@@ -0,0 +1,22 @@
1
+ ---
2
+ notifications:
3
+ email:
4
+ - slyphon@gmail.com
5
+
6
+ # pull in releaseops submodule
7
+ before_install:
8
+ - git submodule update --init --recursive
9
+
10
+ env:
11
+ - SPAWN_ZOOKEEPER='true'
12
+
13
+ rvm:
14
+ - 1.9.3
15
+ - 1.9.2
16
+ - 1.8.7
17
+ - ree
18
+ - jruby-18mode
19
+ - jruby-19mode
20
+
21
+ bundler_args: --without development docs coverage
22
+
data/CHANGELOG CHANGED
@@ -1,9 +1,42 @@
1
- v0.9.4 Fix shutdown timing bug
1
+ v1.0.0 Single Zookeeper namespace
2
2
 
3
- * Because we now release the GIL, ruby may call close while there's still
4
- a pending synchronous call (since we give up the interpreter during that
5
- time). Protect calls with a mutex so that close can only be called when
6
- there isn't an in-flight call.
3
+ * The top level Zookeeper class is now a module, the former Zookeeper
4
+ class is now Zookeeper::Client
5
+
6
+ * Consolidate the 6 top-level namespaces into one, Zookeeper module
7
+
8
+ ZookeeperCommon -> Zookeeper::Common
9
+ ZookeeperCallbacks -> Zookeeper::Callbacks
10
+ ZookeeperConstants -> Zookeeper::Constants
11
+ ZookeeperExceptions -> Zookeeper::Exceptions
12
+ ZookeeperACLs -> Zookeeper::ACLs
13
+ CZookeeper -> Zookeeper::CZookeeper
14
+
15
+ * Added a 'zookeeper/compatibility' file that will define the old names
16
+ and look up the new constants for users, and print a warning telling them
17
+ the change has occurred and that they should update their code
18
+
19
+ * Added scripts/upgrade-1.0-sed-alike.rb which will basically do a
20
+ find-and-replace, changing the old names to the new names (worked on
21
+ both the Zookeeper and ZK codebases).
22
+
23
+ * Java and C now use different names for the base class, to avoid the
24
+ possibility of error. Java is now JavaBase, C remains ZookeeperBase.
25
+
26
+ * All client methods are defined in the ClientMethods module and mixed
27
+ into the constructed Client class.
28
+
29
+ * Fix all requires, no longer monkey with $LOAD_PATH, use require_relative
30
+
31
+ * Bugfix for C client.
32
+
33
+ Because we release the GIL, there's the possibilty that in the middle of a
34
+ synchronous C call, ruby will have switched thread contexts and one of
35
+ those threads will call close. It seems that during normal operation, this
36
+ is not a problem, but during shutdown, this causes CPU to spike to 100% and
37
+ a deadlock. This fix essentially wraps every call to the C layer in a
38
+ mutex. There may be a slightly less heavyweight optimization in the future,
39
+ but this is the safest option at the moment.
7
40
 
8
41
  v0.9.3 Event thread shutdown fix, Windows compatibility fix
9
42
 
data/Gemfile CHANGED
@@ -4,11 +4,28 @@ gemspec
4
4
 
5
5
  gem 'rake', '~> 0.9.0'
6
6
 
7
+ platform :mri_19 do
8
+ gem 'simplecov', :group => :coverage, :require => false
9
+ end
10
+
7
11
  group :test do
8
12
  gem "rspec", "~> 2.8.0"
9
- gem 'flexmock', '~> 0.8.11'
10
13
  gem 'eventmachine', '1.0.0.beta.4'
11
14
  gem 'evented-spec', '~> 0.9.0'
15
+
16
+ gem 'zk-server', '~> 1.0.0'
17
+ end
18
+
19
+ platform :mri_19 do
20
+ gem 'simplecov', :group => :coverage, :require => false
21
+ end
22
+
23
+ group :docs do
24
+ gem 'yard', '~> 0.8.0'
25
+
26
+ platform :mri_19 do
27
+ gem 'redcarpet'
28
+ end
12
29
  end
13
30
 
14
31
  group :development do
@@ -1,5 +1,7 @@
1
1
  # zookeeper #
2
2
 
3
+ [![Build Status](https://secure.travis-ci.org/slyphon/zookeeper.png?branch=master)](http://travis-ci.org/slyphon/zookeeper)
4
+
3
5
  An interface to the Zookeeper cluster coordination server.
4
6
 
5
7
  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).
data/Rakefile CHANGED
@@ -1,114 +1,70 @@
1
- # def gemset_name
2
- # ENV.fetch('GEM_HOME').split('@').last
3
- # end
4
-
5
- GEM_FILES = FileList['*zookeeper-*.gem']
6
-
7
- # need to releaase under both names until ZK is updated to use just 'zookeeper'
8
- GEM_NAMES = %w[zookeeper slyphon-zookeeper]
9
-
10
- namespace :mb do
11
- namespace :gems do
12
- task :build do
13
- GEM_NAMES.each do |gem_name|
14
- ENV['JAVA_GEM'] = nil
15
- sh "rvm 1.8.7 do env ZOOKEEPER_GEM_NAME='#{gem_name}' gem build zookeeper.gemspec"
16
- sh "rvm 1.8.7 do env JAVA_GEM=1 ZOOKEEPER_GEM_NAME='#{gem_name}' gem build zookeeper.gemspec"
17
- end
18
- end
1
+ release_ops_path = File.expand_path('../releaseops/lib', __FILE__)
19
2
 
20
- task :push => :build do
21
- raise "No gemfiles to push!" if GEM_FILES.empty?
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')
22
9
 
23
- GEM_FILES.each do |gem|
24
- sh "gem push #{gem}"
25
- end
26
- end
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])
27
12
 
28
- task :clean do
29
- rm_rf GEM_FILES
30
- end
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
31
16
 
32
- task :all => [:build, :push, :clean]
33
- end
34
- end
17
+ # Define a task to run code coverage tests
18
+ ReleaseOps::TestTasks.define_simplecov_tasks
35
19
 
36
- gemset_name = 'zookeeper'
20
+ # set up yard:server, yard:gems, and yard:clean tasks
21
+ # for doing documentation stuff
22
+ ReleaseOps::YardTasks.define
37
23
 
38
- # this nonsense w/ tmp and the Gemfile is a bundler optimization
24
+ task :clean => 'yard:clean'
39
25
 
40
- %w[1.8.7 1.9.2 jruby rbx 1.9.3].each do |ns_name|
41
- rvm_ruby = (ns_name == 'rbx') ? "rbx-2.0.testing" : ns_name
26
+ namespace :zk do
27
+ namespace :gems do
28
+ task :build do
29
+ require 'tmpdir'
42
30
 
43
- ruby_with_gemset = "#{rvm_ruby}@#{gemset_name}"
31
+ raise "You must specify a TAG" unless ENV['TAG']
44
32
 
45
- create_gemset_name = "mb:#{ns_name}:create_gemset"
46
- clobber_task_name = "mb:#{ns_name}:clobber"
47
- clean_task_name = "mb:#{ns_name}:clean"
48
- build_task_name = "mb:#{ns_name}:build"
49
- bundle_task_name = "mb:#{ns_name}:bundle_install"
50
- rspec_task_name = "mb:#{ns_name}:run_rspec"
33
+ ReleaseOps.with_tmpdir(:prefix => 'zookeeper') do |tmpdir|
34
+ tag = ENV['TAG']
51
35
 
52
- phony_gemfile_link_name = "Gemfile.#{ns_name}"
53
- phony_gemfile_lock_name = "#{phony_gemfile_link_name}.lock"
36
+ sh "git clone . #{tmpdir}"
54
37
 
55
- file phony_gemfile_link_name do
56
- # apparently, rake doesn't deal with symlinks intelligently :P
57
- ln_s('Gemfile', phony_gemfile_link_name) unless File.symlink?(phony_gemfile_link_name)
58
- end
38
+ orig_dir = Dir.getwd
59
39
 
60
- task :clean do
61
- rm_rf [phony_gemfile_lock_name, phony_gemfile_lock_name]
62
- end
40
+ cd tmpdir do
41
+ sh "git co #{tag} && git reset --hard && git clean -fdx"
63
42
 
64
- task create_gemset_name do
65
- sh "rvm #{rvm_ruby} do rvm gemset create #{gemset_name}"
66
- end
43
+ ENV['JAVA_GEM'] = nil
44
+ sh "rvm 1.8.7 do gem build zookeeper.gemspec"
45
+ sh "rvm 1.8.7 do env JAVA_GEM=1 gem build zookeeper.gemspec"
67
46
 
68
- task clobber_task_name do
69
- unless rvm_ruby == 'jruby'
70
- cd 'ext' do
71
- sh "rvm #{ruby_with_gemset} do bundle exec rake clobber"
47
+ mv FileList['*.gem'], orig_dir
48
+ end
49
+ end
72
50
  end
73
- end
74
- end
75
51
 
76
- task clean_task_name do
77
- unless rvm_ruby == 'jruby'
78
- cd 'ext' do
79
- sh "rvm #{ruby_with_gemset} do bundle exec rake clean"
80
- end
81
- end
82
- end
52
+ task :push => :build do
53
+ gems = FileList['*.gem']
54
+ raise "No gemfiles to push!" if gems.empty?
83
55
 
84
- task build_task_name => [create_gemset_name, clean_task_name] do
85
- unless rvm_ruby == 'jruby'
86
- cd 'ext' do
87
- sh "rvm #{ruby_with_gemset} do bundle exec rake build"
56
+ gems.each do |gem|
57
+ sh "gem push #{gem}"
58
+ end
88
59
  end
89
- end
90
- end
91
60
 
92
- task bundle_task_name => [phony_gemfile_link_name, build_task_name] do
93
- sh "rvm #{ruby_with_gemset} do bundle install --gemfile #{phony_gemfile_link_name}"
94
- end
95
-
96
- task rspec_task_name => bundle_task_name do
97
- sh "rvm #{ruby_with_gemset} do env BUNDLE_GEMFILE=#{phony_gemfile_link_name} bundle exec rspec spec --fail-fast"
98
- end
99
-
100
- task "mb:#{ns_name}" => rspec_task_name
101
-
102
- task "mb:test_all_rubies" => rspec_task_name
103
- end
61
+ task :clean do
62
+ rm_rf FileList['*.gem']
63
+ end
104
64
 
105
- task "mb:test_all" do
106
- require 'benchmark'
107
- t = Benchmark.realtime do
108
- Rake::Task['mb:test_all_rubies'].invoke
65
+ task :all => [:build, :push, :clean]
66
+ end
109
67
  end
110
-
111
- $stderr.puts "Test run took: #{t} s"
112
68
  end
113
69
 
114
70
  task :clobber do
@@ -142,23 +98,5 @@ task :build do
142
98
  end
143
99
  end
144
100
 
145
- namespace :spec do
146
- task :define do
147
- require 'rubygems'
148
- require 'bundler/setup'
149
- require 'rspec/core/rake_task'
150
-
151
- RSpec::Core::RakeTask.new('spec:runner') do |t|
152
- t.rspec_opts = '-f d' if ENV['TRAVIS']
153
- end
154
-
155
- task 'spec:runner' => :build
156
- end
157
-
158
- task :run => :define do
159
- Rake::Task['spec:runner'].invoke
160
- end
161
- end
162
-
163
- task :default => 'spec:run'
101
+ task 'spec:run' => 'build:clean' unless defined?(::JRUBY_VERSION)
164
102
 
@@ -1,12 +1,16 @@
1
- require 'zookeeper/constants'
2
- require File.expand_path('../zookeeper_c', __FILE__)
1
+ require_relative '../lib/zookeeper/common'
2
+ require_relative '../lib/zookeeper/constants'
3
+ require_relative 'zookeeper_c'
4
+
5
+ # require File.expand_path('../zookeeper_c', __FILE__)
3
6
 
4
7
  # TODO: see if we can get the destructor to handle thread/event queue teardown
5
8
  # when we're garbage collected
9
+ module Zookeeper
6
10
  class CZookeeper
7
- include ZookeeperCommon
8
- include ZookeeperConstants
9
- include ZookeeperExceptions
11
+ include Zookeeper::Common
12
+ include Zookeeper::Constants
13
+ include Zookeeper::Exceptions
10
14
 
11
15
  DEFAULT_SESSION_TIMEOUT_MSEC = 10000
12
16
 
@@ -209,4 +213,4 @@ class CZookeeper
209
213
  end
210
214
  end
211
215
  end
212
-
216
+ end
@@ -1,16 +1,18 @@
1
- require File.expand_path('../c_zookeeper', __FILE__)
1
+ # require File.expand_path('../c_zookeeper', __FILE__)
2
+
3
+ require_relative 'c_zookeeper'
2
4
  require 'forwardable'
3
5
 
4
6
  # The low-level wrapper-specific methods for the C lib
5
7
  # subclassed by the top-level Zookeeper class
8
+ module Zookeeper
6
9
  class ZookeeperBase
7
10
  extend Forwardable
8
- include ZookeeperCommon
9
- include ZookeeperCallbacks
10
- include ZookeeperConstants
11
- include ZookeeperExceptions
12
- include ZookeeperACLs
13
- include ZookeeperStat
11
+ include Zookeeper::Common # XXX: clean this up, no need to include *everything*
12
+ include Zookeeper::Callbacks
13
+ include Zookeeper::Constants
14
+ include Zookeeper::Exceptions
15
+ include Zookeeper::ACLs
14
16
 
15
17
  # @private
16
18
  class ClientShutdownException < StandardError; end
@@ -73,6 +75,10 @@ class ZookeeperBase
73
75
  end
74
76
 
75
77
  @mutex.synchronize do
78
+ # keep track of what process we were in to protect
79
+ # against reuse after fork()
80
+ @pid = Process.pid
81
+
76
82
  # flushes all outstanding watcher reqs.
77
83
  @watcher_reqs.clear
78
84
  set_default_global_watcher
@@ -115,8 +121,14 @@ class ZookeeperBase
115
121
  # if either of these happen, the user will need to renegotiate a connection via reopen
116
122
  def assert_open
117
123
  @mutex.synchronize do
118
- raise ZookeeperException::SessionExpired if state == ZOO_EXPIRED_SESSION_STATE
119
- raise ZookeeperException::NotConnected unless connected?
124
+ raise Exceptions::SessionExpired if state == ZOO_EXPIRED_SESSION_STATE
125
+ raise Exceptions::NotConnected unless connected?
126
+ unless Process.pid == @pid
127
+ raise InheritedConnectionError, <<-EOS.gsub(/(?:^|\n)\s*/, ' ').strip
128
+ You tried to use a connection inherited from another process [#{@pid}]
129
+ You need to call reopen() after forking
130
+ EOS
131
+ end
120
132
  end
121
133
  end
122
134
 
@@ -195,7 +207,7 @@ protected
195
207
  end
196
208
  end
197
209
 
198
- # pass this along to the ZookeeperCommon implementation
210
+ # pass this along to the Zookeeper::Common implementation
199
211
  super(req_id, meth_name, call_opts)
200
212
  end
201
213
 
@@ -229,4 +241,4 @@ protected
229
241
  @chroot_path
230
242
  end
231
243
  end
232
-
244
+ end
@@ -26,7 +26,9 @@
26
26
  #include "zkrb_wrapper.h"
27
27
  #include "dbg.h"
28
28
 
29
- static VALUE Zookeeper = Qnil;
29
+
30
+ static VALUE mZookeeper = Qnil; // the Zookeeper module
31
+ static VALUE CZookeeper = Qnil; // the Zookeeper::CZookeeper class
30
32
  static VALUE ZookeeperClientId = Qnil;
31
33
 
32
34
  // slyphon: possibly add a lock to this for synchronizing during get_next_event
@@ -160,7 +162,7 @@ static VALUE method_zkrb_init(int argc, VALUE* argv, VALUE self) {
160
162
 
161
163
  VALUE data;
162
164
  struct zkrb_instance_data *zk_local_ctx;
163
- data = Data_Make_Struct(Zookeeper, struct zkrb_instance_data, 0, free_zkrb_instance_data, zk_local_ctx);
165
+ data = Data_Make_Struct(CZookeeper, struct zkrb_instance_data, 0, free_zkrb_instance_data, zk_local_ctx);
164
166
  zk_local_ctx->queue = zkrb_queue_alloc();
165
167
 
166
168
  if (zk_local_ctx->queue == NULL)
@@ -654,9 +656,9 @@ static VALUE method_zerror(VALUE self, VALUE errc) {
654
656
 
655
657
  static void zkrb_define_methods(void) {
656
658
  #define DEFINE_METHOD(method, args) { \
657
- rb_define_method(Zookeeper, #method, method_ ## method, args); }
659
+ rb_define_method(CZookeeper, #method, method_ ## method, args); }
658
660
  #define DEFINE_CLASS_METHOD(method, args) { \
659
- rb_define_singleton_method(Zookeeper, #method, method_ ## method, args); }
661
+ rb_define_singleton_method(CZookeeper, #method, method_ ## method, args); }
660
662
 
661
663
  // the number after the method name should be actual arity of C function - 1
662
664
  DEFINE_METHOD(zkrb_init, -1);
@@ -686,10 +688,10 @@ static void zkrb_define_methods(void) {
686
688
  // Make these class methods?
687
689
  DEFINE_METHOD(zerror, 1);
688
690
 
689
- rb_define_singleton_method(Zookeeper, "set_zkrb_debug_level", klass_method_zkrb_set_debug_level, 1);
691
+ rb_define_singleton_method(CZookeeper, "set_zkrb_debug_level", klass_method_zkrb_set_debug_level, 1);
690
692
 
691
- rb_attr(Zookeeper, rb_intern("selectable_io"), 1, 0, Qtrue);
692
- rb_define_method(Zookeeper, "wake_event_loop!", method_wake_event_loop_bang, 0);
693
+ rb_attr(CZookeeper, rb_intern("selectable_io"), 1, 0, Qtrue);
694
+ rb_define_method(CZookeeper, "wake_event_loop!", method_wake_event_loop_bang, 0);
693
695
 
694
696
  }
695
697
 
@@ -712,11 +714,13 @@ static VALUE zkrb_client_id_method_initialize(VALUE self) {
712
714
  void Init_zookeeper_c() {
713
715
  ZKRBDebugging = 0;
714
716
 
715
- /* initialize Zookeeper class */
716
- Zookeeper = rb_define_class("CZookeeper", rb_cObject);
717
+ mZookeeper = rb_define_module("Zookeeper");
718
+
719
+ /* initialize CZookeeper class */
720
+ CZookeeper = rb_define_class_under(mZookeeper, "CZookeeper", rb_cObject);
717
721
  zkrb_define_methods();
718
722
 
719
- ZookeeperClientId = rb_define_class_under(Zookeeper, "ClientId", rb_cObject);
723
+ ZookeeperClientId = rb_define_class_under(CZookeeper, "ClientId", rb_cObject);
720
724
  rb_define_method(ZookeeperClientId, "initialize", zkrb_client_id_method_initialize, 0);
721
725
  rb_define_attr(ZookeeperClientId, "session_id", 1, 1);
722
726
  rb_define_attr(ZookeeperClientId, "passwd", 1, 1);