zookeeper 0.9.4 → 1.0.0.beta.1

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 (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);